OC之WebView 和原生 App 交互。
最近参加了很多面试,都问到了关于 Hybrid 开发。
我基本可以把 WebView 和 OC 之间的双向交互的原理说明白。
并且可以自己手动的写 js 代码完成双端的交互。
但由于,之前没有用过类似的混合开发的框架,被面试官给一票否决了。
想想挺郁闷的。
我所理解的 Hybrid 开发。
说实在话,为什么要用 Hybrid 开发模式?
- 可以动态的更新界面,比如活动等。App 端则基本不用做修改。
- HTML5可以写出很绚丽的界面。而使用 OC 原生的要写出这么绚丽的界面是一件很费时费力的过程。
说白了,在界面表现灵动性的方面,HTML5比原生的 OC 强大多了。代价也更小。这种情况对于 OC 一个纯开发 App 界面的语言来说,不知道有什么想法。
从 WebView 到 OC 的数据流向。
WebView 本质上就是一个内置的浏览器。
浏览器的执行过程简单来看:
- 请求 URL
- 服务器返回 HTML 数据
- 浏览器解析渲染 HTML + CSS
- 浏览器执行 JS。
那么 WebView 如何跟原生的 OC 发生交互呢?
原理就在:当 WebView 这个浏览器发送 URL 请求的时候,在 OC 级别我们可以使用 WebView 的代理方法捕获到这个信号。
**- (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType
这个代理方法返回值是 BOOL 类型。
返回 YES 表示,请求继续往下走,该干嘛干嘛。
返回 NO 表示,截获了这个请求,请不要往下走了。也就是说,URL 请求,压根就没有发布出去。
对于 WebView 到 App 之间的交互,就是通过这个代理方法来执行的。
简单实现:
- 在 HTML 中,镶嵌一个 A 标签,给 href 属性设置一个目的是不跳转到百度,而是被截获的协议链接。
<a href='gqs://ccccc'>从浏览器到 OC</a><br />
当点击 WebView 中这个 A 标签的时候,会发送 URL 请求。于是进进入到上面的那个代理方法。
在代理方法中,过滤需要截获的请求。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([request.URL.absoluteString containsString:@"gqs"]) {
NSLog(@"%@",@"捕获到了自定义协议");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"这是标题" message:@"浏览器到 OC 的通道打通了!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"知道了!" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:confirmAction];
[self presentViewController:alertController animated:YES completion:nil];
return NO;
}
// 正常的URL链接就让它们继续去执行。
return YES;
}
到此为止,WebView -> App 的流向就走通了。
原理一句话:App 通过代理方法,截获 WebView 的请求,根据请求筛选,做一些响应的事情。
从 App 到 WebView 的走向。
说白了,就是一个方法。
webView stringByEvaluatingJavaScriptFromString:
这儿方法,就是在当前的 HTML 中,插入一段 js 代码。
你插入的是什么 js 代码,WebView 就执行什么代码。
一个简单的业务场景:
用户需要从联系人列表中,选中一个联系人号码(App 端)。然后把这个号码赋值给 WebView 的某个 HTML 文本框里。
也就是数据走向 : App -> WebView
做法如下:
- 在 HTML 中,实现定义一个用户显示用户号码的 js 函数。
<html>
<head>
<title> 标题</title>
</head>
<body>
<a href='gqs://ccccc'>从浏览器到 OC</a><br />
用户的电话号码:<input type="text" id="userPhone" />
</body>
</html>
<script type="text/javascript">
function showUserPhoneNum(phoneNum) {
document.getElementById("userPhone").value = phoneNum;
}
</script>
- 在 App 中,选择了用户手机号码之后,调用 stringByEvaluatingJavaScriptFromString 将手机号码传递到 WebView 的 Input id = userPhone 这个文本框上。
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty {
// NSArray<CNLabeledValue<CNPhoneNumber*>*>
/**
] (
"<CNLabeledValue: 0x618000275a00: identifier=E297F1F7-CAFC-4A9D-ABF8-F79DB4496C87, label=_$!<Mobile>!$_, value=<CNPhoneNumber: 0x61800022be00: countryCode=us, digits=8885555512>>",
"<CNLabeledValue: 0x618000275d00: identifier=5E423897-5B64-4129-AF55-10B1B3153697, label=_$!<Home>!$_, value=<CNPhoneNumber: 0x61800022c280: countryCode=us, digits=8885551212>>"
)
*/
NSString *phoneNumber = [contactProperty.value stringValue];
NSLog(@"%@",phoneNumber); // 拿到用户的电话号码
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"showUserPhoneNum(\"%@\")",phoneNumber]];
}
从 App -> WebView 原理:一句话,通过stringByEvaluatingJavaScriptFromString调用 HTML 中已经写好的,或者自己写的 js 代码,来实现App -> WebView 的数据走向。