WKWebView與H5交互

iOS 與js交互方法

下面主要來說說WKScriptMessageHandler漩氨,WKWebView已經(jīng)內置了JS與OC的互調柿究、傳值等方法慕购,在H5頁面中,可以通window.webkit.messageHandlers接口與Native進行交互犹芹。您可以通過這個接口向原生代碼發(fā)送消息,并且獲取到原生代碼處理的結果。

JS調OC

H5實現(xiàn)下面方法
// JS調OC,方法名就是交互的名稱喧伞,數(shù)據(jù)就是JS給OC傳的值  
  window.webkit.messageHandlers.<方法名>.postMessage(<data>)

坑點

  • 如果傳的數(shù)據(jù)為空,需要這樣寫postMessage(null)绩郎。
OC響應
  1. viewWillAppear添加配置
-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"getVerifyResult"]; 
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"getVerifyResult"]; 
}

注意

  • 這里的name就是JS的方法名字潘鲫,方法名必須一致"
  1. 實現(xiàn) WKScriptMessageHandler 協(xié)議
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if([message.name isEqualToString:@"getVerifyResult"]){
        // 獲取到驗證結果后,可以進行不同的業(yè)務操作
        NSLog(@"data: %@", message.body);
    }
}

注意

  • 這里的name也是js的方法名字肋杖,方法名必須一致溉仑,通過方法名字判斷響應H5對應的js方法

OC調JS

webView加載完成,傳值給H5
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
       NSDictionary *dict = @{@"status":@(1)};
       NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:(NSJSONWritingPrettyPrinted) error:nil];
       NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
       NSString *js = [NSString stringWithFormat:@"updateStatus(%@)", jsonStr];
      [self.webView evaluateJavaScript: js completionHandler:^(id _Nullable res, NSError * _Nullable error) {
          if (error) {
               NSLog(@"js執(zhí)行失敗:%@", error);             
           } else {
               NSLog(@"js執(zhí)行成功");
          }
      }];
}

注意

  • H5 中的js方法也要和updateStatus(params)定義的方法名字一致

實踐例子

需求
Native引入H5的一個驗證服務状植,當H5中觸發(fā)驗證時浊竟,需要將驗證相關參數(shù)傳遞給Native, 然后Native再去異步驗證,并且要把驗證結果回傳給H5津畸,但其中要求H5發(fā)出與Native傳值交互后振定,需要同步拿到Native驗證結果,并在在觸發(fā)驗證方法里面返回驗證結果肉拓。

上述列子要實現(xiàn)的大概流程

 // 觸發(fā)驗證服務的回調函數(shù)(帶驗證信息)
 
  async function captchaVerifyCallback(verifyParam) {
    // 1. 向Native發(fā)送驗證參數(shù)
    window.webkit.messageHandlers.getVerifyResult.postMessage(verifyParam)
    //2. 獲取驗證結果
    const isSucceed = await xxxx('http://您的業(yè)務請求地址', {
        verifyParam: verifyParam, // 驗證碼參數(shù)
     });
     // 3. 構造標準返回參數(shù)
    const verifyResult = {
        status: isSucceed
    };
    return verifyResult;
  }

由于我們第二步的驗證結果是在Native中進行的后频,通常,這種交互是異步的,因為它依賴于原生代碼的處理和回調卑惜。然而膏执,window.webkit.messageHandlers本身并不直接支持Promise或者async/await機制。消息的發(fā)送通常是單向的露久,從JavaScript發(fā)送到原生代碼更米,而原生代碼的回復則需要通過其他機制來實現(xiàn)。如果要讓這種交互能夠使用await毫痕,需要構建一個Promise并在原生代碼處理完畢后通過某種方式(通常是一個回調函數(shù))來解決(resolve)這個Promise征峦。

以下是H5Native的具體實現(xiàn)

