簡介
在移動應用開發中,經常會遇到加載網頁的需求,打開網頁通常有兩種方式,即在應用內使用內置的組件打開和使用系統自帶的瀏覽器打開。不過,在Flutter應用開發中,由於官方並沒有提供類似Webview的網頁加載組件,所以如果項目中涉及網頁加載需要使用第三方插件庫,如webview_flutter、flutter_webview_plugin等。
其中,webview_flutter是Flutter官方開發和維護的網頁加載插件庫,而flutter_webview_plugin則是Flutter開源社區推出的網頁加載插件。兩個插件功能都差不多,都支持加載本地html文本、Flutter調用js以及js調用Flutter等,但是我建議使用官方推出的插件,因為它會持續的跟進已知的問題。
和其他Flutter插件的使用方式一樣,使用webview_flutter之前需要先在pubspec.yaml文件中添加依賴腳本,如下所示。
dependencies: webview_flutter: ^0.3.22+1
然后,我們使用flutter packages get命令將webview_flutter插件拉取到本地后,就可以使用它進行網頁加載開發了。
vi設計http://www.maiqicn.com 辦公資源網站大全https://www.wode007.com
基本使用
如下所示,是WebView組件的構造函數。
WebView({
Key key,
this.onWebViewCreated, //WebView創建完成之后的回調 this.initialUrl, // 初始化 URL this.JavaScriptMode = JavaScriptMode.disabled, //JS執行模式,默認是不調用 this.javascriptChannels, // JS可以調用Flutter 的通道 this.navigationDelegate, // 路由委托,可以使用它執行攔截操作 this.gestureRecognizers, // 手勢相關 this.onPageStarted, //開始加載頁面回調 this.onPageFinished, // 頁面加載完成的回調 this.onWebResourceError, //資源加載失敗回調 this.debuggingEnabled = false, this.gestureNavigationEnabled = false, this.userAgent, this.initialMediaPlaybackPolicy = AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, })
使用時,只需要按照參數傳遞對應的值即可。不過,在實際使用前,為了方便使用,我們一般會對它進行二次封裝,主要是界面和功能的封裝。下面是我封裝的一個可以加載本地和網絡文件的WebViewPage。
class WebViewPage extends StatefulWidget { String url; final String title; final bool isLocalUrl; WebViewController _webViewController; WebViewPage({this.url, this.isLocalUrl = false, this.title}); @override _WebViewPage createState() => _WebViewPage(); } class _WebViewPage extends State<WebViewPage> { JavascriptChannel jsBridge(BuildContext context) => JavascriptChannel( name: 'jsbridge', // 與h5 端的一致 不然收不到消息 onMessageReceived: (JavascriptMessage message) async{ debugPrint(message.message); }); @override Widget build(BuildContext context) { return Scaffold( appBar: _buildAppbar(), body: _buildBody() ); } _buildAppbar() { return AppBar( elevation: 0, backgroundColor: Color(0xccd0d7), title: Text(widget.title, style: TextStyle(color: Colors.black),), centerTitle: true, leading: IconButton(icon: Icon(Icons.arrow_back, color: Color(0xFF23ADE5),), onPressed: () { }) ); } _buildBody() { return Column( children: <Widget>[ SizedBox( height: 1, width: double.infinity, child: const DecoratedBox(decoration: BoxDecoration(color: Color(0xFFEEEEEE))), ), Expanded( flex: 1, child: WebView( initialUrl: widget.isLocalUrl ? Uri.dataFromString(widget.url, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')) .toString(): widget.url, javascriptMode: JavascriptMode.unrestricted, javascriptChannels: <JavascriptChannel>[ jsBridge(context) ].toSet(), onWebViewCreated: (WebViewController controller){ widget._webViewController = controller; if(widget.isLocalUrl){ _loadHtmlAssets(controller); }else{ controller.loadUrl(widget.url); } controller.canGoBack().then((value) => debugPrint(value.toString())); controller.canGoForward().then((value) => debugPrint(value.toString())); controller.currentUrl().then((value) => debugPrint(value)); }, onPageFinished: (String value){ widget._webViewController.evaluateJavascript('document.title') .then((title) => debugPrint(title)); }, ), ) ], ); } //加載本地文件 _loadHtmlAssets(WebViewController controller) async { String htmlPath = await rootBundle.loadString(widget.url); controller.loadUrl(Uri.dataFromString(htmlPath,mimeType: 'text/html', encoding: Encoding.getByName('utf-8')) .toString()); } }
使用時,只需要按照傳入對應的屬性即可。需要說明的是,加載本地Html文件時,需要在pubspec.yaml文件中申明這個Html文件,如下所示。
flutter:
// ... assets: - assets/real_data_help.html
然后,我們使用封裝的組件即可加載本地的Html文件。例如:
class MyApp extends StatelessWidget { String localUrl = 'assets/real_data_help.html'; @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home:WebViewPage(url:localUrl, isLocalUrl: true, title: '加載本地文件'), ); } }
