使用 JSBridge 與原生 IOS、Android 進行交互(含 H五、Android、IOS 端代碼,附 Demo)

本文詳細講述瞭如何使用 JSBridge 在 H5 和原生 Android、IOS之間進行交互。IOS 端包含 OC 和 Swift 的版本,Android 端包含 Java 和 Kotlin 版本。javascript

1、寫在前面

本文主要是經過代碼講述瞭如何使用 JSBridge 在 H5 和 原生之間進行通訊。文中包含 H五、IOS、Android 三部分的代碼。 IOS 中使用 OC 和 Swift 分別進行了代碼實現。Android 中使用 Java 和 Kotlin 分別進行了代碼實現。php

Demo 地址:jsbridge-examplehtml

  • JSBridgeH5H5 端代碼實現
  • JSBridgeIOSOC:原生 IOSOC 代碼實現
  • JSBridgeIOSSwift:原生 IOSSwift 代碼實現
  • JSBridgeAndroidJava:原生 AndroidJava 代碼實現
  • JSBridgeAndroidKotlin:原生 IOSKotlin 代碼實現

本文沒有講解關於原理的部分,只是詳細使用代碼介紹了 JSBridge 的使用。想要了解原理的朋友,能夠另行搜索關於原理的博客。java


2、H5 端代碼

  • 初始化 WebViewJavascriptBridge,方式代碼以下
  • 註冊供原生調用的事件函數: window.setupWebViewJavascriptBridge(bridge => bridge.registerHandler('fnName', function) )
  • 調用原生事件函數: window.setupWebViewJavascriptBridge(bridge => bridge.callHandler('fnName', data, callback) )

一、初始化 WebViewJavascriptBridge

在項目入口文件或者根 js 文件下,添加如下代碼:android

// 這裏根據移動端原生的 userAgent 來判斷當前是 Android 仍是 ios
const u = navigator.userAgent;
// Android終端
const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
// IOS 終端
const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); 

/** * 配合 IOS 使用時的初始化方法 */
const iosFunction = (callback) => {
    if (window.WebViewJavascriptBridge) { return callback(window.WebViewJavascriptBridge) }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback) }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function(){
         document.documentElement.removeChild(WVJBIframe);
    }, 0);
}

/** * 配合 Android 使用時的初始化方法 */
const androidFunction = (callback) => {
    if (window.WebViewJavascriptBridge) {
        callback(window.WebViewJavascriptBridge);
    } else {
        document.addEventListener('WebViewJavascriptBridgeReady', function () {
            callback(window.WebViewJavascriptBridge);
        }, false)
    }
}

window.setupWebViewJavascriptBridge = isAndroid ? androidFunction : iosFunction;

isAndroid && window.setupWebViewJavascriptBridge(function (bridge) {
    // 註冊 H5 界面的默認接收函數(與安卓交互時,安卓端能夠不調用函數名,直接 send 數據過來,就可以在這裏接收到數據)
    bridge.init(function (msg, responseCallback) {
        console.log(msg);
        responseCallback("JS 返回給原生的消息內容");
    })
});
複製代碼

二、註冊與原生交互的事件函數

/* window.setupWebViewJavascriptBridge(bridge => { bridge.registerHandler('事件函數名',fun 執行函數); }) */
window.setupWebViewJavascriptBridge(bridge => {
    /** * data:原生傳過來的數據 * fn: 原生傳過來的回調函數 */
    bridge.registerHandler("H5Function", (data, fn) => {
        console.log(data);
        fn && fn();
    });
});
複製代碼

三、調用原生註冊的事件函數

調用原生註冊的時間函數時使用以下的代碼:ios

/* window.setupWebViewJavascriptBridge(bridge => { bridge.callHandler('安卓端函數名', "傳給原生端的數據", callback 回調函數); }) */
window.setupWebViewJavascriptBridge(bridge => {
    bridge.callHandler('changeData', data, (result) => {
        console.log(result);
    });
})
複製代碼

