C与Javascript交互总结,JSCore的基本使用

JSCore全称为JavaScriptCore,是苹果公司在iOS中投入的三个新的framework。该framework为OC与JS代码互相操作的提供了高大的造福。该工程私下认可是未曾导入工程中的,要求大家手动增加。

一、在iOS7从前,对JavaScript操作只好利用UIWebView中二个主意stringByEvaluatingJavaScriptFromString,JavaScript对Objective-C的回调都是依照UENVISIONL的拦截进行操作。
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    self.webView.delegate = self;
    [self.view addSubview:self.webView];
    NSURL * url = [NSURL URLWithString:@"https://www.baidu.com"];
    NSURLRequest * request = [[NSURLRequest alloc] initWithURL:url];

    [self.webView loadRequest:request];
}

一、iOS7 之前

1. OC 调用 JS

// 在 iOS7 之前,OC 调用 JS 只有一种方法,使用 UIWebView 的 stringByEvaluatingJavaScriptFromString:,因为涉及到 UI 更新,所以该方法只能在主线程中执行,另外, stringByEvaluatingJavaScriptFromString 是同步执行 JS 代码,即会阻塞到该 JS 执行完毕,才继续执行接下来的代码。

dispatch_async(dispatch_get_main_queue(), ^{
    NSString *jsString = [NSString stringWithFormat:@"alert("提示弹框")"];
    [webView stringByEvaluatingJavaScriptFromString:jsString];
});

2. JS 调用 OC

// 在 iOS7 之前,JS 调用 OC 主要是通过拦截 URL 请求,即 JS 发送一个伪 URL 请求,通过 webView 的代理方法进行监听,根据 JS 与 OC 约定好的协议进行拦截,然后根据 URL 中的 path、query 等进行相应的处理。

// 主要通过 UIWebViewDelegate 中的 webView:shouldStartLoadWithRequest:navigationType: 方法拦截

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
    if([request.URL.scheme isEqualToString:@"js2oc"]) {
        // oc 进行相应的处理操作
        return NO;
    }
    return YES;
}
  • JavaScriptCore简介
  • JavaScriptCore中关键的类
  • JSContext
  • JSValue
  • JSExport
  • JSManagedValue
  • JSVirtualMachine
  • Native Code 和 JS 之间的交互调用
  • Native Code 与UIWebView中的JS交互
  • Native Code 与JS文件一直互动

图片 1显示器快照二〇一五-10-25 上午1.23.28.png

1.stringByEvaluatingJavaScriptFromString在UIWebView加载实现时利用,以下是简轻便单利用境况:
#pragma mark -- UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //当前页面URL
    NSString * currentUrl = [webView stringByEvaluatingJavaScriptFromString:@"document.location.href"];
    //当前页面的title
    NSString * title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    //填充文本输入框的内容
    [self.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('index-kw').value = 'apple';"];
    //模拟点击按钮
    [self.webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('index-bn').click();"];
}

二、iOS7 之后 (JavaScriptCore)

参考

iOS7 之后,苹果官方引进了 JavaScriptCore 框架,使得 OC 能够在退出 webView 的场合下直接运维 JS,并且,能够插入自定义 OC 对象到 JavaScript 情形中。

JavaScriptCore 框架中最首要有以下多少个类:

JSContext: 重要提供在 OC 中实践 Java Script 代码的条件,管理 Java Script Object 生命周期,各类 JSValue 都与 JSContext 强关联,只要 JSValue 存在,JSContext 就保持援用,知道全体 JSValue 都被放飞,JSContext 才有望被释放。 一个 JSContext 是贰个大局境遇的实例。

JSValue: 是 JS value(JS 变量和格局) 的包裹,首要用于 JS 对象 与 OC 对象相互转变。各类 JSValue 都和 JSContext 相关联并且强援用 JSContext。

JSManagedValue: 是 JS 和 OC 对象的内部存储器管理支持对象,主要用于保存 JSValue,从而化解 OC 对象存款和储蓄 JSValue 导致循环援引难点。JS 内部存款和储蓄器管理是污物回收机制,在那之中装有目的都是强引用,可是大家不用忧郁循环援用,因为垃圾回收会打破这种强援引;OC 是引用计数机制。JSValue 强引用相关 JSContext,把 OC 暴光给 JSContext,JSContext 强引用 OC,假诺 OC 再强援引 JSValue 对象,就能招致循环援用,JSContext 释放不了,内部存款和储蓄器泄漏。

为了化解 OC 与 JSValue 和 JSContext 的巡回援引,引进了 JSManagedValue。

NSManagedValue *managedValue = [NSManagedValue managedValueWithValue:jsValue];
// managedValue 相当于弱引用 jsValue,如果 jsValue 指向 JSVirtualMachine 中 javascript value 被垃圾回收机制回收,jsValue 会自动设为 nil。
[jsVirtualMachine addManagedReference:managedValue withOwner:self];
// 该方法将原生的引用来告知 jsVirtualMachine,只要这种引用链存在,jsVirtualMachine 就不会对 managedValue.value 指向的 java script value 进行垃圾回收。
[jsVirtualMachine removeManagedReference:managedValue withOwner:self];
// 该方法在 jsVirtualMachine 中去除原生引用链,然后 java script value 就可能会被垃圾回收。

JSVirtualMachine: JS 运营的设想机,有独立的堆空间和污源回收机制。首要用来二十二十四线程并发实施 JS 及 JS 与 OC 之间的内部存款和储蓄器管理。

各种 JSContext 属于二个 JSVirtualMachine,每种 JSVirtualMachine 饱含多少个JSContext,所以 属于同一个 JSVirtualMachine 的 JSContext 能够并行传值,因为国有同样的客栈,而区别的 JSVirtualMachine 之间无法相互传值。

一经想并发实施 JS,必要使用多少个 JSVirtualMachine,各个 JSVirtualMachine 对应二个线程,同一个 JSVirtualMachine 中,只好串行试行 JS,当推行二个 JS 时,其他的内需拭目以俟。

JSExport: 是一个说道,那几个体协会议将原生对象的本性、方法暴光给 JavaScript,使得 JavaScript 能够一向调用 OC 对象的方法、属性。坚守JSExport 公约,就足以定义大家本人的协议,在情商业中学宣称的 API 都会暴光在 JS 中。
若果 JS 想调用 OC 对象的措施,只要使 OC 对象落成那些合同,而且将以此 OC 对象实例绑定到 JS。

1. 利用 JSContext 和 JSValue 实现 JS 与 OC 交互

HTML

<html>
    <head>
        <title>JS_OC</title>
    </head>
    <body>
    <h1>发送伪URL请求</h1>
        <div style="margin-top: 10px">
            <input type="button" value="Call OC With URL" onclick="callOC()">
        </div>
    <h3> JS Call OC Wth JavaScriptCore</h3>
        <div style="margin-top: 20px">
            <input type="button" value="Call OC System Camera" onclick="callOCSystemCamera()">
        </div>
        <div style="margin-top: 10px">
            <input type="button" value="Call OC Alert" onclick="showOCAlertMsg('js title','js msg')">
        </div>
    </body>
    <script>
        function callOC(){
            window.location.href = 'js2oc://callOC?p1=1&p2=2';
        }
    </script>
    <script type="text/javascript">
        function showJSAlertMsg(msg){
            alert(msg);
        }
    </script>
</html>

UIWebView 加载实现后,获取 JS 的运行运转情形 - JSContext。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
}

