iOS开发iOS旅途IOS开发路上的故事

iOS使用WKWebView与H5交互—JS调用原生方法

2018-07-07  本文已影响176人  朝阳小麦

适合人群:iOS开发人员。
内容:iOS中通过UIWebView与H5交互,实现提供原生方法给内嵌H5页面调用。
(UIWebView的交互方式写法与此不同,详见:
https://www.jianshu.com/p/387129b5b350)。

简要:现在iOS开发基本都把UIWebView替换成WKWebView了。于是,项目中之前用的UIWebView与H5交互,也做了更改。本文介绍JS调用OC原生方法。

1.首先呢,写个测试html文件。不会的可以复制下面代码:

<!DOCTYPE html>
<html>
    <header>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript">
             //首先在JS代码中加入对事先约定好的 ScriptMessage(JS事件)的调用
             //window.webkit.messageHandlers.<事件名>.postMessage(需要传递的数据)
             //注意:目前测试来看,postMessage(3)必须要传参数,没有的话就放个占位参数,否则OC收不到响应。
            function changeOrientation() {
                window.webkit.messageHandlers.changeOrientation.postMessage("1");
            }
            function selectBrowse() {
                window.webkit.messageHandlers.selectBrowse.postMessage("6");
            }
            function saveFloorId() {
                window.webkit.messageHandlers.saveFloorId.postMessage("1234321");
            }
        </script>
        
        <style>
            button {
                width:500px;
                height:100px;
                font-size:30px;
            }
        
            </style>
    </header>

    <body>
        <br/>
        <br/>
        <button type="button" onclick="changeOrientation()">changeOrientation</button>
        <br/>
        <br/>
        <button type="button" onclick="selectBrowse()">selectBrowse</button>
        <br/>
        <br/>
        <button type="button" onclick="saveFloorId()">saveFloorId</button>

    </body>
</html>

2.接下来就是OC部分了。创建一个控制器界面,用于显示H5页面。先上代码吧,代码不多,也都有注释。

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController


@end

ViewController.m


#import "ViewController.h"
#import <WebKit/WebKit.h>//用WKWebView需要导入

@interface ViewController ()<WKNavigationDelegate, WKScriptMessageHandler>

@property (nonatomic, strong) WKWebView *webView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.webView];
    self.webView.frame = self.view.bounds;
    
    NSString *weburl = [[NSBundle mainBundle] pathForResource:@"color"ofType:@"html"];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:weburl]]];
        
}


#pragma mark - WKScriptMessageHandler协议方法
//    - (void)changeOrientation:(NSInteger)param;
//    - (void)selectBrowse;
//    - (void)saveFloorId:(NSString *)floorId;
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    
    NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name,message.body);
    if ([message.name isEqualToString:@"changeOrientation"]) {
        NSInteger body = [message.body integerValue];
        [self changeOrientation:body];
    }
    else if ([message.name isEqualToString:@"selectBrowse"]) {
        [self selectBrowse];
    }
    else if ([message.name isEqualToString:@"saveFloorId"]) {
        [self saveFloorId:message.body];
    }
}

#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    
}

#pragma mark - methods.

- (void)changeOrientation:(NSInteger)param {
    NSLog(@"changeOrientation---%ld", (long)param);
}

- (void)selectBrowse {
    NSLog(@"selectBrowse---");
}

- (void)saveFloorId:(NSString *)floorId {
    NSLog(@"saveFloorId---%@", floorId);
}

#pragma mark - lazy load.

- (WKWebView *)webView {
    if (!_webView) {
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        config.preferences.javaScriptEnabled = YES;
        
        config.userContentController = [[WKUserContentController alloc] init];
        [config.userContentController addScriptMessageHandler:self name:@"changeOrientation"];
        [config.userContentController addScriptMessageHandler:self name:@"selectBrowse"];
        [config.userContentController addScriptMessageHandler:self name:@"saveFloorId"];
        
        WKPreferences *preferences = [WKPreferences new];
        preferences.javaScriptCanOpenWindowsAutomatically = YES;
        config.preferences = preferences;
        
        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
        _webView.navigationDelegate = self;
    }
    return _webView;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

3.就这么多代码。现在简单概括两点:
(1)WKWebView的初始化:

 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        
        config.userContentController = [[WKUserContentController alloc] init];
//注册WKScriptMessageHandler协议代理
        [config.userContentController addScriptMessageHandler:self name:@"changeOrientation"];
        [config.userContentController addScriptMessageHandler:self name:@"selectBrowse"];
        [config.userContentController addScriptMessageHandler:self name:@"saveFloorId"];
        
        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
        _webView.navigationDelegate = self;

(2)实现WKScriptMessageHandler协议方法:

#pragma mark - WKScriptMessageHandler协议方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    
    NSLog(@"JS 调用了 %@ 方法,传回参数 %@",message.name,message.body);
    if ([message.name isEqualToString:@"changeOrientation"]) {
        NSInteger body = [message.body integerValue];
        [self changeOrientation:body];
    }
    else if ([message.name isEqualToString:@"selectBrowse"]) {
        [self selectBrowse];
    }
    else if ([message.name isEqualToString:@"saveFloorId"]) {
        [self saveFloorId:message.body];
    }
}

完成。
写法上比UIWebView简单方便多了。

4.关于WKScriptMessageHandler协议代理是否需要注销问题,目前不确定是否会影响到内存泄漏。

//销毁代理
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"changeOrientation"];
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"selectBrowse"];
    [_webView.configuration.userContentController removeScriptMessageHandlerForName:@"saveFloorId"];

这个疑问有答案了再解决吧。目前观察看,没发现严重内存泄漏。

上一篇 下一篇

猜你喜欢

热点阅读