我的原创地址:https://www.jianshu.com/p/1ad536e76640css
1.需求与使用场景
打开一个新页面,要求可以加载本地zip格式的h5应用,该应用使用了某些原生能力;可以加载远程应用,该应用也使用了部分原生能力;可以在多个h5应用时一样适用;h5应用可以移植到其它场景,如web、第三方移动应用;h5应用无需复杂适配移动端,如android、iOS等;
2.目的
让h5应用只专一于开发h5,涉及到原生功能,则交给原生应用去实现,经过cordova js功能进行h5与原生功能的交互。
3.前提
须要3个应用,以下所示 html
对以上3个应用的解读:前端
4. 原生部分vue
h5应用部分省略不表,原生部分以iOS为例
4.1 如何建立cordova项目node
在mac上,安装node,再在terminal中npm install -g cordova@lastest;react
4.2 因为UIWebView有缺陷以及再也不维护,而且官方推荐使用WKWebView,因此以WKWebView为例,进行config.xml的修改以及cordova-plugin-wkwebview-engine的简单使用的讲解
4.2.1 config.xml的修改android
1. 容许远程网页加载 ATSios
<content src="index.html" />是本地加载的入口,也可设置远程地址 <allow-navigation href="https://*/*" /> <allow-navigation href="http://*/*" /> <allow-navigation href="data:*" />
以上三行等价于nginx
<allow-navigation href="*" /> 容许全部的网址跳转。
2. 白名单设置web
<access origin="*" /> 设置白名单,容许访问全部域 <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <allow-intent href="*" /> 等价于以上两行
3. 偏好设置
<preference name="StatusBarStyle" value="lightcontent" /> //设置状态栏颜色
4. feature功能引入,以便cordova.js识别
<feature name="Camera"> <param name="ios-package" value="CDVCamera" /> </feature>
添加后,cordova.exec才能够正确找到对应的原生文件,调用方式如`cordova.exec(success, failed, 'Camera', 'getPicker',[参数])`
5. 插件添加
<plugin name="cordova-plugin-wkwebview-engine" spec="^1.2.0" /> <plugin name="cordova-plugin-camera" spec="^4.1.0" /> <plugin name="cordova-plugin-device" spec="^2.0.3" />
指定添加的插件和版本号
6. 在info.plist文件添加私有权限
某些插件和功能须要开启相关的权限才可以使用,所以必须手动开启权限
4.2.2 wkwebviewengine的简单使用
先决条件:
1. 简单的本地加载
cordova加载本地本身的h5应用,须要在HtmlViewController初始化init的地方修改startPage,必定要在viewDidLoad以前;
缘由在于CDVViewController源码会在viewDidLoad的地方调用了与网页相关的三个方法:
`- loadSetting`、`- createGapView`、`- appUrl`,并设置了默认appUrl;
适用场景:
在应用内下载了zip格式的h5应用后,将其保存并解压,再将工程目录下的www文件夹copy到应用程序内,并将h5应用替换(不是合并)对应文件,如替换www/index.html,即将www/cordova_plugins.js、www/cordova-js-src、www/cordova.js、www/plugins copy到h5应用下。
2. 加载远程应用
uiwebview:只须要设置下 self.startPage为远程地址便可;
须要注意的地方:
<allow-navigation href="https://*/*" /> <allow-navigation href="http://*/*" />
wkwebviewengine貌似则不能这样,我试了几回均不行,因此采用了如下方法:
#import <Cordova/CDVViewController.h> #import <Cordova/CDVCommandDelegateImpl.h> @interface HtmlViewController : CDVViewController @end @interface CustomWKCommandDelegate: CDVCommandDelegateImpl // 核心指令 @end @interface CustomCmdQueue : CDVCommandQueue @end
HtmlViewController.m修改添加内容
#import <WebKit/WebKit.h> @interface HtmlViewController ()<WKNavigationDelegate> @end @implementation CustomWKWebViewController - (id)init { self = [super init]; if (self) { // 重写CDVCommandDelegate,加载wkwebview的代理 _commandDelegate = [[CustomWKCommandDelegate alloc] initWithViewController:self]; _commandQueue = [[CustomCmdQueue alloc] initWithViewController:self]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // 因为支持滑动返回,导航栏能够隐藏了 [self.navigationController setNavigationBarHidden:YES animated:NO]; // 使用驱动器加载 [self.webViewEngine loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:20]]; } // 处理跨域等状况建议使用nginx - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { // 不能跨域的进行单独处理 NSURL *url = navigationAction.request.URL; if ([url.scheme isEqualToString:@"域名"]) { //在取消跨域请求以前,自定义处理,如使用safari浏览器打开网页,若带参数,则将其进行拼接 NSDictionary *param = nil; if (@available(iOS 10.0, *)) { [[UIApplication sharedApplication] openURL:url options:param completionHandler:^(BOOL success) { }]; } else { // Fallback on earlier versions [[UIApplication sharedApplication] openURL:url]; } decisionHandler(WKNavigationActionPolicyCancel);// web view取消本次 } else { decisionHandler(WKNavigationActionPolicyAllow); } } @end @implementation CustomWKCommandDelegate //- (id)initWithViewController:(CDVViewController *)viewController { // self = [super initWithViewController:viewController]; // if (self) { // self.viewController = viewController; // } // return self; //} - (id)getCommandInstance:(NSString *)pluginName { return [super getCommandInstance:pluginName]; } // 重写资源路径的方法,进行拦截 - (NSString *)pathForResource:(NSString *)resourcepath { // if (<#condition#>) { // <#statements#> // } NSLog(@"path ---> %@", resourcepath); return [super pathForResource:resourcepath]; } @end @implementation CustomCmdQueue - (BOOL)execute:(CDVInvokedUrlCommand *)command { return [super execute:command]; } @end
这样写的缘由,在于CDVViewController会自动加载CDVWKWebViewEngine并自动实现WKUIDelegate,在wkwebview的代理函数中,实现本身的业务逻辑.
适用场景:本地h5应用、html字符串、远程应用(若是较少的www文件,可采用wkwebview预加载,提高加载速度)
5. 关于自定义插件部分
原有插件不能知足需求,须要自定义,大体流程为:
建议将插件以pod的方式引入,方便管理,这就涉及到Podfile语法了
6. 持续优化:webview预加载、js\css\image离线缓存、避免无用的js引入;