iOS開發(fā)中webview和OC交互

1.簡介

iOS開發(fā)中不可避免會遇到跟H5界面的問題跷敬,本文將詳細講解OC和web的交互重绷,供大家學(xué)習(xí)參考篱竭。

2.概述

2.1交互方式

  • OC調(diào)用JS
  • JS調(diào)用OC

2.2加載JS的方式

OC開發(fā)中加載網(wǎng)頁有兩種選擇昼接,iOS7之前使用UIWebView构韵,iOS8之后時候WKWebView,后續(xù)將分別講解UIWebView和WKWebView如何和網(wǎng)頁交互實現(xiàn)JS和OC的相互調(diào)用爵嗅。

2.3網(wǎng)頁中加載框顯示異常

主要有如下兩個問題

  • 提示框無法顯示
  • 提示框標(biāo)題顯示異常

3.UIWebView和網(wǎng)頁的交互

3.1原生OC調(diào)用網(wǎng)頁的JS

[_web stringByEvaluatingJavaScriptFromString:@"callJS('ok');" ];
以上代碼即可實現(xiàn)webView調(diào)用網(wǎng)頁骄蝇,其中的callJS為js的方法,ok是傳入的參數(shù)

3.2網(wǎng)頁JS調(diào)用原生OC的方法

3.2.1 攔截請求

OC端代碼

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *requestString = [[request URL] absoluteString];
    NSArray *components = [requestString componentsSeparatedByString:@":"];
    //攔截UIWebView請求的URL操骡,根據(jù)不同的規(guī)則,可以調(diào)用不同的OC方法
    if ([components count] > 1 && [(NSString *)[components objectAtIndex:0] isEqualToString:@"testapp"])
    {
        [self back];
        return false;
    }
    return true;
}
- (void)back
{
    [self dismissViewControllerAnimated:true completion:^{
        
    }];
}

JS端代碼

在這里插入代碼片
function clickLink(){
            var url="testapp:"+"alert"+":"+"你好嗎赚窃?";
            document.location = url;
        }

3.3.2 注入JS代碼

OC端代碼

 [self.web stringByEvaluatingJavaScriptFromString:@"var script = document.createElement('script');"
     "script.type = 'text/javascript';"
     "script.text = \"function myFunction() { "   //定義myFunction方法
     "alert('注入js');"
     "}\";"
     "document.getElementsByTagName('head')[0].appendChild(script);"];  
     OC代碼中自定義JS方法myFunction注入到網(wǎng)頁中册招,JS端可以直接調(diào)用myFunction方法。由于該方法是OC中注入的勒极,故而可以傳入一定的參數(shù)用于網(wǎng)頁端和OC端的通信是掰。

JS端代碼

function callInjeJs(){
            myFunction();
        }

4.WKWebView和網(wǎng)頁的交互

4.1.原生OC調(diào)用網(wǎng)頁的JS

OC端代碼

 [_web evaluateJavaScript:@"callJS('ok')" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    }];
 以上代碼即可實現(xiàn)webView調(diào)用網(wǎng)頁,其中的callJS為js的方法辱匿,ok是傳入的參數(shù)

JS端代碼

 function callJS(str1)
        {
            alert(str1);
        }

4.2.網(wǎng)頁JS調(diào)用原生OC的方法

OC端代碼

 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
 [config.userContentController addScriptMessageHandler:self name:@"AppModel"];
 WKWebView *web = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0,400, 250) configuration:config];
  [self.view addSubview:web];
    
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSString *name = message.name;
    if([name isEqualToString:@"AppModel"])
    {
        NSString *bodyStr = message.body;
        NSLog(@"JS調(diào)用OC成功 參數(shù)為= %@",bodyStr);
    }
}
該方法為WKScriptMessageHandler的協(xié)議方法键痛,務(wù)必遵守該協(xié)議

JS端代碼

 function callOC()
        {
            window.webkit.messageHandlers.AppModel.postMessage({body: 'param1'});
        }
        其中AppModel為名稱炫彩,{body,'param1'}為自定義的參數(shù)

5.JS提示框顯示異常問題

5.1.JS提示框在UIWebView中顯示異常

