美文网首页
iOS 原生和JS交互总结

iOS 原生和JS交互总结

作者: 魔都兰陵王 | 来源:发表于2018-12-09 16:31 被阅读3次

    iOS 有两种 WebView, 一个是从iOS 2.0 开始加入的 UIWebView, 一个是从iOS 8.0 加入的 WKWebView.从性能和API 方面WKWebView 都比UIWebView 优秀,只是无法使用NSURLProtocol 进行URL 拦截过滤.

    UIWebView 相关交互
    1.通过shouldStartLoadWithRequest中拦截 url

    • (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType ;

    NSString *requestString = request.URL.absoluteString;

    1.JS 通过document.location 调用原生方法 setData:
    function sendCommand(cmd, args) {
    var url = "iosapp:" + cmd + ":" + args;
    document.location = url;
    }
    sendCommand('setData', 'token'); // iosapp:setData:token

    2.JS用打开一个iFrame的方式调用原生方法 load
    function iframe(){
    var iFrame;
    iFrame = document.createElement("iframe");
    iFrame.setAttribute("src", "load");
    iFrame.setAttribute("style", "display:none;");
    iFrame.setAttribute("height", "0px");
    iFrame.setAttribute("width", "0px");
    iFrame.setAttribute("frameborder", "0");
    document.body.appendChild(iFrame);
    // 发起请求后这个 iFrame 就没用了,所以把它从 dom 上移除掉
    iFrame.parentNode.removeChild(iFrame);
    iFrame = null;
    }

    2.通过 JavaScriptCore
    在webViewDidFinishLoad方法中通过javaScriptContext ,将share 这个block桥接到JS, JS在使用时可以通过 share({}) 就能调用到share block 中的操作.
    -(void)webViewDidFinishLoad:(UIWebView *)webView{
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //添加js代用方法
    self.jsContext[@"share"]= ^(){
    NSArray *array = [JSContext currentArguments];
    for (NSString *value in array) {
    NSLog(@"收到js值:%@",value);
    }
    };
    }

    js 端代码
    share({});

    3.通过 JSExport
    凡是实现JSExport 协议的对象,都可以 通过
    jscontext[@"JS中实现了JSExport协议的实例别名"] = 实现了JSExport协议的实例,
    如: self.jsContext[@"native"]= self;
    这样JS 就可以简单的调用到 JSExport 协议中的原生方法 :
    如 native.getMessage({});
    @protocol JSObjcDelegate<JSExport>
    -(void)getMessage:(id)msg;
    @end

    @interface WebViewController ()<UIWebViewDelegate, JSObjcDelegate>
    -(void)webViewDidFinishLoad:(UIWebView )webView{
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext[@"native"]= self;
    //异常检查,当oc本地调用的js方法不存时,会打印异常信息
    self.jsContext.exceptionHandler = ^(JSContext
    context,JSValue *exceptionValue){
    context.exception = exceptionValue;
    NSLog(@"异常信息:%@", exceptionValue);
    };
    }

    js 端代码
    native.getMessage({});

    OC 调用 JS
    方式一
    NSString *jsStr = [NSString stringWithFormat:@"jsGetValueFromOC('Hello world!')"];
    [self.webView stringByEvaluatingJavaScriptFromString:jsStr];

    方式二 通过使用JavaScriptCore
    JSValue *callback = self.jsContext[@"jsGetValueFromOC"];
    [callback callWithArguments:@[@"Hello world!"]];
    或者
    NSString *jsStr = @"jsGetValueFromOC('Hello world!')";
    [self.jsContext evaluateScript:jsStr];

    WKWebView 交互
    WKWebView交互相对简单,API对于交互考虑的很全面
    [config.userContentController addScriptMessageHandler:self name:@"share"]; 可以向JS 暴露原生方法
    注意 在 controller dealloc 时候,需要 removeScriptMessageHandlerForName: 不然就会内存泄漏了.

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.preferences = [[WKPreferences alloc] init];
    config.preferences.minimumFontSize = 10;
    config.preferences.javaScriptEnabled = YES;
    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
    config.userContentController = [[WKUserContentController alloc] init];
    config.processPool = [[WKProcessPool alloc] init];
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds
    configuration:config];
    //记得实现对应协议,不然方法不会实现.
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate =self;
    [self.view addSubview:self.webView];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.1.188/index1.html"]]];

    // **************** 此处划重点 **************** //
    //添加注入js方法, oc与js端对应实现
    [config.userContentController addScriptMessageHandler:self  name:@"share"];
    [config.userContentController addScriptMessageHandler:self  name:@"goBack"];
    

    }

    //js端代码
    //window.webkit.messageHandlers.share.postMessage({ id: 'goodsId=1212'});

    pragma mark - WKScriptMessageHandler

    //实现js注入方法的协议方法

    • (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message {
      //找到对应js端的方法名,获取messge.body
      if ([message.name isEqualToString:@"share"]) {
      NSLog(@"%@", message.body);
      }
      }

    NSString * jsStr =[NSString stringWithFormat:@"sendKey('%@')",jsUserId];
    [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    //此处可以打印error.
    }];

    相关文章

      网友评论

          本文标题:iOS 原生和JS交互总结

          本文链接:https://www.haomeiwen.com/subject/rihkhqtx.html