JavaScript与原生APP(Android/iOS)之间相互调用通信总结
Author:zhoulujun Date:
Android与js互相调用
对于Android调用JS代码的方法有2种:
通过WebView的loadUrl()
通过WebView的evaluateJavascript()
对于JS调用Android代码的方法有3种:
通过WebView的addJavascriptInterface()进行对象映射:漏洞问题:你不知道的 Android WebView 使用漏洞
通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
安卓调用js方法:
webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/show.html");
定义按钮的点击事件:
Button btn = findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { testJS(); } });
其中testJS代码为:
@SuppressLint("SetJavaScriptEnabled") public void testJS() { webView.loadUrl("javascript:test()"); }
据此,就实现了安卓调用js方法。
js调用安卓方法:
需要在activity中定义被调用的方法:
@JavascriptInterface public void hello(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }
并且需要给webview绑定上java对象:
webView.addJavascriptInterface(this, "justTest");
最后,在js中调用该方法:
<button onclick="justTest.hello('js调用安卓方法!')">调用安卓方法</button>
具体案例,参考《android 调用js,js调用android》
IOS与JavaScript之间的调用
原理其实差不多
JS调用原生OC篇
UIWebView的代理方法拦截这次请求,然后再做相应的处理。
loadURL("firstClick://shareClick?title=分享的标题&content=分享的内容&url=链接地址&imagePath=图片地址");
JS中的firstClick,在拦截到的url scheme全都被转化为小写。
html中需要设置编码,否则中文参数可能会出现编码问题。
JS用打开一个iFrame的方式替代直接用document.location的方式,以避免多次请求,被替换覆盖的问题。
早期的JS与原生交互的开源库很多都是用得这种方式来实现的,例如:PhoneGap、WebViewJavascriptBridge。
JavaScriptCore
在iOS 7之后,apple添加了一个新的库JavaScriptCore,用来做JS交互,因此JS与原生OC交互也变得简单了许多。
JSContext 是 JS 执行上下文,你可以把它理解为 JS 运行的环境。
JSValue 是对 JavaScript 值的引用,任何 JS 中的值都可以被包装为一个 JSValue。
JSManagedValue 是对 JSValue 的包装,加入了“conditional retain”。
JSVirtualMachine 表示 JavaScript 执行的独立环境。
还有 JSExport 协议:实现将 Objective-C 类及其实例方法,类方法和属性导出为 JavaScript 代码的协议。
导入JavaScriptCore库, 然后在OC中获取JS的上下文
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
可能最新版本的iOS系统做了改动,现在(iOS9,Xcode 7.3,去年使用Xcode 6 和iOS 8没有线程问题)中测试,block中是在子线程,因此执行UI操作,控制台有警告,需要回到主线程再操作UI。
推荐阅读《iOS 与 JS 交互开发知识总结》
iOS Native 调用 JS
iOS Native 调用 JS 的实现方法也被 JavaScriptCore 划分开来:
webview 直接注入 JS 并执行
JavaScriptCore 方法
在 iOS 平台,webview 有注入并执行 JS 的 API。
UIWebView
UIWebView 有直接注入 JS 的方法:
NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"这里是JS中alert弹出的message"]; [_webView stringByEvaluatingJavaScriptFromString:jsStr];
注意:该方法会同步返回一个字符串,因此是一个同步方法,可能会阻塞UI。方法会返回运行 JS 的结果(nullable NSString *),它是一个同步方法,会阻塞当前线程!尽管此方法不被弃用,但最佳做法是使用 WKWebView 类的 evaluateJavaScript:completionHandler:method。
WKWebView
不同于 UIWebView,WKWebView 注入并执行 JS 的方法不会阻塞当前线程。因为考虑到 webview 加载的 web content 内 JS 代码不一定经过验证,如果阻塞线程可能会挂起 App。
NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')", @"北京市东城区南锣鼓巷纳福胡同xx号"]; [_webview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@----%@", result, error); }];
Note: 方法不会阻塞线程,而且它的回调代码块总是在主线程中运行。
使用JavaScriptCore库来做JS交互
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; NSString *textJS = @"showAlert('这里是JS中alert弹出的message')"; [context evaluateScript:textJS];
JSValue 实例是对 JavaScript 值的引用。 您可以使用 JSValue 类来转换 JavaScript 和 Objective-C 或 Swift 之间的基本值(如数字和字符串),以便在本机代码和 JavaScript 代码之间传递数据。
stringByEvaluatingJavaScriptFromString是一个同步的方法,使用它执行JS方法时,如果JS 方法比较耗的时候,会造成界面卡顿。尤其是js 弹出alert 的时候。
alert 也会阻塞界面,等待用户响应,而stringByEvaluatingJavaScriptFromString又会等待js执行完毕返回。这就造成了死锁。
官方推荐使用WKWebView的evaluateJavaScript:completionHandler:代替这个方法。
其实我们也有另外一种方式,自定义一个延迟执行alert 的方法来防止阻塞,然后我们调用自定义的alert 方法。同理,耗时较长的js 方法也可以放到setTimeout 中。
MessageHandler 是继 Native 截获 JS 假请求后另一种 JS 调用 Native 的方法,该方法利用了 WKWebView 的新特性实现。对比截获假 Request 的方法来说,MessageHandler 传参数更加简单方便。
MessageHandler
WKUserContentController 类有一个方法:
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
该方法用来添加一个脚本处理器,可以在处理器内对 JS 脚本调用的方法做出处理,从而达到 JS 调用 Native 的目的。
参考文章:
https://www.cnblogs.com/aibabel/p/11101759.html
https://zhuanlan.zhihu.com/p/33092431
转载本站文章《JavaScript与原生APP(Android/iOS)之间相互调用通信总结》,
请注明出处:https://www.zhoulujun.cn/html/OS/IOS/IOS-Develop/2020_0710_8510.html