3、IOS 端代碼

  • 初始化 WebViewJavascriptBridge:git

    + (instancetype)bridgeForWebView:(id)webView;
    + (instancetype)bridge:(id)webView;
    複製代碼
  • 註冊與 H5 端交互的事件函數: - (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler;github

  • 調用 H5 端事件函數:web

    - (void)callHandler:(NSString*)handlerName;
    - (void)callHandler:(NSString*)handlerName data:(id)data;
    - (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback;
    複製代碼

一、引入 WebViewJavascriptBridge

直接使用方式

  • 下載 WebViewJavascriptBridgeswift

  • 找到 WebViewJavascriptBridge文件夾,直接拖入到 XCode 項目中,在提示的彈窗中選擇 Copy items if neededCreate groups,以下圖:

    Drag Group

  • ViewController.h 頭文件中引入 #import "WebViewJavascriptBridge.h" 便可

Cocopad 使用方式

如必須使用這種方式請自行 Google。

二、初始化 WebViewJavascriptBridge

// 啓用 WebViewJavascriptBridge Log
[WebViewJavascriptBridge enableLogging];

// 初始化 WKWebViewConfiguration 對象
self.webConfig = [[WKWebViewConfiguration alloc] init];
// 設置偏好設置
_webConfig.preferences = [[WKPreferences alloc] init];
// 默認爲0
_webConfig.preferences.minimumFontSize = 10;
// 默認認爲YES
_webConfig.preferences.javaScriptEnabled = YES;
// 在iOS上默認爲NO,表示不能自動經過窗口打開
_webConfig.preferences.javaScriptCanOpenWindowsAutomatically = NO;

// TODO: 請替換成頁面的 url 地址
NSString *URLSTR = @"http://xxx.xxx.xxx.xx:xxxx";
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:_webConfig];
// 設置 UserAgent 後綴
_webView.customUserAgent = [NSString stringWithFormat:self.webView.customUserAgent, @"app"];
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
NSURL *url = [NSURL URLWithString:URLSTR];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[_webView loadRequest:urlRequest];
[self.view addSubview:_webView];

self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[_bridge setWebViewDelegate:self];
複製代碼

三、註冊與 H5 端交互的事件函數

// 例:註冊修改 User 名稱的 changeUser 函數
[self.bridge registerHandler:@"changeUser" handler:^(id data, WVJBResponseCallback responseCallback) {
    // 在這裏處理邏輯
    NSLog(@"JS 傳過來的數據%@", data);
    if (responseCallback) {
        // 執行回調函數
        responseCallback(@"返回給 JS 的數據");
    }
}];
複製代碼

四、調用 H5 端事件函數

// 調用 H5 界面的 changeName 事件函數
[self.bridge callHandler:@"changeName" data:name responseCallback:^(id responseData) {
    NSLog(@"JS 調用 OC 回調函數返回的值:%@", responseData);
}];
複製代碼

4、Android 端代碼

  • 註冊與 H5 交互的事件函數:
    public void registerHandler(String handlerName, BridgeHandler handler) {
        if (handler != null) {
            messageHandlers.put(handlerName, handler);
        }
    }
    複製代碼
  • 調用 H5 端事件函數
    public void callHandler(String handlerName, String data, CallBackFunction callBack) {
        doSend(handlerName, data, callBack);
    }
    複製代碼
  • 註冊與 H5 交互的默認事件,即 H5 端不調用函數名,直接使用 send 函數傳遞數據,安卓端也能夠在這個事件中接收到數據
    // 設置默認接收函數
    public void setDefaultHandler(BridgeHandler handler) {
        this.defaultHandler = handler;
    }
    複製代碼
  • 調用 H5 端註冊的默認事件函數
    @Override
    public void send(String data, CallBackFunction responseCallback) {
        doSend(null, data, responseCallback);
    }
    複製代碼

一、引入 BridgeWebView

  • 在項目的 build.gradle 文件中添加以下代碼:
    buildTypes {
        // ...
        repositories {
            // ...
            maven { url "https://jitpack.io" }
        }
    }
    複製代碼
  • 添加依賴:implementation 'com.github.lzyzsd:jsbridge:1.0.4'

二、初始化 BridgeWebView

activity_main.xml 文件中添加布局

<com.github.lzyzsd.jsbridge.BridgeWebView android:id="@+id/main_wv" android:layout_width="match_parent" android:layout_height="match_parent">
</com.github.lzyzsd.jsbridge.BridgeWebView>
複製代碼

在 MainActivity 中初始化 BridgeWebView

mWebView = findViewById(R.id.main_wv);

mWebView.getSettings().setAllowFileAccess(true);
mWebView.getSettings().setAppCacheEnabled(true);
mWebView.getSettings().setDatabaseEnabled(true);
// 開啓 localStorage
mWebView.getSettings().setDomStorageEnabled(true);
// 設置支持javascript
mWebView.getSettings().setJavaScriptEnabled(true);
// 進行縮放
mWebView.getSettings().setBuiltInZoomControls(true);
// 設置UserAgent
mWebView.getSettings().setUserAgentString(mWebView.getSettings().getUserAgentString() + "app");
// 設置不用系統瀏覽器打開,直接顯示在當前WebView
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(new MyWebViewClient(mWebView));

mWebView.loadUrl(URL);
複製代碼

三、註冊與 H5 交互的事件函數

// 默認事件函數
mWebView.setDefaultHandler(new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
        function.onCallBack("安卓返回給 JS 的消息內容");
    }
});

