1. 程式人生 > >ios與H5通過WKWebView互動詳解

ios與H5通過WKWebView互動詳解

WK的基本用法先不說了,主要在這裡記錄一下使用WKWebView在於H5互動時走過的一些坑,以及如果web端的同學如果沒有做過和ios端的互動,那麼自己也可以去幫助web端去完成;另外在除錯過程中,也不用一味的去等待和H5去聯調,可以自己寫一個本地的連結供自己去提前除錯
這裡主要寫js呼叫OC的兩種場景

首先需要和H5端去定義一些協議,來完成不同的功能,例如:在app的H5介面,進入OC的某個介面;H5端需要動態的獲取OC的一些引數等

第一種場景:
舉一個H5介面需要呼叫app分享的例子,分享的過程中可以給app傳遞一些引數, 首先定義一個公共的協議名稱 ‘shareByApp’
js的程式碼就非常簡單了,只需要在方法中這樣去寫就可以了

window.webkit.messageHandlers.定義的方法名(shareByApp).postMessage(引數)

第一個坑:
引數如果不需要刻意不傳,但是如果傳物件型別的,這就需要和安卓端的有所不同了,這裡寫的key是不需要加雙引號的,只有value需要加單引號,否則在app端是接收不到正確的資料的,下面是正確寫法

window.webkit.messageHandlers.shareByApp.postMessage({shareType:'1',shareUrl:'http://www.baidu.com',shareTitle:'我是分享的標題',shareDesc:'我是分享的描述'
,shareImgUrl:'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1526379795&di=3ceb1bdfa94f3148d4d54cd24a6ae2f6&imgtype=jpg&er=1&src=http%3A%2F%2Ftupian.aladd.net%2F2015%2F9%2F228.jpg'
})

app端需要實現的程式碼:

    WKUserContentController* userContent = [[WKUserContentController
alloc] init]; //首先新增訊息處理,注意:self指代的物件需要遵守WKScriptMessageHandler協議,結束時需要移除 [userContent addScriptMessageHandler:self name:@"shareByApp"]; //然後將將UserConttentController設定到配置檔案 WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.userContentController = userContent 移除的方法 [self.webview.configuration.userContentController removeScriptMessageHandlerForName:@"shareByApp"];

然後,只要H5端觸發這段程式碼,就可以在WKScriptMessageHandler下面這個代理方法中捕捉到了

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    //有時可能需要呼叫很多app的方法,所以根據message.name來區分執行不同的方法。message.body中傳過來的就是在js中寫好的引數
    //進行name判斷,就可以寫指定的方法了
}

第二種場景:
有些時候,H5介面某些互動可能需要判斷app是否登入了,這就需要js主動去掉OC的方法,並且將app的一些資訊傳遞回去,首先還是指定一個協議 ‘isLoginApp’

然後WKWebView需要匯入一個檔案(WebViewJavascriptBridge),下載連結

然後需要在js裡面注入一部分程式碼,用於初始化

放到需要呼叫OC方法的js檔案中就可以
function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) {
        return callback(WebViewJavascriptBridge);
    }
    if (window.WVJBCallbacks) {
        return window.WVJBCallbacks.push(callback);
    }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function () {
        document.documentElement.removeChild(WVJBIframe)
    }, 0)
}

然後再去實現這個方法
function processIosGetCoupon() {
    WebViewJavascriptBridge.callHandler('isLoginApp', null, function (response) {
        //response就是從app端返回的引數
    })
}

OC的程式碼實現:

    //匯入標頭檔案後初始化
    self.webViewBridge = [WKWebViewJavascriptBridge bridgeForWebView:self.webview];
    [self.webViewBridge setWebViewDelegate:self];
    //然後將需要傳入的引數放入這個block中
    [_webViewBridge registerHandler:@"isLoginApp" handler:^(id data, WVJBResponseCallback responseCallback) {
        // 將需要的引數傳給js
        responseCallback(@"已登入/未登入");
    }];

第二個坑:這裡的問題主要在於,H5中的將注入上面程式碼的js檔案放進去,app端呼叫web的URL後面如果拼接任何引數,一定得保證新的url中一定含有注入上面程式碼的js檔案,否則介面上看不出任何問題,但是就是進入不到OC程式碼的回撥裡,這裡一定得注意