webview_flutter 遠程或本地網(wǎng)頁JaveScript與futter 交互

完整實例代碼 Gitee

flutter dependencies

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^0.3.15+1
  fluttertoast: ^3.1.3
class _ComponentWebviewState extends State<ComponentWebview> {
  bool _loading = false;
  WebViewController _webViewController;
  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    //加載  遠程網(wǎng)頁 OR 本地網(wǎng)頁
    var isRemote = widget.url.contains('http');
    return Stack(
      children: <Widget>[
        Scaffold(
          body: isRemote ? loadRemoteUrl() : loadAssetsUrl(),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              _webViewController
                  ?.evaluateJavascript(
                      'customeFunc("Flutter 調(diào)用 JS Time: ${DateTime.now().toUtc()}")')
                  ?.then((result) {
                // You can handle JS result here.
                print("customeFunc" + result);
              });
            },
            child: Text('調(diào)用JS'),
          ),
        ),
        //加載網(wǎng)頁提示
        uiLoading()
      ],
    );
  }
  Widget uiLoading() {
    if (_loading)
      return Center(child:CircularProgressIndicator()) ;//Center(child: Icon(Icons.play_circle_filled));
    else
      return Container(height: 0.0, width: 0.0);
  }
  // 定義 網(wǎng)頁中能夠調(diào)用的 Flutter 方法
  JavascriptChannel jsChannelShowToast(BuildContext context) {
    return JavascriptChannel(
        name: 'flutterShowToast',
        onMessageReceived: (JavascriptMessage message) {
          Fluttertoast.showToast(
              msg: message.message,
              toastLength: Toast.LENGTH_SHORT,
              gravity: ToastGravity.CENTER,
              timeInSecForIos: 1,
              backgroundColor: Colors.red,
              textColor: Colors.white,
              fontSize: 16.0);
        });
  }
  ///JS和Flutter通信的Channel译红;
  /// js 調(diào)用 flutter 方法
  List<JavascriptChannel> _getWebViewJavascriptChannels() {
    return <JavascriptChannel>[
      jsChannelShowToast(context),
    ];
  }
  _navigationDelegateHandle(NavigationRequest request) {
    print('request.url =======> : ${request.url}');
    //路由委托(可以通過在此處攔截url實現(xiàn)JS調(diào)用Flutter部分);
    ///通過攔截url來實現(xiàn)js與flutter交互
    if (request.url.toLowerCase().startsWith('webviewflutterurl://')) {
      // Fluttertoast.showToast(msg:'JS調(diào)用了Flutter By navigationDelegate');
      print('blocking navigation to $request}');
      return NavigationDecision.prevent;
      ///阻止路由替換,不能跳轉(zhuǎn)裕照,因為這是js交互給我們發(fā)送的消息
    }
    return NavigationDecision.navigate;
    //允許路由替換
  }
  ///頁面加載完成處理
  _onPageFinished(String url) async {
    // 獲取當前加載頁面的 title
    String title = await _webViewController.getTitle();
    widget.titleChandge(title);
    setState(() {
      _loading = false;
    });
    print('Page finished url ====> : $url');
    //添加一些 webview 初始化數(shù)據(jù)
    var jsonData = {'platform': Platform.isAndroid ? 'android' : 'ios'};
    var jsonDataString = jsonEncode(jsonData);
    print(jsonDataString);
    //通知網(wǎng)頁服務器加載完成并觸發(fā)加載完成事件
    _webViewController
        ?.evaluateJavascript(
            'triggerEventWebViewFlutterJSBridgeReady($jsonDataString)')
        ?.then((result) {
      print(result);
    });
  }
}

Remote 網(wǎng)頁

  ///加載 遠程 html
  Widget loadRemoteUrl() {
    return WebView(
        initialUrl: widget.url,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          setState(() { _loading = true; }); 
          _webViewController = webViewController;
        },
        javascriptChannels: _getWebViewJavascriptChannels().toSet(),
        navigationDelegate: (request) => _navigationDelegateHandle(request),
        onPageFinished: (url) => _onPageFinished(url));
  }

localhost 網(wǎng)頁

需要引入

import 'dart:io';
import 'package:flutter/services.dart';
 
  ///加載 本地 html
  Widget loadAssetsUrl() {
    return FutureBuilder(
        future: _loadHtmlFile(),
        builder: (context, snapshot) => WebView(
            initialUrl: Uri.dataFromString(snapshot.data, mimeType: 'text/html',  encoding: Encoding.getByName('utf-8')) .toString(),
            javascriptMode: JavascriptMode.unrestricted,
            onWebViewCreated: (WebViewController webViewController) {
              setState(() { _loading = true; });
              _webViewController = webViewController;
            },
            javascriptChannels: _getWebViewJavascriptChannels().toSet(),
            navigationDelegate: (request) => _navigationDelegateHandle(request),
            onPageFinished: (url) => _onPageFinished(url)));
  }
  /// 加載本地 HTML 文件
  Future<String> _loadHtmlFile() async {
    return await rootBundle.loadString(widget.url);
  }

