原生應用使用cordova並與h5應用分離

我的原創地址:https://www.jianshu.com/p/1ad536e76640css

1.需求與使用場景
    打開一個新頁面,要求可以加載本地zip格式的h5應用,該應用使用了某些原生能力;可以加載遠程應用,該應用也使用了部分原生能力;可以在多個h5應用時一樣適用;h5應用可以移植到其它場景,如web、第三方移動應用;h5應用無需複雜適配移動端,如android、iOS等;
2.目的
    讓h5應用只專一於開發h5,涉及到原生功能,則交給原生應用去實現,經過cordova js功能進行h5與原生功能的交互。
3.前提
須要3個應用,以下所示 html

  • h5應用:前端開發者只專一於前端開發和打包應用,應支持ionic、vue、react等應用
  • cordova應用:原生開發者建立,將cordova插件安裝到cordova應用中,並生成對應的platforms即android、iOS
  • 原生應用:原生開發者建立,iOS應用經過pod引入cordova插件,並將config.xml 經過group 方式添加,www則以文件夾folder的形式引入,即config.xml相對路徑引入,www絕對路徑引入;


對以上3個應用的解讀:前端

  • h5應用,正常的前端應用,若使用js則無需聲明,若使用ts則須要聲明 `declare let cordova: any;`全局變量
  • cordova應用,目的是將config.xml文件和platforms/android/www、platforms/ios/www文件夾copy出來備用。將其歸爲原生開發者建立範疇,是由於cordova.js經過exec來調用原生插件,將插件的管理交給原生應用。
  • 原生應用,管理插件,提供對應的原生能力。若使用cordova.exec方式交互(推薦),則將config.xml和www/cordova.js引入;若使用js service方式交互,則h5應用須要導入npm包,cordova應用添加插件,並將platforms/./www文件夾copy出來,放到原生應用下.

4. 原生部分vue

h5應用部分省略不表,原生部分以iOS爲例
4.1 如何建立cordova項目node

在mac上,安裝node,再在terminal中npm install -g cordova@lastest;react

    建立應用`cordova create myApp org.apache.cordova.myApp myApp`
  • 項目目錄下`cd myApp`* 安裝插件`cordova plugin add cordova-plugin-camera`
  • 生成iOS應用 `cordova platform add ios`
  • cordova應用下的config.xml和platforms/ios/www是咱們須要用到的

 

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的簡單使用
先決條件:

  • iOS原生應用pod 引入cordova以及插件
  • 新建繼承自CDVViewController的ViewController,如HtmlViewController

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爲遠程地址便可;
須要注意的地方:

  • self.startPage的賦值,必須在[super viewDidLoad]以前,不然self.startPage 會被默認賦值爲index.html。
  • 須要在config.xml中修改一下配置,不然加載遠程H5時,會自動打開瀏覽器加載。
<allow-navigation href="https://*/*" />
<allow-navigation href="http://*/*" />
  • 遠程H5中也要引用cordova.js文件。
  • 在 info.plist 中添加 App Transport Security Setting的設置。

wkwebviewengine貌似則不能這樣,我試了幾回均不行,因此採用瞭如下方法:

  • pod 引入cordova-plugin-wkwebview-engine
  • 修改HtmlViewController.h
#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. 關於自定義插件部分
原有插件不能知足需求,須要自定義,大體流程爲:

  • 新建集成自CDVPLugin的原生類
  • 修改原生類.h和.m,實現相應函數,
  • 修改config.xml,將自定義插件以feature添加進去
  • js經過cordova.exec的方式調用

建議將插件以pod的方式引入,方便管理,這就涉及到Podfile語法

6. 持續優化:webview預加載、js\css\image離線緩存、避免無用的js引入;

相關文章
相關標籤/搜索