快應誕生背景
微信的小程序使得不少原來須要調動APP的場景不復存在,正式因爲微信小程序的衝擊,3月20日,華爲聯手九大手機廠商,共同舉辦了「快應用」標準啓動發佈會。「快應用」是幾家手機廠商基於硬件平臺共同推出的新型應用生態,用戶沒必要下載安裝,即點即用,可以享受到原生應用的性能體驗。「快應用」使用前端技術棧開發與原生渲染,兼具H5頁面和原生應用的雙重優勢。javascript
快應用使用場景
進入小米應用商店,搜索「餓了麼」:html
點擊「秒開」就可使用快應用了前端
在華爲應用市場搜索「快應用」:java
點擊查看更多:node
能夠看到一些快應用app已經上線了,使用起來體驗也不錯,體積也至關小webpack
微信小程序VS快應用
微信小程序推出後,儘管前期受到了很多質疑,但卻一直髮展很是穩健。騰訊3月21日剛剛公佈的2017年整年財報中披露,自2017年1月推出小程序以來,截至2018年1月已推出58萬個小程序,日活躍帳戶超過1.7億個。張小龍也曾經表示,將來兩年內,小程序將取代80%的應用市場。若是該目標達成,這意味着微信小程序創建起一個強大的超級生態,極大擠壓了國產手機廠商應用分發和數字廣告業務的成長空間。所以,國產手機廠商的「快應用」主要針對微信小程序,與後者爭搶用戶和流量。web
那麼快應用要和微信小程序去競爭,它們各自又有什麼優缺點,誰又會更佔優點呢?我我的總結以後列出了以下幾點:正則表達式
微信小程序shell
優勢:npm
- 微信小程序已經在市場上取得了必定的規模效益,搶佔了市場先機
- 微信自帶用戶流量,用戶黏度較高,經過微信打開小程序很是方便
- 微信小程序支持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服務器地址有兩種方式,如下二者選其一便可:
打開調試器 --> 點擊"掃碼安裝"
,掃描終端窗口中的二維碼便可完成配置(若掃描不成功,可在瀏覽器中打開頁面:http://localhost:<your port>
,掃描頁面中的二維碼)打開調試器 --> 點擊右上角menu --> 設置
,輸入終端窗口中提示的HTTP服務器地址
配置完成後,若沒有自動喚起平臺運行rpk包,點擊在線更新
喚起平臺運行rpk包
若提示安裝失敗
,請檢查執行npm run server的終端窗口是否正常運行
2. 本地安裝
複製rpk包到手機中
將<ProjectName>/dist
目錄下編譯產出的rpk
包經過USB數據線或其餘方式,複製到手機文件系統中
本地安裝rpk包
打開調試器 --> 點擊"本地安裝"
,選擇手機文件系統中的rpk包,並自動喚起平臺運行rpk包,查看效果
配置應用基本信息
每一個應用都要有專屬的名稱,圖標等,這些信息都須要在manifest.json
文件中配置;詳細信息請參考文檔:manifest文件
應用包名(package)
應用包名,是區別於其餘應用的惟一標識
推薦採用com.company.module的格式,示例以下:
{
"package": "com.example.demo" }
應用名稱(name)
應用名稱,6個漢字之內,與應用商店保存的名稱一致;框架提供保存到桌面的功能,桌面上顯示的應用名即爲此屬性
示例以下:
{
"name": "發票小助手" }
應用圖標(icon)
規則爲正方形(不能是圓角),且務必無白邊
{
"icon": "/Common/logo.png" }
注意:
請使用絕對路徑,其中/
對應於路徑<ProjectName>/src/
應用版本名稱、版本號(versionName、versionCode)
應用版本名稱、版本號爲開發者的應用包維護的版本信息
應用版本名稱爲主版本.次版本
格式
應用版本號爲整數,從1
開始,每次更新上架請自增1
示例以下:
{
"versionName": "1.0", "versionCode": 1 }
支持的最小平臺版本號(minPlatformVersion)
支持的最小平臺版本號爲必填項,默認值爲1000,標識開發者的rpk包兼容支持的最小運行平臺版本
當使用了1000以上的平臺版本新增特性時,就必須確保minPlatformVersion
最低爲該平臺版本號,避免上線後在更低版本平臺上運行出錯
示例以下:
{
"minPlatformVersion": "1000" }
配置接口列表(features)
在使用接口時,須要先在manifest中聲明接口。在每一個接口文檔的頂部,都附有聲明接口的配置代碼
以fetch網絡請求爲例,示例以下:
{
"features": [ { "name": "system.fetch" } ] }
配置頁面路由(router)
路由,用於定義頁面的實際地址、跳轉地址。若是ux頁面沒有配置路由,則不參與項目編譯。一個目錄下最多隻能存在一個主頁面文件(不包括組件文件)
首頁名稱(router.entry)
首頁,即應用平臺啓動時默認打開的頁面。首頁需配置爲應用中某頁面的名稱,即在<ProjectName>/src
目錄下,頁面目錄的相對路徑
示例以下:
假設工程根目錄以下所示
└── src └── Demo 頁面目錄,存放各自頁面私有的資源文件和組件文件 └── index.ux 頁面文件,文件名沒必要與父文件夾相同(推薦index.ux)
假設首頁爲Demo目錄下的index.ux文件,則首頁對應的頁面名稱爲Demo
{
"router": { "entry": "Demo" } }
頁面路由對象(router.pages)
頁面路由對象,key爲頁面名稱(<ProjectName>/src
目錄下,頁面目錄的相對路徑),value爲頁面具體路由配置,key不要重複
頁面具體路由配置(router.pages的value)包括如下屬性:
- component:頁面對應的ux文件名
- path:頁面路徑,不填則默認爲頁面名稱(
<ProjectName>/src
目錄下,頁面目錄的相對路徑)
示例以下:
假設工程根目錄以下所示
└── src |── Demo 頁面目錄,存放各自頁面私有的資源文件和組件文件 | └── index.ux 頁面文件,文件名沒必要與父文件夾相同(推薦index.ux) └── Doc └── Layout 頁面目錄,存放各自頁面私有的資源文件和組件文件 └── index.ux 頁面文件,文件名沒必要與父文件夾相同(推薦index.ux)
當頁面名稱(router.pages的key)爲Demo
時,對應的頁面配置(router.pages的value)包括:
- component:頁面對應的ux文件名
index
- path:頁面路徑,默認爲頁面名稱
Demo
{
"router": { "pages": { "Demo": { "component": "index" }, "Doc/Layout": { "component": "index" } } } }
如今,開發者就能夠經過/Demo
訪問到Demo目錄下的index.ux頁面了
配置頁面UI顯示(display)
UI顯示,用於定義與UI顯示相關的配置。支持定義:頁面公用的默認UI顯示、頁面私有的UI顯示
頁面公用的默認UI顯示
頁面公用的默認UI顯示,即被全部頁面共享
以標題欄文字的配置爲例:
{
"display": { "titleBarText": "頁面公用的默認標題" } }
未配置私有標題的頁面,標題欄文字均將顯示爲頁面公用的默認標題
頁面私有的UI顯示
頁面私有的UI顯示,在display.pages
對象下配置:key爲頁面名稱(與路由中的頁面名稱保持一致),value爲頁面私有的UI顯示
以標題欄文字的配置爲例:
{
"display": { "pages": { "Demo": { "titleBarText": "Demo頁面的標題" } } } }
manifest文件
manifest.json文件中包含了應用描述、接口聲明、頁面路由信息
manifest
屬性
|
類型
|
默認值
|
必填
|
描述
|
---|---|---|---|---|
package | String | - | 是 | 應用包名,確認與原生應用的包名不一致,推薦採用com.company.module的格式,如:com.example.demo |
name | String | - | 是 | 應用名稱,6個漢字之內,與應用商店保存的名稱一致,用於在桌面圖標、彈窗等處顯示應用名稱 |
icon | String | - | 是 | 應用圖標,提供192x192大小的便可 |
versionName | String | - | 否 | 應用版本名稱,如:"1.0" |
versionCode | Integer | - | 是 | 應用版本號,從1 自增,推薦每次從新上傳包時versionCode +1 |
minPlatformVersion | Integer | 1000 | 是 | 支持的最小平臺版本號,原理同Android API Level,兼容性檢查,避免上線後在低版本平臺運行並致使不兼容 |
features | Array | - | 否 | 接口列表,絕大部分接口都須要在這裏聲明,不然不能調用,詳見每一個接口的文檔說明 |
config | Object | - | 是 | 系統配置信息,詳見下面說明 |
router | Object | - | 是 | 路由信息,詳見下面說明 |
display | Object | - | 否 | UI顯示相關配置,詳見下面說明 |
config
用於定義系統配置和全局數據。
屬性
|
類型
|
默認值
|
描述
|
---|---|---|---|
logLevel | String | log | 打印日誌等級,分爲off,error,warn,info,log,debug |
designWidth | Integer | 750 | 頁面設計基準寬度,根據實際設備寬度來縮放元素大小 |
data | Object | - | 全局數據對象,屬性名不能以$或_開頭,在頁面中可經過this進行訪問;若是全局數據屬性與頁面中data屬性重名,則頁面初始化時,全局數據會覆蓋頁面中對應的屬性值 |
router
用於定義頁面的組成和相關配置信息,若是頁面沒有配置路由信息,則在編譯打包時跳過。
屬性
|
類型
|
默認值
|
描述
|
---|---|---|---|
entry | String | - | 首頁名稱 |
pages | Object | - | 頁面配置列表,key值爲頁面名稱(對應頁面目錄名,例如Hello對應'Hello'目錄),value爲頁面詳細配置page,詳見下面說明 |
router.page
用於定義單個頁面路由信息。
屬性
|
類型
|
默認值
|
必填
|
描述
|
---|---|---|---|---|
component | String | - | 是 | 頁面對應的組件名,與ux文件名保持一致,例如'hello' 對應 'hello.ux' |
path | String | /<頁面名稱> | 否 | 頁面路徑,例如「/user」,不填則默認爲/<頁面名稱>。 path必須惟一,不能和其餘page的path相同。 下面page的path由於缺失,會被設置爲「/Index」: "Index": {"component": "index"} |
filter | Object | - | 否 | 聲明頁面能夠處理某種請求 |
router.page.filter
聲明頁面能夠處理某種請求,頁面能夠從$page獲取打開頁面的參數,參見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,能夠是下面的格式:
|
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,能夠是下面的格式:
|
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