OC 调用 JS

JSValue *jsValue = [self.jsContext evaluateScript:@"oc_call_js_func"];
[jsValue callWithArguments:@[args,...]];

JS 调用 OC

// 即为 JS 调用 OC 的函数指定相应的 block
self.jsContext[@"js_call_oc_func"] = ^(args,...){
    // 主线程执行 native UI 操作
}

2. 利用 JSExport 实现 JS 与 OC 交互

HTML

<html>
    <head>
        <title>JS_OC</title>
    </head>
    <body>
    <h1>发送伪URL请求</h1>
        <div style="margin-top: 10px">
            <input type="button" value="Call OC With URL" onclick="callOC()">
        </div>
    <h3> JS Call OC Wth JavaScriptCore</h3>
        <div style="margin-top: 20px">
            <input type="button" value="Call OC System Camera" onclick="OCModel.callOCSystemCamera()">
        </div>
        <div style="margin-top: 10px">
            <input type="button" value="Call OC Alert" onclick="OCModel.showOCAlertMsg('js title','js msg')">
        </div>
    </body>
    <script>
        function callOC(){
            window.location.href = 'js2oc://callOC?p1=1&p2=2';
        }
    </script>
    <script type="text/javascript">
        function showJSAlertMsg(msg){
            alert(msg);
        }
    </script>
</html>

由 HTML 文件得以看出来,JS 不是一直调用某一艺术,而是调用有些对象 OCModel 的措施,只要成立一个 OC 对象 OCModel 并让他促成 JS 要调用的不二等秘书技,然后将它绑定到 JS 就可以。

扬言三个 JSExport 合同,并在内部注解 JS 调用 OC 的这一个方法:

#import <JavaScriptCore/JavaScriptCore.h>

@protocol JSExportProtocol <JSExport>

- (void)callOCSystemCamera;
- (void)showOCAlertMsg:(NSString *)msg;

@end

钦赐类实现地点表明的公约:

@interface OCModel : NSObject <JSExportProtocol>

@end

@implementaion OCModel

- (void)callOCSystemCamera {
    // 主线程操作
}

- (void)showOCAlertMsg:(NSString *)msg {
    // 主线程操作
}

@end

将上述类实例绑定到 JSContext 中:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    JSContext *jsContext. = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    jsContext[@"OCModel"] = [OCModel new];
}

下一场 JS 就足以经过 JSExport 共同商议调用 OC 的方法了。

注:JavaScriptCore 中,JS 是在子线程中调用 OC 方法,如果 OC 方法中有 UI 相关操作,需要在主线程中执行。
用 JavaScriptCore 进行 OC 与 JS 交互,又一个显著的缺点:只有 html 加载完毕后,OC 才能调用 JS 成功

增进完成后,我们能够看看JavaScriptCore.h中带有以下5个首要的文书。

2.JavaScript对Objective-C的回调基于UHighlanderL的阻挠举行操作:
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL * url = request.URL;
    NSString * scheme = [URL scheme];
    if ([scheme isEqualToString:@"XXXX"]) {
        //do something
        return NO;
    }
    return YES;
}

三、WKWebView

iOS8之后,苹果推出了新框架 WebKit,提供了替换 UIWebView 的组件 WKWebView。WKWebView 在性质、牢固性和功力方面都有非常的大的进步,最刚毅的独到之处正是私吞的内部存款和储蓄器大幅度减小。

