堅果派由堅果創(chuàng)建,團隊擁有 12 個華為 HDE,以及若干其他領(lǐng)域的三十余位萬粉博主運營。 團隊成員聚集在北京,上海,南京,深圳,廣州,寧夏等地,歡迎合作。
首先鋪墊兩個基礎(chǔ)知識:
1.為什么桌面卡片需要使用特殊機制來刷新?
主要有兩個原因:第一是 OpenHarmonyOS Api9 的桌面卡片出于降低系統(tǒng)能耗的目的,被限制了只有 5 秒的活動時間。超過 5 秒以后桌面卡片的相關(guān)進程會被強制銷毀,變成一個靜態(tài)的頁面。只有通過 router 機制、call 機制或者 message 機制拉起相關(guān)后臺,才能再次進行卡片內(nèi)容的刷新。
第二個原因是從實際的運行機制來說,桌面卡片實際上并不是應(yīng)用主體的一部分,而是歸屬于 OpenHarmony 系統(tǒng)中的桌面應(yīng)用所管理的一系列服務(wù),桌面卡片與其對應(yīng)的應(yīng)用主體之間相互隔離,只能使用專門的接口來進行數(shù)據(jù)交互與頁面管理。
每張卡片都有一個獨立的 LocalStorage 可以用來存儲頁面級變量,但同一個 LocalStorage 的數(shù)據(jù)只能在 UIAbility 內(nèi)部共享,對外隔離,UIAbility 無法直接訪問。
桌面卡片刷新機制的本質(zhì)就是通過專門的接口,改變特定桌面卡片的 LocalStorage 參數(shù)。以實現(xiàn)桌面卡片的 UI 更新。
2.router 機制、call 機制與 message 機制有什么不同?
這三個機制都可以用來刷新桌面卡片的,三種機制的數(shù)據(jù)都以 JSON 的格式進行配置,并使用**formBindingData.createFormBindingData()**函數(shù)構(gòu)建數(shù)據(jù)對象。
主要區(qū)別在于:
router 機制會直接打開應(yīng)用界面,效果有點像點擊桌面圖標。也可以帶參數(shù)打開應(yīng)用,直接進入應(yīng)用內(nèi)部的某個特定位置,或者觸發(fā)某項功能。
call 機制是不打開應(yīng)用界面,僅在后臺拉起應(yīng)用主體的 UIAbility,來執(zhí)行 UIAbility 內(nèi)部的相關(guān)代碼。call 機制不受 5 秒時長的限制,可以先實現(xiàn)復(fù)雜且費時的數(shù)據(jù)加載,再提供給桌面卡片進行刷新。
message 機制則不涉及到應(yīng)用的 UIAbility,只是拉起桌面卡片自己的 FormAbility,也可以刷新卡片,但仍然受 5 秒時長的限制,更適合輕量化的的實現(xiàn)卡片內(nèi)容的刷新。
接下來進入正式講解:
本案例使用 call 機制,通過拉起應(yīng)用主體的方式來刷新卡片內(nèi)容。
使用 call 機制刷新卡片的全流程主要分為 3 個階段:
1.通過卡片的 postCardAction 接口觸發(fā) call 事件 →
2.call 事件拉起應(yīng)用主體的后臺,進行數(shù)據(jù)準備,通過 updateForm 接口執(zhí)行刷新事件 →
3.卡片 page 頁面接收到數(shù)據(jù),更新卡片界面。
由于卡片與應(yīng)用主體是獨立運作的,并且一個應(yīng)用可能會有多個應(yīng)用卡片,應(yīng)用其實并不知到是哪個卡片觸發(fā)了 call 事件,所以我們需要把卡片 id 作為參數(shù)一起寫入接口,讓卡片的管理方能找到我們要刷新的卡片。
補全以后的全流程如下:
1.(卡片創(chuàng)建時)FormAbility 獲取卡片的 FormID,將其作為參數(shù)交給卡片頁面儲存 →
2.卡片頁面初始化自己的 FromID
3.(點擊刷新時)卡片通過 postCardAction 接口觸發(fā) call 事件,將卡片的 FormID 與要執(zhí)行的函數(shù)名 method 都作為參數(shù)提交,由系統(tǒng)啟動對應(yīng)應(yīng)用的 UIAbility→
4.UIAbility 啟動成功,通過預(yù)置的觸發(fā)器執(zhí)行 method 對應(yīng)的函數(shù),完成數(shù)據(jù)準備后通過 updateForm 接口將數(shù)據(jù)推送給卡片管理方 →
5.對應(yīng) FormID 的卡片檢測并同步到數(shù)據(jù)變動,完成頁面變更。
案例代碼:
1.卡片創(chuàng)建時 FormAbility 獲取 FormID,并交給卡片頁面
import formBindingData from '@ohos.app.form.formBindingData';
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want) {//創(chuàng)建卡片時產(chǎn)生的want中包含F(xiàn)ormID,需要再此處讀取出來同步給LocalStorage。
let formId = want.parameters["ohos.extra.param.key.form_identity"];
let dataObj1 = {
"formId": formId
};
let obj1 = formBindingData.createFormBindingData(dataObj1);
return obj1;
}
};
?
2.卡片頁面初始化自己的 FromID
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('formId') formId: string = '0';//在Form頁面中使用@LocalStorageProp來進行FromID變量的初始化
}
?
3.卡片通過 postCardAction 接口觸發(fā) call 事件,讓系統(tǒng)拉起應(yīng)用后臺的 pageAbility
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp ("formId") @Watch('firstFresh') formId:string='0'//此處使用一個watch裝飾器,在FormID初始化完成后實現(xiàn)第一次的數(shù)據(jù)刷新。
@LocalStorageProp('text')movieName: string = '加載中...';
@LocalStorageProp('imgName')imgName: string = 'imageName';
firstFresh(){
console.log('卡片初始化')
postCardAction(this, {
"action": 'call',
"abilityName": this.ABILITY_NAME,
"params": {
"method":"funA",
"formId":this.formId,
}
});
}
build() {
Column() {
Button('刷新')
.height('15%')
.onClick(() => {
postCardAction(this, {
"action": 'call',//call事件
"abilityName": 'EntryAbility',//指向目標應(yīng)用的Ability
"params": {
"method":"funA",//UIAbility中注冊的用于刷新卡片的事件
"formId":this.formId,//卡片自身的FormID
}
});
})
}
}
?
4.pageAbility 啟動,執(zhí)行對應(yīng)的函數(shù),完成數(shù)據(jù)準備后通過 updateForm 接口將數(shù)據(jù)推送給卡片管理方
(數(shù)據(jù)來源于對應(yīng)的 severless 服務(wù)器,為方便演示,severless 的安全機制設(shè)為了不做身份校驗即可訪問數(shù)據(jù)的形式)
注意:callee 監(jiān)聽事件必須要先申請"ohos.permission.KEEP_BACKGROUND_RUNNING"權(quán)限才能正常運行!??!
import UIAbility from '@ohos.app.ability.UIAbility';
import formBindingData from '@ohos.app.form.formBindingData';
import formProvider from '@ohos.app.form.formProvider';
import hilog from '@ohos.hilog';
import Window from '@ohos.window';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import {AGCCloudDB} from'../services/AGCCloudDB'
import {AGCStorageReference} from'../services/Storage'
import request from '@ohos.request';
import fs from '@ohos.file.fs';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {//如果觸發(fā)call事件時UIAbility未啟動,會先執(zhí)行onCreate再執(zhí)行監(jiān)聽事件。如果觸發(fā)Call事件時UIAbility已經(jīng)在運行中則直接執(zhí)行監(jiān)聽事件。
this.callee.on('funA',(str)=>{//監(jiān)聽器,檢測到對應(yīng)參數(shù)就執(zhí)行回調(diào)函數(shù)
let params = JSON.parse(str.readString())
if (params.formId != undefined) {
let formId = params.formId
const agcCloudDB = AGCCloudDB.instance(this.context)
agcCloudDB.init(this.context).then((res) => {
let CloudDB = new AGCStorageReference(this.context)
agcCloudDB.getMovie().then((allRecords) => {//從數(shù)據(jù)庫獲取數(shù)據(jù)組
let radomNumber = Math.floor(Math.random() * allRecords.length) CloudDB.getDownloadUrl(allRecords[radomNumber].movieName).then((url) => {//從數(shù)據(jù)組中隨機抽取一項,獲取對應(yīng)的圖片下載鏈接
let tempDir = this.context.getApplicationContext().tempDir;
let tmpFile = tempDir + '/file' + Date.now();
request.downloadFile(this.context, {//將圖片下載到本地,并得到本地的圖片地址
url: url, filePath: tmpFile
}).then((task) => {
task.on('complete', function callback() {
console.info('ArkTSCard download complete:' + tmpFile);
let file;
try {
file = fs.openSync(tmpFile);
} catch (e) {
console.error(`openSync failed: ${JSON.stringify(e)}`);
}
console.log(JSON.stringify(allRecords))
let formData = {//進行數(shù)據(jù)打包
"text": allRecords[radomNumber].movieName,
"imgName": allRecords[radomNumber].movieName,
'formImages': {},
} formData.formImages[allRecords[radomNumber].movieName]=file.fd//由于Image的刷新機制必須接受不同的值才能識別到image變化,因此movieName只能使用變量的形式寫入。
let formInfo = formBindingData.createFormBindingData(formData)//創(chuàng)建FormBindingData對象
formProvider.updateForm(formId, formInfo)
})//執(zhí)行updateForm事件,刷新指定卡片。
task.on('fail', function callBack(err) {//數(shù)據(jù)準備失敗時顯示的內(nèi)容
console.info('ArkTSCard download task failed. Cause:' + err);
let formInfo = formBindingData.createFormBindingData({
'text': '刷新失敗,請重試'
})
formProvider.updateForm(formId, formInfo)
})
})
return null
})
})
})
}
})
}
}
?
5.對應(yīng) FormID 的卡片收到新的數(shù)據(jù),完成頁面變更。
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp ("formId") @Watch('firstFresh') formId:string='0'
@LocalStorageProp('text')movieName: string = '加載中...';
@LocalStorageProp('imgName')imgName: string = 'imageName';
//LocalStorageProp檢測到text與imgName變量發(fā)生改變,單向同步最新的數(shù)據(jù),并觸發(fā)卡片頁面的文本與圖片刷新。
build() {
Column() {
Text(this.text)
.fontSize('12vp')
.textAlign(TextAlign.Center)
.width('100%')
.height('15%')
Row() {
Image('memory://' + this.imgName)//imgName變化以后image組件會自動尋找對應(yīng)的圖片進行加載
.width('50%')
.height('50%')
.margin('5%')
}.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
Button('刷新')
.height('15%')
.onClick(() => {
postCardAction(this, {
"action": 'call',
"abilityName": 'EntryAbility',
"params": {
"method":"funA",//UIAbility中注冊的用于刷新卡片的事件
"formId":this.formId,
}
});
})
}
.width('100%').height('100%')
.alignItems(HorizontalAlign.Center)
.padding('5%')
}
}
?
postCardAction 接口 call 事件的寫法如下:


