本文实现flutter代码调用Android原生Webview(本文比较长)

1.新建一个Flutter项目

2.在项目根目录下右键new>module>flutter plugin

3.自动生成如下图所示项目结构

其中webview_plugin就是我们新建的WebView插件,名字可以自由命名。

展开webview_plugin文件夹的结构如下:

我们目前只关注Android的,所以我们只需要在android文件下写,其他不变,android文件下有个WebviewPlugin.java文件,以下是我修改完的代码:

/** * WebviewPlugin */public class WebviewPlugin implements MethodCallHandler {    private Activity activity;    private WebView webView;    private Result result;    /**     * Plugin registration.     */    public static void registerWith(Registrar registrar) {        final MethodChannel channel = new MethodChannel(registrar.messenger(), "webview_plugin");        channel.setMethodCallHandler(new WebviewPlugin(registrar.activity()));    }    @TargetApi(Build.VERSION_CODES.ECLAIR_MR1)    public WebviewPlugin(Activity activity) {        this.activity = activity;        webView=new WebView(activity);        webView.getSettings().setJavaScriptEnabled(true);        webView.getSettings().setLoadWithOverviewMode(true);        webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);        webView.getSettings().setLoadsImagesAutomatically(true);// 加载网页中的图片        webView.getSettings().setUseWideViewPort(true); //设置使用视图的宽端口        webView.getSettings().setAllowFileAccess(true);// 可以读取文件缓存(manifest生效)        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {         webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);        }    }    @Override    public void onMethodCall(MethodCall call, Result result) {        this.result=result;        switch (call.method) {            case "load":                FrameLayout.LayoutParams params = buildLayoutParams(call);                LinearLayout linearLayout=new LinearLayout(activity);                linearLayout.setOrientation(LinearLayout.VERTICAL);                final TextView titleView=new TextView(activity);                titleView.setSingleLine(true);                titleView.setEllipsize(TextUtils.TruncateAt.END);                titleView.setTextColor(Color.parseColor("#FFFFFF"));              titleView.setPadding(dp2px(activity,10),dp2px(activity,20),dp2px(activity,10),0);                ViewGroup.LayoutParams titleViewParams= new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);                titleView.setLayoutParams(titleViewParams);                titleView.setText("我是标题");                titleView.setGravity(Gravity.CENTER);                ViewGroup.LayoutParams layoutParams= new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,dp2px(activity,70));                titleView.setLayoutParams(layoutParams);                titleView.setBackgroundColor(Color.parseColor("#4876FF"));                linearLayout.addView(titleView);                linearLayout.addView(webView);                activity.addContentView(linearLayout, params);                webView.setWebViewClient(new MyWebViewClient(activity, (title, isError) -> titleView.setText(title)));                webView.loadUrl(call.argument("url").toString());                break;        }    }    public class MyWebViewClient extends WebViewClient {        private final WebClientLoadListener loadListener;        Activity activity;        private boolean isError;        public MyWebViewClient(Activity activity, WebClientLoadListener loadListener) {            this.activity = activity;            this.loadListener = loadListener;        }        @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            return super.shouldOverrideUrlLoading(view, url);        }        @Override        public void onPageStarted(WebView view, String url, Bitmap favicon) {            super.onPageStarted(view, url, favicon);            isError = false;        }        @Override        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {            super.onReceivedError(view, request, error);            isError = true;        }        /**         * 界面加载完后回调         *         * @param view         * @param url         */        @Override        public void onPageFinished(WebView view, String url) {            String title = view.getTitle(); // 获取网页标题            loadListener.loadFinished(title, isError);            super.onPageFinished(view, url);        }    }    public interface WebClientLoadListener {        void loadFinished(String title, boolean isError);    }    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)    private FrameLayout.LayoutParams buildLayoutParams(MethodCall call) {        Map rc = call.argument("rect");        FrameLayout.LayoutParams params;        if (rc != null) {            params = new FrameLayout.LayoutParams(                    dp2px(activity, rc.get("width").intValue()), dp2px(activity, rc.get("height").intValue()));            params.setMargins(dp2px(activity, rc.get("left").intValue()), dp2px(activity, rc.get("top").intValue()),                    0, 0);        } else {            Display display = activity.getWindowManager().getDefaultDisplay();            Point size = new Point();            display.getSize(size);            int width = size.x;            int height = size.y;            params = new FrameLayout.LayoutParams(width, height);        }        return params;    }    private int dp2px(Context context, float dp) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dp * scale + 0.5f);    }}

其中registerWith(Registrar registrar)就是注册插件的方法,这个不用改

   public static void registerWith(Registrar registrar) {        final MethodChannel channel = new MethodChannel(registrar.messenger(), "webview_plugin");        channel.setMethodCallHandler(new WebviewPlugin(registrar.activity()));    }

最主要的是onMethodCall(MethodCall call, Result result)方法,以下call.method是约定的方法名,外面通过此方法与原生的进行通讯,在此plugin里我只约定了“load”这个方法,其他方法照写,我这个plugin比较简单,就一个LinnearLayout里包含一个Textview(标题)和WebView,详情代码见如下,最后执行activity.addContentView(linearLayout, params)来实现创建布局。

    @Override    public void onMethodCall(MethodCall call, Result result) {        this.result=result;        switch (call.method) {            case "load":                FrameLayout.LayoutParams params = buildLayoutParams(call);                LinearLayout linearLayout=new LinearLayout(activity);                linearLayout.setOrientation(LinearLayout.VERTICAL);                final TextView titleView=new TextView(activity);                titleView.setSingleLine(true);                titleView.setEllipsize(TextUtils.TruncateAt.END);                titleView.setTextColor(Color.parseColor("#FFFFFF"));                titleView.setPadding(dp2px(activity,10),dp2px(activity,20),dp2px(activity,10),0);                ViewGroup.LayoutParams titleViewParams= new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);                titleView.setLayoutParams(titleViewParams);                titleView.setText("我是标题");                titleView.setGravity(Gravity.CENTER);                ViewGroup.LayoutParams layoutParams= new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,dp2px(activity,70));                titleView.setLayoutParams(layoutParams);                titleView.setBackgroundColor(Color.parseColor("#4876FF"));                linearLayout.addView(titleView);                linearLayout.addView(webView);                activity.addContentView(linearLayout, params);                webView.setWebViewClient(new MyWebViewClient(activity, (title, isError) -> titleView.setText(title)));                webView.loadUrl(call.argument("url").toString());                break;        }    }

