iOS與JS交互的4中方法

iOS與JS交互的方法:
1.攔截url (適用于UIWebView和WKWebView)
2.JavaScriptCore (只適用于UIWebView, iOS7+)
3.WKScriptMessageHandler(只適用與WKWebView, iOS8+)
4.WebViewJavascriptBridge (適用于UIWebView和WKWebView, 屬于第三方框架.以后會單講這個框架)

方法一.攔截url
(1) web調(diào)用原生:
<1> 和后端同事協(xié)定好協(xié)議腮出,如jxaction://scan 表示啟動二維碼掃描.
jxaction://location表示獲取定位恒削。
<2> 實現(xiàn)UIWebView代理的shouldStartLoadWithRequest: navigationType:方法, 在方法中對url進(jìn)行攔截,如果是步驟<1>中定義好的協(xié)議則執(zhí)行對應(yīng)原生代碼,返回false, 否則返回true繼續(xù)加載原url娶吞。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    if ([request.URL.absoluteString isEqualToString:@"jxaction://scan"]) {
        //調(diào)用原生掃描二維碼
        return NO;
    }
    return YES;
}

h5代碼:

<a href="jxaction://scan">掃一掃(攔截url)</a>

(2)原生調(diào)用js
若(1)中掃描二維碼結(jié)束后, 需要把掃描結(jié)果返回給web頁,直接調(diào)用UIWebView的stringByEvaluatingJavaScriptFromString方法,或者WKWebView的evaluateJavaScript: completionHandler:方法

//回調(diào)方法
    [self.webView stringByEvaluatingJavaScriptFromString:@"scanResult('我是掃描結(jié)果~')"];
    [self.wkWebView evaluateJavaScript:@"scanResult" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        //回調(diào)結(jié)果
    }];

方法二. JavaScriptCore
方法一web調(diào)用原生只適合簡單的調(diào)用称簿,如果要傳遞參數(shù), 雖然也可以拼接在url上, 如jxaction://scan?method=aaa, 但是需要我們自行對字符串進(jìn)行分割解析,并且特殊字符需要編碼。在iOS7系統(tǒng)提供了JavaSciptCore议蟆,可以更優(yōu)雅地實現(xiàn)js與原生交互.
(1) js調(diào)用原生
<1>新建類繼承自NSObject(如AppJSObject)
<2>.h文件中聲明一個代理并遵循JSExport,代理內(nèi)的方法和js定義的方法名一致.
<3>.m文件中實現(xiàn)<2>代理中對應(yīng)的方法萎战,可以在方法內(nèi)處理事件或通知代理.
AppJSObject.h

#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>

NS_ASSUME_NONNULL_BEGIN

@protocol AppJSObjectDelegate <JSExport>

- (void)scan:(NSString *)message;

@end

@interface AppJSObject : NSObject

@property (nonatomic, weak) id<AppJSObjectDelegate> delegate;

@end

NS_ASSUME_NONNULL_END

AppJSObject.m

#import "AppJSObject.h"

@implementation AppJSObject

- (void)scan:(NSString *)message{
    [self.delegate scan:message];
}

@end

h5代碼:

<input type="button" name="" value="掃一掃" onclick="scan()">
<br/>
<p id="result">掃描結(jié)果:</p>

<script type="text/javascript">
    //調(diào)用APP的掃描方法   h5->app
    function scan(){
        app.scan('scanResult');
    }

    //掃描結(jié)果回調(diào)方法    app->h5
    function scanResult(result){
        document.getElementById("result").innerHTML = '掃描結(jié)果:' + result;  
    }
</script>

<4>在UIWebView加載完成的代理中把AppJSObject實例對象類注入到JS中,那么在js中調(diào)用方法就會調(diào)用到原生AppJSObject實例對象中對應(yīng)的方法了咐容。

//將AppJSObject實例注入到JS中 那么在js中調(diào)用方法就會調(diào)用到原生AppJSObject實例對象中對應(yīng)的方法了。
- (void)webViewDidFinishLoad:(UIWebView *)webView{
    
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
     
    AppJSObject *jsObject = [[AppJSObject alloc] init]; //AppJSObject的實例
    jsObject.delegate = self;
    context[@"app"] = jsObject;
    
}

代碼:https://github.com/dolacmeng/JSDemo/tree/master
*也可以通過block實現(xiàn)而不創(chuàng)建新類AppJSObject:

