前段时间公司做的app内嵌了h5页面,其中有js与iOS原生方法交互的问题,我研究了一段时间,闲来无事,写了一个demo,以供遇到难题的小伙伴参考。
github地址 https://github.com/jie0394/HybridAppTest
废话不多说,开始贴代码,webView页面,
//
// ViewController.m
// HybridAppTest
//
// Created by 李然豪 on 2017/4/24.
// Copyright © 2017年 李然豪. All rights reserved.
//
#import "ViewController.h"
#import "SZKoclaJScontextModel.h"//这个model里面已经引用了<JavaScriptCore/JavaScriptCore.h>,所以此页面不用再重复引用
@interface ViewController ()<UIWebViewDelegate,SZKoclaJScontextModelDelegate>
@property (strong, nonatomic)UIWebView *webView;
@property (nonatomic, strong) JSContext *jsContext;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_webView];
self.view.backgroundColor = [UIColor whiteColor];
self.webView.backgroundColor = [UIColor whiteColor];
self.webView.delegate = self;
NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL];
self.webView.backgroundColor = [UIColor clearColor];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"调用js" style:UIBarButtonItemStylePlain target:self action:@selector(btnJS:)];
[self.navigationItem setRightBarButtonItem:rightItem];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
/*****************说明**************
用model的原因是防止内存泄漏
很多demo是这样写的
self.jsContext[@"web"] = self;
但是这样写会造成循环引用,导致内存泄漏
****************/
SZKoclaJScontextModel *model = [SZKoclaJScontextModel new];
self.jsContext[@"web"] = model;//js方法有别名的,将别名写到这,使用代理方法进行回调,
model.jsContext = self.jsContext;
[model setDelegate:self];
[self callCamera:self.jsContext];//js方法没有别名,使用block回调;
self.jsContext.exceptionHandler =
^(JSContext *context, JSValue *exceptionValue)
{
context.exception = exceptionValue;
NSLog(@"%@", exceptionValue);
};
}
#pragma mark js调用iOS方法
-(void)share{
NSArray *args = [JSContext currentArguments];
[_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"shareCallback()"]];//方法回调成功弹出js的alert;
NSLog(@"%@",args);
//
// SZKoclaJScontextModel.h
// JS_OC_JavaScriptCore
//
// Created by 李然豪 on 17/4/7.
// Copyright © 2017年 李然豪. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol JSExportDelegate <JSExport>
//-(void)scanClick;
//
//-(void)payClick;
-(void)share;
@end
@protocol SZKoclaJScontextModelDelegate <NSObject>
//-(void)scanClick;
//
//-(void)payClick;
-(void)share;
@end
@interface SZKoclaJScontextModel : NSObject<JSExportDelegate>
@property (strong, nonatomic)JSContext *jsContext;
@property (weak, nonatomic)id<SZKoclaJScontextModelDelegate>delegate;
@end
}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}#pragma mark iOS调用js方法-(void)btnJS:(id)sender{ [_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"callCamera()"]];//弹出js的alert; NSString *result = [_webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"callBack(%@,%@)",@"123",@"456"]]; NSLog(@"%@",result); }-(void)callCamera:(JSContext *)context{ context[@"callCamera"]=^() {// NSArray *args = [JSContext currentArguments];//如果有参数,使用这种方法获取参数; NSLog(@"callCamera"); };}@end 接下来就是model的页面了
.h页面
//
// SZKoclaJScontextModel.h
// JS_OC_JavaScriptCore
//
// Created by 李然豪 on 17/4/7.
// Copyright © 2017年 李然豪. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol JSExportDelegate <JSExport>
//-(void)scanClick;
//
//-(void)payClick;
-(void)share;
@end
@protocol SZKoclaJScontextModelDelegate <NSObject>
//-(void)scanClick;
//
//-(void)payClick;
-(void)share;
@end
@interface SZKoclaJScontextModel : NSObject<JSExportDelegate>
@property (strong, nonatomic)JSContext *jsContext;
@property (weak, nonatomic)id<SZKoclaJScontextModelDelegate>delegate;
@end
.m文件
//
// SZKoclaJScontextModel.m
// JS_OC_JavaScriptCore
//
// Created by 李然豪 on 17/4/7.
// Copyright © 2017年 李然豪. All rights reserved.
//
#import "SZKoclaJScontextModel.h"
@implementation SZKoclaJScontextModel
//-(void)scanClick{
// if ([self.delegate respondsToSelector:@selector(scanClick)]) {
// [self.delegate scanClick];
// }
//}
//
//-(void)payClick{
// if ([self.delegate respondsToSelector:@selector(payClick)]) {
// [self.delegate payClick];
// }
//}
-(void)share{
if ([self.delegate respondsToSelector:@selector(share)]) {
[self.delegate share];
}
}
@end
index.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div style="margin-top: 100px">
<h1>Objective-C和JavaScript交互的那些事</h1>
<input type="button" value="CallCamera" onclick="callCamera()">
</div>
<div>
<input type="button" value="Share" onclick="callShare()">
</div>
<script>
var callShare = function() {
web.share("123","123");
}
var shareCallback = function(){
alert('share回调success');
}
function callCamera(){
alert('callCamera调用success');
}
function callBack(s1,s2){
return s1+s2;
}
</script>
</body>
</html>
混合并不是太复杂,理解了原理就比较好用了