快应诞生背景
微信的小程序使得很多原来需要调动APP的场景不复存在,正式由于微信小程序的冲击,3月20日,华为联手九大手机厂商,共同举办了“快应用”标准启动发布会。“快应用”是几家手机厂商基于硬件平台共同推出的新型应用生态,用户不必下载安装,即点即用,能够享受到原生应用的性能体验。“快应用”使用前端技术栈开发与原生渲染,兼具H5页面和原生应用的双重优点。
快应用使用场景
进入小米应用商店,搜索“饿了么”:
点击“秒开”就可以使用快应用了
在华为应用市场搜索“快应用”:
点击查看更多:
可以看到一些快应用app已经上线了,使用起来体验也不错,体积也相当小
微信小程序VS快应用
微信小程序推出后,尽管前期受到了不少质疑,但却一直发展非常稳健。腾讯3月21日刚刚公布的2017年全年财报中披露,自2017年1月推出小程序以来,截至2018年1月已推出58万个小程序,日活跃账户超过1.7亿个。张小龙也曾经表示,未来两年内,小程序将取代80%的应用市场。如果该目标达成,这意味着微信小程序建立起一个强大的超级生态,极大挤压了国产手机厂商应用分发和数字广告业务的成长空间。因此,国产手机厂商的“快应用”主要针对微信小程序,与后者争抢用户和流量。
那么快应用要和微信小程序去竞争,它们各自又有什么优缺点,谁又会更占优势呢?我个人总结之后列出了如下几点:
微信小程序
优点:
- 微信小程序已经在市场上取得了一定的规模效益,抢占了市场先机
- 微信自带用户流量,用户黏度较高,通过微信打开小程序非常方便
- 微信小程序支持iOS和安卓两大操作系统,覆盖了所有的用户群体,不同操作系统用户之间数据共享方便,比如iOS用户可以通过一个微信链接响安卓用户发送一个微信小程序链接
缺点:
- 微信小程序基于系统上层进行的封装,在性能上和原生app差距较大
快应用
优点:
- 基于系统层开发,将脚本转化为原生组件,运行效率更接近原声app,用户体验会更加好
缺点:
- 只支持安卓系统,在用户群体上受到限制,也无法在安卓和iOS系统之间做到数据共享
- 几大厂商合作,可能会产生分歧,如何去协调各大厂商,以及后期的利益分配等是一个大问题
- 缺乏用户粘性和使用场景,如果每次打开其他应用都要去应用商店搜索快应用app的话显然不如微信小程序方便
总结:
从快应用的诞生,我们能够看到国内手机硬件厂商开始反思自己在安卓生态中的地位,寻求转型和突破以争取更大的话语权和利益。这个方向显然是对的,但是对比微信小程序,较好的性能几乎成了快应用的唯一优势,但是随着现在手机性能不断增强以及微信小程序的不断优化,这个问题将变得忽略不计,况且现在很多微信小程序用户流畅度意境做的相当不错了,而在用户群体、使用方便性等几大方面,微信小程序占据着绝对优势,而且快应用由于自生的缺陷无法弥补这几方面的劣势,所以说快应用几乎无法撼动微信小程序的地位,更不用说打败小程序,不过如果快应用能够在应用分发市场上对微信形成一定威胁并且从中分得一杯羹的话,那也能够证明快应用取得了成功。
环境配置
6.0版本以上NodeJS,官方推荐 v6.11.3 LTS
安装hap-toolkit:
npm install -g hap-toolkit(帮助开发者通过命令行工具来完成工程的创建等工作),在命令行中执行hap -V
会输出版本信息表示hap-toolkit
安装成功,如下命令所示:
hap -V
创建项目
建好环境后,开发者就可以利用全局hap
命令创建一个项目模板,如下所示,其中<ProjectName>
为自定义的项目名称
hap init <ProjectName>
命令执行后,会在当前目录下创建<ProjectName>
文件夹,并作为项目根目录
这个项目已经包含了项目配置与简单页面的初始代码,项目根目录结构如下:
├── node_modules
├── sign rpk包签名模块
│ └── debug 调试环境
│ ├── certificate.pem 证书文件
│ └── private.pem 私钥文件
├── src
│ ├── Common 公用的资源文件和组件文件
│ │ └── logo.png manifest.json中配置的icon
│ ├── Demo 页面目录
│ | └── index.ux 页面文件,文件名不必与父文件夹相同
│ ├── app.ux APP文件(用于包括公用资源)
│ └── manifest.json 项目配置文件(如:应用描述、接口申明、页面路由等)
└── package.json 定义项目需要的各种模块及配置信息,npm install根据这个配置文件,自动下载所需的运行和开发环境
目录的简要说明如下:
- src:项目源文件夹
- node_modules:项目的依赖类库
- sign:签名模块,当前仅有
debug
签名,如果内测上线,请添加release
文件夹,增加线上签名;签名生成方法请参考文档:编译工具
的openssl
编译项目
安装npm依赖
在项目根目录下,运行如下命令安装依赖包(webpack,babel等)
npm install
编译项目
在项目的根目录下,运行如下命令进行编译打包,生成rpk包
npm run build
编译打包成功后,项目根目录下会生成文件夹:build、dist
- build:临时产出,包含编译后的页面js,图片等
- dist:最终产出,包含rpk文件。其实是将build目录下的资源打包压缩为一个文件,后缀名为
rpk
,这个rpk
文件就是项目编译后的最终产出
自动重新编译
如果希望每次修改源代码文件后,都自动重新编译项目,请使用如下命令:
npm run watch
手机安装调试器
调试器APK是一个Android应用程序,请从站点地址下载
说明如下:
- 扫码安装:配置HTTP服务器地址,下载rpk包,并唤起平台运行rpk包
- 本地安装:选择手机文件系统中的rpk包,并唤起平台运行rpk包
- 在线更新:重新发送HTTP请求,更新rpk包,并唤起平台运行rpk包
- 开始调试:唤起平台运行rpk包,并启动远程调试工具
注意:若无法正常使用调试器,请升级手机系统到最新版本或安装平台预览版
手机安装平台预览版
较新的系统版本中内置平台正式版,即真实的运行环境。然而,更新平台正式版的时间周期较长,开发调试平台新功能可使用平台预览版
平台预览版存在以下优缺点:
- 优点:迭代速度快,可立即体验平台新功能
- 缺点:实现与真实的运行环境存在差异,对厂商服务和第三方服务的支持存在缺陷
平台预览版APK是一个Android应用程序,请从站点地址下载
下载安装成功后,在调试器中点击切换运行平台至...mockup
即可在平台预览版上运行rpk包
在平台上运行rpk包
在调试器中唤起平台打开rpk包有多种途径,以下两者选其一即可,推荐第一种途径:
- HTTP请求:开发者启动HTTP服务器,打开调试器,点击
扫码安装
配置HTTP服务器地址,下载rpk包,并唤起平台运行rpk包 - 本地安装:开发者将rpk包拷贝到手机文件系统,打开调试器,点击
本地安装
选择rpk包,并唤起平台运行rpk包
1. HTTP请求
启动HTTP服务器
在终端中新建一个窗口,进入项目的根目录运行如下命令,启动本地服务器(默认端口为12306)
npm run server
自定义端口(如:8080)
npm run server -- --port 8080
在手机上预览运行效果
配置HTTP服务器地址有两种方式,以下两者选其一即可:
打开调试器 --> 点击"扫码安装"
,扫描终端窗口中的二维码即可完成配置(若扫描不成功,可在浏览器中打开页面:script脚本。filter的结构如下:
"filter": {
"<action>": {
"uri": "<pattern>"
}
}属性 类型 默认值 必填 描述 action String - 是 请求的动作,目前仅支持view这一种 uri Pattern - 是 请求的数据的匹配规则。必须是正则表达式。如 https?://.*
可以匹配所有http和https类型的网址可以处理所有http和https请求的filter定义如下:
"filter": {
"view": {
"uri": "https?://.*"
}
}display
用于定义与UI显示相关的配置。
属性 类型 默认值 描述 backgroundColor String #ffffff 窗口背景颜色 fullScreen Boolean false 是否是全屏模式,默认不会同时作用于titleBar,titleBar需要继续通过titleBar控制 titleBar Boolean true 是否显示titleBar titleBarBackgroundColor String - 标题栏背景色 titleBarTextColor String - 标题栏文字颜色 titleBarText String - 标题栏文字(也可通过页面跳转传递参数(titleBarText)设置) menu Boolean false 是否显示标题栏右上角菜单按钮 pages Object - 各个页面的显示样式,key为页面名(与路由中的页面名保持一致),value为窗口显示样式,页面样式覆盖default样式。 示例:
{
"package": "com.company.unit",
"name": "appName",
"icon": "/Common/icon.png",
"versionName": "1.0",
"versionCode": 1,
"minPlatformVersion": 1000,
"features": [
{ "name": "system.network" }
],
"permissions": [
{ "origin": "*" }
],
"config": {
"logLevel": "off"
},
"router": {
"entry": "Hello",
"pages": {
"Hello": {
"component": "hello",
"path": "/",
"filter": {
"view": {
"uri": "https?://.*"
}
}
}
}
},
"display": {
"backgroundColor": "#ffffff",
"fullScreen": false,
"titleBar": true,
"titleBarBackgroundColor": "#000000",
"titleBarTextColor": "#fffff",
"pages": {
"Hello": {
"backgroundColor": "#eeeeee",
"fullScreen": true,
"titleBarBackgroundColor": "#0000ff",
"titleBarText": "Hello"
}
}
}
}源码文件
APP,页面和自定义组件均通过ux文件编写,ux文件由template模板、style样式和script脚本3个部分组成
app.ux
当前
app.ux
编译后会包含manifest配置信息
(可以在npm run build
之后查看文件内容),所以请不要删除/**manifest**/
的注释内容标识。您可以在
<script>
中引入一些公共的脚本,并暴露在当前app的对象上,如下所示,然后就可以在页面ux文件的ViewModel中,通过this.$app.util
访问<script> import util from './util.js'
module.exports = { /**manifest**/, util: util }
</script>页面路由
导入模块 import router from '@system.router' 或 var router = require("@system.router")接口定义
router.push(OBJECT)
跳转到应用内的某个页面
参数:
参数 类型 必填 说明 uri String 是 要跳转到的uri,可以是下面的格式: - 包含schema的完整uri;目前支持的schema有tel,sms和mailto,例如tel:10086。
- 以‘/’开头的应用内页面的路径;例:/about。
- 以非‘/’开头的应用内页面的名称;例:About。
- 特殊的,如果uri的值是"/",则跳转到path为"/"的页,没有则跳转到首页
支持包含schema的完整uri。对于带有schema的uri,处理流程如下:
- 查找app下所有page的filter设置来选择合适的page处理请求(参见[manifest文件](../../framework/manifest.md))
- 如果没有合适的page能够处理请求,会使用默认策略来处理请求。目前默认策略支持对http、https、internal这几种schema的处理
- 如果默认策略也不能处理请求,会尝试使用系统中的应用来处理请求
- 如果没有系统应用可以处理请求,会抛弃请求
默认策略的处理逻辑:
- 如果schema是http/https,会用内置的web页面打开网页
- 如果schema是internal(参见[文件组织](../../framework/file-organization.md)),会根据uri的文件扩展名来确定文件类型,再调用系统中的应用打开文件
params Object 否 跳转时需要传递的数据,参数可以在页面中通过 this.param1
的方式使用,param1为json中的参数名,param1对应的值会统一转换为String类型示例:
// launch phone app
router.push({
uri: 'tel:10086'
});
// open page by path
router.push({
uri: '/about',
params: {testId:'1'}
});
// open page by name
router.push({
uri: 'About',
params: {testId:'1'}
});
// open web page
router.push({
uri: 'http://www.example.com'
});
// install apk
router.push({
uri: 'internal://cache/example.apk'
});router.replace(OBJECT)
跳转到应用内的某个页面,当前页面无法返回
参数:
参数 类型 必填 说明 uri String 是 要跳转到的uri,可以是下面的格式: - 以"/"开头的应用内页面的路径;例:/about。
- 以非"/"开头的应用内页面的名称;例:About。
- 特殊的,如果uri的值是"/",则跳转到path为"/"的页,没有则跳转到首页
params Object 否 跳转时需要传递的数据,参数可以在页面中通过 this.param1
的方式使用,param1为json中的参数名,param1对应的值会统一转换为String类型示例:
router.replace({
uri: '/test'
params: {testId:'1'}
})router.back()
返回上一页面
参数:
无
示例:
// A页面
router.push({
uri: 'B'
})// B页面
router.push({
uri: 'C'
})// C页面通过back,将返回B页面
router.back();
// B页面通过back,将返回A页面
router.back();router.clear()
清空所有历史页面记录,仅保留当前页面
参数:
无
示例:
router.clear()
router.getLength()
获取当前页面栈的页面数量
返回值:
类型 说明 Number 页面数量 示例:
var length= router.getLength()
console.log("pages' length = "length);router.getState()
获取当前页面状态
返回参数:
参数名 类型 说明 index Number 当前页面在页面栈中的位置 name String 当前页面的名称 path String 当前页面的路径 示例:
var page = router.getState()
console.log("page index = "+page.index);
console.log("page name = "+page.name);
console.log("page path = "+page.path);快应用技术架构
快应用通过脚本来编写组件,安卓内部嵌入一个脚本解析引擎,将脚本转化为原生控件,通过编译生成rpk文件,应用调试器联系起脚本及安卓系统进行调试工作,具体流程图如下:
参考资料
- 开应用开发文档:https://doc.quickapp.cn
- 快应诞生背景
- 快应用使用场景
- 微信小程序VS快应用
- 环境配置
- 6.0版本以上NodeJS,官方推荐 v6.11.3 LTS
- 安装hap-toolkit:npm install -g hap-toolkit(帮助开发者通过命令行工具来完成工程的创建等工作),在命令行中执行hap -V会输出版本信息表示hap-toolkit安装成功,如下命令所示:
- 创建项目
- 编译项目
- 手机安装调试器
- 手机安装平台预览版
- 在平台上运行rpk包
- 配置应用基本信息
- 配置页面路由(router)
- 配置页面UI显示(display)
- manifest文件
- manifest
- 接口定义
- 快应用技术架构
- 参考资料