updateForm 接口的寫法如下:

為了能讓大家更好的學(xué)習鴻蒙 (OpenHarmony) 開發(fā)技術(shù),這邊特意整理了《鴻蒙 (OpenHarmony)開發(fā)學(xué)習手冊》,希望對大家有所幫助:
《鴻蒙(Harmony OS)開發(fā)學(xué)習手冊》
入門必看:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.應(yīng)用開發(fā)導(dǎo)讀(ArKTS)
2.……

HarmonyOS概念:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.系統(tǒng)定義
2.技術(shù)框架
3.技術(shù)特性
4.系統(tǒng)安全

快速入門:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.基本概念
2.構(gòu)建第一個ArkTS應(yīng)用
3.…

開發(fā)基礎(chǔ)知識:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.應(yīng)用基礎(chǔ)知識
2.配置文件
3.應(yīng)用數(shù)據(jù)管理
4.應(yīng)用安全管理
5.應(yīng)用隱私保護
6.三方應(yīng)用調(diào)用管控機制
7.資源分類與訪問
8.學(xué)習ArkTS
9…

基于ArkTS 開發(fā):https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.Ability開發(fā)
2.UI開發(fā)
3.公共事件與通知
4.窗口管理
5.媒體
6.安全
7.網(wǎng)絡(luò)與鏈接
8.電話服務(wù)
9.數(shù)據(jù)管理
10.后臺任務(wù)(Background Task)管理
11.設(shè)備管理
12.設(shè)備使用信息統(tǒng)計
13.DFX
14.國際化開發(fā)
15.折疊屏系列
16………

