Flutter建立JsBridge用于webview與h5通信

項目背景

隨著項目的不斷完善奋蔚,需要做一些運營活動饼齿,通常是H5頁面屡萤,在app中打開這些H5頁面就需要引入WebView锈死,有時候H5需要客戶端提供一些內部的接口贫堰,這時候我們就需要建立JSBridge用于客戶端與H5之間的通訊。

使用

1待牵、安裝webview_flutter

 webview_flutter: ^0.3.16
  1. 在android中添加網(wǎng)絡權限其屏,目錄android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>

3、 ios中在ios/Runner/Info.plist中添加

<key>io.flutter.embedded_views_preview</key>
<string>YES</string>*

4缨该、建立JSBridge

  1. 需要與H5開發(fā)約定協(xié)議偎行,建立Model
/// WebView與h5進行通信
class JsBridge {
  String method; // 方法名
  Map data; // 傳遞數(shù)據(jù)
  Function success; // 執(zhí)行成功回調
  Function error; // 執(zhí)行失敗回調

  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;
  }
  /// jsonDecode(jsonStr)方法返回的是Map<String, dynamic>類型熄云,需要這里將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}";
  }
}
  1. 對接收到的h5方法,進行內部處理汗盘,這里舉個簡單的例子皱碘,客戶端向h5提供了打開微信App的接口openWeChatApp
import 'dart:convert';
import 'package:fluwx/fluwx.dart' as fluwx;

import '../models/JsBridge.dart';
import '../utils/toast.dart';

class JsBridgeUtil {
  /// 將json字符串轉化成對象
  static JsBridge parseJson(String jsonStr) {
    JsBridge jsBridgeModel = JsBridge.fromMap(jsonDecode(jsonStr));
    return jsBridgeModel;
  }

  /// 向H5開發(fā)接口調用
  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();
    }
  }
}
  1. 建立可復用的Webview組件
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:webview_flutter/webview_flutter.dart';

import '../configs/config.dart';
import '../utils/adapter.dart';
import '../utils/privacyProtocolDialog.dart';
import '../utils/JsBridgeUtil.dart';
import '../widgets/AppIcon.dart';
import '../models/appState.dart';
import '../models/userState.dart';

/// WebView頁面
class Webview extends StatefulWidget {
  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判斷當前環(huán)境
              javascriptMode: JavascriptMode.unrestricted, // 啟用 js交互,默認不啟用JavascriptMode.disabled
              javascriptChannels: <JavascriptChannel>[
                _JsBridge(context) // 與h5 通信
              ].toSet(),
            );
          }),

    );
  }
}
  1. h5頁面中引入隐孽,并調用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>
$('body').html('<p>hello world</p>');
FoxApp.postMessage(JSON.stringify({method:"openWeChatApp"}));
</script>
</body>
</html>
  1. flutter 調用h5方法
// flutter 
webViewController.evaluateJavascript("sayHello('hello world')")

// h5 
function sayHello(msg){
   console.log(msg)
}

以上實現(xiàn)了一個簡易版的JsBridge,webview_flutter是官網(wǎng)插件健蕊,功能非常強大菱阵,JS與Flutter交互只是常用的功能,還提供了頁面加載缩功、路由晴及、手勢等功能,感興趣的同學可以去更詳細的了解嫡锌。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末虑稼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子势木,更是在濱河造成了極大的恐慌蛛倦,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啦桌,死亡現(xiàn)場離奇詭異溯壶,居然都是意外死亡,警方通過查閱死者的電腦和手機甫男,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門且改,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人板驳,你說我怎么就攤上這事又跛。” “怎么了若治?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵慨蓝,是天一觀的道長。 經(jīng)常有香客問我直砂,道長菌仁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任静暂,我火速辦了婚禮济丘,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己摹迷,他們只是感情好疟赊,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著峡碉,像睡著了一般近哟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲫寄,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天吉执,我揣著相機與錄音,去河邊找鬼地来。 笑死戳玫,一個胖子當著我的面吹牛,可吹牛的內容都是我干的未斑。 我是一名探鬼主播咕宿,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜡秽!你這毒婦竟也來了府阀?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤芽突,失蹤者是張志新(化名)和其女友劉穎试浙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诉瓦,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡川队,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了睬澡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片固额。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖煞聪,靈堂內的尸體忽然破棺而出斗躏,到底是詐尸還是另有隱情,我是刑警寧澤昔脯,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布啄糙,位于F島的核電站,受9級特大地震影響云稚,放射性物質發(fā)生泄漏隧饼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一静陈、第九天 我趴在偏房一處隱蔽的房頂上張望燕雁。 院中可真熱鬧诞丽,春花似錦、人聲如沸拐格。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捏浊。三九已至懂衩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間金踪,已是汗流浹背浊洞。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留热康,地道東北人沛申。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像姐军,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尖淘,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容