JS提示框在UIWebView顯示時,經(jīng)常會出現(xiàn)一個URL的地址絮短,在其他客戶端(如安卓)沒有此問題江兢。該問題可通過如下代碼解決:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    //獲取js寫的界面的title
        NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    //*解決webview上內(nèi)嵌的頁面中彈出來的alert有域名問題!*/ PS:這個才是這篇博客的關(guān)鍵
    //1丁频、獲取js的執(zhí)行環(huán)境
    JSContext *ctx = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //2杉允、js那邊寫的提示框的函數(shù)入口,這里差不多有點重寫那個函數(shù)的意思席里。JSValue *message參數(shù)可以獲取到j(luò)s中的提示信息叔磷,OC中需要轉(zhuǎn)換為string顯示出來,好了完成了奖磁。
    //解決Alert類型的提示框異常問題
    ctx[@"window"][@"alert"] = ^(JSValue *message) {
        dispatch_async(dispatch_get_main_queue(), ^{
        //自定義原生提示框替換原來的提示框
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"alert" message:[message toString] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
        });
    };
    //解決confirm提示框顯示異常問題
    ctx[@"window"][@"confirm"]=^(JSValue *message) {
        dispatch_async(dispatch_get_main_queue(), ^{
          //自定義原生提示框替換原來的提示框
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"alert" message:[message toString] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
        });
    };
    //解決prompt提示框顯示異常問題
    ctx[@"window"][@"prompt"] = ^(JSValue *message) {
        dispatch_async(dispatch_get_main_queue(), ^{
          //自定義原生提示框替換原來的提示框
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"alert" message:[message toString] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
        });
    };
}

5.2. JS提示框在WKWebView中顯示異常

JS提示框在WKWebView中會無法顯示改基,可以通過以下的方案解決。

// 在JS端調(diào)用alert函數(shù)時咖为,會觸發(fā)此代理方法秕狰。
// JS端調(diào)用alert時所傳的數(shù)據(jù)可以通過message拿到
// 在原生得到結(jié)果后,需要回調(diào)JS案疲,是通過completionHandler回調(diào)
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
    NSLog(@"%@", message);
}

// JS端調(diào)用confirm函數(shù)時封恰,會觸發(fā)此方法
// 通過message可以拿到JS端所傳的數(shù)據(jù)
// 在iOS端顯示原生alert得到Y(jié)ES/NO后
// 通過completionHandler回調(diào)給JS端
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS調(diào)用confirm" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:NULL];
    
    NSLog(@"%@", message);
}

// JS端調(diào)用prompt函數(shù)時,會觸發(fā)此方法
// 要求輸入一段文本
// 在原生輸入得到文本內(nèi)容后褐啡,通過completionHandler回調(diào)給JS
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    NSLog(@"%s", __FUNCTION__);
    
    NSLog(@"%@", prompt);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS調(diào)用輸入框" preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.textColor = [UIColor redColor];
    }];
    
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler([[alert.textFields lastObject] text]);
    }]];
    
    [self presentViewController:alert animated:YES completion:NULL];
}

6 總結(jié)

本文針對ios開發(fā)中webview和網(wǎng)頁的交互問題做了簡單總結(jié)诺舔,后續(xù)有任何問題還會更新。如果各位有任何問題备畦,歡迎回復(fù)低飒。

源碼地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市懂盐,隨后出現(xiàn)的幾起案子褥赊,更是在濱河造成了極大的恐慌,老刑警劉巖莉恼,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拌喉,死亡現(xiàn)場離奇詭異,居然都是意外死亡俐银,警方通過查閱死者的電腦和手機尿背,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捶惜,“玉大人田藐,你說我怎么就攤上這事。” “怎么了汽久?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵鹤竭,是天一觀的道長。 經(jīng)常有香客問我景醇,道長臀稚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任啡直,我火速辦了婚禮烁涌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酒觅。我一直安慰自己撮执,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布舷丹。 她就那樣靜靜地躺著抒钱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颜凯。 梳的紋絲不亂的頭發(fā)上谋币,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音症概,去河邊找鬼蕾额。 笑死,一個胖子當(dāng)著我的面吹牛彼城,可吹牛的內(nèi)容都是我干的诅蝶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼募壕,長吁一口氣:“原來是場噩夢啊……” “哼调炬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舱馅,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缰泡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后代嗤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棘钞,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年干毅,在試婚紗的時候發(fā)現(xiàn)自己被綠了宜猜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡溶锭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出符隙,到底是詐尸還是另有隱情趴捅,我是刑警寧澤垫毙,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站拱绑,受9級特大地震影響综芥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜猎拨,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一膀藐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧红省,春花似錦额各、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痕寓,卻和暖如春傲醉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呻率。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工硬毕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人礼仗。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓吐咳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親藐守。 傳聞我的和親對象是個殘疾皇子挪丢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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