什麼是快應用
簡單地說快應用是國內的十大主流手機廠商比如小米、華為、ov 等聯合推出的一種新型應用。無需安裝,秒開,體驗媲美原生。還提供了像原生應用一樣的入口:應用商店,搜尋頁等。
開發前準備
接下來會教大家如何搭建、啟動、預覽和除錯快應用專案。和官方文件類似,這裡我增加了一些我在這過程中遇到的坑及解決方法。
建立專案
安裝 NodeJS
官方說需安裝 6.0 以上版本的 NodeJS,推薦 v6.11.3,但我本機 NodeJS 是 v9.3.0,暫時沒發現異常就沒切到 6.0。
安裝 hap-toolkit
hap-toolkit 是快應用的開發者工具,幫助開發者通過命令列工具輔助開發工作的完成,主要包括建立模板工程,升級工程,編譯,除錯等功能。類似 vue-cli。
npm install -g hap-toolkit
複製程式碼
安裝之後檢視下版本號看是否安裝成功。
hap -V
複製程式碼
建立專案
執行如下命令會在當前目錄下建立 <ProjectName>
目錄作為專案的根目錄。
hap init <ProjectName>
複製程式碼
這個專案已經包含了專案配置與示例頁面的初始程式碼,專案根目錄主要結構如下。
├── sign rpk 包簽名模組
│ └── debug 除錯環境
│ ├── certificate.pem 證照檔案
│ └── private.pem 私鑰檔案
├── src
│ ├── Common 公用的資源和元件檔案
│ │ └── logo.png 應用圖示
│ ├── Demo 頁面目錄
│ | └── index.ux 頁面檔案,可自定義頁面名稱
│ ├── app.ux APP 檔案,可引入公共指令碼,暴露公共資料和方法等
│ └── manifest.json 專案配置檔案,配置應用圖示、頁面路由等
└── package.json 定義專案需要的各種模組及配置資訊
複製程式碼
安裝依賴
npm install
複製程式碼
啟動專案
編譯
npm run build
複製程式碼
編譯生成的 dist
目錄裡才是最終產物:rpk
檔案。
這一步可能會遇到報錯(我就遇到了)。
Cannot find module `.../node_modules/hap-tools/webpack.config.js`
複製程式碼
主要是因為建立專案後就有一個 node_module
資料夾了,裡面有一個 hap-tools
包。如果 npm install
安裝依賴,高版本的 npm
可能會把 node_module
原有的包清空再安裝依賴,這時只要再手動安裝下 hap-tools
就行了
npm install hap-tools
複製程式碼
如果要監聽原始碼變化自動編譯,可以執行 watch 命令。
npm run watch
複製程式碼
到這一步一個 hello world 的快應用就打包好了,下面需要在手機上把它跑起來。
預覽
首先需要安裝手機偵錯程式。
只安裝這個快應用偵錯程式會發現上面的按鈕都是灰色不可點選的,這時還需要安裝平臺預覽版偵錯程式,總之快應用文件上的手機偵錯程式都要安裝才能除錯。
安裝好偵錯程式後就把快應用安裝包安裝到手機上就可以了。
掃碼安裝
需要啟動一個本地 HTTP 伺服器。
npm run server
複製程式碼
如果命令列中的二維碼掃了沒反應,可以把那個地址在瀏覽器中開啟在掃碼試試(我就是這樣),因為命令列中的二維碼可能繪製的有問題。
本地安裝
把 rpk
檔案傳到手機上安裝即可。
線上更新
快應用偵錯程式右上角可以設定伺服器地址,執行以下命令每次改了程式碼就可以點選線上更新就可以更新了,不用每次都掃碼或本地安裝。
npm run server
npm run watch
複製程式碼
除錯
可以手機上預覽,也可以使用 chrome devtools 除錯介面,還可以檢視除錯日誌。手機上預覽上面說了,其他除錯按官方步驟來就好了。
可能的坑:在用chrome devtools除錯的時候可能打不開除錯介面,或者除錯介面空白。這時需檢查:
- 在手機偵錯程式上點選了開始除錯(點了就會自動在 pc chrome 上開啟 devtools)
- 確保手機和電腦在同一個網段
- 檢查代理,設定了代理的把代理關了試試(我就是因為設定了代理 devtools 空白)
5 分鐘上手教程
以一個列表頁和詳情頁為例說明快應用的程式碼,資料來源迅雷影評。
Manifest.json
在 manifest.json
中配置路由後就可以寫程式碼了,生成的模板有例子。注意不能配置動態路由。
注意用到的系統介面要先在 manifest.json
的 feature
中宣告。看 manifest 的文件瞭解具體的配置項。
{
"package": "com.xunlei.movie",
"name": "迅雷影評",
"versionName": "1.0.0",
"versionCode": "1",
"minPlatformVersion": "101",
"icon": "/Common/logo.png",
"features": [
{ "name": "system.prompt" },
{ "name": "system.router" },
{ "name": "system.shortcut" },
{ "name": "system.fetch" },
{ "name": "system.webview" }
],
"permissions": [
{ "origin": "*" }
],
"config": {
"logLevel": "debug",
"designWidth": 640
},
"router": {
"entry": "List",
"pages": {
"List": {
"component": "index"
},
"Detail": {
"component": "index"
},
"About": {
"component": "index"
}
}
}
}
複製程式碼
列表
列表使用了快應用的list元件,這個元件是Native元件,對長列表滾動效能更好,list元件還有一個onscrollbottom事件,方便下拉載入。
image元件和前端的img標籤類似,但是alt屬性不同,alt是用來顯示佔點陣圖的,只能是本地圖片,在圖片沒載入出來前顯示。
list-item元件中的type是必填的,要實現DOM片段的複用,要求相同type屬性的DOM結構完全相同;所以設定相同type屬性的list-item是優化列表滾動效能的關鍵。
<template>
<list class="list-main" onscrollbottom="loadData">
<list-item class="list-item" type="review" for="{{item in list}}">
<image class ="art-pic"
src="{{item.img}"
alt="../Common/assets/img/default.png">
</image>
<text class="art-title">{{item.title}}</text>
</list-item>
<!-- 載入更多,type屬性自定義命名為loadMore -->
<list-item type="loadMore" class="load-more" show="{{hasMore}}">
<progress type="circular" class="round"></progress>
<text>載入更多</text>
</list-item>
</list>
</template>
複製程式碼
快應用的網路請求是用fetch方法,是callback的形式,不方便呼叫,官方給了一個封裝成promise的例子,可以用async/await的方式呼叫。
將封裝好的fetch方法在app.ux中匯出就可以全域性使用了,由於我使用的介面都返回json,所以直接就在這一層解析了。實際開發時要注意JSON.parse的報錯處理。
// app.ux
const natives = {
/**
* 網路請求
* @param options
* @return {Promise}
*/
async fetch (options) {
const p1 = new Promise((resolve, reject) => {
options.success = function (data, code) {
data = JSON.parse(data.data)
resolve({ data, code })
}
options.fail = function (data, code) {
reject({ data, code })
}
nativeFetch.fetch(options)
})
return p1
}
}
// 注入到全域性
const hookTo = global.__proto__ || global
hookTo.natives = natives
export default {
natives
}
複製程式碼
路由跳轉
<template>
<list>
<list-item onclick="{{goDetail(item.id)}}" for="item in list"></list-item>
</list>
</template>
<script>
import router from `@system.router`
export default {
goDetail (id) {
router.push({
uri: `/Detail`,
params: { id }
})
}
}
</script>
複製程式碼
webview
詳情頁只是載入了一個 webview, 用列表頁傳過來的 id 去請求影評詳情,影評正文是存在 cdn 上的一個地址。使用 web
元件前需在 manifest.json
中宣告使用 webview 介面。
<!-- Detail/indev.ux -->
<template>
<!-- template裡只能有一個根節點 -->
<div>
<web src="{{review.body_url}}" id="web"></web>
</div>
</template>
<script>
import api from `../Common/api/index.js`
export default {
data: {
id: ``, // 列表頁傳過來的id
review: {}
},
onMenuPress() {
this.$app.showMenu()
},
onInit () {
this.getReview()
},
async getReview () {
try {
let data = await api.getReview(this.id)
this.review = data.cinecism_info || {}
this.$page.setTitleBar({ text: this.review.title })
} catch (error) {
console.log(error)
}
}
}
</script>
複製程式碼
與前端開發比較
快應用與前端開發的最大的區別就是 html 和 css 部分,因為快應用是用原生的方式實現的,但沒有實現html的所有標籤,而且與 html 相同的標籤在用法上也有一些差別。
html
快應用中很多 html 都不能用,比如沒有 p,h1~h2 等,因為它只是模擬了部分 html 標籤,最終會轉化成原生元件。
而且快應用中的元件巢狀子元件是有限制的,不是所有的元件都能巢狀子元件,如果巢狀不正確編譯的時候會報錯。比如下面就是不正確的寫法:
<!--錯誤-->
<a href="">
<image src="http://pic.com/1.jpg"></image>
</a>
複製程式碼
文字元件
只能使用 a、span、text、label 放置文字內容
圖片元件
圖片元件是 image 不是 img,用法與 img 類似,只是 alt 的含義不同,在快應用中 alt 是指圖片沒載入出來前的佔點陣圖,只能是本地地址。
<image src="http://pic.com/1.jpg" alt="1.jpg"></image>
複製程式碼
其他
表單元件、video 元件等與前端一致,還有一些快應用特有的元件,比如星級評分元件、進度條元件、list 元件等。
css
- display 只能是 flex 或 none
- position 只能是 fixed 或 none
- 長度單位只有 px 和 %
與傳統 web 頁面不同,px 是相對於專案配置基準寬度的單位,已經適配了移動端螢幕,其原理類似於 rem。基準寬度可以在 mainifest.json 中配置。
javascript
基本語法都能用,ES6 也可以用,專案中已經安裝了 babel 依賴。一些瀏覽器特有的 API 可能不同。比如資料儲存用的是快應用的介面 storage。
與 Vue 比較
由於我們團隊主要是用 Vue 技術棧開發,所以比較下快應用在語法上和 Vue 的共同點和差異之處。快應用看起來和 Vue 類似,其實還是有很大的差別。
- 都有指令的概念,只是寫法不同, 目前不能自定義指令
<!--左邊是 vue 語法 右邊是快應用語法-->
v-for => for
v-show => show
v-if => if
template => block
slot => slot
複製程式碼
- 快應用的路由是通過配置檔案
manifest.json
配置的,在例項中的用法與 vue-router 一致 - 都有元件概念,元件引入的方式略有不同
// vue
import child from `./childComponent`
// 快應用
<import name="child" src="./childComponent"></import>
複製程式碼
- 事件的監聽和觸發與 Vue 類似,都是
$on
$off
$emit
,監聽原生元件的事件寫法不同
<!--vue-->
<div v-on:click="handleClick"><div>
<div @click="handleClick"><div>
<!--快應用-->
<div onclick="{{handleClick()}}"><div>
複製程式碼
- 元件間通訊和純 Vue 類似,可以通過 props,也可以掛載在全域性物件上
- Vue 生態系統都不能用,比如 Vuex,目前沒有外掛機制
優缺點
優點
- 提供了很多系統的功能,比如分享、通知、掃描二維碼、新增圖示到桌面
- 使用者體驗好,無需下載,秒開,佔用記憶體小
- 可以關聯原生應用
缺點
- 每個平臺都要註冊個賬號
- 沒有一個整合開發環境,除錯麻煩,且 devtools 很卡
- rpk 檔案最大1M
- 國內手機廠商推出的,自然是不支援 ios 了
總結
寫 demo 的時候還是遇到了不少坑,主要是 html 和 css 部分。像我們公司前端和重構是分開的,重構只負責寫 html + css,前端負責寫邏輯調介面等雜七雜八的事情,快應用和小程式這種形式對重構來說很麻煩,不能寫一份程式碼到處用了。
還有就是詳情頁顯示影評正文的時候遇到了一個問題。我們影評的正文是存在 cdn 上的一堆 html 標籤,無樣式,可能有一些和快應用不相容的標籤,所以用 webview 的方式載入頁面。但是不知道怎麼向 webview 中注入 css ,所以頁面是亂的。
總的來說,快應用這種形態對使用者來說還是很好的,在下載 APP 前就可以體驗到應用的一些功能。快應用的快在於它進行了很多原生的優化,也在於它小,小到使用者感覺不到,這也註定它不能做的很複雜。
程式碼地址
參考文件
掃一掃關注迅雷前端公眾號
作者:珈藍
校對:前端小透明