現狀
目前主流有兩個外掛,flutter_webview_plugin
和 webview_flutter
。
flutter_webview_plugin
是一個第三方外掛,文件會比較全,star
數也最多。但是使用過程中有兩個主要問題:
- 不能在JS中呼叫Flutter方法
- 不能在H5進入某個URL之前攔截
所以本文使用官方的 webview_flutter,目前還在預覽版,期待更多的功能
安裝外掛
pubspec.yaml
dependencies
增加 webview_flutter: ^0.3.13
,有最新的使用最新版本,
dependencies:
webview_flutter: ^0.3.13
複製程式碼
info.list
路徑:ios/Runner/info.list
,新增配置:
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
複製程式碼
使用
引數一覽
引數名 | 型別 | 預設值 | 說明 |
---|---|---|---|
initialUrl | String | '' | |
onWebViewCreated | Function | WebView建立完成時呼叫 | |
javascriptMode | JavascriptMode | JavascriptMode.disabled | JS執行模式 預設是不呼叫 |
javascriptChannels | Set | 使用javascriptChannel JS可以呼叫Flutter | |
navigationDelegate | Function | 攔截請求 | |
onPageFinished | Function | 頁面載入完成呼叫 | |
gestureRecognizers | Set | 手勢 |
場景
最簡單的地載入一條url
WebView(
initialUrl: "https://flutterchina.club/",
//JS執行模式 是否允許JS執行
javascriptMode: JavascriptMode.unrestricted
)
複製程式碼
h5 呼叫 flutter -- JavascriptChannel
// 往h5 window 裡面插入全域性方法 Toaster
JavascriptChannel _toastJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toaster',
onMessageReceived: (JavascriptMessage message) {
print(message);
Fluttertoast.showToast(
msg: message.message
);
});
}
// 往 Webview 元件註冊 javascriptChannels
new WebView(
...
javascriptChannels: <JavascriptChannel>[ //javascriptChannels這個是api提供的互調的方法,
_toastJavascriptChannel(context),
].toSet()
)
// js 呼叫
Toaster.postMessage('js call flutter success!!')
複製程式碼
h5 呼叫 flutter -- navigationDelegate
new WebView(
...
navigationDelegate: (NavigationRequest request) {
// print('navigationDelegate: ${request.url}');
if(request.url.indexOf('m=webview') > -1) {
String _url = helper.addUrlParam(request.url.replaceAll('&m=webview', ''));
Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
return Browser(
title: ' ',
url: _url
);
}));
return NavigationDecision.prevent;
}
)
複製程式碼
flutter 呼叫 h5
// 在頁面載入完畢,修改 Webview 的標題
new WebView(
...
onPageFinished: (url) {
// 設定標題
_controller.evaluateJavascript("document.title").then((result){
print(result);
setState(() {
widget.title = result;
});
});
},
)
複製程式碼
完整元件
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:fluttertoast/fluttertoast.dart';
import '../helper/index.dart' as helper;
class Browser extends StatefulWidget {
String url;
String title;
Browser({this.url, this.title});
@override
_BrowserState createState() => _BrowserState();
}
class _BrowserState extends State<Browser> {
dynamic _controller;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
JavascriptChannel _toastJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toaster',
onMessageReceived: (JavascriptMessage message) {
print(message);
Fluttertoast.showToast(
msg: message.message
);
});
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stack(
children: <Widget>[
new WebView(
initialUrl: widget.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) {
_controller = controller;
},
/**
* 當 url 帶有 'm=webview',則開啟新的webview
*/
navigationDelegate: (NavigationRequest request) {
// print('navigationDelegate: ${request.url}');
if(request.url.indexOf('m=webview') > -1) {
String _url = helper.addUrlParam(request.url.replaceAll('&m=webview', ''));
Navigator.of(context).push(new MaterialPageRoute(builder: (_) {
return Browser(
title: ' ',
url: _url
);
}));
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
onPageFinished: (url) {
// 設定標題
_controller.evaluateJavascript("document.title").then((result){
print(result);
setState(() {
widget.title = result;
});
});
// var a = '123';
// print(a+1);
// 測試flutter 呼叫我頁面的方法
// _controller.evaluateJavascript("callJSFunc();").then((result){
// // print('callJSFunc has called: $result');
// });
},
javascriptChannels: <JavascriptChannel>[ //javascriptChannels這個是api提供的互調的方法,
_toastJavascriptChannel(context),
].toSet()
)
],
),
);
}
}
複製程式碼
todo
- 接入cordova
- 獲取裝置的網路狀態