iOS OC與JS交互(WebView監(jiān)聽事件)

在iOS應(yīng)用的開發(fā)過程中,我們經(jīng)常會使用到WebView,當(dāng)我們對WebView進行操作的時候,有時會需要進行源生的操作.那么我記下來就與大家分享一下OC與JS交互.

首先先說第一種方法,并沒有牽扯OC與JS交互,只是做攔截和跳轉(zhuǎn).

攔截跳轉(zhuǎn)的URL,跳轉(zhuǎn)源生界面(用起來感覺怪怪的,萬一URL更換了怎么辦.)
UIWebView
//UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *url = request.URL.absoluteString;
    if ([url rangeOfString:@"需要跳轉(zhuǎn)源生界面的URL判斷"].location != NSNotFound) {
        //跳轉(zhuǎn)原生界面
        return NO;
    }
    return YES;
}
WKWebView
//使用WKWebview需要導(dǎo)入WebKit
#import <WebKit/WebKit.h>
//WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSString *url = navigationAction.request.URL.absoluteString;
    if ([url rangeOfString:@"需要跳轉(zhuǎn)源生界面的URL判斷"].location != NSNotFound) {
        //跳轉(zhuǎn)原生界面
        
        //Cancel the navigation
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

----------?↓↓↓↓↓↓?----------

OC與JS交互(WebView監(jiān)聽事件)

正入主題.

一.OC調(diào)用JS

1.UIWebView

①直接運行

NSString *jsStr = @"執(zhí)行的JS代碼";
[webView stringByEvaluatingJavaScriptFromString:jsStr];

②使用JavaScriptCore框架

#import <JavaScriptCore/JavaScriptCore.h>  
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //獲取webview中的JS內(nèi)容
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    NSString *runJS = @"執(zhí)行的JS代碼";
    //準(zhǔn)備執(zhí)行的JS代碼
    [context evaluateScript:runJS];
}
2.WKWebView
[webView evaluateJavaScript:@"執(zhí)行的JS代碼" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
  
}];

二.JS調(diào)用OC ??????

當(dāng)網(wǎng)頁觸發(fā)某種操作,可以給App傳遞消息.比如WebView中購買某樣?xùn)|西,點擊購買,需要獲取這件商品的訂單信息,并且需要App進行源生的支付.
這種方法需要你和后臺或者前端協(xié)商好一下,讓他們在執(zhí)行JS方法的時候,將你需要的數(shù)據(jù)放到你能拿到的位置.

下面簡單貼一個HTML文件.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>App與WebView交互</title>
</head>
<body>
<button style="width: 100%; height: 100px;" onclick="buttonClick()">點擊購買</button>
</body>
<script>
    //按鈕點擊事件
    function buttonClick() {
        //傳遞的信息
        var jsonStr = '{"id":"666", "message":"我是傳遞的數(shù)據(jù)"}';

        //UIWebView使用
        getMessage(jsonStr);

       //WKWebView使用
       //使用下方方法,會報錯,為使界面執(zhí)行邏輯通暢,因此使用try-catch
        try {
            window.webkit.messageHandlers.getMessage.postMessage(jsonStr)
        } catch(error) {
            console.log(error)
        }
    }
    function getMessage(json){
        //空方法
    }
</script>
</html>

window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)
JS端寫此方法的盆友可能會報錯,導(dǎo)致界面邏輯無法進行,因此使用try-catch就好了.

我在網(wǎng)頁上只寫了一個按鈕.點擊按鈕,會觸發(fā)buttonClick()方法.

UIWebView

在網(wǎng)頁加載完成的時候檢測JS方法執(zhí)行.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //核心方法如下
    JSContext *content = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //此處的getMessage和JS方法中的getMessage名稱一致.
    content[@"getMessage"] = ^() {
        NSArray *arguments = [JSContext currentArguments];
        for (JSValue *jsValue in arguments) {
            NSLog(@"=======%@",jsValue);
        }
    };
}

由上方方法,當(dāng)JS方法getMessage()執(zhí)行的時候,此方法回調(diào)的jsValue內(nèi)容就是我們需要的內(nèi)容.(HTML中JS傳遞的數(shù)據(jù))

WebView中的getMessage與HTML文件JS方法的getMessage名稱需保持一致.

WKWebView

實現(xiàn)WKScriptMessageHandler的代理方法.

//設(shè)置addScriptMessageHandler與JS對應(yīng)方法名.并且設(shè)置<WKScriptMessageHandler>協(xié)議與協(xié)議方法
[[_webView configuration].userContentController addScriptMessageHandler:self name:@"getMessage"];

//WKScriptMessageHandler協(xié)議方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    //code
    NSLog(@"name = %@, body = %@", message.name, message.body);
}

上方-addScriptMessageHandler:name:方法中name填寫的方法名必須與window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>)中的方法名一致.

當(dāng)JS端執(zhí)行window.webkit.messageHandlers.<方法名>.postMessage(<數(shù)據(jù)>).
此協(xié)議方法就會被執(zhí)行.,根據(jù)message.name判斷一下自己需要執(zhí)行哪步操作.message.body即是傳輸?shù)膮?shù)信息.(HTML中JS傳遞的數(shù)據(jù))

WKWebView 內(nèi)存泄露

但是這樣WebView所在的ViewController的- (void)dealloc{}不執(zhí)行.那么內(nèi)存又有問提了.
可以另外創(chuàng)建一個代理對象,然后通過代理對象回調(diào)指定的self.

//.h
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>

@property (nonatomic, assign) id<WKScriptMessageHandler> scriptDelegate;

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;

@end


//.m
@implementation WeakScriptMessageDelegate

- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}

@end

設(shè)置代理

[[_webView configuration].userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"方法名"];

WebView的ViewController的- (void)dealloc{}方法中進行銷毀.

- (void)dealloc {
    ...
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"方法名"];
    ...
}

----------END

當(dāng)然,安卓開發(fā)的盆友也是可以通過這種方式從中獲取網(wǎng)頁的數(shù)據(jù)的.安卓注入的接口名稱在JS中也是會報錯的.因此也需要try-catch.

好了.以上就是與大家分享的OC與JS交互(WebView監(jiān)聽事件).有不足之處還請各位大佬指出.萬分感激~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內(nèi)容

  • 前言 關(guān)于UIWebView的介紹,相信看過上文的小伙伴們,已經(jīng)大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    Dark_Angel閱讀 28,970評論 67 291
  • 隨著H5技術(shù)的興起,在iOS開發(fā)過程中,難免會遇到原生應(yīng)用需要和H5頁面交互的問題。其中會涉及方法調(diào)用及參數(shù)傳值等...
    Chris_js閱讀 3,100評論 1 8
  • 前言 關(guān)于UIWebView的介紹,相信看過上文的小伙伴們,已經(jīng)大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    CoderLF閱讀 9,000評論 2 12
  • 最近整理了一下原生與H5之間的交互方式,簡單的做個總結(jié)。OC端與JS的交互,大致有這幾種:攔截協(xié)議、JavaScr...
    談Xx閱讀 31,151評論 41 75
  • 前言 上一篇專門講解了WKWebView相關(guān)的所有類、代理的所有API。前篇文章地址:http://blog.cs...
    iwolfox閱讀 1,114評論 1 1