// 普通事件函數
mWebView.registerHandler("reloadUrl", new BridgeHandler() {

    @Override
    public void handler(String data, CallBackFunction function) {
        mWebView.reload();
        Toast.makeText(MainActivity.this, "刷新成功~", Toast.LENGTH_SHORT).show();
        function.onCallBack("");
    }
});
複製代碼

四、調用 H5 端事件函數

// 調用 H5 端默認事件函數
mWebView.send("安卓傳遞給 JS 的消息", new CallBackFunction() {
    @Override
    public void onCallBack(String data) {
        Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
    }
});

// 調用 H5 端普通事件函數
mWebView.callHandler("changeName", mEditName.getText().toString(), new CallBackFunction() {
    @Override
    public void onCallBack(String data) {
        Toast.makeText(MainActivity.this, "name 修改爲功", Toast.LENGTH_SHORT).show();
        mEditName.setText("");
    }
});
複製代碼

五、添加網絡權限

這一步是必須的,不然的話, WebView 加載不出來,手機界面會提示 Webpage not available

  • AndroidManifest.xml 清單文件中添加:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    複製代碼
  • 添加了權限以後,網頁可能仍是加載不出來,多是由於對未加密的流量不信任,在 AndroidManifest.xmlapplication 中添加一個屬性:android:usesCleartextTraffic="true"。以下:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ...>
        <application ... android:usesCleartextTraffic="true">
            ...
        </application>
    </manifest>
    複製代碼

5、Tips

一、在 Swift 中使用 WebViewJavascriptBridge

和在 OC 中使用相似,直接將下載好的 WebViewJavascriptBridge 文件夾拖到 Swift 項目中。 但此時還不能直接使用,由於 WebViewJavascriptBridge 中使用 OC 編寫的。因此須要先建立一個頭文件,名爲:項目名-Bridging-Header.h,將須要用到的 OC 的頭文件引入進去。 這裏我建議不要手動建立,可讓 XCode 自動幫忙建立。建立方式:在 Swift 項目中建立一個 OC 文件:

建立 OC 文件

以後 XCode 會自動提示建立 Bridging Header

建立 Bridging Header

建立以後,在文件夾中引入 WebViewJavascriptBridge.h 頭文件:

引入 OC 頭文件

最後,就能夠在 Swift 代碼中正常使用 OC 編寫的方法了:

使用 OC 編寫方法

二、運行 XCode 項目報錯,控制檯提示:Unknown class ViewController in Interface Builder file.

解決辦法: 打開 Main.storyboard 文件,按照下圖所示,找到箭頭所指輸入框中的 ViewController,刪除掉,以後再從新輸入,找到新的 ViewController,填進去便可:

解決異常


6、參考連接


7、Demo 地址

jsbridge-example

若是有所幫助,歡迎 Star!

相關文章
相關標籤/搜索