iOS js調(diào)用原生的幾種實(shí)現(xiàn)方式

公司最近需求,有一些頁面使用了H5,主要場景是js要調(diào)用原生方法盲赊,同時(shí)原生把返回值傳個(gè)js

一、UIWebView 的 js原生交互

1敷扫、原生調(diào)用js

原生中主要代碼:

 聲明一個(gè)協(xié)議
@protocol JSObjctDeleagte <JSExport>
// iOSWebView對象調(diào)用的JavaScript方法哀蘑,必須聲明!?凇绘迁!
- (NSString *)jsCallOc:(NSString *)param;
@end

在webview加載完成時(shí)
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 獲取webView的JSContext對象
    self.context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    //將iOSWebView對象指向自身
    //js 中加入 window.iOSWebView.jsCallOc 就會(huì)調(diào)用原生里的jsCallOc方法
    self.context[@"iOSWebView"] = self; //與js中保持一致
    self.context[@"console"][@"log"] = ^(JSValue * msg) {
        NSLog(@"H5  log : %@", msg);
    };
    
/**
 實(shí)現(xiàn)js需要調(diào)用的原生方法待js調(diào)用
 */
- (NSString *)jsCallOc:(NSString *)param {
    NSLog(@"我被js調(diào)用了,并接收到參數(shù)為:%@",param);
    return [NSString stringWithFormat:@"我被js調(diào)用了,js參數(shù)為:%@",param];
}

js中需要添加的代碼

//js調(diào)用oc方法
            function jsCallOc(param) {
                //iOSWebView js與原生約定好卒密,保持一致
                var tempValue = window.iOSWebView.jsCallOc(param);//JS傳給oc的參數(shù)
                alert(tempValue);
            }

2缀台、原生調(diào)用js

原生oc主要代碼:

- (void)buttonAction {    
    // oc調(diào)用js函數(shù) js無返回值
    NSString *jsAction = @"ocCallJs(11)";
    [self.context evaluateScript:jsAction];
    // oc調(diào)用js函數(shù) 傳參 并且有js返回值
    NSString *str1 = [self.webView stringByEvaluatingJavaScriptFromString:@"jsCallOc2(oc調(diào)用js函數(shù) 并傳參 接收js返回值);"];
    NSLog(@"js函數(shù)給我的返回值:%@", str1);
}

js中實(shí)現(xiàn)oc需要調(diào)用的方法

function jsCallOc2(param) {
            alert(param)
            return  '哈哈' + param
        }

到此一切看上去都很完美
但是在進(jìn)行調(diào)試的時(shí)候發(fā)現(xiàn),當(dāng)H5頁面內(nèi)部進(jìn)行頁面跳轉(zhuǎn)的時(shí)候哮奇,發(fā)現(xiàn)js 調(diào)用原生方法失效膛腐,找了網(wǎng)上的方法,很多都是說在- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 代理方法中鼎俘,remove掉之前的webview重新進(jìn)行創(chuàng)建哲身,然而并沒有解決我的問題,也沒有找到其他方法而芥,可能是我太菜??

然后就打算使用WKWebView替換UIWebView

好,接下來介紹基于WKWebView 的js原生交互
二膀值、WKWebView 的 js原生交互
js 調(diào)用原生方法

原生中的代碼大概是這樣子的:

// js配置
    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    //需要JS調(diào)用iOS 原生的方法棍丐,都要添加到這里
    [userContentController addScriptMessageHandler:self name:@"finishHandle"];
    // WKWebView的配置
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = userContentController;
// 顯示W(wǎng)KWebView
    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight-NavitionbarHeight) configuration:configuration];
    self.webView.UIDelegate = self; // 設(shè)置WKUIDelegate代理
    [self.view addSubview:self.webView];

然后js 中只需

window.webkit.messageHandlers.finishHandle.postMessage('哈哈');

window.webkit.messageHandlers是固定寫法


image.png