網(wǎng)頁部分

<section style="text-align: center;">
        <div id="content"> </div>
        <button id="btnFlutterFunc">jquery調(diào)用Flutter</button> <hr>
        <button onclick="showToast()">原生Js調(diào)用Flutter</button> <hr>
        <a href="webviewflutterurl://fff?p1=123&p2=321">連接攔截 GO ==> :webviewflutterurl://fff?p1=123&p2=321</a>
    </section>
    <script type="text/javascript" src="./jquery.min.js"></script>
    <script type="text/javascript">
        function showToast(message) {
            flutterShowToast.postMessage(message || "JS調(diào)用了Flutter");
        }
        // 首先需要提前定義好事件鸯屿,并且注冊相關的EventListener
        var eventWebViewFlutterJSBridgeReady = new CustomEvent('webViewFlutterJSBridgeReady', {
            detail: { 
                //平臺 android OR ios
                platform: '' 
            },
        });
        function triggerEventWebViewFlutterJSBridgeReady(jsonData) {
            console.log(JSON.stringify(jsonData))
            setTimeout(function () {
                eventWebViewFlutterJSBridgeReady.detail.platform = jsonData.platform
                if (window.dispatchEvent)
                    window.dispatchEvent(eventWebViewFlutterJSBridgeReady);
                else
                    window.fireEvent(eventWebViewFlutterJSBridgeReady);
            }, 200)
            return '已觸發(fā)事件:webViewFlutterJSBridgeReady:platform:${jsonData.platform}';
        }
        window.addEventListener('webViewFlutterJSBridgeReady', function (event) {
            console.log('觸發(fā):webViewFlutterJSBridgeReady');
        });
        window.addEventListener('webViewFlutterJSBridgeReady', function (event) {
            showToast('Js:CustomEvent:webViewFlutterJSBridgeReady'+JSON.stringify(event.detail));
        });
        function customeFunc(message) {
            document.getElementById("content").innerHTML = message;
            return 'customeFunc 調(diào)用完成'
        }
        $(function () {
            var elementContent = $('.content');
            var elementBtnFlutterFunc = $('#btnFlutterFunc');
            elementBtnFlutterFunc.unbind('click').bind('click', function () {
                showToast();  
            })
        })
    </script>

網(wǎng)頁中加入 自定義事件 CustomEvent webViewFlutterJSBridgeReady
以便通知網(wǎng)頁網(wǎng)頁加載完成 在調(diào)用的時候初始化部分 信息 如 硬件平臺信息 等

加載本地網(wǎng)頁加載JQuery 還沒研究透 ... 沒找到方法

String title = 'webview title';
  @override
  Widget build(BuildContext context) {
    var url = 'https://www.baidu.com';
    url = 'http://www.baidu.com';
    url = 'http://192.168.2.65:9777/Content/static/webview_flutter.html';
    var now =new DateTime.now();
    url = '$url?t=${now.toUtc()}';
    // url = "assets/www/webview_flutter.html";
    return Scaffold(
      appBar: AppBar(title:Text(title)),
      body: ComponentWebview(url: url,titleChandge: (value){
        print(value);
        setState(() {
          title = value;
        });
      }),
    );
  }

關于WebView_Fultter 啟用 http 請看 上一篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呼伸,一起剝皮案震驚了整個濱河市腔丧,隨后出現(xiàn)的幾起案子警没,更是在濱河造成了極大的恐慌葫哗,老刑警劉巖缔刹,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異劣针,居然都是意外死亡校镐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門捺典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸟廓,“玉大人,你說我怎么就攤上這事襟己∫眨” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵擎浴,是天一觀的道長员咽。 經(jīng)常有香客問我,道長贮预,這世上最難降的妖魔是什么骏融? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮萌狂,結(jié)果婚禮上档玻,老公的妹妹穿的比我還像新娘。我一直安慰自己茫藏,他們只是感情好误趴,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著务傲,像睡著了一般凉当。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上售葡,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天看杭,我揣著相機與錄音,去河邊找鬼挟伙。 笑死楼雹,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贮缅,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼榨咐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谴供?” 一聲冷哼從身側(cè)響起块茁,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎桂肌,沒想到半個月后数焊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡崎场,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年昌跌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片照雁。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚕愤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饺蚊,到底是詐尸還是另有隱情萍诱,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布污呼,位于F島的核電站裕坊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏燕酷。R本人自食惡果不足惜籍凝,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苗缩。 院中可真熱鬧饵蒂,春花似錦、人聲如沸酱讶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泻肯。三九已至渊迁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灶挟,已是汗流浹背琉朽。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稚铣,地道東北人箱叁。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓墅垮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝌蹂。 傳聞我的和親對象是個殘疾皇子噩斟,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355