iOS 混合开发 —— OC和H5交互
纵观所有iOS与H5交互的方案,有以下几种:
第一种:有很多的app直接使用在webview的代理中通过拦截的方式与native进行交互,通常是通过拦截url scheme判断是否是我们需要拦截处理的url及其所对应的要处理的功能是什么。任意版本都支持。
第二种:iOS7之后出了JavaScriptCore.framework用于与JS交互,但是不支持iOS6,对于还需要支持iOS6的app,就不能考虑这个了。若需要了解,看最后的推荐阅读。
第三种:WebViewJavascriptBridge开源库使用,本质上,它也是通过webview的代理拦截scheme,然后注入相应的JS。
第四种:react-native,这个没玩过(与前三种不同)。
1、UIWebView 和 js 交互 【JavaScriptCore.framework】
ViewController.m:
#import "WebViewController.h" #import "WebViewModel.h" @interface WebViewController () <UIWebViewDelegate> @property (nonatomic, strong) UIWebView *webView; @property (nonatomic, strong) JSContext *jsContext; @property (nonatomic, strong) WebViewModel *model; @end @implementation WebViewController - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.webView]; [self createButtons]; // // 一个JSContext对象,就类似于Js中的window,只需要创建一次即可。 // self.jsContext = [[JSContext alloc] init]; // // // jscontext可以直接执行JS代码。 // [self.jsContext evaluateScript:@"var num = 10"]; // [self.jsContext evaluateScript:@"var squareFunc = function(value) { return value * 2 }"]; // // 计算正方形的面积 // JSValue *square = [self.jsContext evaluateScript:@"squareFunc(num)"]; // // // 也可以通过下标的方式获取到方法 // JSValue *squareFunc = self.jsContext[@"squareFunc"]; // JSValue *value = [squareFunc callWithArguments:@[@"20"]]; // NSLog(@"%@", square.toNumber); // NSLog(@"%@", value.toNumber); } - (void)createButtons { NSArray *array = @[@"ocCallJS", @"ocCallJSWithString", //@"ocCallJSWithTitle:message", //@"ocCallJSWithDictionary", //@"ocCallJSWithArray" ]; NSInteger index = 0; for (NSString *string in array) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [button setTitle:string forState:UIControlStateNormal]; [button addTarget:self action:@selector(buttonAciton:) forControlEvents:UIControlEventTouchUpInside]; button.frame = CGRectMake(kScreenWidth-300, 100+(index * 50), 280, 30); button.layer.borderColor = [UIColor redColor].CGColor; button.layer.borderWidth = 1; button.layer.cornerRadius = 3; index ++; [self.view addSubview:button]; } } - (void)buttonAciton:(UIButton *)button { if ([button.currentTitle isEqualToString:@"ocCallJS"]) { [self.model ocCallJS]; }else if ([button.currentTitle isEqualToString:@"ocCallJSWithString"]) { [self.model ocCallJSWithString:@"myocString"]; }else if ([button.currentTitle isEqualToString:@"ocCallJSWithTitle:message"]) { // [self.model ocCallJSWithString]; }else if ([button.currentTitle isEqualToString:@"ocCallJSWithDictionary"]) { [self.model ocCallJSWithDictionary:@{@"title":@"myoctitle",@"message":@"myocmessage"}]; }else if ([button.currentTitle isEqualToString:@"ocCallJSWithArray"]) { [self.model ocCallJSWithArray:@[@"myoctitle",@"myocmessage",@"30"]]; } } - (UIWebView *)webView { if (_webView == nil) { _webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"callEach" withExtension:@"html"]; [_webView loadRequest:[NSURLRequest requestWithURL:url]]; //忽略web页面与_WebView组件的大小关系如果设置为YES可以执行缩放,但是web页面加载出来的时候,就会缩小到UIWebView组件的大小 _webView.scalesPageToFit = NO; _webView.delegate = self; } return _webView; } #pragma mark - UIWebViewDelegate - (void)webViewDidFinishLoad:(UIWebView *)webView { self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; WebViewModel *model = [[WebViewModel alloc] init]; self.jsContext[@"CallEachModel"] = model; model.jsContext = self.jsContext; model.webView = self.webView; model.currentVC = self; self.model = model; self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"异常信息:%@", exceptionValue); }; } - (void)webViewDidStartLoad:(UIWebView *)webView { } @end
model.h:
#import <Foundation/Foundation.h> @protocol WebViewJSExport <JSExport> /** 遵守了 协议后 这些方法就暴露给 js 调用 **/ /** jsCallOC **/ - (void)jsCallOC; - (void)jsCallOCWithString:(NSString *)string; //js调用时候取函数名就好了 不要冒号 jsCallOCWithTitleMessage - (void)jsCallOCWithTitle:(NSString *)title message:(NSString *)msg; - (void)jsCallOCWithDictionary:(NSDictionary *)dictionary; - (void)jsCallOCWithArray:(NSArray *)array; /** ocCallJS **/ - (void)ocCallJS; - (void)ocCallJSWithString:(NSString *)string; - (void)ocCallJSWithTitle:(NSString *)title message:(NSString *)message; - (void)ocCallJSWithDictionary:(NSDictionary *)dictionary; - (void)ocCallJSWithArray:(NSArray *)array; /** callEach **/ - (void)jsCallOCAndOCCallJSWithParams:(NSDictionary *)params; - (void)ocCallJSAndJSCallOCWithParams:(NSDictionary *)params; @end @class BaseViewController; @interface WebViewModel : NSObject <WebViewJSExport> @property (nonatomic, weak) JSContext *jsContext; @property (nonatomic, weak) UIWebView *webView; @property (nonatomic, weak) BaseViewController *currentVC; @end
model.m
#import "WebViewModel.h" #import "BaseViewController.h" @implementation WebViewModel #pragma mark - jsCallOC - (void)jsCallOC { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"jsCallOC" delegate:nil cancelButtonTitle:@"I konw" otherButtonTitles:nil, nil]; [alert show]; }); } - (void)jsCallOCWithString:(NSString *)string { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:string message:nil delegate:nil cancelButtonTitle:@"I konw" otherButtonTitles:nil, nil]; [alert show]; }); } - (void)jsCallOCWithTitle:(NSString *)title message:(NSString *)msg { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"I konw" otherButtonTitles:nil, nil]; [alert show]; }); } - (void)jsCallOCWithDictionary:(NSDictionary *)dictionary { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:dictionary[@"title"] message:dictionary[@"message"] delegate:nil cancelButtonTitle:@"I konw" otherButtonTitles:nil, nil]; [alert show]; }); NSLog(@"===== %@",dictionary); } - (void)jsCallOCWithArray:(NSArray *)array { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:array[0] message:array[1] delegate:nil cancelButtonTitle:@"I konw" otherButtonTitles:nil, nil]; [alert show]; }); NSLog(@"===== %@",array); } #pragma mark - OCCallJS - (void)ocCallJS { JSValue *jsFunc = self.jsContext[@"func1"]; [jsFunc callWithArguments:nil]; } - (void)ocCallJSWithString:(NSString *)string { NSInteger arc = arc4random()%1000; JSValue *jsFunc = self.jsContext[@"func2"]; [jsFunc callWithArguments:@[@{@"title": @"change--> myoctitle", @"message": @(arc)}]]; } - (void)ocCallJSWithTitle:(NSString *)title message:(NSString *)message { } - (void)ocCallJSWithDictionary:(NSDictionary *)dictionary { } - (void)ocCallJSWithArray:(NSArray *)array { } #pragma mark - callEach - (void)jsCallOCAndOCCallJSWithParams:(NSDictionary *)params { [self.currentVC createTopView]; self.currentVC.field.text = params[@"title"]; [self.currentVC setBlock:^(NSString *string){ if (string != nil && string.length > 0) { JSValue *jsFunc = self.jsContext[@"func2"]; [jsFunc callWithArguments:@[@{@"title":@"js 调出来topView 输入填充到html:" , @"message": string}]]; } }]; } - (void)ocCallJSAndJSCallOCWithParams:(NSDictionary *)params { JSValue *jsFunc = self.jsContext[@"func3"]; [jsFunc callWithArguments:@[@{@"title": @"myoctitle", @"message": @"myocmessage"}]]; } @end
github地址: https://github.com/lc081200/H5ObjCExample