1.UIWebview的js交互
iOS7之后苹果推出了JavaScriptCore这个框架,从而让web页面和本地原生应用交互起来非常方便,而且使用此框架可以做到Android那边和iOS相对统一,web前端写一套代码就可以适配客户端的两个平台,从而减少了web前端的工作量。
JavaScriptCore有如下几个类
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"
1>JSContext代表一个JavaScript的执行环境的一个实例。
创建方法
JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
2>JSValue的主要作用就是用来接收JSContext执行后的返回结果
<script type="text/javascript">
var myObject = "myObject";
</script>
JSValue *myObject = self.context[@"myObject"];
NSLog(@"%@",[myObject toString]);
3>JSManagedValue JS和OC对象的内存管理辅助对象。由于JS内存管理是垃圾回收,并且JS中的对象都是强引用,而OC是引用计数。如果双方相互引用,势必会造成循环引用,而导致内存泄露。我们可以用JSManagedValue保存JSValue来避免。
4>JSVirtualMachine JS运行的虚拟机,有独立的堆空间和垃圾回收机制。
5>JSExport 一个协议,如果JS对象想直接调用OC对象里面的方法和属性,那么这个OC对象只要实现这个JSExport协议就可以了。
iOS调用js方法
#pragma mark js代码
// 有参数
function numAddMethod(num1,num2){
alert(num1 + num2);
return num1 + num2;
}
// 无参数
function numAddMethod2(){
alert('调用numAddMethod2');
}
#pragma mark iOS方法
- (void)iOSMethod{
//创建上下文
JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//调用有参数的js方法
JSValue *value = [context[@"numAddMethod"] callWithArguments:@[@(5),@(6)]];
//调用无参数的js方法
JSValue *value2 = [context[@"numAddMethod2"] callWithArguments:@[]];
NSLog(@"有参数返回值=%d === 无参数返回值",value.toInt32,value2.toInt32);
//打印结果,有参数返回值=11===无参数返回值0
}
js调用iOS方法
#pragma mark js代码
<head>
<script type = "text/javascript">
function viewClicked(){
share('1','2','3');
}
</script>
</head>
<body>
<button type="button" onclick="viewClicked()">Click Me!</button>
</body>
#pragma mark iOS代码
-(void)viewDidLoad{
[super viewDidLoad];
JSContext *context = [self.myWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"share"] = ^(){
NSArray *args = [JSContext currentArguments];
for (JSValue *jsValue in args) {
NSLog(@"%@",jsValue.toString);
}
};
//arguments保存js传入的参数,打印结果为1,2,3.
}
WKWebView的js交互
首先来一段代码,来创建一个WKWebView
@interface WKWebViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) WKUserContentController *userContent;
@end
@implementation WKWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
self.userContent = [[WKUserContentController alloc] init];
[self.userContent addScriptMessageHandler:self name:@"ocMethod"];
config.userContentController = self.userContent;
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
self.webView.UIDelegate = self;
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
特别关注WKUserContentController的addScriptMessageHandler:name:方法
/*! @abstract Adds a script message handler.
//添加一个js要调用的方法
@param scriptMessageHandler The message handler to add.
//添加消息处理界面
@param name The name of the message handler.
//js要执行的方法名称
@discussion Adding a scriptMessageHandler adds a function
window.webkit.messageHandlers.<name>.postMessage(<messageBody>) for all
frames.
//需要js执行的方法规则
//window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
*/
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
这个方法可能会引起内存泄漏,解决方法百度上有很多,这里不做说明。
1>iOS原生方法调用js方法
#pragram mark -- js代码
function jsMethod(obj){
return obj;
}
#pragram mark -- iOS代码
- (void)iOSMethod{
NSDictionary *dict = @{@"key1":@"value1",@"key2":@"value2"};
NSData *dictData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSString *dictStr = [[NSString alloc] initWithData:dictData encoding:NSUTF8StringEncoding];
NSString *jsStr = [NSString stringWithFormat:@"jsMethod(%@)",dictStr];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"return == %@",result);
}];
//iOS给js传入多个参数可以通过转成字符串的方法传给js
//打印结果为@{@"key1":@"value1",@"key2":@"value2"},说明js方法返回值都在result里面
}
2>js调用iOS原生方法
#pragram mark -- js代码
<head>
<script type = "text/javascript">
function viewClicked(){
//固定写法,方法名为iOS原生要执行的方法(这里的方法名为ocMethod,上面已经注册过),参数放在()中
window.webkit.messageHandlers.ocMethod.postMessage({'key':'value'});
}
</script>
</head>
<body>
<button type="button" onclick="viewClicked()">Click Me!</button>
</body>
#pragram mark -- iOS代码
#pragram mark -- WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSString *messageName = message.name;
if ([@"ocMethod" isEqualToString:messageName]) {
id messageBody = message.body;
NSLog(@"%@",messageBody);
//当js调用ocMethod时,就可以来到这里,然后就可以在这里写iOS原生代码了,js所传的参数都在message.body里面了
}
}