HyBird混合开发的几个注意的地方

做混合开发APP的时候,我们的方案是内置了H5相关的dist包,以本地文件的方式用WebView进行加载。
期间遇到了Webview的安全相关的几个坑点。
1. JS同源策略与跨域访问
   同源策略是浏览器上为安全性考虑实施的非常重要的安全策略。
   何谓同源:
        URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
   同源策略:
        浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性。
        从一个域上加载的脚本不允许访问另外一个域的文档属性。
    由于我们的H5是本地加载的,Ajax要访问远程的服务端接口提供功能,那么属于跨域请求了。那么需要对WebView进行设置。
    Android:
         WebSettings settings =  webView.getSettings();
            settings.setAllowFileAccessFromFileURLs(true);
        settings.setAllowUniversalAccessFromFileURLs(true);
    iOS:
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        config.preferences = [[WKPreferences alloc] init];
        [config.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
        if(@available(iOS 10.0, *)){
            [config setValue:@YES forKey:@"allowUniversalAccessFromFileURLs"];
        }
     这样设置加上的话,就能够跨域访问远程服务端的API了。
2. Cookie的期限与自动登陆。
   虽然是混合开发的,但首先是个APP,它要有自动登陆功能。某段期限内,下次启动的时候,需要能自动登陆。我们是使用
   Cookie实现的。当账号密码登陆完成的时候,COOKIE需要保存到文件里并加密。
   这个我们直接提供了原生的接口来操作读、写与删除。并且,启动的时候,需要将COOKIE设置到Webview里。这样,Ajax
   访问远程服务的时候,就自动带上了。
   关于设置COOKIE到浏览器。
   Android:
             CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.removeSessionCookies(null);
            if (cookieVal.length() > 0) {
                String cookieStr = cookieName+"="+cookieVal+";path="+path+";max-age="+maxAge;
                Logger.log("[Trace@JSBridge] cookieStr = "+cookieStr);
                cookieManager.setCookie(url, cookieStr);
            }
            cookieManager.flush();
   iOS:
           if(@available(iOS 11.0, *)){
                WKHTTPCookieStore *cookieStorage = weakSelf.webView.configuration.websiteDataStore.httpCookieStore;
                [cookieStorage setCookie:cookie completionHandler:^{
                    NSLog(@"[Trace@setcookie] set cookies success, cookieName=%@,cookieValue=%@",cookieName,cookieVal);
                    successCallBack(@{@"code":@(0)});
                }];
            }else{
                   //iOS11以下,无法设置,采用其它的一些方案, 网上搜的。
            }            
 3.  JS-Native接口的回调
     H5需要调用原生提供功能。于是提供了bridge.js这样一个文件给前端调用。有的直接调用就同步返回了,有的是异步的,比如调用
     系统相册、拍照、定位等。
     那么就需要提供带回调的JS接口出来,也就是调用方提供一个function为参数,在合适的时候,原生再调回来。
     但是Webview没有提供这样的功能,需要做个转换:传递的是一个js的函数名,然后通过原生调用JS的接口再调回来。
     Android:
         webView.loadUrl("javascript:"+cbName+"('"+errStr+"','{\"result\":"+rspStr+"}')");
     iOS:
        NSString *jsStr = [NSString stringWithFormat:@"%@('%@','%@')",cbName,params[0],params[1]];
        [self.webview evaluateJavaScript:jsStr completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            if(error){
                NSLog(@"[Trace@JSBridge] Exception==>%@\r\n",error);
            }
        }];
     bridge.js:
        var cbName = 'CB_' + Date.now() + '_' + Math.ceil(Math.random() * 10);
        win[cbName] = function(err, result) {
             webBridge.trace("after call router==>"+result);
             var resultObj = null;
             var code = 0;
             if (typeof(result) !== 'undefined' && result !== 'null' && result !== null) {
                 resultObj = JSON.parse(result)['result'];
             }else{
              code = -1;
             }
             callback(code, resultObj);
             delete win[cbName];
      };
      if (isAndroid()) {
          win.bridge.callRouter(JSON.stringify(req), cbName);
      }else{
          win.webkit.messageHandlers.callRouter.postMessage({"cbName":cbName,"reqStr":JSON.stringify(req)});
      }      
4. Webview第一次启动优化
    第一次启动的时候,Webview加载那叫一个慢吞吞的,体验极差。为了优化,几乎试验了各种办法。最后
    有个总结:
    1)。启动页延时。启动页面最好做成View,挂在Webview上面。当Webview加载了首页之后,等待一下,再移除启动页。
    2)。首页要做成轻量级的,这样加载起来快,最好跟后面混合的东西分离开来,一般Vue做的东西是个整体,一起加载很慢。
    3)。其它根据每个移动平台自身的特点做了一些优化,比如Android的WebView缓存等。

你可能感兴趣的:(HyBird混合开发的几个注意的地方)