js调用android代码怎么写( 三 )


那么如何向 js 层导出同步接口呢?我们知道,在 Android 框架中,通过 WebView.() 这个函数,可以将 java 接口导出到 js 层,并且这样导出的接口是同步接口 。但是在 iOS 的 Cocoa 框架中,想导出同步接口却不容易,究其原因,是因为 UIWebView 和 WKWebView 没有 这样的功能 。
同时,Android 这个功能爆出过安全漏洞,那么,我们有没有别的方式实现同步调用呢?我们以 iOS UIWebView 为例提供一种实现,WKWebView 和 Android 也可以参考 。为了找到问题的关键,我们看一下 iOS 中实现 js 调用 app 的通行方法:首先,自定义 UIWebViewDelegate,在函数 :navigationType: 中拦截请求 。
- (BOOL) webView:(UIWebView* _Nonnull):(NSURLRequest* _Nonnull)requestnavigationType:()navigationType {if ([request.HTTPMethod compare:@"GET" options:] != NSOrderedSame) {// 不处理非 get 请求return YES;}NSURL* url = request.URL;if ([url.scheme isEqualToString:@'YourCustomProtocol']) {return [self onMyRequest:request];}return YES;}这种做法实质上就是将函数调用命令转化为 url,通过请求的方式通知 app 层,其中 onMyRequest: 是自定义的 request 响应函数 。为了发送请求,js 层要建立一个隐藏的 iframe 元素,每次发送请求时修改 iframe 元素的 src 属性,app 即可拦截到相应请求 。
12345678910111213/*** js 向 native 传递消息* @method js_* @memberof JSToNativeIOSPolyfill* @public* @param str {String} 消息字符串,由 HybridMessage 转换而来*/JSToNativeIOSPolyfill.prototype.js_ = function (str) {if (!this.ifr_) {this._prepareIfr();}this.ifr_.src = 'YourCustomProtocol://__message_send__?msg=' + encodeURIComponent(str); }当 app 执行完 js 调用的功能,执行结果无法直接返回,为了返回结果,普遍采用回调函数方式——js 层记录一个 callback,app 通过 UIWebView 的 函数调用这个 callback(类似 jsonp 的机制) 。注意,这样封装的接口,天然是异步接口 。
因为 js_ 这个函数会立即返回,不会等到执行结果发回来 。所以,我们要想办法把 js 代码“阻塞”住 。
请回忆一下,js 中是用什么方法能把 UI 线程代码“阻塞”住,同时又不跑满 CPU?1234var async = false;var url = '';var method = 'GET';var req = new XMLHttpRequest();req.open(method, url, async);req.send(null);“同步”ajax(其实没这个词,ajax 内涵异步的意思)可以!在 baidu 的响应没返回之前,这段代码会一直阻塞 。一般来说同步请求是不允许使用的,有导致 UI 卡顿的风险 。
但是在这里因为我们并不会真的去远端请求内容,所以不妨一用 。至此实现方式已经比较清楚了,梳理一下思路:使用同步 XMLHttpRequest 配合特殊构造的 URL 通知 app层 。
app 层拦截请求执行功能,将结果作为 Response 返回 。XMLHttpRequest.send() 返回,通过 status 和 responseText 得到结果 。
那么,如何拦截请求呢?大家知道,UIWebViewDelegate 是不会拦截 XMLHttpRequest 请求的,但是 iOS 至少给了我们两个位置拦截这类请求——NSURLCache 和 NSURLProtocol 。一、NSURLCache 是 iOS 中用来实现自定义缓存的类,当你创建了自定义的 NSURLCache 子类对象,并将其设置为全局缓存管理器,所有的请求都会先到这里检查有无缓存(如果你没禁掉缓存的话) 。
我们可以借助这个性质拦截到接口调用请求,执行并返回数据 。- (NSCachedURLResponse*) :(NSURLRequest *)request {if ([request.HTTPMethod compare:@"GET" options:] != NSOrderedSame) {// 只对 get 请求做自定义处理return [super :request];}NSURL* url = request.URL;NSString* path = url.path;NSString* query = url.query;if (path == nil || query == nil) {return [super :request];}LOGF(@"url = %@, path = %@, query = %@", url, path, query);if ([path isEqualToString:@"__env_get__"]) {// 读环境变量return [self getEnvValueByURL:url]; //*} else if ([path。