WebKit 将 UIWebView 和 UIWebViewDelegate 重构为14个类和3个协议。实际参照他事他说加以考察

WKWebView: 用于显示 web 内容。

WKWebViewConfiguration: 用于在初叶化 WKWebView 时,内定其设置新闻。

WKPreferences: 内定 WKWebView 的宠幸设置。

WKScriptMessage: WKWebView 向 native 发送的新闻。

WKUserScript: 注入 web view 的客户脚本。

WKUserContentController: 首要用以向 web view 注入脚本和点名 web view 发送新闻的接收管理(钦定 JS 调用 OC 的兑当代码)。

UINavigation: 加载 web view 时重回的指标,首要用以追踪 web view 加载进度。

WKProcessPool、WKBackForwardList、WKBackForwardListItem等。

WKNavigationDelegate: 公约,首要用以拍卖 web view 的加载和跳转。

WKUIDelegate: 合同,主要用以拍卖 JS 脚本,以及将 JS 的承认、警告等对话框用 native 表示。

WKScriptMessageHandler: 左券,主要用于收纳、处理 web view 发送的音讯。

1. 创建 WKWebView

// 初始化配置对象
WKWebviewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 初始化偏好设置
config.preferences = [[WKPreferences alloc] init];
// 指定最小字体,默认是 0
config.preferences.minimumFontSize = 10;
// 是否支持 javascript
config.preferences.javaScriptEnable = YES;
// javascript 不通过用户交互是否可以自动打开窗口
config.preferences.javaScriptCanOpenWindowsAutomatically = YES;
// 创建 web view
WXWebView *webView = [[WKWebView alloc] initWithFrame:frame configuration:config];
webView.navigationDelegate = self;
webView.UIDelegate = self;
[webView loadRequest:urlRequest];
// 向 web view 中注入用户脚本,可以通过该方法将 native 中的方法转换为 JS 函数,比如,获取 app 版本号等。
[webView.config.userContentController addUserScript:userScript];
// 指定 web view 发送消息的接收者(要及时执行 removeScriptMessageHandler:name 方法移除接收者,否者会循环引用而内存泄漏)
[webView.config.userContentController addScriptMessageHandler:self name:@"msgName"];
[self.view addSubview:webView];

2. JS 调用 OC

WKWebView 首要透过向 native 发送音讯来调用 native 方法, native 根据接收到的音讯实行对应的管理

// WKWebView 中 JS 发送消息
function clickAction() {
    window.webkit.messageHandlers.msgName.postMessage(messageBody);
}

// native 主要通过 WKScriptMessageHandler 协议来接收消息,并进行处理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if([message.name isEqualToString:@"msgName"]) {
        // native action
    }else {
        // ...
    }
}

3. OC 调用 JS

[webView evaluateJavaScript:jsString completionHandler^(id result, NSError *error){
    // ...
}];
// 使用该方法执行 JS 脚本,或者直接执行 webView 暴露出来的全局函数,通常是后者。

4. WKUIDelegate 商议落到实处

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void(^)(void))completionHandler {
    // 使用 UIAlertViewController 将 JS Alert 转换为 native alert
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    // 将 JS 确认框转换为 native 框。
}

//...其他的协议方法

5. WKNavigationDelegate 切磋落到实处

// web view 开始接收 web content 时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

// 开始加载 web content 时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation; 

// 当需要进行 server 重定向时调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;

// 当 web 需要进行验证时调用
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;

// web view 跳转失败时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation 
  withError:(NSError *)error;

// web view 加载失败时调用 
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation 
  withError:(NSError *)error;

// web view 跳转结束时调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

// web view 处理终止时调用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;

// web view 是否允许跳转,比如点击某个超链接时触发,可以根据情况允许或者取消
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

// 已经知道响应结果,是否允许跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

选取 WKWebView 难题及减轻方案

  • iOS中的JavaScriptCore.framework其实只是依靠webkit(Safari的浏览器引擎)中以C/C 完成的JavaScriptCore的三个封装,在iOS7中,Apple将其当作三个标准库供开采者使用
#import "JSContext.h"#import "JSValue.h"#import "JSManagedValue.h"#import "JSVirtualMachine.h"#import "JSExport.h"
二、iOS7事后苹果推出JavaScriptCore框架,该框架让Objective-C与Javascript代码的互相变得更为简便易行方便。
JavaScriptCore下的类和商量:
  • JSContext:JS奉行的情状,同偶尔间也通过JSVirtualMachine管理着全数指标的生命周期,每种JSValue都和JSContext相关联并且强援用context。
  • JSValue:JavaScript和Object-C之间调换的大桥。
  • JSManagedValue:JS和OC对象的内存管理帮忙对象,由于JS内部存款和储蓄器管理是废物回收,并且JS中的对象都是强引用,而OC是援用计数。借使两个相互援用,势必会产生循环援引,而招致内部存储器走漏。大家可以用JSManagedValue保存JSValue来幸免。
  • JSVirtualMachine:JS运维的设想机,有独立的堆空间和垃圾回收机制,管理线程相关,使用非常少。
  • JSExport:三个公约,若是JS对象想直接调用OC对象里面包车型客车法门和个性,那么这么些OC对象只要完毕这么些JSExport左券就能够了。

