android开发分享Flutter使用JsBridge方式处理Webview与H5通信的方法

目前,移动跨平台开发作为移动开发的重要组成部分,是移动开发者必须掌握的技能,也是自我提升的重要手段。作为google推出的跨平台技术方案,flutter具有诸多的优势,已经或正在被广大开发者应用在移动

目前,移动跨平台开发作为移动开发的重要组成部分,是移动开发者必须掌握的技能,也是自我提升的重要手段。作为google推出的跨平台技术方案,flutter具有诸多的优势,已经或正在被广大开发者应用在移动应用开发中。在过去的2019年,我看到越来越多的公司和个人开始使用flutter来开发跨平台应用,对于移动应用开发来说,flutter能够满足几乎所有的业务开发需求,所以,学习flutter正当时。

众所周知,使用flutter进行项目开发时,就免不了要加载h5页面,在移动开发中打开h5页面需要使用webview组件。同时,为了和h5页面进行数据交换,有时候还需要借助jsbridge来实现客户端与h5之间的通讯。除此之外,hybrid开发模式也需要webview与js做频繁的交互。

安装

android开发分享Flutter使用JsBridge方式处理Webview与H5通信的方法使用的是flutter官方的webview_flutter组件,目前的最新版本是0.3.19+9。使用前需要先添加webview_flutter插件依赖,如下所示。

  webview_flutter: 0.3.19+9

然后,使用flutter packages get命令将插件拉取到本地并保持依赖。由于加载webview需要使用网络,所以还需要在android中添加网络权限。打开目录android/app/src/main/androidmanifest.xml,然后添加如下代码即可。

  <uses-permission android:name="android.permission.internet"/>

由于ios在9.0版本默认开启了https,所以要运行http的网页,还需要在ios/runner/info.plist文件中添加如下代码。

  <key>io.flutter.embedded_views_preview</key>  <string>yes</string>

基本使用

打开webview组件的源码,webview组件的构造函数如下所示。

  const webview({   key key,   this.onwebviewcreated,   this.initialurl,   this.javascriptmode = javascriptmode.disabled,   this.javascriptchannels,   this.navigationdelegate,   this.gesturerecognizers,   this.onpagestarted,   this.onpagefinished,   this.debuggingenabled = false,   this.gesturenavigationenabled = false,   this.useragent,   this.initialmediaplaybackpolicy =    automediaplaybackpolicy.require_user_action_for_all_media_types,   }) : assert(javascriptmode != null),    assert(initialmediaplaybackpolicy != null),    super(key: key);  

其中,比较常见的属性的含义如下:

  • onwebviewcreated:在webview创建完成后调用,只会被调用一次;
  • initialurl:初始load的url;
  • javascriptmode:js执行模式(是否允许js执行);
  • javascriptchannels:js和flutter通信的channel;
  • navigationdelegate:路由委托(可以通过在此处拦截url实现js调用flutter部分);
  • gesturerecognizers:手势监听;
  • onpagefinished:webview加载完毕时的回调。import ‘dart:async’;

使用webview加载网页时,很多时候需要与js进行交互,即js调用flutter和flutter调用js。flutter调用js比较简单,直接调用 _controller.evaluatejavascript()函数即可。而js调用flutter则比较烦一点,之所以比较烦,是因为javascriptchannels目录只支持字符串类型,并且js的方法是固定的,即只能使用postmessage方法,对于ios来说没问题,但是对于android来说就有问题,当然也可以通过修改源码来实现。

js调用flutter

javascriptchannels方式

javascriptchannels方式也是推荐的方式,主要用于js给flutter传递数据。例如,有如下js代码。

  <button onclick="callflutter()">callflutter</button>  function callflutter(){   toast.postmessage("js调用了flutter");   }  

使用postmessage方式 toast 是定义好的名称,在接受的时候要拿这个免费精选名字大全 去接收,flutter端的代码如下。

  webview(    javascriptchannels: <javascriptchannel>[     _alertjavascriptchannel(context),   ].toset(),  )    javascriptchannel _alertjavascriptchannel(buildcontext context) {   return javascriptchannel(    name: 'toast',    onmessagereceived: (javascriptmessage message) {    showtoast(message.message);    });  }    

navigationdelegate

除此之外,另一种方式是navigationdelegate,主要是加载网页的时候进行拦截,例如有下面的js协议。

  document.location = "js://webview?arg1=111&args2=222";  

