iOS下 JS 與OC 互相調用(一) - UIWebView 攔截 URL

序言

在實際開發中,我們避免不了需要和 UIWebView 打交道,這就涉及到 JS 與原生 OC 的交互,今天抽空總結一下 JS 與原生交互使用 UIWebView 攔截 URL 的方式。

JS 調用原生 OC

我們可以利用 JS 發起一個假的 URL 請求,然后利用 UIWebView 的代理方法攔截這次請求,然后再做相應的處理。

參考網上例子,寫了一個簡單的 HTML 網頁和一個按鈕點擊事件用來和原生 OC 交互,HTML代碼如下:

<html>
    <header>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript">
            
            function showAlert(message){
                asyncAlert(message);
            }
        
            function asyncAlert(content) {
                setTimeout(function(){
                           alert(content);
                           },1);
            }
        
            function loadURL(url) {
                var iFrame;
                iFrame = document.createElement("iframe");
                iFrame.setAttribute("src", url);
                iFrame.setAttribute("style", "display:none;");
                iFrame.setAttribute("height", "0px");
                iFrame.setAttribute("width", "0px");
                iFrame.setAttribute("frameborder", "0");
                document.body.appendChild(iFrame);
                // 發起請求后這個 iFrame 就沒用了,所以把它從 dom 上移除掉
                iFrame.parentNode.removeChild(iFrame);
                iFrame = null;
            }
            function firstClick() {
                loadURL("firstClick://shareClick?title=分享的標題&content=分享的內容&url=鏈接地址&imagePath=圖片地址");
            }
        </script>
    </header>
    
    <body style="width:100%; height:100%;">
        <h2> 這里是第一種方式 </h2>
        <br/>
        <br/>
        <button type="button" onclick="firstClick()">Click Me!</button>
        
    </body>
</html>

雖然 HTML 內容比較少,還是有很多學問的

1.為什么定義一個loadURL方法,不直接使用window.location.href?
答:因為如果當前網頁正在使用window.location.href加載網頁的同時,調用window.location.href去調用 OC 原生方法,會導致加載網頁的操作被取消掉。同樣的,如果連續使用window.location.href執行兩次 OC 原生調用,也有可能導致第一次的操作被取消掉。所以我們使用自定義的loadURL,來避免這個問題。loadURL的實現來自關于UIWebView和PhoneGap的總結一文。
2.為什么 loadURL 中的鏈接,使用統一的 scheme?
答:便于在 OC 中做攔截處理,減少在 JS 中調用一些 OC 沒有實現的方法時,webView 做跳轉。我再 OC 攔截 URL 時,根據 scheme即(firstclick)來區分是調用原生的方法還是正常的網頁跳轉。然后根據host(即//后面的部分shareClick)來區分執行什么操作。
3.為什么自定義一個asyncAlert方法?
答:因為有的 JS 調用是需要 OC 返回結果到 JS 的。
stringByEvaluatingJavaScriptFromString是一個同步方法,會等待 js 方法執行完成。而彈出的 alert 也會阻塞界面等待用戶響應,所以他們可能會造成死鎖。導致 alert 卡死界面。如果回調的 JS 是一個耗時操作,那么建議將耗時的操作也放入setTimeoutfunction中。

然后在項目的控制器中實現 UIWebView 的代理方法

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL * url = [request URL];
    if ([[url scheme] isEqualToString:@"firstclick"]) {  // firstClick://shareClick?title=分享的標題&content=分享的內容&url=鏈接地址&imagePath=圖片地址
        NSArray *params = [url.query componentsSeparatedByString:@"&"];
        
        NSMutableDictionary *tempDict = [NSMutableDictionary dictionary];
        NSMutableString *strM = [NSMutableString string];
        for (NSString *paramStr in params) {
            NSArray *dictArray = [paramStr componentsSeparatedByString:@"="];
            if (dictArray.count > 1) {
                NSString *decodeValue = [dictArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                decodeValue = [decodeValue stringByRemovingPercentEncoding];
                [tempDict setObject:decodeValue forKey:dictArray[0]];
                [strM appendString:decodeValue];
            }
        }
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"這是OC原生的彈出窗" message:strM delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];
        [alertView show];
        NSLog(@"tempDic:%@",tempDict);
        return NO;
    }
    return YES;
}

1.JS中的firstClick,在攔截到的url scheme全都被轉化為小寫。
2.html 中需要設置編碼,否則中文參數可能會出現編碼問題。
3.JS用打開一個iFrame的方式替代直接用document.location的方式,以避免多次請求,被替換覆蓋的問題。

OC 調用 JS

在 OC 原生中

NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"這里是JS中alert彈出的message"];
[self.webView stringByEvaluatingJavaScriptFromString:jsStr];

注意:該方法會同步返回一個字符串,因此是一個同步方法,可能會阻塞主線程。

在 html 文件中

function showAlert(message) {
  alert(message);
}

早期的JS與原生交互的開源庫很多都是用得這種方式來實現的,例如:PhoneGap、WebViewJavascriptBridge。關于這種方式調用OC方法,唐巧早期有篇文章有過介紹:
關于UIWebView和PhoneGap的總結

效果如下:

js_oc_intercept_url.gif

項目連接地址


更多 JS 與 OC 交互文章請看下面
iOS下 JS 與OC 互相調用(二) - JavaScriptCore
iOS 下 JS 與 OC 互相調用(三) - WKWebView 攔截 URL
iOS下JS與OC互相調用(四)-MessageHandler
iOS下 JS 與 OC 互相調用(五) - UIWebView+WebViewJavascriptBridge
iOS下 JS 與 OC 互相調用(六) - WKWebView+WKWebViewJavascriptBridge

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容