iOS Hybrid开发演进

栏目: IOS · 发布时间: 4年前

内容简介:Web技术相对于Native来说有很多优势,比如:跨端(浏览器、Android、iOS)、排版更灵活、实时生效等。所以,在开发中我们经常会采用一些Web页面嵌入到APP中。这样,就引入了web与Native的交互,往往也就是JavaScript与Native的交互。Native调用JS比较简单

Web技术相对于Native来说有很多优势,比如:跨端(浏览器、Android、iOS)、排版更灵活、实时生效等。所以,在开发中我们经常会采用一些Web页面嵌入到APP中。

这样,就引入了web与Native的交互,往往也就是JavaScript与Native的交互。

JS与Native的交互,可以大致分为:Native调用JS、JS调用Native。

Native调用JS

Native调用JS比较简单

//UIWebView
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

//WKWebView
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
复制代码

注意:

  • UIWebView执行JS是同步的,在WKWebView中是异步的。
  • UIWebView返回值只支持可String化的基本类型,并不支持集合类型(Array、Dictionary)和对象。
  • WKWebView执行JS的回调Block中支持集合类型和对象,也支持可String化的基本类型。

h5代码

<!DOCTYPE html>
<html>
<head>
	<title>WKWebView</title>
    <meta charset="UTF-8" />
	
    <script type="text/javascript">
        function methodA(username, password) {
            console.log("Hello, I am methodA");
            let dict = {
                "username" : username,
                "password" : password
            };
            return "username: " + username + ", password: " + password;
            <!--return dict;-->
            <!--return ["A", "B"];-->
        }
	</script>
</head>
<body>
</body>
</html>
复制代码

Native代码

//UIWebView
NSString *str = [self.webView stringByEvaluatingJavaScriptFromString:@"methodA('zhangsan', '123456')"];
NSLog(@"str");

//WKWebView
[self.webView evaluateJavaScript:@"methodA('zhangsan', '123456')" completionHandler:^(id _Nullable value, NSError * _Nullable error) {
    if (error) {
        NSLog(@"%@", error);
        return ;
    }
    NSLog(@"%@", value);
}];
复制代码

JS调用Native

其实,JS调用Native的交互经历过几个阶段。

iOS7之前

iOS7之前,JS想要调用Native时主动触发加载一个新的url。我们通过拦截URL通过提前约定的协议来判断是否为调用原生功能,用这种方式来处理JS对Native的调用。

JS端主要通过 window.location.assign 来触发新的加载。

iOS中在 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 中针对URL做判断。

JS代码

<!DOCTYPE html>
<html>
<head>
	<title>WKWebView</title>
	<meta charset="UTF-8" />
	<script type="text/javascript">
        function callNative() {
            window.location.assign("native://func1?name=zhangsan&password=123456");
        }
	</script>
</head>
<body>
	<button onClick="callNative()">CallNative</button>
</body>
</html>
复制代码

OC代码

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *urlPath = [request.URL absoluteString];
    /*
     * 与Web端协商定义交互协议 scheme://function_name?para1=value1&para2=value2&para3=value3&callback=callback_value
     *  scheme为native时,是要与原生进行交互。
     *  function_name指定要调用原生的什么功能。
     *  para1是参数名称,value1是参数值
     *  callback是原生执行完后对js的回调
     */
    if ([urlPath hasPrefix:@"native://"]) {
        urlPath = [urlPath substringFromIndex:@"native://".length];
        NSArray *questionMarkArray = [urlPath componentsSeparatedByString:@"?"];
        NSString *funcName;
        NSArray *paraArray;
        if (questionMarkArray.count > 0) {
            funcName = [questionMarkArray firstObject];
            if (questionMarkArray.count > 1) {
                // 从问号后还是都认定为参数
                NSString *paraStr =  [urlPath substringFromIndex:funcName.length + 1];
                paraArray = [paraStr componentsSeparatedByString:@"&"];
            }
        }
        
        // funcname 匹配
        if ([funcName isEqualToString:@"func1"]) {
            
        } else if ([funcName isEqualToString:@"func2"]) {
            
        } else if ([funcName isEqualToString:@"func3"]) {
            
        } else {
            
        }
        
        return NO;
    } else {
        return YES;
    }
}
复制代码

iOS7

iOS7开始,系统公开了JavaScriptCore框架,我们可以基于此来进行JS与Natvie的交互。

插播Javascript的调试方法(我们可以在Mac上调试JS代码)。

Safari的 偏好设置 中勾选底部的 在菜单栏中显示“开发”菜单 ,然后Safari的菜单栏中就多出了 开发 菜单,当webview加载完h5后就可以选择对应的模拟器下对应的应用进行web调试。详细步骤和真机的调试方法请自行Google。

iOS7中通常采用的方式是拿到JSContext,然后将OC的方法或对象注入到JS中。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    // JS的异常回调
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"%@", exception);
    };
    
    // 注入方法
    self.jsContext[@"addNum"] = ^(int a, int b) {
        return a + b;
    };
    
    // 注入对象
    NSDictionary *dict = @{@"aaa" : @"aaa", @"bbb" : @"bbb"};
    self.jsContext[@"dict"] = [JSValue valueWithObject:dict inContext:self.jsContext];
}
复制代码

然后在JS中就可以调用相应的对象和方法,调用方式和调用原生的方法或对象一致。

function callByContext() {
    <!-- addNum为原生向JS注入的方法 -->
    var num = addNum(5, 8);
    console.log(num);
    <!-- dict为原生向JS注入的对象 -->
    console.log(dict);
}
复制代码

iOS8 WKWebView

UIWebView有很多的性能问题,所以苹果在iOS8中引入了新的浏览器组件WKWebView。

并且在iOS12后苹果废弃了UIWebView,所以请同学们务必赶紧升级到WKWebView!!!

在WKWebView的交互中,要使用WKUserContentController。在WKWebView构建的时候,需要传入WKWebViewConfiguration,而WKWebViewConfiguration可以添加WKUserContentController为ScriptMessageHandler。

WKUserContentController *userContent = [[WKUserContentController alloc] init];
[userContent addScriptMessageHandler:id<WKScriptMessageHandler> name:@"MyNative"];
    
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = userContent;
    
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
复制代码

handler 对象需要实现指定协议,实现指定的协议方法,当 JS 端通过 window.webkit.messageHandlers 发送 Native 消息时,handler 对象的协议方法被调用,通过协议方法的相关参数传值。

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {}
复制代码

JS调用iOS的方法

// Javascript
function callNative() {
  window.webkit.messageHandlers.MyNative.postMessage('body');
}
复制代码

相关的JS和iOS代码已上传至GitHub( github.com/NewFarmer21… ),可自行下载和调试。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Powerful

Powerful

Patty McCord / Missionday / 2018-1-25

Named by The Washington Post as one of the 11 Leadership Books to Read in 2018 When it comes to recruiting, motivating, and creating great teams, Patty McCord says most companies have it all wrong. Mc......一起来看看 《Powerful》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具