好像也挺簡單,但是這種方式原生沒有辦法把返回值傳給js
還有在使用這種方案沧踏,在頁面消失時(shí)需要removeScriptMessageHandlerForName歌逢,否則會(huì)造成循環(huán)引用

- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
 [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"finishHandle"];
}

接上,下面介紹的這種方案有返回值翘狱,而且不會(huì)有重定向問題
實(shí)現(xiàn)的大致思路是秘案,讓js調(diào)用prompt()方法,然后iOS 就會(huì)調(diào)用runJavaScriptTextInputPanelWithPrompt代理方法潦匈,在代理方法中攔截js參數(shù)阱高,再進(jìn)行判斷
原生代碼:
實(shí)現(xiàn)代理方法

//接收到輸入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    NSError *err = nil;
    NSData *dataFromString = [prompt dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:dataFromString options:NSJSONReadingMutableContainers error:&err];
    if (!err){
        NSString *type = [payload objectForKey:@"type"];
       //如果type == iOS 進(jìn)行處理,調(diào)用原生方法
        if (type && [type isEqualToString:@"iOS"]){
            completionHandler([self getReturnValueWithPayload:payload]);
            return;
        }
    }
   
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.text = defaultText;
    }];
    [alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alertController.textFields[0].text?:@"");
    }])];
    
    [self presentViewController:alertController animated:YES completion:nil];
}

- (void)configMethod:(NSDictionary *)payload {
    NSString *returnValue = @"";
    //JS調(diào)用原生方法名
    NSString *functionName = [payload objectForKey:@"functionName"];
   //JS傳入?yún)?shù)
    NSString *args = [payload objectForKey:@"arguments"]; // JS傳入的值
  //以下根據(jù)業(yè)務(wù)需要處理參數(shù)茬缩,然后返回值給js
}

js代碼:

//從移動(dòng)端獲取數(shù)據(jù)
function  getAppData(functionName,param){
    var webView = isWebView();
    if(webView == "ios"){
        var payload = {"type": "iOS", "functionName": functionName, "arguments": param};
       //讓js調(diào)用prompt方法赤惊,傳入payload參數(shù),原生會(huì)接收到參數(shù)
      //functionName 需要調(diào)用的原生方法
        return prompt(JSON.stringify(payload));
    }else{
        throw new Error("環(huán)境異常凰锡!");
    }
}

以上方案大致符合公司需求未舟,采用的就是這樣方案圈暗,但是這種方法有一個(gè)bug,就是在其他微信和支付寶中打開頁面會(huì)顯示彈窗

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裕膀,一起剝皮案震驚了整個(gè)濱河市员串,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌昼扛,老刑警劉巖寸齐,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異野揪,居然都是意外死亡访忿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門斯稳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來海铆,“玉大人,你說我怎么就攤上這事挣惰∥哉澹” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵憎茂,是天一觀的道長珍语。 經(jīng)常有香客問我,道長竖幔,這世上最難降的妖魔是什么板乙? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮拳氢,結(jié)果婚禮上募逞,老公的妹妹穿的比我還像新娘。我一直安慰自己馋评,他們只是感情好放接,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著留特,像睡著了一般纠脾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜕青,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天苟蹈,我揣著相機(jī)與錄音,去河邊找鬼右核。 笑死汉操,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蒙兰。 我是一名探鬼主播磷瘤,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼芒篷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了采缚?” 一聲冷哼從身側(cè)響起针炉,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扳抽,沒想到半個(gè)月后篡帕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贸呢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年镰烧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楞陷。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怔鳖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出固蛾,到底是詐尸還是另有隱情结执,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布艾凯,位于F島的核電站献幔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏趾诗。R本人自食惡果不足惜蜡感,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恃泪。 院中可真熱鬧郑兴,春花似錦、人聲如沸悟泵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糕非。三九已至,卻和暖如春球榆,著一層夾襖步出監(jiān)牢的瞬間朽肥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工英融, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淀衣,地道東北人二驰。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像始腾,于是被迫代替她去往敵國和親州刽。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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