对应的flutter代码如下。

  navigationdelegate: (navigationrequest request) {   if (request.url.startswith('js://webview')) {    showtoast('js调用了flutter by navigationdelegate');    print('blocking navigation to $request}');   navigator.push(context,    new materialpageroute(builder: (context) => new testnav()));   return navigationdecision.prevent;   }   print('allowing navigation to $request');   return navigationdecision.navigate; //必须有  },  

其中,navigationdecision.prevent表示阻止路由替换,navigationdecision.navigate表示允许路由替换。

jsbridge

除此之外,我们还可以自己开发jsbridge,并建立一套通用规范。首先,需要与h5开发约定协议,建立model。

  class jsbridge {   string method; // 方法名   map data; // 传递数据   function success; // 执行成功回调   function error; // 执行失败回调     jsbridge(this.method, this.data, this.success, this.error);     /// jsonencode方法中会调用实体类的这个方法。如果实体类中没有这个方法,会报错。   map tojson() {   map map = new map();   map["method"] = this.method;   map["data"] = this.data;   map["success"] = this.success;   map["error"] = this.error;   return map;   }      static jsbridge frommap(map<string, dynamic> map) {   jsbridge jsonmodel = new jsbridge(map['method'], map['data'], map['success'], map['error']);   return jsonmodel;   }     @override   string tostring() {   return "jsbridge: {method: $method, data: $data, success: $success, error: $error}";   }  }    

然后,对接收到的h5方法进行内部处理。举个例子,客户端向h5提供了打开微信app的接口openwechatapp,如下所示。

  class jsbridgeutil {   /// 将json字符串转化成对象   static jsbridge parsejson(string jsonstr) {   jsbridge jsbridgemodel = jsbridge.frommap(jsondecode(jsonstr));   return jsbridgemodel;   }     /// 向h5开发接口调用   static executemethod(context, jsbridge jsbridge) async{   if (jsbridge.method == 'openwechatapp') {    /// 先检测是否已安装微信    bool _iswechatinstalled = await fluwx.iswechatinstalled();    if (!_iswechatinstalled) {    toast.show(context, '您没有安装微信');    jsbridge.error?.call();    return;    }    fluwx.openwechatapp();    jsbridge.success?.call();   }   }  }    

为了让我们封装得webview变得更加通用,可以对webview进行封装,如下所示。

   final string url;   final string title;   webviewcontroller webviewcontroller; // 添加一个controller   final privacyprotocoldialog privacyprotocoldialog;     webview({key key, this.url, this.title = '', this.privacyprotocoldialog})    : super(key: key);     @override   webviewstate createstate() => webviewstate();  }    class webviewstate extends state<webview> {   bool isphone = adapter.isphone();   javascriptchannel _jsbridge(buildcontext context) => javascriptchannel(    name: 'foxapp', // 与h5 端的一致 不然收不到消息    onmessagereceived: (javascriptmessage msg) async{    string jsonstr = msg.message;    jsbridgeutil.executemethod(jsbridgeutil.parsejson(jsonstr));    });     @override   widget build(buildcontext context) {   return scaffold(    backgroundcolor: isphone ? colors.white : color(config.foxcolors.bg),    appbar: appbar(    backgroundcolor: isphone ? null : color(config.foxcolors.bg),    leading: appicon(config.foximages.backgreyurl,     callback: (){      navigator.of(context).pop(true);      if (widget.privacyprotocoldialog != null) { // 解决切换页面时弹框显示异常问题      privacyprotocoldialog.show(context);      }     }),    title: text(widget.title),    centertitle: true,    elevation: 0,    ),    body: storeconnector<appstate, userstate>(     converter: (store) => store.state.userstate,     builder: (context, userstate) {     return webview(      initialurl: widget.url,      useragent:"mozilla/5.0 foxapp", // h5 可以通过navigator.useragent判断当前环境      javascriptmode: javascriptmode.unrestricted, // 启用 js交互,默认不启用javascriptmode.disabled      javascriptchannels: <javascriptchannel>[      _jsbridge(context) // 与h5 通信      ].toset(),     );     }),     );   }  }    

当js需要调用flutter时,直接调用jsbridge即可,如下所示。

  <!doctype html>  <html lang="en">  <head>   <meta charset="utf-8">   <meta name="viewport"     content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">   <meta http-equiv="x-ua-compatible" content="ie=edge">   <title>document</title>  </head>  <script src="https://cdn.bootcss.com/jquery/2.0.1/jquery.js"></script>  <body>  coming baby!  <script>  var str = navigator.useragent;  if (str.includes('foxapp')) {  foxapp.postmessage(json.stringify({method:"openwechatapp"}));  } else {  $('body').html('<p>hello world</p>');  }  </script>  </body>  </html>  

到此这篇关于flutter使用jsbridge方式处理webview与h5通信的方法的文章就介绍到这了,更多相关flutter webview与h5通信内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/898716.html

(1)
上一篇 2021年10月22日
下一篇 2021年10月22日

精彩推荐