iOS面试总结网络

OC与JS交互总结

2019-03-23  本文已影响8人  聪莞

UIWebView篇

1.在webView加载完成后调用:

//在oc中调用js的jsFun方法,并传入参数“hi,js”
[self.webView stringByEvaluatingJavaScriptFromString:@"jsFun('hi,js')"];
  1. 通过JavaScriptCore的方式(该方法需要导入JavaScriptCore框架)
    在webView加载完成后调用:
    //JSContext就为其提供着运行环境 H5上下文
    JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext = jsContext;

    //给js传参
    [self.jsContext evaluateScript:@"var arr = [3, 'Cooci', 'abc'];"];

也可以用这种方式:

    // 将js方法转换成一个JSValue对象 然后调用并传参数
    JSValue * value = self.jsContext[@"jsFun"];
  
    dispatch_async(dispatch_get_main_queue(), ^{
           [value callWithArguments:@[@"hi",@"js"]];
     });
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    
    NSLog(@"%@",request.URL.scheme); // 标识 我们自己协议
    NSLog(@"%@",request.URL.host);   // 方法名
    NSLog(@"%@",request.URL.pathComponents);  // 参数

    // JS 调用OC 的原理就是 拦截URL
    NSString *scheme = request.URL.scheme;
    if ([scheme isEqualToString:@"custom"]) {
        NSLog(@"来了,我们自定义的协议");
        
        NSArray *args = request.URL.pathComponents;
        NSString *methodName = args[1];
        
        // 方法1
//        if ([methodName isEqualToString:@"getSum"]) {
//            [self getSum];
//        }
        // 方法2
        SEL methodSel = NSSelectorFromString(methodName);
        if ([self respondsToSelector:methodSel]) {
#pragma clang diagnostic push
            // 让编译器忽略错误
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            // 让编译器出栈,恢复状态,继续编译后续的代码!
            [self performSelector:methodSel withObject:args[2]];
#pragma clang diagnostic pop
        }
        // 方法3
//        objc_msgSend(self,methodSel,args[2],args[3]);
        
        ((void (*) (id, SEL, id))(objc_msgSend))(self, methodSel,args[2]);
        
        // 定义kc_msgSend 函数指针  (void *) 替代了 (void (*)(id, SEL, id))
        void (*kc_msgSend) (id, SEL, id) = (void *)objc_msgSend;
        kc_msgSend(self,methodSel,args[2]);
        
        return NO;
    }
}
  1. 也可以采用JavaScriptCore的方式
//实现js里的jsFun方法  [JSContext currentContext]来避免循环引用
self.jsContext[@"jsFun"] = ^() {
        
        NSArray *args = [JSContext currentArguments];
        NSLog(@"args:%@",args);  //获取js里调用该方法传的参数
        
        NSDictionary *dict = @{@"name":@"cooci",@"age":@18};
        
        //这里可以继续去调用js方法  如此反复
dispatch_async(dispatch_get_main_queue(), ^{
        [[JSContext currentContext][@"jsFun"] callWithArguments:@[dict]];
 });
    }

JavaScriptCore的另外一些用法:

JS可以直接调用OC的对象方法:

OC中建立一个协议,并遵循JSExport协议,建立一个对象,遵循该协议

@protocol JSObjectProtocol <JSExport>
- (void)hello;
//相当于一个方法的简写。js中可以直接通过getSum来调用 getSumWithFirst 方法
JSExportAs(getSum, -(int)getSumWithFirst:(int)a second:(int)b third:(int)c);
@end

@interface JSObject : NSObject<JSObjectProtocol>
@end

@implementation JSObject
- (void)hello {
    NSLog(@"hello");
}

- (int)getSumWithFirst:(int)a second:(int)b third:(int)c {
    return a+b+c;
}
@end

使用:

    //OC中绑定
    JSObject * jsObject = [[JSObject alloc] init];
    self.jsContext[@"jsObject"] = jsObject;

    //js中调用
    jsObject.hello()
    jsObject.getSum(1,2,3)

JS异常处理:
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        context.exception = exception;
        NSLog(@"exception == %@",exception);
        NSLog(@"%@",context);
    };

WKWebView篇

    NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"登陆成功"];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@",result, error);
    }];
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    NSURL *URL = navigationAction.request.URL;
    NSString *scheme = [URL scheme];
    if ([scheme isEqualToString:@"custom"]) {
        NSString *host = [URL host];
        if ([host isEqualToString:@"jsCallOC"]) {
            NSMutableDictionary *temDict = [self decoderUrl:URL];
            NSString *username = [temDict objectForKey:@"username"];
            NSString *password = [temDict objectForKey:@"password"];
            NSLog(@"%@---%@",username,password);

          具体使用同上 :uiwebview里
        }else{
            NSLog(@"不明地址 %@",host);
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

2.通过MessageHandle的方式

    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    [configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@“jsFun”];

此处,messageHandle对self强引用了,所以需要在viewWillDisAppear里打破循环引用

[webView.configuration.userContentController removeScriptMessageHandlerForName:@"jsFun"];

写在文末

还有一些优秀的第三方的oc、js交互框架,例如:WebViewJavascriptBridge,使用起来非常的方便,就是需要前端配合一起开发才可以使用,感兴趣的可以去了解一下。WebViewJavaScriptBridge 基本使用

上一篇 下一篇

猜你喜欢

热点阅读