Just My Life & My Work

現在製作 App,很多時候需要嵌入 WebView,如此能快速開發與更新。既然 App 與 Web 互動頻繁,那麼就需要來了解如何讓 WKWebView 與 Native 互通資料

多年前我也有寫過 Objective C與Javascript的溝通,然而那時還能使用 UIWebView,現在已經被棄用,所以我們就直接使用 WKWebView 吧!

為了好 Demo 流程運作,需要準備一個檔案 test.html,放在 Xcode 專案底下。

test.html 檔案內容:

<html>

<head>
    <title>JS Bridge Demo</title>
    <meta charset="utf-8">
    <script type="text/javascript">
    function shareSuccess(token) {
        print(token);
        print("Hello, Happy World!");
        var h1Elements = document.getElementsByTagName("h1");
        for(var i = 0; i < h1Elements.length; i++) {
            h1Elements[i].style.color = "#FF3456";
            h1Elements[i].innerHTML = token;
        }
    }

    function btnClick() {
        try {
            window.webkit.messageHandlers.shareAction.postMessage([{ "title": "分享", "content": "快樂測試", "url": "連結" }, "shareSuccess"])
        } catch (err) {
            alert(err)
        }
    }
    </script>
</head>

<body>
    <h1>JS Bridge Happy Demo</h1>
    <p style="text-align: center;">
        <button type="button" onclick="btnClick()" style="font-size: 77px;">Test JS</button>
    </p>
</body>

</html>

如果是用 Chrome 開啟該檔案,會如此呈現:

接著來寫 iOS Native 程式碼:

/**
 Theme: Interaction for Native and WebView
 IDE: Xcode 13.3.1
 Language: Objective C (iOS)
 Date: 111/11/29
 Author: HappyMan
 Blog: https://cg2010studio.wordpress.com/
 */

#import "WebViewController.h"
#import <WebKit/WKWebView.h>
#import <WebKit/WKUserContentController.h>
#import <WebKit/WKScriptMessage.h>
#import <WebKit/WKWebViewConfiguration.h>
#import <WebKit/WKFrameInfo.h>

@interface WebViewController () <WKScriptMessageHandler>
{
    WKWebView *wv;
}

@end

@implementation WebViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    WKUserContentController *ucc = [[WKUserContentController alloc] init];
    [ucc addScriptMessageHandler:self name:@"shareAction"];// JS 函式名稱
    
    WKWebViewConfiguration *wvc = [[WKWebViewConfiguration alloc] init];
    wvc.userContentController = ucc;
    
    wv = [[WKWebView alloc] initWithFrame:UIScreen.mainScreen.bounds configuration:wvc];
    [self.view addSubview:wv];
    [self.view insertSubview:wv atIndex:0];
    
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];// HTML 檔
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    [wv loadRequest:urlRequest];
}

#pragma mark - WKScriptMessageHandler
// <name> 函式名稱,<messageBody> 參數
// window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"message.body: %@", message.body);
    NSLog(@"message.name: %@", message.name);
    NSLog(@"message.frameInfo.request: %@", message.frameInfo.request);
    
    // 收到 JS 訊息
    if ([message.name isEqualToString:@"shareAction"]) {// JS 函式名稱
        NSDictionary *dict = ((NSArray *)message.body)[0];
        NSLog(@"title: %@", dict[@"title"]);
        NSLog(@"content: %@", dict[@"content"]);
        NSLog(@"url: %@", dict[@"url"]);
        
        // 回傳給 JS 結果
        NSString *str = ((NSArray *)message.body)[1];// JS 函式名稱
        NSString *scriptStr = [NSString stringWithFormat:@"%@(\"happy studio ^_^\")", str];
        
        [wv evaluateJavaScript:scriptStr completionHandler:^(id _Nullable, NSError * _Nullable error) {
            NSLog(@"error: %@", error);
        }];
    }
}

@end

我們期望的流程是:

點擊 Test JS,會有 Log:

message.body: (
        {
        content = "快樂測試";
        title = "分享";
        url = "連結";
    },
    shareSuccess
)
message.name: shareAction
message.frameInfo.request: <NSMutableURLRequest: 0x6000018cc520> { URL: file:///Users/happyboy/Library/Developer/CoreSimulator/Devices/TestWebView.app/test.html }
title: 分享
content: 快樂測試
url: 連結
error: (null)

需留意的地方:

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)

  • <name>:函式名稱
  • <messageBody>:參數

Native 必須加入 WebView Message Handler:shareAction

於是大部分需求都能如此互通有無~😀

參考:

廣告

隨意留個言吧:)~

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

標籤雲

%d 位部落客按了讚: