iOS与H5的交互方案:
第一种方法比较简单,通过字符串的比对。这种方式iOS端代码比较简单,网页加载完成后后台需要重新定义网页url,将移动端需要的参数拼接到url上返回,或者按照和后台约定好的字段来进行字符串比对以达到调用iOS方法的目的。
第二种方法,JSContext注入模型,JS直接用oc方法名来调用oc方法,类似于安卓.addJavascriptInterface(new JsObject(), "Android")方法,头文件需要导入#import <JavaScriptCore/JavaScriptCore.h>。
个人认为第二种方式比较好,两边可以直接进行互调。
参考文章:这里边写的已经很清楚了(http://www.jianshu.com/p/f896d73c670a/comments/1335187)。
项目中的代码:
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
//JSExport是一个协议,遵守此协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来,才能调用
@protocol JSObjcDelegate <JSExport>
//是否登录,点击收藏的时候H5调用的
- (BOOL)isLogin;
//点击活动详情H5页面的立即报名
- (void)applyAction:(BOOL)isApply;
@end
@interface JSModel : NSObject<JSObjcDelegate>
@property (nonatomic, strong) JSContext *jsContext;
@end
#import "JSModel.h"
@implementation JSModel
- (BOOL)isLogin{
NSLog(@"JS调用本地isLogin方法");
if (![LoginViewController isLogin]) {
//没登录
[LoginViewController checkLogin:^(id result) {
;
}];
//JS调用完OC方法后,执行下边的JS回调方法,并回传响应的参数
//isLoginCallback : H5那边约定的回调方法
//@[@"0"]] :回传的参数
JSValue *shareCallback = self.jsContext[@"isLoginCallback"];
[shareCallback callWithArguments:@[@"0"]];
return NO;
}else{
//登录了,直接给H5回传1
JSValue *shareCallback = self.jsContext[@"isLoginCallback"];
[shareCallback callWithArguments:@[@"1"]];
return YES;
}
}
- (void)applyAction:(BOOL)isApply{
NSLog(@"JS调用本地applyAction方法");
//如果是点击活动详情的立即报名按钮
if (![LoginViewController isLogin]) {
//没登录
[LoginViewController checkLogin:^(id result) {
;
}];
}else{
//登录了
if (isApply) {
//报名了
[JFTools showTipOnHUD:@"您已报名此活动!"];
}else{
//没报名
[JFTools callCustomerService];
}
}
}
@end
在 (void)webViewDidFinishLoad:(UIWebView *)webView 方法中加入下面的代码,即可。
//获得JavaScript提供运行的上下文环境
self.jsModel.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//LinkModel :对象名,这个和H5约定好,那边调用方法就使用这个对象
self.jsModel.jsContext[@"LinkModel"] = self.jsModel;
//异常信息
self.jsModel.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"JS交互异常信息:%@", exceptionValue);
};
大概就是这些东西了,今天有时间总结了一下,有需要的朋友可以参考一下。。。。。。
更新:2018年3月
第三种方法:使用WKWebView
lazy var webView : WKWebView = {
/// 自定义配置
var conf = WKWebViewConfiguration()
conf.userContentController = WKUserContentController()//用来做native与JavaScript的交互管理
conf.preferences.javaScriptEnabled = true
//MARK:将于H5约定好的方法名,加到子类中
//在子类中添加和移除约定的交互方法,避免内存泄露
let web = WKWebView( frame: self.view.frame,configuration:conf)
self.view.addSubview(web)
return web
}()
class NoticeWebViewController: BaseWebViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//在这里添加与web页交互的方法
//公告点击查看附件 方法
webView.configuration.userContentController.add(self as WKScriptMessageHandler, name: "JLModel")
}
override func viewWillDisappear(_ animated: Bool) {
//在这里移除与web页交互的方法,不移除的话会造成内存泄露
webView.configuration.userContentController.removeScriptMessageHandler(forName: "JLModel")
}
deinit {
printDebug(content: "控制器销毁")
}
//用于与JS交互
override func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// JLModel:是和Web约定的方法
if(message.name == "JLModel") {
printDebug(content: "JavaScript is sending a message \(message.body)")
//传过来的文件的url地址
let fileUrl = message.body as? String
let fileScanWebVC = BaseWebViewController()
fileScanWebVC.title = "附件详情"
fileScanWebVC.str_URL = fileUrl
kCurNavController?.pushViewController(fileScanWebVC, animated: true)
}
}
}