四、第三方库(WebViewJavascriptBridge)

Github地址

WebViewJavascriptBridge 也是通过 U大切诺基L 拦截来落到实处 JS 与 OC 的相互,何况还要帮忙 UIWebView、WKWebView。

优点:

html 加载时,只要 JS 代码被周转就足以开展交互,不需静观其变 html 加载落成才具相互。

iOS 与 Android 都有一套对应的库,那样 H5 只要求联合一套就行了。

缺点:

亟需在 html 中步入固定的 JS 代码片段。

1. JS 处理

第一包括八个部分,固定注解清码、注册 OC 须要调用的 JS 函数 和 JS 调用 OC 方法入口声明。

<!-- 声明交互 固定代码 -->
function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
    window.WVJBCallbacks = [callback];
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}

<!-- 处理交互  方法名要和 iOS 内定义的对应 -->
setupWebViewJavascriptBridge(function(bridge) {

    <!-- 注册 OC 调用的 JS 函数 -->
    bridge.registerHandler('OC2JS', function(data, responseCallback) {
        //处理 OC 给的传参
        alert('OC 请求 JS  传值参数是:' data)                               
        var responseData = { 'result':'handle success' }
        // 将处理结果回传给 OC
        responseCallback(responseData)
    })

    var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
    callbackButton.innerHTML = '点击我,我会调用 OC 的方法'
    callbackButton.onclick = function(e) {
        e.preventDefault()                                 
        <!--JS 调用 OC -->
        bridge.callHandler('loginAction', {'userId':'zhangsan','name': 'HeHe'}, function(response) {
             // 处理 OC 回传的数据
             alert('收到 OC 的回调:' response)
        })
    }
})

2. OC 处理

OC 中入眼也是挂号 JS 调用的 OC 方法,和 证明 OC 调用 JS 方法入口。

_bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
[_bridge setWebViewDelegate:self];

// 声明 JS 调用的 OC 方法
[_bridge.registerHandler:@"JS2OC" handler:^(id data, WVJBResponseCallback responseCallback){、
    // 对 JS 传过来的 data 进行处理
    // 将处理结果回传给 JS
    responseCallback(data);
}];

// 调用 JS
_bridge.callHandler:@"OC2JS" data:nil responseCallback:^(id responseData) {
    // 处理 JS 回传数据
}

3. WebViewJavascriptBridge 达成原理

个别在 OC 情状和 JS 情况都保存叁个 bridge 对象,里面维持着 requestId、callbackId 以及各类Id对应的切切实实贯彻。

OC 通过 JS 情形的 window.WebViewJavascriptBridge 对象找到切实可行的办法,然后施行。

JS 通过改造 iframe 的 src 来唤起 webview 的代理方法 webView:(WKWebView* )webView decidePolicyForNavigationAction:(WKNavigationAction* )navigationAcion decisionHandler:(void(^)(WKNavigationActionPolicy))decisionHandler 也许UIWebView 对应的代办方法,进而达成把 JS 音讯发送给 OC。

  1. JavaScriptCore首借使对JS进行剖判和提供推行碰着。代码是开源的,JavaScriptCore源码
  2. JavaScriptCore能够让我们脱离webview直接运营我们的js
  3. JavaScriptCore提供一种动态局地进级和翻新的逻辑,大大提升应用的可扩充性
  4. 对手提式无线电话机内嵌web情势的新尝试点,即透过Native JS file的主意代替webview的主意

JSContext: 代表JavaScript的实践情况。你能够成立JSContent在OC意况中举办JavaScript脚本,同有的时候间也得以在JavaScript脚本中做客OC中的值大概措施。

1.Objective-C调用Javascript:
//Objective-C -> JavaScript
JSContext * context = [[JSContext alloc] init];
[context evaluateScript:@"function maxNum(x, y) { return x > y ? x : y}"];
JSValue * max = context[@"maxNum"];
NSLog(@"function:%@",max);

JSValue:是OC和JavaScript值相互转化的大桥。他提供了无数主意把OC和JavaScript的数据类型实行互动转化。其一一对应提到如下表所示:

2.Javascript调用Objective-C,使用block或JSExport protocol:

使用block:

self.context = [[JSContext alloc] init];
self.context[@"maxNum"] = ^(NSInteger a, NSInteger b) {
        NSLog(@"%@",[NSNumber numberWithInteger:(a > b ? a : b)]);
};
[self.context evaluateScript:@"maxNum(11,13)"];

使用JSExport protocol:

//JSProtocolObj.h
//定义一个JSExport protocol
@protocol JSExportTest <JSExport>
//用宏转换下,将JS函数名字指定为maxNum;
JSExportAs(maxNum, - (NSInteger)maxNum:(NSInteger)x y:(NSInteger)y);
- (NSInteger)add:(NSInteger)a b:(NSInteger)b;
@property (nonatomic, assign) NSInteger sum;
@end

@interface JSProtocolObj : NSObject<JSExportTest>
@end

//JSProtocolObj.m
@implementation JSProtocolObj
@synthesize sum = _sum;
- (NSInteger)maxNum:(NSInteger)x y:(NSInteger)y {
    return x > y ? x : y;
}
//实现协议方法
- (NSInteger)add:(NSInteger)a b:(NSInteger)b {
    return a b;
}
//重写setter方法方便打印信息,
- (void)setSum:(NSInteger)sum {
    NSLog(@"--%@", @(sum));
    _sum = sum;
}
@end