審核編輯 黃宇
-
鴻蒙
+關(guān)注
關(guān)注
60文章
2963瀏覽量
45920 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2153瀏覽量
36071 -
OpenHarmony
+關(guān)注
關(guān)注
33文章
3952瀏覽量
21117
發(fā)布評論請先 登錄
TC275HSM能支持SecOC中的密鑰刷新機制嗎?
求大神分享一種基于bootloader的嵌入式軟件自動更新機制
#HarmonyOS征文#鴻蒙卡片-物聯(lián)網(wǎng)DTU污水液位計卡片
HarmonyOS卡片開發(fā)--服務(wù)卡片概述
HarmonyOS原子化服務(wù)開發(fā)實戰(zhàn)-卡片刷新圖片問題記錄
Android系統(tǒng)固件更新機制設(shè)計資料分享
求助,請問鴻蒙卡片如何去掉應(yīng)用的桌面圖標?
ArkTS語言HarmonyOS/OpenHarmony應(yīng)用開發(fā)-message事件刷新卡片內(nèi)容
HarmonyOS元服務(wù)開發(fā)實踐:桌面卡片字典
ADO_NET數(shù)據(jù)集更新機制及并發(fā)控制策略
嵌入式系統(tǒng)自更新機制的設(shè)計與應(yīng)用
適用動態(tài)存儲的自適應(yīng)刷新機制算法設(shè)計
B站添加鴻蒙服務(wù)卡片教程
【鴻蒙】桌面卡片開發(fā)教程:從底層原理開始講透call事件的刷新機制 “堅果派-咸魚”
評論