iOS中JS 与OC的交互(JavaScriptCore.framework)
iOS中实现js与oc的交互,目前网上也有不少流行的开源解决方案;
如:react native
当然一些轻量级的任务使用系统提供的UIWebView 以及JavaScriptCore.framework 里面提供的api就能快速满足的。
方式一:iOS6上使用UIWebView 拦截url方式
以下是演示的js和oc端的代码
<html> <head><title>JAAndOC1</title></head> <script> function sdkhi() { alert("hello world!"); } function sdkhito(name) { alert("hello to "+name); } </script> <body> <h1>hello world</h1> <h1>hello world</h1> <h1>hello world</h1> <h1>hello world</h1> <h1><a href="TCSDK://START?name=cc&age=18&phone=10086">START</a></h1> <h1><a href="javascript:sdkhi()">SDKHI</a></h1> </body> </html>
@interface ViewController ()<UIWebViewDelegate> { UIWebView *theWeb; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; theWeb = [[UIWebView alloc]initWithFrame:self.view.bounds]; theWeb.scalesPageToFit = YES; theWeb.delegate = self; [self.view addSubview:theWeb]; //本示例方法适用于iOS 6 + NSURL *reqUrl = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"js1.html" ofType:nil]]; [theWeb loadRequest:[NSURLRequest requestWithURL:reqUrl]]; UIButton *clickBtn = [UIButton buttonWithType:UIButtonTypeCustom]; clickBtn.frame = CGRectMake(100, 100, 100, 100); [clickBtn setTitle:@"clisk" forState:0]; [clickBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [self.view addSubview:clickBtn]; [clickBtn addTarget:self action:@selector(clickToCloseAlert) forControlEvents:UIControlEventTouchUpInside]; } //OC调JS 并传参数 - (void)clickToCloseAlert { //在弹出的alert中可能会有来自 xxx.html 字样 (百度去掉) [theWeb stringByEvaluatingJavaScriptFromString:@"sdkhito('cc')"]; } //JS 调 OC 并传参数 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { //访问如下自定义协议连接 //request.URL tcsdk://START?name=cc&age=18&phone=10086 //request.URL.scheme tcsdk 取出协议 //request.URL.host START 取出host //request.URL.query name=cc&age=18&phone=10086 取出参数 NSLog(@"%@",request.URL); NSLog(@"%@",request.URL.scheme); return YES; }
1. OC 调用js代码主要通过如下接口
[theWeb stringByEvaluatingJavaScriptFromString:@"sdkhito('cc')"];
流程:iOS的UIWebView 加载 包含js的网页;在js中定义好函数接口;
然后在oc上就可以通过上面接口直接调用的;
2. JS 调用OC 主要通过UIWebView的代理方法shouldStartLoadWithRequest 拦截URL
//JS 调 OC 并传参数
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//访问如下自定义协议连接
//request.URL tcsdk://START?name=cc&age=18&phone=10086
//request.URL.scheme tcsdk 取出协议
//request.URL.host START 取出host
//request.URL.query name=cc&age=18&phone=10086 取出参数
NSLog(@"%@",request.URL);
NSLog(@"%@",request.URL.scheme);
return YES;
}
流程:iOS UIWebView 加载包含js的网页;在网页中用<a> 标签名其他跳转方式改变url的操作;
然后在代理中通过拆分url的结构,分别取出协议,host,参数等;来达到js调用oc方法的的目的。
问题:通过url传参有限制
方式二:iOS7之后使用 JavaScriptCore.framework
该框架提供完整的js运行环境,在处理oc与js的交互中非常的方法;
如下测试代码
<html> <head><title>JAAndOC2</title></head> <script> //以下方法由oc 调用 js function sdkhi3TO(name) { alert("hello world2!"+name); } function sdkhi2() { alert("hello world2!"); } function sdkhito(name) { alert("hello to "+name); } </script> <body> <h1>hello world</h1> <h1>hello world</h1> <h1>hello world</h1> <h1>hello world</h1> <h1><a href="TCSDK://START?name=cc&age=18&phone=10086">START</a></h1> <h1><a href="javascript:sdkhi2()">SDKHI</a></h1> <!-- 以下由js 调用oc 的方法 --> <h1><a href="javascript:ocsayhi('abc')">OCHI</a></h1> <h1><a href="javascript:alert(pl.fullyName())">OCHI</a></h1> </body> </html>
#import "ViewController.h" #import <JavaScriptCore/JavaScriptCore.h> #import "Person.h" @interface ViewController ()<UIWebViewDelegate> { UIWebView *theWeb; JSContext *jsCXT; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //以下使用javascriptcore.framewordk //适用于iOS7.0 theWeb = [[UIWebView alloc]initWithFrame:self.view.bounds]; theWeb.scalesPageToFit = YES; theWeb.delegate = self; [self.view addSubview:theWeb]; NSURL *reqUrl = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"js2.html" ofType:nil]]; [theWeb loadRequest:[NSURLRequest requestWithURL:reqUrl]]; } - (void)webViewDidFinishLoad:(UIWebView *)webView { //使用webview的js执行环境 jsCXT = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; //异常处理 jsCXT.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"%@", exceptionValue); }; //OC 调用JS //[jsCXT[@"sdkhi2"] callWithArguments:nil]; //sdkhito //[jsCXT[@"sdkhito"] callWithArguments:@[@"aa"]]; //注册一个方法由js调用 jsCXT[@"ocsayhi"] = ^(NSString *name) { NSLog(@"say hi to %@",name); }; Person *pp = [[Person alloc]init]; pp.firstName = @"cc"; pp.lastName = @"j"; pp.site = @"baidu.com"; jsCXT[@"pl"] = pp; [jsCXT evaluateScript:@"alert(pl.fullyName())"]; }
#import <Foundation/Foundation.h> #import <JavaScriptCore/JavaScriptCore.h> @protocol PersonPtl <JSExport> @property (nonatomic,copy)NSString *site; /** 对于多参数的方法,JavaScriptCore的转换方式将Objective-C的方法每个部分都合并在一起,冒号后的字母变为大写并移除冒号。比如下边协议中的方法,在JavaScript调用就是:doFooWithBar(foo, bar); **/ - (NSString *)fullyName; @end @interface Person : NSObject<PersonPtl> @property (nonatomic, copy) NSString *firstName; @property (nonatomic, copy) NSString *lastName; @end
#import "Person.h" @implementation Person @synthesize site; - (NSString *)fullyName { return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; } @end
1. OC调用js
流程我们创建UIWebView 在 代理中获取当前页面的js环境;就是JSContext
jsCXT = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
然后在网页js中定义的方法,在这里我们就可以直接调用了;
//OC 调用JS
[jsCXT[@"sdkhi2"] callWithArguments:nil];
[jsCXT[@"sdkhito"] callWithArguments:@[@"aa"]];
2. JS 调用 OC
这里有两个方式,我们可以通过block的方法在oc里为js 注入一下方法,让js调用
//注册一个方法由js调用
jsCXT[@"ocsayhi"] = ^(NSString *name) {
NSLog(@"say hi to %@",name);
};
另外一个方法,稍麻烦一点,我们需要先声明协议,然后实现协议方法;通过JSExport 来暴露给JS环境调用
如上面的代码中的Person类;
调用方式:
Person *pp = [[Person alloc]init];
pp.firstName = @"cc";
pp.lastName = @"j";
pp.site = @"baidu.com";
jsCXT[@"pl"] = pp;
//以下是在当前jscxt中执行代码,当然网页js中也可以直接写
[jsCXT evaluateScript:@"alert(pl.fullyName())"];
最后完整示例工程:
https://github.com/cocoajin/TDDDemo/tree/master/JSAndOC
参考:http://www.skyfox.org/ios-wkwebview-cookie-opration.html
相关文章
- 史上最全的 iOS测试工具集锦(自动化、性能)
- iOS常用数学方法
- ios开发者证书 签发者无效
- iOS 打包静态类库 lib.a
- Vue - 实现用 JS 调用自定义组件 / 类似 ElementUI 弹框组件(在 js 文件中通过 this.xxx 方式调用并显示自定义弹框模态框组件)
- Vue - 在纯 JS 文件中调用自定义组件 / 类似 ElementUI 弹框组件 Message、Modal(在纯 js 文件中通过 import 方式引入并调用弹框模态框组件显示出来,)
- HBuilder打包iOS教程
- iOS Simulator功能介绍关于Xamarin IOS开发
- 《iOS应用开发》——2.4节重要的设计模式
- iOS CoreData (二) 版本升级和数据库迁移
- iOS-个人开发者账号转公司开发者账号(邓白氏码申请教程)
- iOS 8 自适应 Cell
- iOS - OC 与 JS 交互六种方式总结
- ios GUI系统综述:iOS的图形绘制、动画与runloop
- iOS--App功耗优化
- iOS开发UI篇—ios应用数据存储方式(归档)
- Delphi xe7 FireMonkey / Mobile (Android, iOS)生成 QR Code完整实例
- JS模板引擎handlebars.js的简单使用
- iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载
- iOS 多媒体编程(一)——音频(AudioServices、AVAudioPlayer)