ViewController中调用:

//创建context
self.context = [[JSContext alloc] init];
//设置异常处理
self.context.exceptionHandler = ^(JSContext * context,JSValue *exception) {
      [JSContext currentContext].exception = exception;
      NSLog(@"exception:%@",exception);
};
_objModel = [JSProtocolObj new];
self.context[@"OCModel"] = self.objModel;
[self.context evaluateScript:@"OCModel.sum = OCModel.addB(2,3)"];
[self.context evaluateScript:@"OCModel.sum = OCModel.maxNum(12,18)"];
  1. JSContext --- 在OC中开创JavaScript运转的上下文情形

    - (instancetype)init; // 创建JSContext对象,获得JavaScript运行的上下文环境// 在特定的对象空间上创建JSContext对象,获得JavaScript运行的上下文环境- (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;// 运行一段js代码,输出结果为JSValue类型- (JSValue *)evaluateScript:(NSString *)script;// iOS 8.0以后可以调用此方法- (JSValue *)evaluateScript:(NSString *)script withSourceURL:sourceURL NS_AVAILABLE(10_10, 8_0);// 获取当前正在运行的JavaScript上下文环境  (JSContext *)currentContext;// 返回结果当前执行的js函数 function () { [native code] } ,iOS 8.0以后可以调用此方法   (JSValue *)currentCallee NS_AVAILABLE(10_10, 8_0); // 返回结果当前方法的调用者[object Window]   (JSValue *)currentThis; // 返回结果为当前被调用方法的参数   (NSArray *)currentArguments; // js的全局变量 [object Window] @property (readonly, strong) JSValue *globalObject;
    
  2. JSValue --- JavaScript中的变量和艺术,可以转成OC数据类型,每一个JSValue都和JSContext相关联并且强引用context

     @textblock Objective-C type | JavaScript type -------------------- --------------------- nil | undefined NSNull | null NSString | string NSNumber | number, boolean NSDictionary | Object object NSArray | Array object NSDate | Date object NSBlock  | Function object  | Wrapper object  Class  | Constructor object  @/textblock // 在context创建BOOL的JS变量   (JSValue *)valueWithBool:value inContext:(JSContext *)context; // 将JS变量转换成OC中的BOOL类型 - toBool; // 修改JS对象的属性的值 - setValue:value forProperty:(NSString *)property; // JS中是否有这个对象 @property  BOOL isUndefined; // 比较两个JS对象是否相等 - isEqualToObject:value; // 调用者JSValue对象为JS中的方法名称,arguments为参数,调用JS中Window直接调用的方法 - (JSValue *)callWithArguments:(NSArray *)arguments;// 调用者JSValue对象为JS中的全局对象名称,method为全局对象的方法名称,arguments为参数 - (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;// JS中的结构体类型转换为OC   (JSValue *)valueWithPoint:point inContext:(JSContext *)context;
    
  3. JSExport --- JS调用OC中的方法和性质写在后续自JSExport的合计个中,OC对象实现自定义的说道

    // textFunction -- JS方法// -  ocTestFunction:(NSNumber *)value sec:(NSNumber *)number -- OC方法JSExportAs (textFunction,-  ocTestFunction:(NSNumber *)value sec:(NSNumber *)number);
    
  4. JSManagedValue --- JS和OC对象的内部存款和储蓄器管理协理对象,首要用以保存JSValue对象,消除OC对象中存放js的值,导致的轮回援用难点

    JSManagedValue *_jsManagedValue = [JSManagedValue managedValueWithValue:jsValue];[_context.virtualMachine addManagedReference:_jsManagedValue];
    

    JSManagedValue本人只弱援引js值,需求调用JSVirtualMachine的addManagedReference:withOwner:把它增加到JSVirtualMachine中,那样假若JavaScript能够找到该JSValue的Objective-C owner,该JSValue的引用就不会被放走。

  5. JSVirtualMachine --- JS运营的虚构机,有独立的堆空间和垃圾回收机制,运行在分裂虚构机遇到的JSContext能够透过此类通讯。

图片 2显示器快速照相二〇一四-10-25 中午1.36.28.png

3.UIWebView中Objective-C与Javascript互相调用:
//test.html
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title> my javascript </title>
</head>
    <style>
        p{
            padding-left:100px;
            color: aqua;
        }
    </style>
<body>
<h1>
    <script>
        document.write("hello world");
        document.write("<h1>这是一个标题</h1>");
        document.write("<p>这是一个段落</p>");
    </script>
</h1>

<p1 id="demo" >
    JavaScript 能改变 HTML 元素的内容。
</p1>
<button type="button" onclick="myFunction()">元素改变</button>
<button type="button" onclick="loginClick()">点击登录</button>
<button type="button" onclick="callSystemCamera()">调用系统照相机</button>
<script>
    function myFunction() {
        x=document.getElementById("demo");  // 找到元素
        x.innerHTML="Hello JavaScript!";    // 改变内容
    }
    function loginClick() {
        logIn("18200133537","ls123321");
    }
    function callSystemCamera() {
        //调用系统照相机
    }
    //
    function userInterface() {
        x=document.getElementById("demo");  // 找到元素
        x.innerHTML="oc-->js 内容改变";    // 改变内容
        //alert("what's your name?");
        //if (confirm("确定跳转")) {
            //window.open('http://www.baidu.com')
        //}
        x.innerHTML=prompt("你的名字是什么?","胡杨魂");
    }
