个人原创地址:https://www.jianshu.com/p/1ad536e76640

1.需求与使用场景
    打开一个新页面,要求能够加载本地zip格式的h5应用,该应用使用了某些原生能力;能够加载远程应用,该应用也使用了部分原生能力;能够在多个h5应用时同样适用;h5应用能够移植到其它场景,如web、第三方移动应用;h5应用无需复杂适配移动端,如android、iOS等;
2.目的
    让h5应用只专注于开发h5,涉及到原生功能,则交给原生应用去实现,通过cordova js功能进行h5与原生功能的交互。
3.前提
需要3个应用,如下所示

  • 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. 原生部分

h5应用部分省略不表,原生部分以iOS为例
4.1 如何创建cordova项目

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

    创建应用`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的修改

1. 允许远程网页加载 ATS

<content src="index.html" />是本地加载的入口,也可设置远程地址
<allow-navigation href="https://*/*" />
<allow-navigation href="http://*/*" />
<allow-navigation href="data:*" />

以上三行等价于

<allow-navigation href="*" /> 允许所有的网址跳转。

2. 白名单设置

<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:]]; } // 处理跨域等情况建议使用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引入;

原生应用使用cordova并与h5应用分离的更多相关文章

  1. H5动静分离

    1. 动静分离的实现思路(类似于iOS.安卓的思路,后台提供数据接口,前端用ajax异步请求json数据,再把json数据渲染到页面) 动静分离是将网站静态资源(HTML,JavaScript,CSS ...

  2. Android H5混合开发(3):原生Android项目里嵌入Cordova

    前言 如果安卓项目已经存在了,那么如何使用Cordova做混合开发? 方案1(适用于插件会持续增加或变化的项目): 新建Cordova项目并添加Android平台,把我们的安卓项目导入Android平 ...

  3. H5程序员如何利用cordova开发跨平台应用

    什么是Cordova? Cordova以前也叫PhoneGap,它提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头.麦克风等.Cordova还 ...

  4. Android H5混合开发(4):构建Cordova Jar包

    前言 上一节,介绍了原生项目如何嵌入Cordova,我们对Cordova的依赖使用的是CordovaLib Module,这也是安卓项目常用的方式. 但是,也有项目希望以Jar包的方式依赖Cordov ...

  5. 原生Android项目里嵌入Cordova

    Android H5混合开发():原生Android项目里嵌入Cordova 如果安卓项目已经存在了,那么如何使用Cordova做混合开发? 方案1(适用于插件会持续增加或变化的项目): 新建Cord ...

  6. 【quickhybrid】H5和原生的职责划分

    前言 在JSBridge实现后,前端网页与原生的交互已经通了,接下来就要开始规划API,明确需要提供哪一些功能来供前端调用. 但是在这之前,还有一点重要工作需要做: 明确H5与Native的职责划分, ...

  7. 如何在原生工程中引入Cordova工程-for iOS 【转】

    http://blog.csdn.net/e20914053/article/details/50170487 如今混合开发方兴未艾,有的项目可能一开始是原生开发的,后期需要加入混合开发,如将Cord ...

  8. Android 原生开发、H5、React-Native使用利弊和场景技术分享

    http://m.blog.csdn.net/article/details?id=51778086 发表于2016/6/28 18:52:46  1176人阅读      最近工作中接触到React ...

  9. H5和原生APP之间的区别

    最近项目中因各种客观因素,移动端都是默认用的纯H5 APP,感受最深的就是各种坑啊,好大的坑啊.产品上线后,带着各种坑后的总结原因方发现很多人都说纯H5 APP一次编写就能支持android和IOS两 ...

随机推荐

  1. Paxos算法——前世

    Paxos算法是基于消息传递且具有高度容错特性的一致性算法.我们将从一个简单的问题开始,逐步的改进我们的设计方案,最终得到Paxos,一个可以在逆境下工作的协议. 一.客户端-服务器模型 我们从最小的 ...

  2. CentOS 7更新系统时间

    Linux系统在安装的时候,总是会出现时区,时间的错误. 将Linux系统时间和本地区网络时间同步,ntpdate可以从网络同步时间, 需要安装sudo yum install ntp ntpdate ...

  3. HTML5新增的表单验证功能

    一.HTML5表单的特点: HTML5 表单增加了许多内置的控件和控件属性 XHTML 中需要放在 form 之中的诸如 input/button/select/textarea 等标签元素,在 HT ...

  4. Go - Map 集合

    目录 概述 声明 Map 生成 JSON 编辑和删除 推荐阅读 概述 Map 集合是无序的 key-value 数据结构. Map 集合中的 key / value 可以是任意类型,但所有的 key ...

  5. Codeforces Gym100623J:Just Too Lucky(数位DP)

    http://codeforces.com/gym/100623/attachments 题意:问1到n里面有多少个数满足:本身被其各个数位加起来的和整除.例如120 % 3 == 0,111 % 3 ...

  6. C# Socket 简单的控制台案例

    一.服务器端 1. 实例化并设置socket实例对象 a.创建ip地址和端口 b.绑定监听地址 c.设置一下允许同时访问数 2. 监听连接 a.通过启动一个新的线程执行,这样主线程不会假死(启动线程, ...

  7. [MySQL]快速解决"Table '.\sjzlf\zbp_post' is marked as crashed and should be repaired"故障

    为了不冒失修复,故采取保守做法,我们知道 MySQL 一个高效的管理工具便是 PhpMyAdmin,而在该管理软件中就包含了对表的检查.分析.修复.优化功能,比起网上提供的含糊命令行来说更安全更简便. ...

  8. python接口自动化(三十)--html测试报告通过邮件发出去——中(详解)

    简介 上一篇,我们虽然已经将生成的最新的测试报告发出去了,但是MIMEText 只能发送正文,无法带附件,因此我还需要继续改造我们的代码,实现可以发送带有附件的邮件.发送带附件的需要导入另外一个模块 ...

  9. Docker笔记(四):Docker镜像管理

    原文地址:http://blog.jboost.cn/2019/07/16/docker-4.html 在Docker中,应用是通过容器来运行的,而容器的运行是基于镜像的,类似面向对象设计中类与对象的 ...

  10. 获取一个整数所有的质因数(C语言实现)

    一.题目要求 1. 用户输入任意一个整数,要求程序输出此整数所有的质因数: 2. 用户可以反复输入,直至输入字符'q'退出程序. 二.分析 质因数的概念大家可以问度娘. 题目关键有几个要点,分析透了这 ...