使用stringByEvaluatingJavaScriptFromString,直接调用H5的函数名字,参数的json字符串:例如:
- (void)webViewDidFinishLoad:(UIWebView *)webView { NSMutableDictionary *dictInfo = [NSMutableDictionary dictionary]; [dictInfo setValue:@"value1" forKey:@"key1"]; [dictInfo setValue:@"value2" forKey:@"key2"]; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictInfo options:kNilOptions error:nil]; if (jsonData) { NSString *strValueJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSString *jsCode = [NSString stringWithFormat:@"picCallback&& picCallback(%@)", strValueJson]; [webView stringByEvaluatingJavaScriptFromString:jsCode]; } }window.location.href这里是改变主窗口的指向从而马上发出一个链接为Toyun://callCamera请求,而想要传给原生应用的参数也可已包含到此请求中,而在iOS方法中我们要拦截这个请求,根据请求内容去判断JavaStript想要做的事情,从而实现web页面和本地应用之间的交互
(BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType{NSString *url = request.URL.absoluteString;if ([url rangeOfString:@"toyun://"].location != NSNotFound) {
// url的协议头是Toyun NSLog(@"callCamera"); return NO;}return YES;}
注意:url后面可以拼接参数,参数的每个value要在H5里面单独转码,避免特殊符号,&=以及中文.....
H5的url上面每个value要单独进行encodeURIComponent的转码,之后再拼接成toyun://callCamera?key1=value1,比如:encodeURIComponent(value1)。
H5代码:
<!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="Toyun.callCamera()"> </div> <div style="margin-top: 100px"> <input type="button" value="share" onclick="callShare()"> </div> <script type="text/javascript"> function callShare() { var shareInfo = JSON.stringify({"title":"标题","desc":"内容","shareUrl":"http://www.jianshu.com/p/f896d73c670a"}); Toyun.share(shareInfo); } </script> <script> function picCallback(photos){ alert(photos); } </script> <script> function shareCallback(){ alert("success"); } </script> </body> </html>对H5稍作解释:先说Toyun是iOS和Android这两边在本地要注入的一个对象【参考下面iOS的代码更容易明白】,充当原生应用和web页面之间的一个桥梁。页面上定义了两个按钮名字分别为CallCamera和Share。点击CallCamera会调用Toyun最终桥梁对象的方法:callCamera()。而点击Share会先调用本文件中的javascript方法callShared(),这里将要分享的内容格式转为Json字符串格式,然后再调用Toyun最终桥梁对象的方法: (void)share:(NSString *)shareInfo方法这个是有传参的,参数为shareInfo。而下面的两个方法为原生方法调用后的回调方法,其中picCallback为获取图片成功的回调方法,并且传回拿到的图片photos;shareCallback为分享成功的回调方法。
IOS:JSContext:给JavaScript提供运行的上下文环境JSValue:JavaScript和Objective-C数据和方法的桥梁凡事添加了JSExport协议的协议,所规定的方法变量等,就会对js开放,我们可以通过JSContext调用到。
@protocol JSObjcDelegate <JSExport> - (void)callCamera; - (void)share:(NSString *)shareString; @end @interface ViewController : UIViewController <UIWebViewDelegate, JSObjcDelegate> @property (nonatomic, strong) JSContext *jsContext; @property (weak, nonatomic) IBOutlet UIWebView *webView; @end @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"]; [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:url]]; self.webView.delegate = self; } #pragma mark - UIWebViewDelegate - (void)webViewDidFinishLoad:(UIWebView *)webView { self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; self.jsContext[@"Toyun"] = self; self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"异常信息:%@", exceptionValue); }; } #pragma mark - JSObjcDelegate - (void)callCamera { NSLog(@"callCamera"); // 获取到照片之后在回调js的方法picCallback把图片传出去 JSValue *picCallback = self.jsContext[@"picCallback"]; [picCallback callWithArguments:@[@"photos"]]; } - (void)share:(NSString *)shareString { NSLog(@"share:%@", shareString); // 分享成功回调js的方法shareCallback JSValue *shareCallback = self.jsContext[@"shareCallback"]; [shareCallback callWithArguments:nil]; } @end自定义JSObjcDelegate协议,而且此协议必须遵守JSExport这个协议,自定义协议中的方法就是暴露给web页面的方法:callCamera和share方法。self.jsContext[@"Toyun"] = self;即把self赋值为名为Toyun的桥梁对象,则H5里面调用Toyun对象方法,即为此viewController处的方法。在JavaStript调用完本地应用的方法做完相对应的事情之后,又回调了JavaStript中对应的方法,从而实现了web页面和本地应用之间的通讯。