• 在ANDROID中,WebView控件有setJavaScriptEnable接口,这里大概的意思就是让客户端能够响应来自WebView的回调,还有一个接口是addJavaScriptInterface(obj, "external"),这个接口的大概意思是给obj开一个叫...

      在ANDROID中,WebView控件有setJavaScriptEnable接口,这里大概的意思就是让客户端能够响应来自WebView的回调,还有一个接口是addJavaScriptInterface(obj, "external"),这个接口的大概意思是给obj开一个叫"external"的口子,这样前端通过window.external.func(param1,param2...)这样的方式就可以直接调用obj中名叫"func"的方法了。

        在IOS中,要想实现这样的WebView需要经过一段周章,下面开始简要说明一下前端能够调用到客户端的代码的基本原理:客户端不管是根据本地的html加载网页还是url动态加载网页,实际上都已经接管了网页上的源码,然而这个源码是用JavaScript写的,这种源码是不能直接对IOS的OC代码进行调用的,我们要做的就是这样的一个转换,让JS通过一个bridge间接调用OC。

        

    ;(function() {
        var messagingIframe,
            bridge = 'external',
            CUSTOM_PROTOCOL_SCHEME = 'jscall';
      
        if (window[bridge]) { return }
    
    	function _createQueueReadyIframe(doc) {
            messagingIframe = doc.createElement('iframe');
    		messagingIframe.style.display = 'none';
    		doc.documentElement.appendChild(messagingIframe);
    	}
    	window[bridge] = {};
        var methods = [%@];
        for (var i=0;i<methods.length;i++){
            var method = methods[i];
            var code = "(window[bridge])[method] = function " + method + "() {messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + ':' + arguments.callee.name + ':' + encodeURIComponent(JSON.stringify(arguments));}";
            eval(code);
        }
      
        //创建iframe,必须在创建external之后,否则会出现死循环
        _createQueueReadyIframe(document);
        //通知js开始初始化
        //initReady();
    })();

    我们通常使用IOS的WebView控件都是通过实现shouldStartLoadWithRequest等相关代理来截获网页url变化这个通知,在url中通常就隐含了我们需要的参数,然而这种方式并不够人性化,前端要是能够直接通过函数调用的方法来call OC的native是比较合理的方式。

    shouldStartLoadWithRequest什么时候会被调用?是否一定要url变化才会调用?

    shouldStartLoadWithRequest不仅在url变化的时候调用,而且只要网页内容变化的时候也能调用

    上面的JS代码

    messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + ':' + arguments.callee.name + ':' + encodeURIComponent(JSON.stringify(arguments));

    就是对网页内容进行改变,通过在webview中植入这样的代码,就可以调到shouldStartLoadWithRequest,shouldStartLoadWithRequest是OC的代码,这样就实现了从JS到OC的调用。和Java的反射有点类似。

    接下来解决如何在webview中植入这样的代码

    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        if (webView != _webView) { return; }
        //is js insert
        if (![[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"typeof window.%@ == 'object'", kBridgeName]] isEqualToString:@"true"]) {
            //get class method dynamically
            unsigned int methodCount = 0;
            Method *methods = class_copyMethodList([self class], &methodCount);
            NSMutableString *methodList = [NSMutableString string];
            for (int i=0; i<methodCount; i++) {
                NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
                //防止隐藏的系统方法名包含“.”导致js报错
                if ([methodName rangeOfString:@"."].location!=NSNotFound) {
                    continue;
                }
                [methodList appendString:@"\""];
                [methodList appendString:[methodName stringByReplacingOccurrencesOfString:@":" withString:@""]];
                [methodList appendString:@"\","];
            }
            if (methodList.length>0) {
                [methodList deleteCharactersInRange:NSMakeRange(methodList.length-1, 1)];
            }
            free(methods);
            NSBundle *bundle = _resourceBundle ? _resourceBundle : [NSBundle mainBundle];
            NSString *filePath = [bundle pathForResource:@"WebViewJsBridge" ofType:@"js"];
            NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
            [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:js, methodList]];
        }
    }

    webViewDidFinishLoad这个代理在webview加载完成后调用。

    stringByEvaluatingJavaScriptFromString

    相当于在webview的尾部追加一段代码,这里不仅追加进去了js代码,还有本地的函数列表,也就是OC暴露给前端可以调用的函数列表,当我们点击webview中的某个按钮触发前端执行了window.external.func(param1, param2)这样的代码,而这个代码因为我们注入了上面那段JS代码,不仅触发了shouldStartLoadWithRequest的执行,还把前端调用的函数名和参数传了回来,接下来就是在shouldStartLoadWithRequest中对这些参数进行整合,变成OC可以识别的代码,就能够正确调用到OC的native方法了

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        if (webView != _webView) { return YES; }
        NSURL *url = [request URL];
        
        NSString *requestString = [[request URL] absoluteString];
        if ([requestString hasPrefix:kCustomProtocolScheme]) {
            NSArray *components = [[url absoluteString] componentsSeparatedByString:@":"];
            
            NSString *function = (NSString*)[components objectAtIndex:1];
            NSString *argsAsString = [(NSString*)[components objectAtIndex:2]
                                      stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            NSData *argsData = [argsAsString dataUsingEncoding:NSUTF8StringEncoding];
            NSDictionary *argsDic = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:argsData options:kNilOptions error:NULL];
            //convert js array to objc array
            NSMutableArray *args = [NSMutableArray array];
            for (int i=0; i<[argsDic count]; i++) {
                [args addObject:[argsDic objectForKey:[NSString stringWithFormat:@"%d", i]]];
            }
            //ignore warning
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            SEL selector = NSSelectorFromString([args count]>0?[function stringByAppendingString:@":"]:function);
            if ([self respondsToSelector:selector]) {
                [self performSelector:selector withObject:args];
            }
            return NO;
        }else {
            return YES;
        }

    这里的request和真实的url改变带回来的参数组成不太一样,这个值是在JS代码中拼接的,所以这里解析也要按照那个规则逆向解析,后面用到了selector,将函数名function转换成selector,在run-time时就会调到了那个OC中的同名函数了

    - (void)writeTopic:(NSArray *)params
    {
        NSLog(@"writeTopic called");
    }

    这里整合成一个参数,params数组,可以通过objectAtIndex来取出每个参数,进行后面的相关操作。


    总结:

    1 通过注入JS代码到webview

    2 注入的JS代码在能改变webview的内容,实现网页的跳转(这里用的是一个空白的什么都没有的不可见的网页)

    3 根据注入的JS中的规则在shouldStartLoadWithRequest中反向解析,并通过SEL动态调用。

    前端直接调用OC的native方法

    展开全文
  • iOS WebViewNative交互

    2017-04-27 18:04:49
    我们在项目中不可避免的要使用到WebView,一般的用法就是WebView直接加载URL,做一些基本展示操作。...备注:这里的Native是相对于JavaScript来说的,是指OC代码。1. UIWebView我们这里要做到双向交互,要求

    我们在项目中不可避免的要使用到WebView,一般的用法就是WebView直接加载URL,做一些基本展示操作。但是对于一些特定的需求或逻辑,我们可能就需要WebView传递一些数据到Native,由Native来对数据做处理,比如有跨域限制或拦截WebView请求的需求时候。

    备注:这里的Native是相对于JavaScript来说的,是指OC代码。

    1. UIWebView

    我们这里要做到双向交互,要求UIWebView加载的Html可调用Naitve函数,Native可调用Html函数。我在这里使用的是Apple官方的JavaScriptCore库。

    1.1 Native调用JavaScript

    在Native中我们调用JS的函数,函数名为showAlert

    OC代码:

    - (void)webViewDidFinishLoad:(UIWebView *)webView{
      NSString *result = [webView stringByEvaluatingJavaScriptFromString:@"showAlert('webViewDidFinishLoad')"];
      NSLog(@"html返回给native的返回值是:%@",result);
    }

    对应的JS代码:

    <script>
            function showAlert (str) {
                alert(str);
                return 'html的返回值';
            }
        </script>

    1.2 JavaScript调用Native

    OC代码:

    #import <CoreLocation/CoreLocation.h>
    //这里最主要是创建一个JSContext
    JSContext *context = [w valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //通过这个context可以将OC中函数添加到JavaScript的运行环境中
    context[@"add"] = ^(NSInteger a, NSInteger b){
            return a+b;
        };
    //这里就是向JavaScript添加了一个add函数,将JavaScript传入的两个参数和返回至调用的JavaScript中。

    对应的JS代码:

    <button onclick="alert(add(2,3))">这个是注入module</button>

    当然也可以将JSBridage抽象出来,统一在WebView中进行初始化。这样可以在JS中通过一个对象统一掉用Native的函数,可以避免JavaScript函数与Native的OC函数名冲突.
    在OC中这样写:

    #import <Foundation/Foundation.h>
    #import "JSBridgeModule.h"
    #import "StringUtil.h"
    #import <JavaScriptCore/JavaScriptCore.h>
    
    @implementation JSBridgeModule
    
    - (NSString *)getTime:(NSString *)str{
      NSLog(@"getTime native log:%@",str);
      return [StringUtil getCurrentTime];
    }
    
    - (void)initJSBridge:(JSContext *)jsContext{
      [jsContext setObject:self forKeyedSubscript:@"bridge"];//这里将整个JSBridgeModule赋给了JavaScript运行环境,在JavaScript便可以使用bridge.函数名来调用Native函数
      jsContext.exceptionHandler = ^(JSContext* context, JSValue* exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"js页面异常了:%@", exceptionValue);
      };
    }
    
    - (void)callJSFunction:(JSContext *)jsContext{
      JSValue *result = [jsContext evaluateScript:@"showAlert('这是native传递个html的数据')"];
      NSLog(@"html返回给native的返回值是:%@",result);
    }
    
    @end

    对应的JS使用方法

    <button onclick="alert(bridge.getTime('这个是注入module'))">这个是注入module</button>

    2. WKWebView

    在iOS 8.0中更新了WKWebView来替代UIWebView,WKWebView的性能和效率比UIWebView要强。

    这里有个插曲,,由于我们项目的需要,我们要对WebView加载的Html进行网络请求的拦截,只允许Html中的请求加载按照我们规范的地址。我对UIWebView和WKWebView分别作了研究,注册WebView的请求delegate是行不通的,我在UIWebView中重写URlSession来拦截所有的网络请求,这样可以达到拦截UIWebView请求目的,但是这个方法在WKWebView中行不通,因为WKWebView和当前项目是不同同一个进程中运行的,所以无法拦截WKWebView中的网络请求,所以这条路行不通。我会新写一篇文章详细的讲解这个问题。

    下面言归正传,WKWebView中JS与Native的交互

    2.1 Native调用JavaScript

    这里很简单,和UIWebView差不多

    OC代码:

    //这是是调用JS的showAlert函数,并传入参数hello
    [self.webView evaluateJavaScript:@"showAlert('hello')" completionHandler:nil];

    JS代码:

    <script>
            function showAlert (str) {
                alert(str);
                return 'html的返回值';
            }
        </script>

    2.2 JavaScript调用Native

    OC代码:

    向WebView中注入可供JS调用对象

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
      WKUserContentController *controller = [[WKUserContentController alloc]init];
      [controller addScriptMessageHandler:self name:@"bridge"];
      //这里的bridge对象即为JS调用Native的桥接
      config.userContentController = controller;

    注册WebView delegate

    //JavaScript与Native的交互
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
      NSDictionary *body = message.body;
      NSLog(@"userContentController message.body:%@",body);
      //这里来判断JS传递过来的数据是否是需要的
      if ([message.name isEqualToString:@"xxx"]) {
        NSString *method = [body valueForKey:@"function"];
        if ([method isEqualToString:@"nativeSetParam"]) {
          NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
          [userDefault setValue:[body valueForKey:@"value"] forKey:[body valueForKey:@"key"]];
          [userDefault synchronize];
        }
      }
    }

    对应JS使用代码:

    <button onclick="postMessage()">JS调用Native</button>
    //必须通过 xxx.postMessage才能将JS的数据发送到Native中,Native在回调中获取JS传递过来的数据
    <script>
        var bridge = window.webkit.messageHandlers.bridge;
            function postMessage(){
                alert('要发送消息了');
                var message = {
                    'method' : 'hello',
                    'param1' : 'param',
                };
                bridge.postMessage(message);
            }
       </script>
    展开全文
  • 源码地址:https://github.com/littleFeng/javaScriptNative.git 最近工作不忙 抽时间看...优点:WebKit 使用Nitro JavaScript引擎,webview可以和Safari加载一样快。加载网页占用的内存大大优化。高达60fps的滚动刷新

    源码地址:https://github.com/littleFeng/javaScriptNative.git

    最近工作不忙 抽时间看了下iOS8 的 WKWebView ,WKWebView基于WebKit,OSX和iOS开发共用库。

    优点:WebKit 使用Nitro JavaScript引擎,webview可以和Safari加载一样快。加载网页占用的内存大大优化。高达60fps的滚动刷新频率及内置手势。开放了更多API给开发者(14个类、3个协议);

    使用:首先引入库 

    #import  <WebKit/WebKit.h>

    初始化:WKWebViewConfiguration class wkwebview的基本配置类 

        WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init]; 先实例化配置类 以前UIWebView的属性有的放到了这里

       _wkwebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0.0f, screen_width, screen_height) configuration:configuration];


    新的属性:

        _wkwebView.allowsBackForwardNavigationGestures =YES;//打开网页间的 滑动返回

        _wkwebView.allowsLinkPreview = YES;//允许预览链接

            backForwardList 中包含backList(访问过未返回的地址) forwardList(访问过已返回的地址)currentItem(当前访问的地址)


       wkwebview提供了KVO属性 可以用来获取加载进度(estimatedProgress) URL(URL)、TITLE(title)是否变化、是否可以前进或后退

        [_wkwebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];//注册observer 拿到加载进度


    wkwebview除了后退:goBack 前进: goForward 方法外 还提供了reload方法 刷新当前页面 以及stopLoading 停止刷新

    加载h5页面和UIWebView相似:[_wkwebView loadRequest:[NSURLRequest requestWithURL:url]];

    代理:


    //WKNavigationDelegate


    //发送请求前 决定是否允许跳转

    /*

     typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {

     WKNavigationActionPolicyCancel,不允许

     WKNavigationActionPolicyAllow, 允许

     } NS_ENUM_AVAILABLE(10_10, 8_0);

     */

    发生请求前是否允许跳转

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

    {

        decisionHandler(WKNavigationActionPolicyAllow);

        NSLog(@"发送请求前 allow 跳转");

    }


    //接收到服务器响应 后决定是否允许跳转

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

    {

        decisionHandler(WKNavigationResponsePolicyAllow);

        NSLog(@"接收到响应后 allow 跳转");


    }


    //接收到服务器跳转响应后 调用

    -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation

    {

        NSLog(@"tiaozhuan");


    }


    //开始加载页面

    -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;

    {

        NSLog(@"开始加载页面");

    }


    //加载页面数据完成

    -(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation

    {

        NSLog(@"加载页面完成");

        NSLog(@"backlist ===%@",webView.backForwardList.backList);访问过未返回的页面

        NSLog(@"forwordlst==%@",webView.backForwardList.forwardList);访问过已返回的页面

        NSLog(@“url===%@",webView.backForwardList.currentItem.URL);当前访问的页面

        在这里可以拿到web页的相关信息 做一些操作   

    }


    //接收数据

    -(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation

    {

        NSLog(@"接收数据中");

    }


    //加载失败

    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;

    {

        NSLog(@"页面加载失败");

    }

    //在这个方法里实现注册的供js调用的oc方法

    -(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

    {

          js native 交互

    }


    WKUIDelegate 页面中有调用了js的alert、confirm、prompt方法,应该实现下面这几个代理方法,然后在原来这里调用native的弹出窗,因为使用WKWebView后,HTML中的alert、confirm、prompt方法调用是不会再弹出窗口了,只是转化成ios的native回调代理方法(没咋用)。


    JS NATIVE 交互:wkwebview提供了API实现js交互 不需要借助JavaScriptCore或者webJavaScriptBridge。使用WKUserContentController实现js native交互

    oc代码:

     首先需要在实例化WKWebViewConfiguration时 实例 WKUserContentController类并将其赋值给confiuration的属性:userContentController。

    WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];

        //注册供js调用的方法

        userContentController =[[WKUserContentController alloc]init];

        [userContentController addScriptMessageHandler:self  name:@“aaa”];//注册一个name为aaa的js方法

        configuration.userContentController = userContentController;

        configuration.preferences.javaScriptEnabled = YES;打开JavaScript交互 默认为YES

        _wkwebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0.0f, screen_width, screen_height) configuration:configuration];

    实现WKScriptMessageHandler的协议方法

    -(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

    {

    userContentController 注册message的WKUserContentController;

    message:js传过来的数据

    id body:消息携带的信息 Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNull.

    NSString *name:消息的名字 如aaa

     //message.name  js发送的方法名称

        if([message.name  isEqualToString:@"aaa"])

        {

            NSString * body = [message.body objectForKey:@“body"];

         在这里写oc 实现协议的native方法 }

    }



    前端h5代码:前端需要用 window.webkit.messageHandlers.注册的方法名.postMessage({body:传输的数据} 来给native发送消息

    例如:

    function secondClick() {

        window.webkit.messageHandlers.aaa.postMessage({body: 'call js alert in js'});

    }


    **重要 如果注册了方法    [userContentController addScriptMessageHandler:self  name:@“aaa"];

    会导致hangler一直被引用 导致不走Delloc web页面无法释放 所以要在-(void)viewDidDisappear:(BOOL)animated中将messageHandler移除

        [userContentController removeScriptMessageHandlerForName:@“aaa"]; 关闭web页时会释放内存。


    目前只是了解这些,深入的有时间再更。





    展开全文
  • WebView与iOS Native交互

    2016-08-06 15:44:58
    Objective-C语言调用JavaScript语言 Objective-C语言调用JavaScript语言,是通过UIWebView的 — (NSString )stringByEvaluatingJavaScriptFromString:(NSString )script;的方法来实现的。 该方法向UIWebView传递...

    Objective-C语言调用JavaScript语言
    Objective-C语言调用JavaScript语言,是通过UIWebView的
    — (NSString )stringByEvaluatingJavaScriptFromString:(NSString )script;的方法来实现的。
    该方法向UIWebView传递一段需要执行的JavaScript代码最后获取执行结果。
    Objective-C调用JavaScript代码的时候是同步的

    <html>
        <head>
            <meta http-equiv="content-type" content="text/html;charset=utf-8" />
            <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
            <meta content="always" name="referrer" />
            <title>测试网页</title>
        </head>
        <body>
            <br />
            <a href=“devzeng://login?name=zengjing&password=123456">点击链接</a>
        </body>
    </html>
    
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
        NSURL *url = [request URL];
        if([[url scheme] isEqualToString:@"devzeng"]) {
            //处理JavaScript和Objective-C交互
            if([[url host] isEqualToString:@"login"])
            {
                //获取URL上面的参数
                NSDictionary *params = [self getParams:[url query]];
                BOOL status = [self login:[params objectForKey:@"name"] password:[params objectForKey:@"password"]];
                if(status)
                {
                    //调用JS回调
                    [webView stringByEvaluatingJavaScriptFromString:@"alert('登录成功!')"];
                }
                else
                {
                    [webView stringByEvaluatingJavaScriptFromString:@"alert('登录失败!')"];
                }
            }
            return NO;
        }
        return YES;
    }
    
    
    
    
    ![这里写图片描述](http://img.blog.csdn.net/20160806153856310)
    **JavaScript调用Objective-C代码**
    JavaScript调用Objective-C代码
    目前,截止至iOS7,iOS原生并没有提供js直接调用native的方式,只能通过UIWebView相关的UIWebViewDelegate协议的
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    
    最最简单且实用的方法莫过于用js创建一个隐藏的iframe设置src了
    function js2native(){
          var iframe = document.createElement("iframe");
          iframe.src="callFunction://";
          iframe.style.display = 'none';
          document.body.appendChild(iframe);
          iframe.parentNode.removeChild(iFrame);
          iframe = null;
    }
    触发这个方法拦截、
    
    • (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType {
      NSURL *url = [request URL];
      if ([[url scheme] isEqualToString:@”callFunction”) {
      return NO;
      } else if (([[url scheme] isEqualToString:@”sendEvent”) {
      return NO;
      } else {
      return YES;
      }
      }
    **JavaScriptCore.framework**
    
    js调用native是 异步 的,但是效率还是很高
    从iOS7开始 苹果公布了JavaScriptCore.framework 它使得JS与OC的交互更加方便了。
    #import "JSContext.h"
    #import "JSValue.h"
    #import "JSManagedValue.h"
    #import "JSVirtualMachine.h"
    #import "JSExport.h"
    **iOS 调用 js**
    

    -(void)webViewDidFinishLoad:(UIWebView *)webView
    {
    //网页加载完成调用此方法
    //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
    JSContext *context=[webView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”];
    NSString *alertJS=@”alert(‘test js OC’)”; //准备执行的js代码
    [context evaluateScript:alertJS];//通过oc方法调用js的alert
    }

    *js调用iOS*  
    第一种情况  
    其中test1就是js的方法名称,赋给是一个block 里面是iOS代码  
    此方法最终将打印出所有接收到的参数,js参数是不固定的 我们测试一下就知道  
    
    

    context[@”test1”] = ^() {
    NSArray *args = [JSContext currentArguments];
    for (id obj in args) {
    NSLog(@”%@”,obj);
    }
    };

    下来我们看第二种情况 就是js 中是通过一个对象来调用方法的。
    JSExport
    凡事添加了JSExport协议的协议,所规定的方法,变量等 就会对js开放,我们可以通过js调用到
    首先创建一个类 继承NSObject 并且规定一个协议
    #import <Foundation/Foundation.h>  
    #import <JavaScriptCore/JavaScriptCore.h>    
    //首先创建一个实现了JSExport协议的协议  
    @protocol TestJSObjectProtocol <JSExport>    
    //此处我们测试几种参数的情况  
    -(void)TestNOParameter;  
    -(void)TestOneParameter:(NSString *)message;  
    -(void)TestTowParameter:(NSString *)message1 SecondParameter:(NSString *)message2;  
    @end  
    

    import “TestJSObject.h”

    @implementation TestJSObject
    //一下方法都是只是打了个log 等会看log 以及参数能对上就说明js调用了此处的iOS 原生方法
    -(void)TestNOParameter
    { NSLog(@”this is ios TestNOParameter”); }
    -(void)TestOneParameter:(NSString *)message
    { NSLog(@”this is ios TestOneParameter=%@”,message); }
    -(void)TestTowParameter:(NSString )message1 SecondParameter:(NSString )message2
    { NSLog(@”this is ios TestTowParameter=%@ Second=%@”,message1,message2); }
    @end
    -(void)webViewDidFinishLoad:(UIWebView *)webView
    {
    //网页加载完成调用此方法
    //首先创建JSContext 对象(此处通过当前webView的键获取到jscontext)
    JSContext *context=[webView valueForKeyPath:@”documentView.webView.mainFrame.javaScriptContext”];
    //第二种情况,js是通过对象调用的,我们假设js里面有一个对象 testobject 在调用方法
    //首先创建我们新建类的对象,将他赋值给js的对象
    TestJSObject *testJO=[TestJSObject new];
    context[@”testobject”]=testJO;

    “`
    第三方框架
    目前很流行的库有WebviewJavaScriptBridge和OVGap,这两个库都是让webview与JS建立起一条桥梁,这样就可以相互通信了.
    我主要看了WebViewJavascriptBridge
    这里写图片描述
    github有源码,感兴趣的可以下载分析!

    展开全文
  • 首先,UP主要承认错误,JS调用OC并没有一百种那么多~但是,也是有很多种办法的,起码我们可以花样使用。好了,废话不多说,下面开始逐一介绍。。。 一、简单介绍 JSCore全称为JavaScriptCore,是苹果公司在iOS...

    首先,UP主要承认错误,JS调用OC并没有一百种那么多~但是,也是有很多种办法的,起码我们可以花样使用。好了,废话不多说,下面开始逐一介绍。。。

    一、简单介绍

    JSCore全称为JavaScriptCore,是苹果公司在iOS中加入的一个新的framework。该framework为OC与JS代码相互操作的提供了极大的便利。该工程默认是没有导入工程中的,需要我们手动添加。


    添加完成后,我们可以看到JavaScriptCore.h中包含以下5个主要的文件。

    #import "JSContext.h"
    #import "JSValue.h"
    #import "JSManagedValue.h"
    #import "JSVirtualMachine.h"
    #import "JSExport.h"

    JSContext: 代表JavaScript的执行环境。你可以创建JSContent在OC环境中执行JavaScript脚本,同时也可以在JavaScript脚本中访问OC中的值或者方法。

    JSValue:是OC和JavaScript值相互转化的桥梁。他提供了很多方法把OC和JavaScript的数据类型进行相互转化。其一一对应关系如下表所示:





    JSManagedValue:JSValue的包装类。JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。

    JSVirtualMachine: JS运行的虚拟机。可以支持并行的JavaScript执行,管理JavaScript和OC转换中的内存管理。

    JSExport:一个协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。

    下面我们通过实例案例来学习JSCore的用法。


    二、OC中调用JS方法

    案例一:我在js中定义了一个函数add(a,b),我们需要在OC中进行调用。

    -(void)OCCallJS{
        self.context = [[JSContext alloc] init];
    
        NSString *js = @"function add(a,b) {return a+b}";
        [self.context evaluateScript:js];
        JSValue *addJS = self.context[@"add"];
    
        JSValue *sum = [addJS callWithArguments:@[@(10),@(17)]];
        NSInteger intSum = [sum toInt32];
        NSLog(@"intSum: %zi",intSum);
    }

    三、JS中调用OC方法

    JS中调用OC有两种方法,第一种为block调用,第二种为JSExport protocol。

    案例二:我们在OC中定义了一个如下方法,我们需要在JS中对它进行调用

    -(NSInteger)add:(NSInteger)a and:(NSInteger)b{
        return  a+b;
    }

    3.1、block调用

    -(void)JSCallOC_block{
        self.context = [[JSContext alloc] init];
    
        __weak typeof(self) weakSelf = self;
        self.context[@"add"] = ^NSInteger(NSInteger a, NSInteger b){
            return [weakSelf add:a and:b];
        };
        JSValue *sum = [self.context evaluateScript:@"add(4,5)"];
        NSInteger intSum = [sum toInt32];
        NSLog(@"intSum: %zi",intSum);
    }

    3.2、JSExport protocol

    第一步:定义一个遵守JSExport的AddJSExport协议。


    @protocol AddJSExport <JSExport>
    //用宏转换下,将JS函数名字指定为add;
    JSExportAs(add, - (NSInteger)add:(NSInteger)a and:(NSInteger)b);
    @property (nonatomic, assign) NSInteger sum;
    @end



    第二步:新建一个对象AddJSExportObj,去实现以上协议。

    AddJSExportObj.h
    @interface AddJSExportObj : NSObject<AddJSExport>
    @property (nonatomic, assign) NSInteger sum;
    @end
    AddJSExportObj.m
    @implementation AddJSExportObj
    -(NSInteger)add:(NSInteger)a and:(NSInteger)b{
        return a+b;
    }
    @end


    第三步:在VC中进行JS调用

    -(void)JSCallOC_JSExport{
        self.context = [[JSContext alloc] init];
    
        //异常处理
        self.context.exceptionHandler = ^(JSContext *context, JSValue *exception){
            [JSContext currentContext].exception = exception;
            NSLog(@"exception:%@",exception);
        };
    
        self.addObj = [[AddJSExportObj alloc] init];
    
        self.context[@"OCAddObj"] = self.addObj;//js中的OCAddObj对象==>OC中的AddJSExportObj对象
        [self.context evaluateScript:@"OCAddObj.sum = OCAddObj.add(2,30)"];
        NSLog(@"%zi",self.addObj.sum);
    }


    四、一个从服务端下发JS脚本,执行本地方法的实现思路


    案例三:本地定义了一系列方法,可以通过服务端下发js脚本去控制具体去执行那些方法。这样就可以在远端实现对于客户端的控制。

    第一步:预置本地方法

    -(void)initJS{
        __weak typeof(self) weakSelf = self;
        self.context[@"execute1"] = ^(){
            [weakSelf execute1];
        };
        self.context[@"execute2"] = ^(){
            [weakSelf execute2];
        };
    }
    -(void)execute1{
        NSLog(@"execute1");
    }
    
    -(void)execute2{
        NSLog(@"execute2");
    }


    第二步:服务端下发脚本

    -(NSString *)getJS{
        //可以从服务端下发
        //return @"execute1()";
        return @"execute2()";
    }

    第三步:根据服务端下发脚本执行

    -(void)executeByJs{
        [self initJS];
        NSString *js = [self getJS];
        [self.context evaluateScript:js];
    }

    五、JSCore在Web容器中的使用

    在UIWebView中,我们可以在- (void)webViewDidFinishLoad:(UIWebView *)webView方法中,通过KVC的方式获取到当前容器的JSContent对象,通过该对象,我们就可以方便的进行hybrid操作。
    JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];


    案例演示:在html中调研OC代码中的分享功能和调用相机功能。

    第一步:HelloWord.html代码如下:

    function jsCallNative(){
        WBBridge.callCamera();
    }
    function jsCallNative2(){
        var shareInfo = "分享内容";
        var str = WBBridge.share(shareInfo);
        alert(str);
    }
    
    <input type="button" οnclick="jsCallNative()" value="jsCallNative" />
    <br/>
    <input type="button" οnclick="jsCallNative2()" value="jsCallNative2" />
    <br/>

    第二步:实现一个遵守JSExport的协议WebViewJSExport


    @protocol WebViewJSExport <JSExport>
    - (void)callCamera;
    - (NSString*)share:(NSString*)shareString;
    @end

    第三步:当前VC需要实现WebViewJSExport


    @interface ViewController ()<UIWebViewDelegate,WebViewJSExport>
    @property (nonatomic, strong) JSContext *context;
    @property (nonatomic, strong) UIWebView *webView;
    @end
    @implementation ViewController
    -(void)initWebView{
        self.context = [[JSContext alloc] init];
    
        _webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
        _webView.delegate = self;
        [self.view addSubview:_webView];
    
        NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:8080/myDiary/HelloWorld.html"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [self.webView loadRequest:request];
    }
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView{
    
        JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        _context = context;
    
        // 将本对象与 JS 中的 WBBridge 对象桥接在一起,在 JS 中 WBBridge 代表本对象
        [_context setObject:self forKeyedSubscript:@"WBBridge"];
        _context.exceptionHandler = ^(JSContext* context, JSValue* exceptionValue) {
            context.exception = exceptionValue;
            NSLog(@"异常信息:%@", exceptionValue);
        };
    }
    
    - (void)callCamera{
        NSLog(@"调用相机");
    }
    
    - (NSString*)share:(NSString*)shareString{
        NSLog(@"分享::::%@",shareString);
        return @"分享成功";
    }
    @end

    上面总计的是一些基本的JS与OC互相调用的方法,下面介绍UIWebView与WKWebView如何进行JS交互:

    一.UIWebView的基本用法

    1.1 加载网页

     UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
        webView.delegate = self;
        [self.view addSubview:webView];
        //网络地址
        NSURL *url = [[NSURL alloc] initWithString:@"http://www.taobao.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [webView loadRequest:request];


    1.2 UIWebViewDelegate几个常用的代理方法

    //进行加载前的预判断,如果返回YES,则会进入后续流程(StartLoad,FinishLoad)。如果返回NO,这不会进入后续流程。
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
    //开始加载网页
    - (void)webViewDidStartLoad:(UIWebView *)webView;
    //加载完成
    - (void)webViewDidFinishLoad:(UIWebView *)webView;
    //加载失败
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;


    1.3 OC调用JS中的方法

    比如我们在加载的HTML文件中有如下js代码:
    <script type="text/javascript">
    function hello(){
        alert("你好!");
    }
    
    function helloWithName(name){
        alert(name + ",你好!");
    }
    </script>

    我们可以调用- (nullable NSString )stringByEvaluatingJavaScriptFromString:(NSString )script;函数进行js调用。

    [webView stringByEvaluatingJavaScriptFromString:@"hello()"];
    [webView stringByEvaluatingJavaScriptFromString:@"helloWithName('jack')"];

    js代码不一定要在js文件中预留,也可以在代码中通过字符串的形式进行调用,比如下面:
      //自定义js函数
        NSString *jsString = @"function sayHello(){ \
                                    alert('jack11')   \
                                }                   \
                               sayHello()";
        [_webView stringByEvaluatingJavaScriptFromString:jsString];
    
        NSString *jsString = @" var p = document.createElement('p'); \
                                p.innerText = 'New Line';            \
                                document.body.appendChild(p);        \
        ";
        [_webView stringByEvaluatingJavaScriptFromString:jsString];

    1.4 JS中调用OC的方法

    具体让js通知native进行方法调用,我们可以让js产生一个特殊的请求。可以让Native代码可以拦截到,而且不然用户察觉。业界一般的实现方案是在网页中加载一个隐藏的iframe来实现该功能。通过将iframe的src指定为一个特殊的URL,实现在- (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType;方案中进行拦截处理。对应的js调用代码如下:

    function loadURL(url) {
            var iFrame;
            iFrame = document.createElement("iframe");
            iFrame.setAttribute("src", url);
            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;
        }


    比如我们在js代码中,调用一下两个js方法:
    function iOS_alert() {//调用自定义对话框
            loadURL("alert://abc");
        }
        function call() {//  js中进行拨打电话处理
            loadURL("tel://17715022071");
        }

    当你触发以上方法的时候,就会进入webview的代理方法中进行拦截。
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        NSURL * url = [request URL];
        if ([[url scheme] isEqualToString:@"alert"]) {//拦截请求,弹出自定义对话框
            UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"test" message:[url host] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alertView show];
            return NO;
        }else if([[url scheme] isEqualToString:@"tel"]){//拦截拨打电话请求
            BOOL result = [[UIApplication sharedApplication] openURL:url];
            if (!result) {
                NSLog(@"您的设备不支持打电话");
            } else {
                NSLog(@"电话打了");
            }
            return NO;
        }
    
        return YES;
    }





    2.WKWebView的基本用法

    2.1 加载网页

    WKWebView *webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        NSURL *url = [NSURL URLWithString:@"http://www.taobao.com"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [webView loadRequest:request];
        [self.view addSubview:webView];

    2.2 几个常用的代理方法

    /**
     *  根据webView、navigationAction相关信息决定这次跳转是否可以继续进行,这些信息包含HTTP发送请求,如头部包含User-Agent,Accept,refer
     *  在发送请求之前,决定是否跳转的代理
     *  @param webView
     *  @param navigationAction
     *  @param decisionHandler
     */
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    
    /**
     *  这个代理方法表示当客户端收到服务器的响应头,根据response相关信息,可以决定这次跳转是否可以继续进行。
     *  在收到响应后,决定是否跳转的代理
     *  @param webView
     *  @param navigationResponse
     *  @param decisionHandler
     */
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
        decisionHandler(WKNavigationResponsePolicyAllow);
    }
    
    /**
     *  准备加载页面。等同于UIWebViewDelegate: - webView:shouldStartLoadWithRequest:navigationType
     *
     *  @param webView
     *  @param navigation
     */
    - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
    }
    
    /**
     *  这个代理是服务器redirect时调用
     *  接收到服务器跳转请求的代理
     *  @param webView
     *  @param navigation
     */
    - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation{
    
    }
    
    - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{
    
    }
    
    /**
     *  内容开始加载. 等同于UIWebViewDelegate: - webViewDidStartLoad:
     *
     *  @param webView
     *  @param navigation
     */
    - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation{
    
    }
    
    /**
     *  页面加载完成。 等同于UIWebViewDelegate: - webViewDidFinishLoad:
     *
     *  @param webView
     *  @param navigation
     */
    - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    
    }
    
    /**
     *  页面加载失败。 等同于UIWebViewDelegate: - webView:didFailLoadWithError:
     *
     *  @param webView
     *  @param navigation
     *  @param error      
     */
    - (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error{
    
    }
    
    - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0){
    
    }
    
    /*
     我们看看WKUIDelegate的几个代理方法,虽然不是必须实现的,但是如果我们的页面中有调用了js的alert、confirm、prompt方法,我们应该实现下面这几个代理方法,然后在原来这里调用native的弹出窗,因为使用WKWebView后,HTML中的alert、confirm、prompt方法调用是不会再弹出窗口了,只是转化成ios的native回调代理方法
     */
    #pragma mark - WKUIDelegate
    
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
        UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"h5Container" message:message preferredStyle:UIAlertControllerStyleAlert];
    //    [alertView addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    //        textField.textColor = [UIColor redColor];
    //    }];
        [alertView addAction:[UIAlertAction actionWithTitle:@"我很确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            completionHandler();
        }]];
        [self presentViewController:alertView animated:YES completion:nil];
    }

    显然WKWebView的代理方法提供了比UIWebView颗粒度更细的方法。让开发者可以进行更加细致的配置和处理。

    2.2 OC调用JS中的方法


    WKWebView提供的调用js代码的函数是:

    - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ __nullable)(__nullable id, NSError * __nullable error))completionHandler;

    比如我们在加载的HTML文件中有如下js代码:

    <script type="text/javascript">
    function hello(){
        alert("你好!");
    }
    
    function helloWithName(name){
        alert(name + ",你好!");
    }
    </script>


    我们可以调用如下代码进行js的调用:

    [_wkView evaluateJavaScript:@"hello()" completionHandler:^(id item, NSError * error) {
    
    }];
    
     [_wkView evaluateJavaScript:@"helloWithName('jack')" completionHandler:^(id item, NSError *error) {
    
    }];


    同UIWebView一样,我们也可以通过字符串的形式进行js调用。

    NSString *jsString = @"function sayHello(){ \
                                        alert('jack11')   \
                                    }                   \
                                   sayHello()";
        [_wkView evaluateJavaScript:jsString completionHandler:^(id item, NSError *error) {
    
        }];
    
        jsString = @" var p = document.createElement('p'); \
        p.innerText = 'New Line';            \
        document.body.appendChild(p);        \
        ";
        [_wkView evaluateJavaScript:jsString completionHandler:^(id item, NSError *error) {
    
        }];




    2.3 JS中调用OC的方法

    除了和UIWebView加载一个隐藏的ifame之外,WKWebView自身还提供了一套js调用native的规范。

    我们可以在初始化WKWebView的时候,给他设置一个config参数。

    //高端配置
        //创建配置
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        //创建UserContentController(提供javaScript向webView发送消息的方法)
        WKUserContentController *userContent = [[WKUserContentController alloc] init];
        //添加消息处理,注意:self指代的是需要遵守WKScriptMessageHandler协议,结束时需要移除
        [userContent addScriptMessageHandler:self name:@"NativeMethod"];
        //将UserContentController设置到配置文件中
        config.userContentController = userContent;
        //高端的自定义配置创建WKWebView
        _wkView = [[YXWKView alloc] initWithFrame:self.view.bounds configuration:config];
        NSURL *url = [NSURL URLWithString:@"http://localhost:8080/myDiary/index.html"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [_wkView loadRequest:request];
        _wkView.UIDelegate = self;
        _wkView.navigationDelegate = self;
        [self.view addSubview:_wkView];


    我们在js可以通过NativeMethod这个Handler让js代码调用native。

    比如在js代码中,我新增了一个方法

    <script type="text/javascript">
        function invokeNativeMethod(){
            window.webkit.messageHandlers.NativeMethod.postMessage("我要调用native的方法");
        }
    </script>

    触发以上方法的时候,会在native以下方法中进行拦截处理。
    #pragma mark - WKScriptMessageHandler
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
        //这里就是使用高端配置,js调用native的处理地方。我们可以根据name和body,进行桥协议的处理。
        NSString *messageName = message.name;
        if ([@"NativeMethod" isEqualToString:messageName]) {
            id messageBody = message.body;
            NSLog(@"%@",messageBody);
        }
    }

    最后总结下WKWebView和UIWebView应该如何取舍

    WKWebView是苹果在WWDC2014发布会中发布IOS8的时候公布WebKit时候使用的新型的H5容器。它与UIWebView相比较,拥有更快的加载速度和性能,更低的内存占用。将UIWebViewDelegate和UIWebView重构成了14个类,3个协议,可以让开发者进行更加细致的配置。

    但是他有一个最致命的缺陷,就是WKWebView的请求不能被NSURLProtocol截获。而我们团队开发的app中对于H5容器最佳的优化点主要就在于使用NSURLProtocol技术对于H5进行离线包的处理和H5的图片和Native的图片公用一套缓存的技术。因为该问题的存在,目前我们团队还没有使用WKWebView代替UIWebVIew。

    展开全文
  • 现在app 上越来越多需求是通过UIWebView 来展示html 或者 ...js 调用 native OC代码 第一种机制 (1)最常用的是 利用 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)reques...
  • JS调用Native方法(OC

    2018-12-24 16:20:46
    最近用到js调用原生方法,在这里做个总结记录。 调用原生时会用到JSContext,官方文档解释如下: /*! @interface @discussion A JSContext is a JavaScript execution environment. All JavaScript execution ...
  • 在app开发中使用webview,经常需要从js端调用和原生相关的交互功能。那么这样一层bridge的开发工作具体采用什么方案来实现呢? JS call OC: 方案1: 最古老也是使用最广泛、且跨平台的方案是在页面内嵌入一个...
  • 前面讲完拦截URL的方式实现JS与OC互相调用,终于到JavaScriptCore了。它是从iOS7开始加入的,用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下,提供了简单快捷的方式与JavaScript交互。
  • 此时前端工程师提到了一个需求,由前端调用native进行操作以及获取返回值。这样可以保证native只有一份代码,h5不用指定方法和native进行确认。为了实现这个需求,从网上的给出的解决办法来看,一种是使用原生的类和...
  • JS和OC相互调用

    2015-12-02 09:48:37
    1、现状:人人都是产品经理 聊聊Web App、Hybrid...1)Native APP:Native Code编程,代码编译之后以2进制或者字节码的形式运行在OS上,直接调用OS的Device API;2)Web APP,以HTML+JS+CSS等WEB技术编程,代码运行在浏
  • 前言:WKWebView是一个展示交互式web内容的视图,支持iOS8.0及macOS10.10以上的系统。提供了替换UIWebView的组件, WKWebView解决了UIWebView加载...1.JS 与 OC 交互 2.OC 向 JS 传递值 1.JS 与 OC 交互 添加注...
  • PlatformView是 flutter 官方提供的一个可以嵌入 Android 和 ...1.创建webView (这里js oc flutter交互不阐述) #import <Foundation/Foundation.h> #import <Flutter/Flutter.h> NS_ASSUME_NONNULL_...
  • 前面讲完拦截URL的方式实现JS与OC互相调用,终于到JavaScriptCore了。它是从iOS7开始加入的,用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下,提供了简单快捷的方式与JavaScript交互。 关于JavaScriptCore...
  • 上一篇文章介绍了UIWebView 如何通过WebViewJavascriptBridge 来实现JS 与OC 的互相调用,这一篇来介绍一下WKWebView 又是如何通过WebViewJavascriptBridge 来实现JS 与OC 的互相调用的。WKWebView 下使用...
  • 这里照搬Github的Demo,其实还是很易懂的,首先,要在控制器的.h文件当中实现浏览器控件的协议: 1 #import 2 3 @interface ExampleAppViewController : UINavigationController 4 5 @end ...
  • OC与JS互相调用并传值

    2018-01-19 11:39:43
    OC与JS间相互调用的几种方式#####第一种:使用JavaScriptCore,iOS7之后系统的原生方法,能够实现一些比较复杂的参数互传及参数返回。使用也比较简单,有以下几篇文章有比较详细的介绍。基本看完就能够熟练的使用了...
  • JS调用OC失败的原因

    2018-06-05 20:37:55
    在使用WKWebView 时,如果JS调用原生失败,只可能有3个原因:1,没有注册方法2,没有给WKWebViewConfiguration设置WKPreferences,这是最容易被忽略的3,没有给WKWebViewConfiguration设置WKUserContentController,...
1 2 3 4 5 ... 20
收藏数 1,276
精华内容 510