APP某个页面嵌入H5页面,当前H5页面拥有登录状态。在此以前,用户进入本页面,即便用户在登录状态,依然显示未登录,因此须要把APP的登录状态传给H5,达到免登录目的。html
下面的截图是咱们APP的活动页面前端
目前主要的JS与OC相互调用方式主要有以下6种:web
初步考虑,App兼容iOS7选择JavaScriptCore方式,App只兼容iOS8以上,能够采用WKWebView,并使用MessageHandler方式。后端
由于咱们前端H5采用的是把登录状态token存放在session Storage里面,采用第二种方式是最简洁方便的。可能有些前端是从URL传登录状态值的,那这种方式就更简单了,只要把请求URL拼接上APP登录token(以上两种状况须要后端把APP和H5端登录信息作统一接口才能最终达到目的。)bash
好了废话很少说,上代码session
先建立webview而后进行偏好设置configurationide
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColorFromRGB(0xf3f6f6);
//添加登录通知,防止APP端未登录状态,在后面的代理对h5登录作拦截处理,回调原生APP的登录方式,
//而后经过通知方式来重载本页面
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(uerislogin) name:@"userIsLogin" object:nil];
JMUserInfoModel *userInfo = [JMLoginManager getInfo];//这是个人本地登录信息
//进行偏好设置,把token传到session里面去。
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];
_userContent = [[WKUserContentController alloc] init];
//关键的地方来了,这一步是对session添加token信息,就算目前APP未登录状态,传入空字符串也是不要紧,
//后面通知重载页面会从新注入信息。
NSString * js = [NSString stringWithFormat:@"window.sessionStorage.setItem('token','%@')",userInfo.user_token];
WKUserScript * userScript = [[WKUserScript alloc]initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[_userContent addUserScript:userScript];
configuration.userContentController = _userContent;
//注意要在建立webview的时候就要把偏好设置给初始化configuration
_webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, DEVICE_WIDTH, DEVICE_HEIGHT- JMHeightGap) configuration:configuration];
_webView.backgroundColor = [UIColor whiteColor];
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
[_webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL]; //添加观察者模式 更换标题
NSString *url = [NSString stringWithFormat:@"https://www.jumifinance.com/h5/views/wheel/wheel.html"];
NSURL *weburl =[[NSURL alloc] initWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:weburl];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
复制代码
在代理里面对H5页面的登录按钮进行拦截url
#pragma mark - UIWebViewDelegate
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSString *url = [navigationAction.request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"请求拦截===== %@",url);
//对请求url进行字符串匹配,若是请求连接里有登录请求,进行拦截
if ([url rangeOfString:@"common/login.html"].location != NSNotFound) {
//UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式一" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];
//[alertView show];
//调用原生登录接口
[[JMLoginManager shareLogin] loginAction];
decisionHandler(WKNavigationActionPolicyCancel);
}else
{
decisionHandler(WKNavigationActionPolicyAllow);
}
}
复制代码
下面代码是修改title的kvo,不须要的能够忽略spa
/**
获取H5页面 当前页面的标题
@param keyPath key
@param object 对象
@param change 。。
@param context 内容
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"title"])
{
if (object == self.webView) {
self.title = self.webView.title;
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
复制代码
而后是通知的回调代理
-(void)uerislogin
{
JMUserInfoModel *userInfo = [JMLoginManager getInfo];
NSString * js = [NSString stringWithFormat:@"window.sessionStorage.setItem('token','%@')",userInfo.user_token];
WKUserScript * userScript = [[WKUserScript alloc]initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[_userContent addUserScript:userScript];
[self.webView reload];
}
复制代码
最后记得在dealloc里面进行销毁通知和KVO
-(void)dealloc
{
[_webView removeObserver:self forKeyPath:@"title"];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
复制代码
到这里已经实现了完美的APP H5同步登录需求啦!