一、快應用誕生的背景——想得美
以往的手機端應用主要有兩種方式:網頁、原生應用;
網頁: 無需安裝,卻體驗不是很好;
原生應用: 體驗流暢,卻需要從應用商店下載安裝,難以一步直達用戶;
快應用的出現,目的就是解決這個痛點,希望能夠讓用戶無需下載安裝,並且還能流暢的體驗應用內容。
二、快應用的具體形態——前端工程師接盤
快應用最終選擇使用前端技術棧開發,原生渲染,同時具備H5與原生應用的雙重優點,開發者使用的前端技術棧資料多,學習成本底,語法形態貌似VUE,其本質還是安卓。只不過,開發者變成了前端開工程師,不用安裝,在負一屏搜索,然後秒開,體積都很小,可以生成桌面快捷方式。
三、 快應用聯盟——友商也有團結一致的時候
快應用在中國起源也是有其根深蒂固的原因,因爲中國的安卓手機已經是一片紅海,幾乎佔領了全世界,好在中國的手機廠商聯合起來推出了快應用技術標準,如果各自爲戰,形成不了統一的標準,技術很難推廣,好在沒有哪家廠商壟斷手機市場,另外,快應用只用於安卓系統
華爲、小米、OPPO、VIVO、中興、金立、聯想、魅族、努比亞
四、快應用發展——年輕、不溫不火
2018年3月20日在北京推出“快應用”標準,對標騰訊小程序。
快應用最初是由小米公司最開始做的,那時候還不叫快應用,叫直達服務,那時候還是2016年,當時,小米只是爲了培養自己的系統也就是MIUI的移動互聯網應用生態,後來得到了大家的認可由九大廠商共同制定標準,並且取名快應用。
快應用在短短的一年內經歷了1010、1020、1030、1040、1050的版本迭代,但是就我個人開發經驗而言,每次都是常規升級,並沒有革命性升級,但是,卻越來越完善。
五、快應用開發技術棧——前端
1,HTML
2,CSS
3,JavaScript,文件以.ux結尾
4,和React、VUE一樣,採用數據驅動的方式渲染頁面,不直接操作DOM,MVVM模式,組件化開發、但是快應用並沒有類似於React的Redux一樣有一個全局的store,用於驅動相關的組件、頁面,快應用也有自己全局數據存儲區,但是,它僅僅只是存儲,不像Redux那樣富有靈魂。
5,一個安卓手機、同一個WiFi(USB方式就不需要同一個WiFi,但是需要數據線),Chrome瀏覽器(用於調試),即可。
六、快應用開發環境、工具
- 需安裝8.0以上版本的 NodeJS (建議使用 10.0+ 以上)
- hap-toolkit,npm可以下載,就一個工具包,幫助開發者通過命令行工具輔助開發工作的完成,主要包括創建模板工程,升級工程,編譯,調試等功能。
- 調試器,這是一個安卓應用(apk),用於開發階段調試,功能如下:
3.1、掃碼安裝快應用,配置 HTTP 服務器地址,下載 rpk 包,並喚起平臺運行 rpk 包
3.2、本地安裝快應用:選擇手機文件系統中的rpk包,並喚起平臺運行rpk包
3.3、在線更新快應用:重新發送 HTTP 請求,更新 rpk 包,並喚起平臺運行 rpk 包
3.4、開始調試快應用:喚起平臺運行 rpk 包,並啓動遠程調試
七、快應用工程化
1,因爲前面講了需要安裝Node,可以猜到,快應用也採用了npm安裝包裹的方式,需要什麼包,直接用npm install即可,但是快應用目前生態、社區並不豐富,所以幾乎也沒什麼可下的。
2,前面講了安裝hap-toolkit,它提供了一個叫做hap的命令,下面介紹一下幾個常用的命令,其實命令很少,總共也沒幾個:
2.1、hap init demo:初始化工程;
2.2、npm install:安裝模塊都在node_modules裏,這和普通前端開發是一樣的;
2.3、hap build:手動編譯項目,編譯打包成功後,項目根目錄下會生成文件夾:build、dist
build:臨時產出,包含編譯後的頁面 js,圖片等
dist:最終產出,包含 rpk 文件。其實是將 build 目錄下的資源打包壓縮爲一個文件,後綴名爲rpk,這個rpk文件就是項目編譯後的最終產出
2.4、hap watch:自動編譯項目,每次修改源代碼,你都想重新編譯生成新的rpk安裝包
2.5、hap server --port 8080,啓動一個HTTP服務器,作用是調試,我們在講調試器的時候列舉了1,2,3,4等等,開啓這個服務器就是爲了掃碼安裝、在線更新快應用,調試
2.6、hap debug
2.7、hap release
八、目錄結構,重點文件的講解
前面不是講了初始化工程 hap init projectName的命令麼,那麼這個命令到底會生成什麼鬼哦?
├── sign rpk包簽名模塊
│ └── debug 調試環境
│ ├── certificate.pem 證書文件
│ └── private.pem 私鑰文件
├── src
│ ├── Common 公用的資源和組件文件
│ │ └── logo.png 應用圖標
│ ├── Demo 頁面目錄
│ | └── index.ux 頁面文件,可自定義頁面名稱
│ ├── app.ux APP文件,可引入公共腳本,暴露公共數據和方法等
│ └── manifest.json 項目配置文件,配置應用圖標、頁面路由等
└── package.json 定義項目需要的各種模塊及配置信息
1,package.json,這裏不想贅述,和React、vue常規前端的package.json是一樣的;
2,src/app.ux:整個快應用項目的入口文件,可以在這裏做工程的初始化工作;
3,src/manifest.json:工程配置文件,參加這裏 點我啊
4,src/common:可以將應用的圖片放這裏
九、快應用生命週期 —— 不細講
1,頁面的生命週期:onInit、onReady、onShow、onHide、onDestroy、onBackPress、onMenuPress
2,頁面的狀態:顯示、隱藏、銷燬
3,APP 的生命週期:onCreate、onDestroy
十、頁面樣式、佈局
1,盒模型:只支持border-box模式,
2,樣式設置:
<template>
<div class="tutorial-page">
<text style="color: #FF0000;">內聯樣式</text>
<text id="title">ID選擇器</text>
<text class="title">class選擇器</text>
<text>tag選擇器</text>
</div>
</template>
<style>
.tutorial-page {
flex-direction: column;
}
/* tag選擇器 */
text {
color: #0000FF;
}
/* class選擇器(推薦) */
.title {
color: #00FF00;
}
/* ID選擇器 */
#title {
color: #00A000;
}
/* 並列選擇 */
.title, #title {
font-weight: bold;
}
/* 後代選擇器 */
.tutorial-page text {
font-size: 42px;
}
/* 直接後代選擇器 */
.tutorial-page > text {
text-decoration: underline;
}
</style>
3,Flex佈局:就是前端常用的flex佈局,沒什麼不同,div標籤是最常用的flex容器,需要注意的是,text、a、span、label 組件爲文本容器組件,其它組件不能直接放置文本內容。
4,可以引入less、postcss等。
十一、快應用框架指令——參照VUE
for
<div class="tutorial-row" for="(personIndex, personItem) in list">
<text>{{personIndex}}.{{personItem.name}}</text>
</div>
show && if
1,當 if/elif 指令的值爲 false 時,節點會從頁面中移除,當 if/elif 指令值爲 true,組件會動態插入節點中;
2,當 show 指令的值爲 true 時,節點可見, 當其值爲 false 時,組件不可見,但節點仍會保留在頁面 DOM 結構中;
3,if/elif/else 節點必須是相鄰的兄弟節點
<template>
<div class="tutorial-page">
<text onclick="onClickShow">顯示隱藏:</text>
<text show="{{showVar}}">show: 渲染但控制是否顯示</text>
<text onclick="onClickCondition">條件指令:</text>
<text if="{{conditionVar === 1}}">if: if條件</text>
<text elif="{{conditionVar === 2}}">elif: elif條件</text>
<text else>else: 其餘</text>
</div>
</template>
<style lang="less">
.tutorial-page {
flex-direction: column;
}
</style>
<script>
export default {
private: {
showVar: true,
conditionVar: 1
},
onInit () {
this.$page.setTitleBar({ text: '指令if與指令show' })
},
onClickShow () {
this.showVar = !this.showVar
},
onClickCondition () {
this.conditionVar = ++this.conditionVar % 3
}
}
</script>
block:block 組件是表達邏輯區塊的組件,沒有對應的Native組件。可以使用實現更爲靈活的"列表/條件渲染",如在上使用 for 指令和 if 指令。
<template>
<div class="tutorial-page">
<text onclick="toggleCityList">點擊:控制是否顯示城市</text>
<div class="city" for="city in cities" if="{{showCityList === 1}}">
<text>城市:{{city.name}}</text>
<block if="{{city.showSpots}}" for="{{city.spots}}">
<text>景點:{{$item.name}}</text>
</block>
</div>
</div>
</template>
slot:插槽,類似於其他框架的內容分發,在快應用中也實現了一套內容分發的 API,我們可以使用 slot 組件作爲承載分發內容的出口。
十二、快應用組件
1,快應用是組件化開發的,頁面都是由各個組件組成,也有父組件、子組件的概念,組件之間傳遞數據等等俗的不能再俗的東西,這裏都有。
2,熟悉自定義組件的開發,瞭解父子組件之間的通信方式,如:props,data,broadcast(),$emit等。
3,組件的引入:快應用中是通過標籤引入組件,如下面代碼所示
<import name="XXX" src="url-path"></import>
4,組件通信:props:父 —> 子,子組件使用protected接收
5,組件通信:子 —> 父
父組件傳遞的數據本身就是對象,子組件直接修改對象中的屬性,父組件的值也會發生改變,不推薦這種;
子組件通過on()監控自定義事件的觸發;
子組件通過$emit()觸發在節點上綁定的自定義事件來執行父組件的方法;
6,組件通信:兄弟組件通信:emit()
十三、快應用路由
快應用的路由其實也很俗,和React之流用法上沒太大區別,無非也是push、back、replace這些人間煙火,但是快應用的路由的作用可是大的很,遠超過普通前端的路由。
1,導入模塊及使用
import router from '@system.router'
or
const router = require('@system.router')
router.push({
uri: '/about',
params: {
body: "message"
}
})
// open web page
router.push({
uri: 'http://www.example.com'
})
// install apk
router.push({
uri: 'internal://cache/example.apk'
})
// 打開另一個快應用
router.push({
uri: 'hap://app/com.example.quickapp/page?key=value'
})
// 打開wifi設置頁面
router.push({
uri: 'hap://settings/wlan_manager'
})
// replace
router.replace({
uri: '/test',
params: {
testId: '1'
}
})
// back
router.back()
// 清空所有歷史頁面記錄,僅保留當前頁面
router.clear()
十四、快應用的系統能力——五星
這個可以說是快應用相對於web頁面來說的一個王炸級的優勢,快應用因爲本質就是安卓,所以獲取系統功能猶如探囊取物,普通的web網頁想獲取系統功能可謂是困難重重,寸步難行,甚至不可能
- 震動
- 二維碼
- 傳感器
- 設備信息
- 電量信息
- 地理定位
- 聯繫人
- 錄音
- 藍牙
- WiFi
- 鬧鐘
- 系統音量
- 網絡狀態
- 。。。
以地理定位來說明它的用法
1,manifest.json中接口聲明
{ "name": "system.geolocation" }
2,導入模塊
import geolocation from '@system.geolocation'
3,示例
geolocation.getLocation({
success: function(data) {
console.log(
`handling success: longitude = ${data.longitude}, latitude = ${
data.latitude
}`
)
},
fail: function(data, code) {
console.log(`handling fail, code = ${code}`)
}
})