接下来就是写plugin包下的的WebviewPlugin.dart文件,这个文件才是相当于一个桥梁,连接着我们的Android代码,也提供了供flutter代码调用的方法,以下我们只声明了一个 launch(String url,Function callback, { Rect rect,}) 方法,url和callback(相当于java中的接口)和可选参数Rect(设置plugin的位置和大小),完成这几个文件,我们就基本完成了Plugin的构建了。

import 'dart:async';import 'dart:ui';import 'package:flutter/services.dart';class WebviewPlugin {  static const MethodChannel _channel = const MethodChannel('webview_plugin');  static Future get platformVersion async {    final String version = await _channel.invokeMethod('getPlatformVersion');    return version;  }  //声明plugin加载的方法,参数为url,callback回调,和可选参数Rect(控制)plugin的大小  Future launch(    String url,    Function callback, {    Rect rect,  }) async {    Map args = {      "url": url,    };    if (rect != null) {      args["rect"] = {        "left": rect.left,        "top": rect.top,        "width": rect.width,        "height": rect.height      };    }    final String result = await _channel.invokeMethod('load', args);    if (callback != null) {      callback(result);    }  }}

下面我们开始来示范如何调用我们完成的了的这个webview_plugin,以下看我们主项目中lib文件夹下的main.dart的代码

首先声明final flutterWebviewPlugin = new WebviewPlugin();

然后点击事件触发以下flutterWebviewPlugin.launch方法,参数依次是url,callbacl和Rect

flutterWebviewPlugin.launch( "https://blog.csdn.net/qq_16247851/article/details/81210771", (data) { setState(() { title = data; }); },rect: new Rect.fromLTWH(0.0, 0.0, MediaQuery.of(context).size.width, MediaQuery.of(context).size.height));
import 'dart:async';import 'package:flutter/material.dart';import 'package:webview_plugin/webview_plugin.dart';void main() => runApp(new MyApp());class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return new MaterialApp(      title: 'Webview',      theme: new ThemeData(        primarySwatch: Colors.blue,      ),      home: new MyHomePage(title: 'Flutter Demo Home Page'),    );  }}class MyHomePage extends StatefulWidget {  MyHomePage({Key key, this.title}) : super(key: key);  final String title;  @override  _MyHomePageState createState() => new _MyHomePageState();  @override  initState() {}}class _MyHomePageState extends State {  StreamSubscription _back;  var title = "demo";  final flutterWebviewPlugin = new WebviewPlugin();  @override  Widget build(BuildContext context) {    return new Scaffold(body: new Center(      child: new RaisedButton(onPressed: () {        flutterWebviewPlugin.launch(            "https://blog.csdn.net/qq_16247851/article/details/81210771",            (data) {          setState(() {            title = data;          });        },            rect: new Rect.fromLTWH(0.0, 0.0, MediaQuery.of(context).size.width,                MediaQuery.of(context).size.height));      }),    ));  }  @override  void initState() {    // TODO: implement initState    super.initState();  }}

这样下来整个项目基本完成了,效果图如下(蓝色部分为头部,内容为网页的title,下面部分是webview):

更多相关文章

  1. Android(安卓)Context简介
  2. 手把手教你打造一个Material Design风格的App(一)
  3. Android中关于SQLite数据库的一些知识
  4. Android超精准计步器开发-Dylan计步
  5. Android(安卓)Activity生命周期
  6. 详细讲解Android(安卓)View的绘制流程
  7. android edittext 设置只允许输入整数,(设置输入类型)
  8. 如何加快Android(安卓)Studio 编译app 的速度
  9. PreferenceActivity-Android的设置界面

随机推荐

  1. android 利用广播实现程序的强制退出
  2. android 平台的RNDIS功能
  3. 关于activity之间及activity与baseAdapte
  4. MSM7627的内存分布图
  5. Android如何缩放应用中的字体大小
  6. 【Android】intent-filter里data匹配分析
  7. [置顶] android MultiDex multide
  8. 通过ViewPager实现类似微信的页面切换(Fra
  9. android获取本地视频路径
  10. Android-SDK-Manager 不能更新最有效的解