iOS開發(fā),js與原生OC交互

需求:APP開發(fā)中 幫助與反饋頁面 有一個鏈接需要跳轉(zhuǎn)到網(wǎng)頁澜建,但是需要點擊網(wǎng)頁上面的返回按鈕返回APP中
解決方案:(小編親測好使)
  1. 使用WKWebViewWKUserContentController
  2. 為OC與js交互注冊通用交互方法js_obj,代碼如下:
    [userContent addScriptMessageHandler:self name:@"js_obj"];
  3. WKScriptMessageHandler協(xié)議userContentController方法里面編寫OC接受js回調(diào)信息米丘,然后判斷約定的字段是否一致,如果一致的話舌镶,就執(zhí)行相應(yīng)的代碼柱彻,代碼如下:
    // 判斷是否是調(diào)用原生的
    if([@"js_obj" isEqualToString:message.name]) {
        if ([@"close" isEqualToString:message.body]) {
            [self back];
        }
    }
  1. 在代碼最后豪娜,一定要把注冊的東西移除掉
- (void)dealloc {
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"js_obj"];
}
  1. 前段所要做的工作只有:
    在點擊按鈕返回的時候調(diào)用
    window.webkit.messageHandlers.js_obj.postMessage("close") // js向OC發(fā)送返回消息
  2. 注意,可能會造成循環(huán)引用哟楷,頁面銷毀時不調(diào)用dealloc方法瘤载,所以要在返回方法里面注銷一下,加入如下代碼:
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"js_obj"];
  3. 全部代碼如下:
#import "MineHelpViewController.h"
#import "UserManager.h"
#import <WebKit/WebKit.h>

@interface MineHelpViewController ()<WKScriptMessageHandler,WKUIDelegate,WKNavigationDelegate>

@property(nonatomic,strong)WKWebView *webView;
@property(nonatomic,weak)NSURLRequest *request;

@end

@implementation MineHelpViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    [self setupFromWebView];
}

// 導(dǎo)航欄返回
- (void)back {
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"js_obj"];
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)setupFromWebView {
    // 1. 配置Configuration信息
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.selectionGranularity = WKSelectionGranularityDynamic;
    config.allowsInlineMediaPlayback = YES;
    WKPreferences *preferences = [WKPreferences new];
    // 是否支持JavaScript
    preferences.javaScriptEnabled = YES;
    // 不通過用戶交互,是否可以打開窗口
    preferences.javaScriptCanOpenWindowsAutomatically = YES;
    config.preferences = preferences;
    // 創(chuàng)建UserContentController(提供JavaScript向webView發(fā)送消息的方法)
    // WKUserContentController 是JavaScript與原生進行交互的橋梁
    WKUserContentController *userContent = [[WKUserContentController alloc] init];
    // 添加消息處理卖擅,注意:self指代的對象需要遵守 WKScriptMessageHandler 協(xié)議鸣奔,結(jié)束時需要移除
    [userContent addScriptMessageHandler:self name:@"js_obj"];
    // 將UserConttentController設(shè)置到配置文件
    config.userContentController = userContent;
    //
    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:config];
    self.webView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.webView];
    NSURL *url = [NSURL URLWithString:[self.webURL stringByAppendingFormat:@"?token=%@",[UserManager defaultManager].token]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 設(shè)置內(nèi)邊距
    self.webView.navigationDelegate = self;
    self.webView.UIDelegate = self;
    [self.webView loadRequest:request];
}

#pragma mark - WKScriptMessageHandler
//  JS 端可通過 window.webkit.messageHandlers.js_obj.postMessage("123") 發(fā)送消息
/* JS 調(diào)用原生 */
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
    // 判斷是否是調(diào)用原生的
    if([@"js_obj" isEqualToString:message.name]) {
        if ([@"close" isEqualToString:message.body]) {
            [self back];
        }
    }
}

#pragma mark - WKNavigationDelegate

/* 頁面開始加載 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"----頁面開始加載");
}

/* 頁面返回內(nèi)容 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSLog(@"----頁面返回內(nèi)容");
}

/* 頁面加載完成 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"----頁面加載完成");
}


/* 頁面加載失敗 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"----頁面加載失敗");
}

/* 在發(fā)送請求之前,決定是否跳轉(zhuǎn) */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURL *url =  navigationAction.request.URL;
    NSString *urlStr = url.absoluteString;
    NSLog(@"【load url】=== %@", urlStr);
    //不允許跳轉(zhuǎn)
    //decisionHandler(WKNavigationActionPolicyCancel);
    //return;
    //允許跳轉(zhuǎn)
    decisionHandler(WKNavigationActionPolicyAllow);
}

/* 在收到響應(yīng)之后,決定是否跳轉(zhuǎn) */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    NSLog(@"===%@",navigationResponse.response.URL.absoluteString);
    //允許跳轉(zhuǎn)
    decisionHandler(WKNavigationResponsePolicyAllow);
    //不允許跳轉(zhuǎn)
    //decisionHandler(WKNavigationResponsePolicyCancel);
}

/* 接受到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用 */
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"----接收到服務(wù)器跳轉(zhuǎn)請求之后調(diào)用");
}

/* 加載數(shù)據(jù)發(fā)生錯誤時調(diào)用  */
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"----數(shù)據(jù)加載發(fā)生錯誤時調(diào)用");
}

/* 需要響應(yīng)身份驗證時調(diào)用,同樣在block中需要傳入用戶身份憑證 */
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    //用戶身份信息
    NSLog(@"----需要響應(yīng)身份驗證時調(diào)用 同樣在block中需要傳入用戶身份憑證");
    NSURLCredential *newCard = [NSURLCredential credentialWithUser:@"" password:@"" persistence:NSURLCredentialPersistenceNone];
    // 為 challenge 的發(fā)送方提供 credential
    [[challenge sender] useCredential:newCard forAuthenticationChallenge:challenge];
    completionHandler(NSURLSessionAuthChallengeUseCredential,newCard);
}

