OC 与 JS 交互遇到的坑

最近做的项目中有一个需要在web页中判断APP是否登陆,如果没有登陆跳转到APP的登陆界面去登陆。而在这里面技术方面主要就是涉及到web端服务端的交互,web前端iOSAndroid的交互。

iOS原生应用和web页面的交互大致上有这几种方法iOS7之后的JavaScriptCore拦截协议第三方框架WebViewJavaScriptBridgeiOS8之后的WKWebView

我在项目中用的是JavaScriptCore方法,首先导入JavaScriptCore.framework库,然后创建一个webView,初始化,添加,打开网址。下面实现UIWebView的代理方法。

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    //在OC中获取JS的上下文
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //其中toAppLogin就是js的方法名称,赋给是一个block 里面是iOS代码
    //打印出所有接收到的参数
    context[@"toAppLogin"] = ^() {
        NSLog(@"js调用oc---------begin--------");
        NSArray *args = [JSContext currentArguments];
        for (JSValue *jsValue in args) {
            NSLog(@"%@",jsValue);
        }
        NSLog(@"js调用oc---------The End-------");
    };
}

这段代码 在 webView 加载完成,用户交互时没有问题,但是如果页面刚加载的时候,H5 就需要和客户端通过js 交互,让客户端回传参数才能显示页面时候,显然是有问题的。然后我又把 jContext  回调赋值放在
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    //在OC中获取JS的上下文
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //其中toAppLogin就是js的方法名称,赋给是一个block 里面是iOS代码
    //打印出所有接收到的参数
    context[@"toAppLogin"] = ^() {
        NSLog(@"js调用oc---------begin--------");
        NSArray *args = [JSContext currentArguments];
        for (JSValue *jsValue in args) {
            NSLog(@"%@",jsValue);
        }
        NSLog(@"js调用oc---------The End-------");
    };
    return YES;
}

这么写还是有问题。获取不到js的方法名称。
后来查了一下原因,感觉是我注入交互对象的时机跟我用JavaScript调用交互方法的时机不对。当我们在- (void)viewDidLoad中注入JS代码之后,如果页面发生了重定向,此时web页面的JS已经发生了变化,而- (void)viewDidLoad方法只会执行一次,所以不再是之前我们注入过的那些JS了,此时再调用本地方法自然就失效了。
如果我们在- (void)webViewDidFinishLoad:(UIWebView )webView方法中注入JS,看起来貌似可以解决重定向之后调用失效的问题,因为webView每次加载完成后都会回调- (void)webViewDidFinishLoad:(UIWebView )webView,也就是说每次重定向之后,只要页面加载完成,JS代码就会重新被注入。如果JS调用OC方法的时机是在页面加载完成之后,比如点击web界面上的按钮或者由用户手动触发一个事件调用OC代码,这种情况一定是web页面加载完成之后才会发生的,而此时我们已经重新注入了JS,这样一点问题都没有。但是,如果JS调用OC方法的时机刚好发生在页面加载过程中呢?比如web界面加载过程中自动执行一些操作需要调用OC代码,而此时- (void)webViewDidFinishLoad:(UIWebView *)webView还没有回调,所以我们的JS代码并没有重新注入,这里仍然会造成失效的问题。应该在每次创建JSContext环境的时候,我们都去注入此交互对象这样就解决了上面的问题。于是我找到了相关的第三方webview的延展UIWebView+TS_JavaScriptContext。解决了该问题。(有可能AppStore审核会被拒绝,说是因为使用了私有的API。我还没有遇到该情况。)
- (void)webView:(UIWebView *)webView didCreateJavaScriptContext:(JSContext *)ctx
{
    //其中toAppLogin就是js的方法名称,赋给是一个block 里面是iOS代码
    ctx[@"toAppLogin"] = ^(){
        NSArray *args = [JSContext currentArguments];
        for (JSValue *jsValue in args) {
            //打印出所有接收到的参数
            NSLog(@"--%@",jsValue);
        }
    };
}

具体解决办法参考了此开源库UIWebView-TS_JavaScriptContext




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值