H5頁面js實現(xiàn)
<script>
  async function verifyCallback(verifyParam) {
    // 1.向向Native發(fā)送相關驗證信息
    let isSucceed = false;
    try {
        result = await sendMessageToNative('getVerifyResult', verifyParam);
        console.log('Received response from native:', result);
        isSucceed = result. isSucceed === 1;
    } catch (error) {
        console.error('error:', error);
    }
     // 2.構造標準返回參數(shù)
    const verifyResult = {
        result: isSucceed
    };
    return verifyResult;
  }
    // 在H5頁面中定義一個函數(shù),用于發(fā)送消息給原生镇草,并返回一個Promise
    // actionName: 函數(shù)名稱眶痰,這里為getVerifyResult
    function sendMessageToNative(actionName, params) {
        return new Promise((resolve, reject) => {
            // 創(chuàng)建一個唯一的回調函數(shù)名稱
            const callbackName = 'method_' + Math.random().toString(36).substring(3);
            // 將回調函數(shù)掛載到window對象上,以便原生代碼可以調用
            window[callbackName] = (response) => {
                resolve(response); // 注意可能要格式轉換梯啤,根據(jù)實際情況
                // 移除掛載的回調函數(shù)竖伯,避免內存泄露
                delete window[callbackName];
            };
            // 發(fā)送消息給原生代碼
            window.webkit.messageHandlers[actionName].postMessage({
                data: params,
                callback: callbackName
            });
        });
    }
</script>
Native 實現(xiàn)

WKWebView初始化

  // 配置頁面自適應縮放
  NSString *javascript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta)";
  WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
  // 設置UserAgent
  configuration.applicationNameForUserAgent = @"iOS_ua";
  WKUserScript *userScript = [[WKUserScript alloc]initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
   WKUserContentController *usercontroller = [[WKUserContentController   [usercontroller addUserScript:userScript];
  configuration.userContentController = usercontroller;
  _webView = [[WKWebView alloc]initWithFrame:CGRectZero configuration:configuration];
  _webView.navigationDelegate = self;

實現(xiàn)WKScriptMessageHandler協(xié)議

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    YLTLog(@"didReceiveScriptMessage: %@", message.name);
    if([message.name isEqualToString:@"getVerifyResult"]){
        // 獲取到驗證結果后,可以進行不同的業(yè)務操作
        NSDictionary *msgDict = message.body;
        NSString *callbackName = msgDict[@"callback"];
        NSString *verifyParam = msgDict[@"data"];
        if (!callbackName || !verifyParam) {
            return;
        }
        // 此處以延時操作模擬驗證過程
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
             NSDictionary *dict = @{@"isSucceed":@(1)};
             NSData *data = [NSJSONSerialization dataWithJSONObject:params options:(NSJSONWritingPrettyPrinted) error:nil];
             NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
             NSString *js = [NSString stringWithFormat:@"%@(%@)", callbackName, response];
            // 執(zhí)行回調因宇,結果傳遞回H5頁面
            [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable res, NSError * _Nullable error) {
                if (error) {
                    NSLog(@" js 執(zhí)行失敗 error: %@", error);
               }else {// 驗證碼發(fā)送成功
                   NSLog(@" js 執(zhí)行成功");
              }
            }];
       });
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末七婴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子察滑,更是在濱河造成了極大的恐慌打厘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贺辰,死亡現(xiàn)場離奇詭異户盯,居然都是意外死亡,警方通過查閱死者的電腦和手機饲化,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門莽鸭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吃靠,你說我怎么就攤上這事硫眨。” “怎么了巢块?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵礁阁,是天一觀的道長。 經(jīng)常有香客問我族奢,道長姥闭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任越走,我火速辦了婚禮泣栈,結果婚禮上,老公的妹妹穿的比我還像新娘弥姻。我一直安慰自己南片,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布庭敦。 她就那樣靜靜地躺著疼进,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秧廉。 梳的紋絲不亂的頭發(fā)上伞广,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音疼电,去河邊找鬼嚼锄。 笑死,一個胖子當著我的面吹牛蔽豺,可吹牛的內容都是我干的区丑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼修陡,長吁一口氣:“原來是場噩夢啊……” “哼沧侥!你這毒婦竟也來了?” 一聲冷哼從身側響起魄鸦,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤宴杀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拾因,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旺罢,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年绢记,在試婚紗的時候發(fā)現(xiàn)自己被綠了扁达。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡庭惜,死狀恐怖罩驻,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情护赊,我是刑警寧澤惠遏,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站骏啰,受9級特大地震影響节吮,放射性物質發(fā)生泄漏。R本人自食惡果不足惜判耕,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一透绩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦帚豪、人聲如沸碳竟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莹桅。三九已至,卻和暖如春烛亦,著一層夾襖步出監(jiān)牢的瞬間诈泼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工煤禽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铐达,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓檬果,卻偏偏與公主長得像瓮孙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子汁汗,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容