/* 進程被終止時調(diào)用 */
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
    NSLog(@"----進程被終止時調(diào)用");
}

#pragma mark - WKUIDelegate

// WKUIDelegate是web界面中有彈出警告框時調(diào)用這個代理方法,主要是用來處理使用系統(tǒng)的彈框來替換JS中的一些彈框的,比如: 警告框, 選擇框, 輸入框等

/**
 webView中彈出警告框時調(diào)用, 只能有一個按鈕
 @param webView webView
 @param message 提示信息
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 警告框消失的時候調(diào)用, 回調(diào)給JS
 */
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"----web界面中有彈出警告框時調(diào)用");
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"警告" message:message preferredStyle:(UIAlertControllerStyleAlert)];
    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"我知道了" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    [alert addAction:ok];
    [self presentViewController:alert animated:YES completion:nil];
}

// JavaScript調(diào)用confirm方法后回調(diào)的方法 confirm是js中的確定框,需要在block中把用戶選擇的情況傳遞進去

/** 對應(yīng)js的confirm方法
 webView中彈出選擇框時調(diào)用, 兩個按鈕
 @param webView webView description
 @param message 提示信息
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 確認框消失的時候調(diào)用, 回調(diào)給JS, 參數(shù)為選擇結(jié)果: YES or NO
 */
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {
    NSLog(@"%@",message);
    completionHandler(YES);
    /*
     UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請選擇" message:message preferredStyle:(UIAlertControllerStyleAlert)];
     UIAlertAction *ok = [UIAlertAction actionWithTitle:@"同意" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
     completionHandler(YES);
     }];
     UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"不同意" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
     completionHandler(NO);
     }];
     [alert addAction:ok];
     [alert addAction:cancel];
     [self presentViewController:alert animated:YES completion:nil];
     */
}

// JavaScript調(diào)用prompt方法后回調(diào)的方法 prompt是js中的輸入框 需要在block中把用戶輸入的信息傳入

/** 對應(yīng)js的prompt方法
 webView中彈出輸入框時調(diào)用, 兩個按鈕 和 一個輸入框
 
 @param webView webView description
 @param prompt 提示信息
 @param defaultText 默認提示文本
 @param frame 可用于區(qū)分哪個窗口調(diào)用的
 @param completionHandler 輸入框消失的時候調(diào)用, 回調(diào)給JS, 參數(shù)為輸入的內(nèi)容
 */
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
    NSLog(@"%@",prompt);
    completionHandler(@"123");
    /*
     UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"請輸入" message:prompt preferredStyle:(UIAlertControllerStyleAlert)];
     [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
     textField.placeholder = @"請輸入";
     }];
     UIAlertAction *ok = [UIAlertAction actionWithTitle:@"確定" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
     UITextField *tf = [alert.textFields firstObject];
     completionHandler(tf.text);
     }];
     UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
     completionHandler(defaultText);
     }];
     [alert addAction:ok];
     [alert addAction:cancel];
     [self presentViewController:alert animated:YES completion:nil];
     */
}

/* 關(guān)閉webView時調(diào)用的方法 */
- (void)webViewDidClose:(WKWebView *)webView {
    NSLog(@"----關(guān)閉webView時調(diào)用的方法");
}

#pragma mark - dealloc

- (void)dealloc {
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"js_obj"];
}

寫在最后:
WKWebView和UIWebView的區(qū)別:
主要是性能問題磨镶,UIWebView占用過多內(nèi)存溃蔫,而且WKWebView有諸多新特性
1.更多的支持HTML5的特性
2.官方宣稱的高達60fps的滾動刷新率以及內(nèi)置手勢
3.與Safari相同的JavaScript引擎
4.將UIWebViewDelegate與UIWebView拆分成了14類與3個協(xié)議
5.增加加載進度屬性:estimatedProgress

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市琳猫,隨后出現(xiàn)的幾起案子伟叛,更是在濱河造成了極大的恐慌,老刑警劉巖脐嫂,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件统刮,死亡現(xiàn)場離奇詭異,居然都是意外死亡账千,警方通過查閱死者的電腦和手機侥蒙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匀奏,“玉大人鞭衩,你說我怎么就攤上這事⊥奚疲” “怎么了论衍?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長聚磺。 經(jīng)常有香客問我坯台,道長,這世上最難降的妖魔是什么瘫寝? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任蜒蕾,我火速辦了婚禮,結(jié)果婚禮上焕阿,老公的妹妹穿的比我還像新娘咪啡。我一直安慰自己,他們只是感情好暮屡,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布瑟匆。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愁溜。 梳的紋絲不亂的頭發(fā)上疾嗅,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音冕象,去河邊找鬼代承。 笑死,一個胖子當著我的面吹牛渐扮,可吹牛的內(nèi)容都是我干的论悴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼墓律,長吁一口氣:“原來是場噩夢啊……” “哼膀估!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耻讽,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤察纯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后针肥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饼记,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年慰枕,在試婚紗的時候發(fā)現(xiàn)自己被綠了具则。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡具帮,死狀恐怖博肋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜂厅,我是刑警寧澤匪凡,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站葛峻,受9級特大地震影響锹雏,放射性物質(zhì)發(fā)生泄漏巴比。R本人自食惡果不足惜术奖,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轻绞。 院中可真熱鬧采记,春花似錦、人聲如沸政勃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奸远。三九已至既棺,卻和暖如春讽挟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丸冕。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工耽梅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胖烛。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓眼姐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佩番。 傳聞我的和親對象是個殘疾皇子众旗,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

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