context[@"openAlbum"] = ^(){
    NSLog(@"js調(diào)用oc打開相冊");
};

(2)原生調(diào)用js
可以通過一中的方法, 也可以通過JSContext:

JSContext *context=[_mainWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *alertJS= [NSString stringWithFormat:@"%@('%@')",_photoMethod,fileUrl];
[context evaluateScript:alertJS];

方法三. WKScriptMessageHandler
現(xiàn)在很多app都是支持iOS8+蚂维,很多人使用WKWebView代替了UIWebView戳粒,但是WKWebView并不支持方法二。此時我們可以使用WKWebView的WKScriptMessageHandler
<1>初始化WKWebView時虫啥,調(diào)用addScriptMessageHandler:name:方法蔚约,name為js中的方法名,如scan:

- (void)setupWKWebView{
    
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];

    configuration.userContentController = [[WKUserContentController alloc] init];

    [configuration.userContentController addScriptMessageHandler:self name:@"scan"];
    
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];

    webView.UIDelegate = self;
}

h5:

window.webkit.messageHandlers.scan.postMessage() 

<2>實現(xiàn)WKScriptMessageHandler代理方法涂籽,當(dāng)js調(diào)用scan方法時苹祟,會回調(diào)此代理方法:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    if ([message.name isEqualToString:@"scan"]) {
        //調(diào)用原生掃碼
     }
}

實現(xiàn)原理:
1、JS與iOS約定好scan方法评雌,用作JS在調(diào)用iOS時的方法树枫;
2、iOS使用WKUserContentController的-addScriptMessageHandler:name:方法監(jiān)聽name為scan的消息景东;
3砂轻、JS通過window.webkit.messageHandlers.jsToOc.postMessage()的方式對scan方法發(fā)送消息;
4斤吐、iOS在-userContentController:didReceiveScriptMessage:方法中讀取name為scan的消息數(shù)據(jù)message.body

PS:[userContentController addScriptMessageHandler:self name:@"scan"]會引起循環(huán)引用問題搔涝。一般來說,在合適的時機(jī)removeScriptMessageHandler可以解決此問題和措。比如:在-viewWillAppear:方法中執(zhí)行add操作庄呈,在-viewWillDisappear:方法中執(zhí)行remove操作。如下:

- (void)viewWillAppear:(BOOL)animated {
    
    [super viewWillAppear:animated];
    
    [_webView.configuration.userContentController addScriptMessageHandler:self name:@"scan"];
}
 
- (void)viewWillDisappear:(BOOL)animated {
    
    [super viewWillDisappear:animated];
    
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"scan"];
}

方法四 WebViewJavascriptBridge
是一個第三方框架, 官方文檔和demo都很完整, 不再累贅, GitHub地址:
https://github.com/marcuswestin/WebViewJavascriptBridge

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末臼婆,一起剝皮案震驚了整個濱河市抒痒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颁褂,老刑警劉巖故响,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颁独,居然都是意外死亡彩届,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門誓酒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來樟蠕,“玉大人贮聂,你說我怎么就攤上這事≌纾” “怎么了吓懈?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長靡狞。 經(jīng)常有香客問我耻警,道長,這世上最難降的妖魔是什么甸怕? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任甘穿,我火速辦了婚禮,結(jié)果婚禮上梢杭,老公的妹妹穿的比我還像新娘温兼。我一直安慰自己,他們只是感情好武契,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布募判。 她就那樣靜靜地躺著,像睡著了一般吝羞。 火紅的嫁衣襯著肌膚如雪兰伤。 梳的紋絲不亂的頭發(fā)上内颗,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天钧排,我揣著相機(jī)與錄音,去河邊找鬼均澳。 笑死恨溜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的找前。 我是一名探鬼主播糟袁,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躺盛!你這毒婦竟也來了项戴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤槽惫,失蹤者是張志新(化名)和其女友劉穎周叮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體界斜,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仿耽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了各薇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片项贺。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出开缎,到底是詐尸還是另有隱情棕叫,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布奕删,位于F島的核電站谍珊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏急侥。R本人自食惡果不足惜砌滞,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坏怪。 院中可真熱鬧贝润,春花似錦、人聲如沸铝宵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹏秋。三九已至尊蚁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間侣夷,已是汗流浹背横朋。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留百拓,地道東北人琴锭。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像衙传,于是被迫代替她去往敵國和親决帖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355