本文介绍了在原生iOS项目中集成Vue编写的商城项目,并实现了Vue与原生iOS之间的交互。具体分为UIWebView和WKWebView两种方式。UIWebView通过JavaScriptCore框架实现Vue调用OC方法,并解决了内存泄漏问题。WKWebView则通过WKScriptMessageHandler协议实现Vue与OC的交互。同时,文章还说明了Vue方法如何暴露给原生iOS调用,并给出了登录回调的示例代码。
用vue写的商城项目需要集成在原生的移动端项目中,并且登录,分享和支付都是调用原来项目的页面和方法,这就需要原生webView与Vue的交互,下面分别用UIWebView和WKWebView来实现与Vue的交互。
一.UIWebView与Vue的交互
Vue调用OC的方法
iOS控制器.h文件引入<JavaScriptCore/JavaScriptCore.h>,并声明JSContext类的属性
#import <JavaScriptCore/JavaScriptCore.h>
@protocol JSObjcDelegate <JSExport>
-(void)call:(NSString*)payStr payType:(NSString*)payType;//支付
-(void)backPage;//返回原生t页面
-(void)gotoLogin;//去登录
-(void)gotoShare:(NSString*)prodectInfo;//分享
@end
@interface MallViewController : SMBaseViewController<UIWebViewDelegate,JSObjcDelegate>
@property(strong,nonatomic)UIWebView*resultwebV;
@property(nonatomic,strong)JSContext*JScontext;
@end
2.在控制器.m文件中 UIWebViewDelegate的代理方法里面用context属性声明一个方法供js调用
- (void)viewDidLoad
{
self.resultwebV = [[UIWebView alloc]initWithFrame:CGRectMake(0, -20, kScreenWidth, kScreenHeight+20)];
self.resultwebV.delegate = self;
self.resultwebV.scrollView.bounces = NO;
NSString *textAccount = USERMODEL.code;
NSString*isLogin;
if(USERMODEL.isLogin){
isLogin = @"ture";
}else{
isLogin = @"false";
}
[self.resultwebV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.0.120:8081/#/? userCode=%@&isLogin=%@&fm=%@",textAccount,isLogin,@"fromApp"]]]];
[self.view addSubview:self.resultwebV];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
[IHUtility removeWaitingView];
_JScontext = [self.resultwebV valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.JScontext[@"tianbai"] = self;
self.JScontext.exceptionHandler = ^(JSContext *context, JSValue *ex){
context.exception = ex;
NSLog(@"异常信息%@",ex);
};
}
documentView.webView.mainFrame.javaScriptContext 是为了获取JSContext的路径。
tianbai 是和web前端约定好的JS和oc桥接的桥梁对象,通过将这个桥梁对象注入iOS端的webView,JS前端就可以通过这个桥梁对象去调用原生应用的方法。
self.JScontext[@"tianbai"] = self 这样JSContext环境引用控制器self,在退出控制器的时候,因为控制器self被JSContext引用而不释放,而JSContext只有等控制器释放了才能随之释放,所以就引起了循环引用,造成内存泄露。
解决泄漏方法:
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
if (self.JScontext) {
self.JScontext[@"tianbai"] = nil;
}
}
3. 在vue中methods:方法中调用原生支付方法
iOS调用Vue方法
1.Vue的方法给原生调用,则需要把方法挂在window下面,在Vue的mounted方法中引入如图:
2. 在methods方法中具体实现登录后回调
// 登录返回 loginBack: function (data) { var _this = this localStorage.setItem('account', data) this.getLoginToken(data).then(function (token) { _this.getUserAdress() }) }
3.在iOS中写这些代码:
NSString *account = notification.object[@"account"]; JSValue *callBack = self.JScontext[@"loginBack"]; [callBack callWithArguments:@[account]];
二.WKWebView与Vue交互
Vue调用OC的方法
1.在控制器.h文件中
#import <WebKit/WebKit.h> @interface MallViewController : SMBaseViewController<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler>@ property(nonatomic,strong) WKWebView * webView; @property(nonatomic,weak) MBProgressHUD*hud; @end
2.在控制器.m文件
WKWebView*webV=[[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:configuration];
[self.view addSubview:webV];
_resultwebV=webV;
webV.UIDelegate=self;
webV.navigationDelegate=self;
NSString *textAccount = USERMODEL.code;
NSString*isLogin;
if(USERMODEL.isLogin){
isLogin = @"ture";
}else{
isLogin = @"false";
}
[_resultwebV loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://192.168.0.120:8081/#/? userCode=%@&isLogin=%@&fm=%@",textAccount,isLogin,@"fromApp"]]]];
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [WKUserContentController new];
[configuration.userContentController addScriptMessageHandler:self name:@"tianbai"];
3.在WKScriptMessageHandler协议的代理方法里面根据message.name来判断js是否调用并作出相关的处理,message.body即为js传过来的参数
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
NSLog(@"%@", message.body);
NSLog(@"%@", message.name);
NSDictionary * body = [message.body objectForKey:@"body"];
if ([message.name isEqualToString:@"tianbai"]) {
//执行
}
}
4. 在vue中methods:方法中调用原生支付方法并传值
iOS调用Vue方法
1. Vue的方法给原生调用,则需要把方法挂在window下面,在Vue的mounted方法中引入如图:
2. 在methods方法中具体实现登录后回调
// 登录返回 loginBack: function (data) { var _this = this localStorage.setItem('account', data) this.getLoginToken(data).then(function (token) { _this.getUserAdress() }) }
3.在iOS中写这些代码:
NSString *account = notification.object[@"account"];
NSString *login = [NSString stringWithFormat:@"loginBack(%@)",account];
[_resultwebV evaluatejsStr completionHandler:^(id _Nullable d, NSError * _Nullable error) {
NSLog(@"%@",d);
NSLog(@"%@",error);
}];
Vue与原生的交互就这样实现了,如果又不懂的地方可以评论提出!
文章独发金蝶云社区
推荐阅读