</script>
</body>
</html>

ViewController中调用:

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
@interface HTMLViewController ()<UIWebViewDelegate>
@property (nonatomic, strong) UIWebView * webView;
@property (nonatomic, strong) JSContext * jsContext;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
    self.webView.delegate = self;
    [self.view addSubview:self.webView];
    NSString* path = [[NSBundle mainBundle] pathForResource:@"onecat" ofType:@"html"];
    NSURL* url = [NSURL fileURLWithPath:path];
    NSURLRequest* request = [NSURLRequest requestWithURL:url] ;
    [self.webView loadRequest:request];
}
#pragma mark -- UIWebViewDelegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //只要我们能拿到 UIWebView 的实例,然后就可以直接使用 KVC 的方法来获取它的 JSContext 对象
    _jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    _jsContext[@"callSystemCamera"] = ^() {
        NSLog(@"js-->oc 现在可以打开照相机");
    };
    _jsContext[@"logIn"] = ^() {
        NSLog(@"现在开始登录");
        NSArray * param = [JSContext currentArguments];
        for (JSValue * jsValue in param) {
            NSLog(@"%@",jsValue);
        }
    };
    //调用Javascript中方法 userInterface();
    [_jsContext evaluateScript:@"userInterface()"];
}

JSManagedValue:JSValue的包装类。JS和OC对象的内部存款和储蓄器处理帮助对象。由于JS内部存款和储蓄器管理是垃圾回收,并且JS中的对象都以强援用,而OC是引用计数。要是两个互为引用,势必会变成循环援引,而导致内部存款和储蓄器败露。大家得以用JSManagedValue保存JSValue来防止。

三、iOS8从此苹果推出了新框架WebKit,提供了替换UIWebView的零部件WKWebView,大幅晋级了品质、功用和平静,大大裁减了加载网页时候占用的内存空间。

//test.html
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title> my javascript </title>
</head>
    <style>
        p{
            padding-left:100px;
            color: aqua;
        }
    </style>
<body>
<h1>
    <script>
        document.write("hello world");
        document.write("<h1>这是一个标题</h1>");
        document.write("<p>这是一个段落</p>");
    </script>
</h1>

<p1 id="demo" >
    JavaScript 能改变 HTML 元素的内容。
</p1>
<button type="button" onclick="myFunction()">元素改变</button>
<button type="button" onclick="loginClick()">点击登录</button>
<button type="button" onclick="callSystemCamera()">调用系统照相机</button>
<script>
    function myFunction() {
        x=document.getElementById("demo");  // 找到元素
        x.innerHTML="Hello JavaScript!";    // 改变内容
    }
    function loginClick() {
        window.webkit.messageHandlers.login.postMessage(['18200133533', 'ls123321'])
    }
    function callSystemCamera() {
        //调用系统照相机
        window.webkit.messageHandlers.callCamera.postMessage(null)
    }
    //
    function userInterface() {
        x=document.getElementById("demo");  // 找到元素
        x.innerHTML="oc-->js 内容改变";    // 改变内容
        //alert("what's your name?");
        //if (confirm("确定跳转")) {
            //window.open('http://www.baidu.com')
        //}
        x.innerHTML=prompt("你的名字是什么?","胡杨魂");
    }
</script>
</body>
</html>

WKWebViewController中调用:

#import "WKWebViewController.h"
#import <WebKit/WebKit.h>
@interface WKWebViewController ()<WKScriptMessageHandler,WKUIDelegate>
@property (nonatomic, strong) WKWebView * webView;
@end

@implementation WKWebViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //在创建WKWebView之前,需要先创建配置对象,用于做一些配置:
    WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc] init];
    config.preferences.minimumFontSize = 18;
    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) configuration:config];
    [self.view addSubview:self.webView];
    NSString* path = [[NSBundle mainBundle] pathForResource:@"onecat" ofType:@"html"];
    NSURL* url = [NSURL fileURLWithPath:path];
    NSURLRequest* request = [NSURLRequest requestWithURL:url] ;
    [self.webView loadRequest:request];

    //而如果需要与在JS调用alert、confirm、prompt函数时,通过JS原生来处理,而不是调用JS的alert、confirm、prompt函数,那么需要设置UIDelegate,在得到响应后可以将结果反馈到JS端:
    self.webView.UIDelegate = self;
    //WKUserContentController 用于给JS注入对象的,注入对象后,JS端就可以使用:
    WKUserContentController * cv = config.userContentController;
     //注入JS对象名称,JS调用OC 添加处理脚本
    [cv addScriptMessageHandler:self name:@"login"];
    [cv addScriptMessageHandler:self name:@"callCamera"];
    //js端 window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"login"]) {
        NSLog(@"js-->oc 开始登录:%@",message.body);
    }
    if ([message.name isEqualToString:@"callCamera"]) {
        NSLog(@"js-->oc 现在打开系统相机");
    }
}
#pragma mark -- WKUIDelegate
#pragma mark -- JS调用alert、confirm、prompt时,不采用JS原生提示,而是使用iOS原生来实现
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"js调用alert" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction * action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }];
    [alert addAction:action];
    [self presentViewController:alert animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"js调用Confirm" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction * actionDone = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }];
    [alert addAction:actionDone];
    UIAlertAction * actionCancel = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }];
    [alert addAction:actionCancel];
    [self presentViewController:alert animated:YES completion:nil];
}
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler {

    UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"js调用Prompt" preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.textColor = [UIColor greenColor];
        textField.text = defaultText;
        textField.placeholder = @"请输入你的名字";
    }];
    UIAlertAction * actionCancel = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alert.textFields.firstObject.text);
    }];
    [alert addAction:actionCancel];
    [self presentViewController:alert animated:YES completion:nil];
    NSLog(@"====%@",defaultText);
}
@end
  1. JS中,点击事件直接调用方法措施JS和Native代码的互调如下:

