iOS H5免登录,同步APP登录状态,OC和JS交互

需求分析

APP某个页面嵌入H5页面,当前H5页面拥有登录状态。在此以前,用户进入本页面,即便用户在登录状态,依然显示未登录,因此须要把APP的登录状态传给H5,达到免登录目的。html

下面的截图是咱们APP的活动页面前端

截图

目前JS与OC相互调用的方式

目前主要的JS与OC相互调用方式主要有以下6种:web

  1. 在JS 中作一次URL跳转,而后在OC中拦截跳转。(这里分为UIWebView 和 WKWebView两种,UIWebView兼容iOS 6)
  2. 利用WKWebView 的MessageHandler。
  3. 利用系统库JavaScriptCore,来作相互调用。(iOS 7推出)
  4. 利用第三方库WebViewJavascriptBridge。
  5. 利用第三方cordova库,之前叫PhoneGap。(这是一个库平台的库)
  6. 当下盛行的React Native。

初步考虑,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同步登录需求啦!

相关文章
相关标签/搜索