最新消息:iOS编程开发交流群(6906921) ,Mac.Cocoa开发交流群(7758675) 欢迎iOS/macOS开发编程爱好及学习者加入!

js(javascript)与ios(Objective-C)相互通信交互

iOS 天狐 173028浏览 2评论

随着苹果SDK的不断升级,越来越多的新特性增加了进来,本文主要讲述从iOS6至今,Native与JavaScript的交互方法

一、UIWebview && iframe && JavaScript  <=iOS6

iOS6原生没有提供js直接调用Objective-C的方式,只能通过UIWebView的UIWebViewDelegate协议

方法来做拦截,并在这个方法中,根据url来调用Objective-C方法

1.javascript调用Objective-C

动态添加个iframe改变其地址 最后删除,这种方法不会使当前页面跳转 效果更佳

javascript代码:

Objective-C代码:

2.Objective-C调用javascript


(PS)如果你想去掉webview弹出的alert 中的来自XXX网页

二、JavaScriptCore && UIWebview >=iOS7

iOS7中加入了JavaScriptCore.framework框架。把 WebKit 的 JavaScript 引擎用 Objective-C 封装。该框架让Objective-C和JavaScript代码直接的交互变得更加的简单方便。

合适时机注入交互对象

什么时候UIWebView会创建JSContext环境?

分两种方式

第一在渲染网页时遇到<script标签时,就会创建JSContext环境去运行JavaScript代码。

第二就是使用方法[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]去获取JSContext环境时,这时无论是否遇到<script标签,都会去创造出来一个JSContext环境,而且和遇到<script标签再创造环境是同一个。

什么时候注入JSContext问题

我通常都会在 - (void)webViewDidFinishLoad:(UIWebView *)webView中去注入交互对象,但是这时候网页还没加载完,JavaScript那边已经调用交互方法,这样就会调不到原生应用的方法而出现问题

改成在- (void)viewDidLoad中去注入交互对象,这样倒是解决了上面的问题,但是同时又引起了一个新的问题就是在一个网页内部点击链接跳转到另一个网页的时候,第二个页面需要交互,这时JSContext环境已经变化,但是- (void)viewDidLoad仅仅加载一次,跳转的时候,没有再次注入交互对象,这样就会导致第二个页面没法进行交互。当然你可以在- (void)viewDidLoad和- (void)webViewDidFinishLoad:(UIWebView *)webView都注入一次,但是一定会有更优雅的办法去解决此问题。

如果上边的方案能满足需求,建议实在迫不得已再用这个方法,  就是在每次创建JSContext环境的时候,我们都去注入此交互对象这样就解决了上面的问题。具体解决办法参考了此开源库UIWebView-TS_JavaScriptContext(有时会被APPStore检查出使用私有API 上架会被拒绝 不建议使用)

多个iFrame中的JSContext问题

1. JavaScriptCore调用Objective-C

html中的JS代码,直接调用oc注入的javascript方法 mutiParams()

直接将方法mutiParams()注入到javascript中,iOS中的代码  UIWebview的delegate

JSExport 协议关联 native对象,进而调用对象协议中约定的方法

Objective-C

将名为"app"的对象注入到javascript window对象中,javascript可以使用"app对象"调用TestJSExport协议中的所有方法

JavaScript

app.pushViewControllerTitle()(也可以调用 window.app.pushViewControllerTitle()),当多参数oc方法与javascript关联时,oc方法转为javascript方法,参数转化为括号(参数1,参数2,参数N...)

2.Objective-C 调用 JavaScriptCore

Objective-C

调用js的showResult方法,这里是一个参数 result,多个就依次写到数组中

JavaScript

callWithArguments 线程问题

JSValue的callWithArguments就是oc调用js函数所执行的方法,正常调用callWithArguments的时候偶尔会崩溃。显示一堆webview 线程出错堆栈。

很容易联想到是callWithArguments的执行线程问题,试了下主线程与子线程与webview thread,最终webview最安全,几乎不会报错。个人理解JavaScriptCore的“主线程”其实就是他所在的webThread。所以放在webThread中是正确的方法。

还有一个解决办法就是在执行callWithArguments之前执行下 [webView stringByEvaluatingJavaScriptFromString:@""];

三、WKWebView && JavaScript >=iOS8

iOS 8引入了一个新的框架——WebKit,之后变得好起来了。在WebKit框架中,有WKWebView可以替换UIKit的UIWebView和AppKit的WebView,而且提供了在两个平台可以一致使用的接口。WebKit框架使得开发者可以在原生App中使用Nitro来提高网页的性能和表现,Nitro就是Safari的JavaScript引擎 WKWebView 不支持JavaScriptCore的方式但提供message handler的方式为JavaScript 与Native通信.

1.Objective-C  调用JavaScript

2. JavaScript 调用 Objective-C

本人的demo只注入了一个"Native"对象,然后使用"function"进行方法区分,当然你也可以注册多个messageHandler。

messageHandle调用方法如下两种方式:

简单的封装一下,本方法兼容安卓与iOS,‘Native’为事先在Objective-C注册注入的js对象

handlerInterface:由iOS addScriptMessageHandler与andorid addJavascriptInterface 代码注入而来,一个app可以输入一个或者多个,本人习惯注入一个。

handlerMethod:为具体调用哪个方法,当然也可以使用handlerInterface来区分调用哪个方法。

parameters:为调用方法所需参数

JavaScript调用

Objective-C实现

js调用原生后会触发didReceiveScriptMessage方法,WKScriptMessage包含js调用方法的所有信息。message.name为messageHander的名称,message.body为调用方法的参数。

四、与安卓的兼容

UIWebview location监听url,解析参数的交互方式,与安卓的监听url变化交互方式相同,调用方法一致。

UIWebview与JavascriptCore的交互方式,与安卓的addJavascriptInterface方式都是往window对象中注入对象,调用方法一致。

WKWebView与安卓的addJavascriptInterface方式,存在很大不同,以下是兼容代码。

 

iOS与android Demo地址: https://github.com/shaojiankui/iOS-WebView-JavaScript

 

转载请注明:天狐博客 » js(javascript)与ios(Objective-C)相互通信交互

微信 OR 支付宝 扫描二维码
为天狐 打赏
非常感谢你的支持,哥会继续努力!
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

网友最新评论 (2)