JSVirtualMachine: JS运营的设想机。能够支持互相的JavaScript实践,管理JavaScript和OC转变中的内部存款和储蓄器管理。

四、使用第三方工具类:WebViewJavascriptBridge:略(暂未利用过)
  • 1.1 JS代码如下

    <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport"><body> <script type="text/javascript"> var nativeCallJS = function(parameter) { alert (parameter); }; </script> <button type="button" onclick = "jsCallNative('jsParameter')" style="width:100%; height:30px;"/>调用OC代码</button></body></html>
    
  • 1.2 OC代码如下

     - __jsLogic { self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){ NSLog(@"JS代码执行中的异常信息%@", exception); }; self.jsContext = [self valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; self.jsContext[@"jsCallNative"] = ^(NSString *paramer){ JSValue *currentThis = [JSContext currentThis]; JSValue *currentCallee = [JSContext currentCallee]; NSArray *currentParamers = [JSContext currentArguments]; dispatch_async(dispatch_get_main_queue(), ^{ /** * js调起OC代码,代码在子线程,更新OC中的UI,需要回到主线程 */ }); NSLog(@"JS paramer is %@",paramer); NSLog(@"currentThis is %@",[currentThis toString]); NSLog(@"currentCallee is %@",[currentCallee toString]); NSLog(@"currentParamers is %@",currentParamers); }; JSValue *jsMethod = self.jsContext[@"nativeCallJS"]; [jsMethod callWithArguments:@[@"nativeCallJS"]]; }
    
  • 1.3 OC运转结果,弹出HTML中的alert提醒

    2016-08-05 17:57:08.974 LeWebViewPro[38150:3082770] JS paramer is jsParameter2016-08-05 17:57:08.975 LeWebViewPro[38150:3082770] currentThis is [object Window]2016-08-05 17:57:08.975 LeWebViewPro[38150:3082770] currentCallee is function () {[native code]}2016-08-05 17:57:08.975 LeWebViewPro[38150:3082770] currentParamers is (jsParameter)
    

JSExport:四个左券,若是JS对象想一直调用OC对象里面的秘籍和天性,那么这么些OC对象只要实现这几个JSExport合同就足以了。

