我的原創地址: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引入;