FlutterWebViewPlugin
简述
在之前对比Flutter和安卓的时候,发现Flutter并没有webview类似的控件,于是一直就在思考要是想在Flutter里面去加载网页应该怎么做呢?流程应该是这样子的,首先一个flutter项目,主入口肯定是dart文件,但是因为flutter没有webview可用来加载网页,所以需要调用安卓原生的webview来加载。这个过程中需要一个plugin来通信。
原生部分
首先创建一个FlutterPlugin项目,然后在这里写上dart。再然后打开android文件夹,在这里面写上java。然后就完成了。
好了,不扯淡了。说正经的。首先创建一个Flutter Plugin的项目,
创建好之后在android文件夹下面会有一个FlutterWebviewPlugin(这个是你创建的module名)的java文件。打开是这样子的。
/** FlutterWebviewPlugin */
public class FlutterWebviewPlugin implements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_webview_plugin");
channel.setMethodCallHandler(new FlutterWebviewPlugin());
}
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else {
result.notImplemented();
}
}
}
registerWith是注册插件的方法,一般情况下不要去动他。创建一个构造器,放到setMethodCallHandler(xxx)里面就算是注册成功了。因为这个文件里面主要是实现原生的webview的加载方法,应该都比较熟悉,所以就直接上代码了。
构造器里面的初始代码:
@TargetApi(Build.VERSION_CODES.ECLAIR_MR1)
public FlutterWebviewPlugin(Activity activity) {
this.mContext = activity;
vWebView = new WebView(activity);
vWebView.getSettings().setJavaScriptEnabled(true);
vWebView.getSettings().setLoadWithOverviewMode(true);
vWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
vWebView.getSettings().setLoadsImagesAutomatically(true);
vWebView.getSettings().setUseWideViewPort(true);
vWebView.getSettings().setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
vWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
}
然后还剩下一个onMethodCall的方法,这个方法就是通信的主要方法。在这里就是dart来通过这个方法,调用java的webview去加载所需要加载的url地址。这里call.method可以自己定义,随便定义成什么都行,也可以定义多个。
@Override
public void onMethodCall(MethodCall call, Result result) {
this.result = result;
switch (call.method) {
case "loadWeb":
FrameLayout.LayoutParams params = setupParamsFromFlutter(call);
LinearLayout linearLayout = new LinearLayout(mContext);
linearLayout.setOrientation(LinearLayout.VERTICAL);
final TextView titleView = new TextView(mContext);
titleView.setTextColor(Color.parseColor("#00000000"));
ViewGroup.LayoutParams titleViewParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
titleView.setLayoutParams(titleViewParams);
titleView.setText("FlutterWebView");
titleView.setGravity(Gravity.CENTER);
linearLayout.addView(titleView);
linearLayout.addView(vWebView);
mContext.addContentView(linearLayout, params);
vWebView.setWebViewClient(new MyWebViewClient(mContext, (title, isError) -> titleView.setText(title)));
vWebView.loadUrl(call.argument("url").toString());
break;
}
}
这里就是创建了一些布局文件,一个标题和一个加载url的webview。都是些常规操作。要说明一点的是,你可能要问我,为什么不在xml里面去写。我当时也是这个想法,context都有了,我写在xml里面再inflate一下不就行了。于是我找了下,结果发现我没有找到可以写布局文件的文件夹。创建的flutter工程里面是没有res这个东西的。因为dart文件的布局是写在dart文件里面的。
Dart部分
打开lib文件夹,里面有个创建好的文件flutter_webview_plugin.dart。
class FlutterWebviewPlugin {
static const MethodChannel _channel = const MethodChannel('flutter_webview_plugin');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}
在这里写plugin加载的方法
//声明plugin加载的方法在这里就是launch
//url参数要加载的地址,callback回调,
//可选参数Rect(控制)plugin的大小
Future<Null> launch(
String url,
Function callback, {
Rect rect,
}) async {
Map<String, dynamic> 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);
}
}
然后是main.dart部分,也是就是主要的执行文件,首先我们没有对象,得new一个对象,和java类似,final flutterWebviewPlugin= new FlutterWebviewPlugin();这个名字就是我们上面定义好的插件的名字,拿到对象之后接下来的操作就是调用他里面声明的方法,这一步操作跟java很类似,只是语言是用dart而已。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_plugin/webview_plugin.dart';
//主入口MyApp
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 WebView Demo'),
);
}
}
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<MyHomePage> {
StreamSubscription<String> _back;
var title = "flutter_webview_plugin";
//webview插件
final flutterWebviewPlugin= new FlutterWebviewPlugin()
@override
Widget build(BuildContext context) {
return new Scaffold(body: new Center(
//按钮点击事件
child: new RaisedButton(onPressed: () {
//拿到flutterwebviewplugin对象,调用他里面的launch方法(我们之前声明过的)
flutterWebviewPlugin.launch(
//对应launch方法里面的参数
"https://www.baidu.com/",
(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();
}
}
然后运行上面这个文件,就大功告成啦~