结束
  1. JS中,点击事件等事件经过调用全局对象的方法调用方法,JS和Native代码的互调如下:

    • 2.1 JS代码如下

      <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport"><body> <script type="text/javascript"> globalObject = new Object(); globalObject.name = 100; globalObject.nativeCallJS = function (parameter) { alert (parameter); }; </script> <button type="button" onclick = "globalObject.jsCallNative('jsParameter')" style="width:100%; height:30px;"/>调用OC代码</button></body></html>
      
    • 2.2 OC代码如下

    • 2.2.1 JSManager 代码,肩负实行JS中的方法

      #import <JavaScriptCore/JavaScriptCore.h>#import <Foundation/Foundation.h>@protocol LeJSExport <JSExport>JSExportAs (jsCallNative,-  jsCallNative:(NSString *)jsParameter);@end@interface JSManager : NSObject<LeJSExport>@end-----.M文件-----#import "JSManager.h"@implementation JSManager- jsCallNative:(NSString *)jsParameter{ JSValue *currentThis = [JSContext currentThis]; JSValue *currentCallee = [JSContext currentCallee]; NSArray *currentParamers = [JSContext currentArguments]; dispatch_async(dispatch_get_main_queue(), ^{ /** * js调起OC代码,代码在子线程,更新OC中的UI,需要回到主线程 */ }); NSLog(@"JS paramer is %@",jsParameter); NSLog(@"currentThis is %@",[currentThis toString]); NSLog(@"currentCallee is %@",[currentCallee toString]); NSLog(@"currentParamers is %@",currentParamers);}@end
      
    • 2.2.2 富含UIWebView类的代码,担负调起JS中的方法

      - nativeCallJS{ self.jsManager = [[JSManager alloc] init]; self.jsContext = [self valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){ NSLog(@"JS代码执行中的异常信息%@", exception); }; self.jsContext[@"globalObject"] = self.jsManager; //1.OC方法调起JS JSValue *varibleStyle = self.jsContext[@"globalObject"]; [varibleStyle invokeMethod:@"nativeCallJS" withArguments:@[@100]]; //2.OC脚本调起JS NSString *jsScript = [NSString stringWithFormat:@"globalObject.nativeCallJS",@100]; [self.jsContext evaluateScript:jsScript];}
      
    • 2.3 OC运转结果,弹出HTML中的alert提醒

      2016-08-07 10:30:11.444 LeWebViewPro[46674:3253852] JS paramer is jsParameter2016-08-07 10:30:11.444 LeWebViewPro[46674:3253852] currentThis is [object JSManager]2016-08-07 10:30:11.444 LeWebViewPro[46674:3253852] currentCallee is function () { [native code]}2016-08-07 10:30:11.445 LeWebViewPro[46674:3253852] currentParamers is ( jsParameter)
      

下边大家由此实例案例来学学JSCore的用法。

案例一:作者在js中定义了八个函数add,大家要求在OC中开展调用。

  1. OC在与UIWebView中的JS交互的逻辑是,先拿走UIWebView中的JS的举办际遇

    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
  2. 赢得UIWebView中的JS的试行情形的机缘,一般在webViewDidFinishLoad时获得,获取不到的景观下,需改在别的格局中拿走

    shouldStartLoadWithRequest:Sent before a web view begins loading a framewebViewDidStartLoad:Sent after a web view starts loading a frame.webViewDidFinishLoad:Sent after a web view finishes loading a frame
    
  3. 线程难题

    • JavaScriptCore中提供的API都是线程安全的,一个JSVirtualMachine在一个线程中,它可以包括七个JSContext,并且相互能够传值,为了保险线程安全,那个context在运作的时候会动用锁,能够感到是串行实践。
    • JS调用OC的回调方法,是在子线程,所以必要更新OC中的UI的话,须求切换来主线程
  4. 内存难点

    • oc中央银行使ARC情势管理内部存款和储蓄器,但JavaScriptCore中动用的是垃圾堆回收措施,在那之中全数的引用都以强援用,可是大家无需忧虑其循环援引,js的废料回收能够打破那个强援用,有个别情状供给挂念如下

    • js调起OC回调的block中拿走JSConetxt轻松循环引用

      self.jsContext[@"jsCallNative"] = ^(NSString *paramer){ // 会引起循环引用 JSValue *value1 = [JSValue valueWithNewObjectInContext: self.jsContext]; // 不会引起循环引用 JSValue *value = [JSValue valueWithNewObjectInContext: [JSContext currentContext]];};
      
    * JavaScriptCore中所有的引用都是强引用,所以在OC中需要存储JS中的值的时候,需要注意>在oc中为了打破循环引用我们采用weak的方式,不过在JavaScriptCore中我们采用内存管理辅助对象JSManagedValue的方式,它能帮助引用技术和垃圾回收这两种内存管理机制之间进行正确的转换
    
-OCCallJS{ self.context = [[JSContext alloc] init]; NSString *js = @"function add {return a b}"; [self.context evaluateScript:js]; JSValue *addJS = self.context[@"add"]; JSValue *sum = [addJS callWithArguments:@[@]]; NSInteger intSum = [sum toInt32]; NSLog(@"intSum: %zi",intSum);}

JavaScriptCore单独使用

  1. js代码如下test.js
globalObject = new Object();globalObject.name = 100;globalObject.nativeCallJS = function (parameter) { alert (parameter);};
  1. OC读取JS文件,并互相通讯
NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"js"]; NSString *jsContent = [[NSString alloc] initWithContentsOfFile:jsPath encoding:NSUTF8StringEncoding error:nil]; JSContext *jsContext = [[JSContext alloc] init]; //捕获运行js脚本的错误信息 jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"异常信息:%@", exceptionValue); }; //js脚本添加到当前的js执行环境中 [jsContext evaluateScript:jsContent]; self.jsManager = [[JSManager alloc] init]; jsContext[@"globalObject"] = self.jsManager; ... ...
  1. jS与OC的相互与经过UIWebView同样
  • JavaScript和Objective-C交互的那么些事

  • 说说JavaScriptCore

JS中调用OC有三种艺术,第一种为block调用,第二种为JSExport protocol。

案例二:大家在OC中定义了贰个之类方法,大家要求在JS中对它举办调用

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

3.1、block调用

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

3.2、JSExport protocol

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

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

-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"]; NSLog(@"%zi",self.addObj.sum);}

案例三:本地定义了一多元措施,能够通过服务端下发js脚本去决定具体去实践那个方法。那样就足以在远端完结对于顾客端的主宰。

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

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

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

在UIWebView中,我们得以在<code>- webViewDidFinishLoad:(UIWebView *)webView</code>方法中,通过KVC的方法取获得当前容器的JSContent对象,通过该对象,大家就足以实惠的进展hybrid操作。

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

案例演示:在html中科学研商OC代码中的分享成效和调用相机作用。

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

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

@interface ViewController ()<UIWebViewDelegate,WebViewJSExport>@property (nonatomic, strong) JSContext *context;@property (nonatomic, strong) UIWebView *webView;@end@implementation ViewController-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];}- 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); };}- callCamera{ NSLog;}- (NSString*)share:(NSString*)shareString{ NSLog(@"分享::::%@",shareString); return @"分享成功";}@end

诸有此类大家就足以在webView中调用我们native建立了,达成了三个简短的hybird效率。那就补充了在UIWebView达成hybird效能的点子。还应该有一种格局便是在iOS H5容器的片段研究:UIWebView和WKWebView的可比和甄选一文中见过的加载隐蔽iframe,来阻拦央浼的章程。

对于WKWebView,近期还不曾能够获得JSContent的对象的方法。

javascriptcore官方资料

JavaScriptCore 使用

iOS7新JavaScriptCore框架入门介绍

博客园腾讯网github简书首页

本文由星彩网app下载发布于计算机编程,转载请注明出处:C与Javascript交互总结,JSCore的基本使用

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。