01、什么是分布式數據對象
在可信組網環境下,多個相互組網認證的設備將各自創建的對象加入同一個 sessionId,使得加入的多個數據對象之間可以同步數據,也就是說,當某一數據對象屬性發生變更時,其他數據對象會檢測到這一變更,同時將自身屬性更新。此時,該 sessionId 下的所有數據對象屬性相同,這樣的數據對象稱之為分布式數據對象。此外,分布式數據對象可以被動退出 sessionId,當分布式數據對象退出 sessionId 后,該對象將檢測不到其他對象的變更。
02、分布式數據對象能力
1、 分布式數據對象創建
2、 分布式數據對象查詢
3、 分布式數據對象修改
4、 分布式數據對象刪除
5、 分布式數據對象保存
6、 分布式數據對象訂閱(數據變更,上下線)
7、分布式數據對象加入、退出分布式組網
03、前提準備
1、 開發工具:DevEco Studio 3.1.0.501
2、API:9
3、 SDK 版本:3.2.12.5
04、創建一個新的項目
新建項目,選擇 API9 版本,stage 模型。
05、權限申請
1、 使用到的權限
○ ohos.permission.DISTRIBUTED_DATASYNC
○ 允許不同設備間的數據交換
○ 權限級別:normal
○ 授權方式:user_grant
○ ACL 使能:TRUE
2、配置文件申明
首先,在項目的模塊級目錄下找到并打開 module.json5 文件,如下圖:
在 module 下的對象里添加如下申明:
此時,配置文件中的權限申明就完成了,但是,此時我們還不能獲得這些權限。由于 ohos.permission.DISTRIBUTED_DATASYNC 權限是 ACL 使能為 TRUE 的權限,需要在簽名工具文件中說明一下。
如何找到對應的簽名工具文件呢?我們在安裝 DevEco Studio 的時候是下載好了 OpenHarmony 的 SDK 的,此時在 OpenHarmony 文件夾中,打開 “Sdk\OpenHarmony SDK 版本\toolchains\lib” 該路徑,此時在 lib 文件夾中,咱們可以找到兩個 json 文件,分別為 UnsgnedDebugProfileTemplate.json 和 UnsgnedReleasedProfileTemplate.json,點擊并打開這兩個文件,添加如下權限:
3、權限申請編碼
在申請 ohos.permission.DISTRIBUTED_DATASYNC 權限時,其文檔中將其標注為用戶手動授權的權限,此時需要我們動態申請權限,在項目中,我們新建一個 ets 文件,我這里取名為 RequestPermission.ets。
首先,導入以下包:
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
import common from '@ohos.app.ability.common';
獲取訪問控制模塊對象實例:
let atManager = abilityAccessCtrl.createAtManager();
編寫如下方法(這里使用的是異步函數):
export async function checkAccessTokenID(permission: Array<Permissions>) {// 獲取應用程序的accessTokenIDlet tokenId: number;let grantStatus: Array<abilityAccessCtrl.GrantStatus> = []try {let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;tokenId = appInfo.accessTokenId;} catch (err) {console.error(`getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}`);}// 校驗應用是否被授予權限,若申請多個權限,建議循環檢查多個權限for (let index = 0;index < permission.length; index++) {try {grantStatus.push(await atManager.checkAccessToken(tokenId, permission[index]))} catch (err) {console.error(`checkAccessToken failed, code is ${err.code}, message is ${err.message}`);}}return grantStatus;
}export async function checkPermission(context: common.UIAbilityContext, permissions: Array<Permissions>) {let grantStatus: Array<abilityAccessCtrl.GrantStatus> = await checkAccessTokenID(permissions)for (let i = 0; i < grantStatus.length; i++) {if (grantStatus[i] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {console.info(`${permissions[i].toString()} 已授權`)} else {//申請權限console.info('開始向用戶申請權限')requestPermissionFromUser(context, permissions)}}
}
export async function requestPermissionFromUser(context: common.UIAbilityContext, permissions: Array<Permissions>) {// requestPermissionsFromUser會判斷權限的授權狀態來決定是否喚起彈窗atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResultslet length: number = grantStatus.lengthfor (let i = 0;i < length; i++) {if (grantStatus[i] === 0) {// 用戶授權,可以繼續訪問目標操作console.info(`${permissions[i].toString()} 權限申請成功`)} else {// 用戶拒絕授權,提示用戶必須授權才能訪問當前頁面的功能,并引導用戶到系統設置中打開相應的權限console.info(`${permissions[i].toString()} 權限申請被用戶拒絕`)}}// 授權成功})
}
此時,我們申請權限的方法就算編寫完成了,在應用入口,即 EntryAbility.ts 文件中的
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam)
方法中回調權限申請函數:
requestPermissionFromUser(this.context, PERMISSIONS)
其中,PERMISSIONS 定義如下:const PERMISSIONS:Array=[‘ohos.permission.DISTRIBUTED_DATASYNC’]
到此,我們的權限申請就算完完全全完成啦,當用戶第一次安裝并打開應用的時候,應用會向用戶通過彈窗形式申請權限,用戶點擊授權即可賦予應用相應的權限啦~
06、上手分布式數據對象代碼開發
登錄了同一華為帳號的 HarmonyOS 設備已經默認了進行了組網認證,所以在進行分布式數據對象開發之前無需再進行多設備組網認證這一階段的開發,開發變得相對簡單了起來。首先,咱們制作一個簡易 UI 界面(UI 界面僅供參考),如下圖所示:
相信對于有 HarmonyOS 開發經驗的小伙伴們來說這樣的 UI 界面制作并不困難,其中紅色圓點、綠色圓點為設備狀態,當設備狀態發生改變如下線時,顏色變為紅色,UI 界面代碼如下:
import router from '@ohos.router'
import { DistributedDeviceManageFunc } from '../modules/DistributedDeviceManager/DistributedDeviceManagerFunctions'
import DistributedObjectFunc from '../modules/DistributedObject/DistributedObjectFunctions'
import { ContinuationDeviceManagerDialog } from '../view/ContinuationDeviceManagerDialog'
import { DistributedDeviceManagerDialog } from '../view/DistributedDeviceManagerDialog'AppStorage.SetOrCreate('distributedDeviceList', [])
AppStorage.SetOrCreate('message', '分布式數據對象Demo測試')
AppStorage.SetOrCreate('statusColor', '#ff4fc100')
AppStorage.SetOrCreate('distributedColor', '#ffff0000')@Entry
@Component
struct DistributedObjectDemo {@StorageLink('message') message: string = ''@StorageLink('statusColor') statusColor: string = ''@StorageLink('distributedColor') distributedColor: string = ''@StorageLink('distributedObj') distributedObj: DistributedObjectFunc = new DistributedObjectFunc()@BuildernavigationTitle() {Row({ space: '10vp' }) {Button({ type: ButtonType.Normal }) {Image($rawfile('ic_public_back.svg')).size({width: '24vp',height: '24vp'})}.width('36vp').height('36vp').backgroundColor(Color.White).borderRadius('10vp').onClick(() => {DistributedDeviceManageFunc.release()router.back()})Text('分布式數據對象測試').fontWeight(FontWeight.Bold).fontSize('20vp')Blank()Button({ type: ButtonType.Normal }) {Image($rawfile('ic_public_connection_filled.svg')).size({width: '24vp',height: '24vp'})}.width('36vp').height('36vp').backgroundColor(Color.White).borderRadius('10vp').onClick(() => {this.distributedDeviceManagerDialogController.open()})}.padding('5vp').width('90%')}build() {Navigation() {Column({ space: '20vp' }) {Row({ space: '20vp' }) {Text(`設備狀態`).fontSize('20vp').fontWeight(FontWeight.Bold)Circle().width('25vp').height('25vp').fill(this.statusColor)}Row({ space: '20vp' }) {Text(`對端設備狀態`).fontSize('20vp').fontWeight(FontWeight.Bold)Circle().width('25vp').height('25vp').fill(this.distributedColor)}Text(`SessionID:${this.distributedObj.getSessionId()}`).fontSize('20vp').fontWeight(FontWeight.Bold)Text(this.message).fontSize('20vp').fontWeight(FontWeight.Bold).maxLines(2)Button('保存分布式數據對象').buttonStyles().onClick(() => {this.distributedObj.saveDistributedObject()})Button('修改分布式數據對象').buttonStyles().onClick(() => {this.distributedObj.updateDistributedObject()})Button('退出組網').buttonStyles().onClick(() => {this.distributedObj.exit()router.back()})}.width('100%')}.width('100%').height('100%').mode(NavigationMode.Auto).titleMode(NavigationTitleMode.Mini).hideBackButton(true).title(this.navigationTitle())}
}@Extend(Button) function buttonStyles() {.fontSize('20vp').width('60%').height('50vp')
}
現在,我們的頁面制作就完成啦,下面開始重頭戲——分布式數據對象開發流程
1、導入模塊
import distributedObject from '@ohos.data.distributedDataObject'
2、初始化 distributedObject. DataObject 對象
定義一個 distributedObject. DataObject 類型的變量。
mDistributedObject: distributedObject.DataObject
調用 distributedObject. Create()函數創建一個 distributedObject. DataObject 對象,并將其返回給定義的變量 mDistributedObject。
this.mDistributedObject = distributedObject.create(globalThis.context, {name: 'jack',age: 18,isVis: false
})
在 create()方法中存在兩個參數,context 和 resource,context 的類型為 Context,resource 類型為 object,在這里我是在 entryAbility.ts 文件下的 onWindowStageCreate()方法里面定義了一個全局變量 globalThis.context。
globalThis.context = this.context
3、設置組網 sessionId
this.mDistributedObject.setSessionId(this.mSessionId)
在 setSessionId()函數中,參數 sessionId 為 string 類型,表示分布式對象組網唯一標識符,設置同步的 sessionId,當可信組網中有多個設備時,多個設備間的對象如果設置為同一個 sessionId,就能自動同步。
4、開啟設備狀態監聽
globalThis.statusCallback = (sessionId: string, networkId: string, status: string) => {AppStorage.Set('message', `組網設備狀況變更,id:${sessionId} status:${status} networkId:${networkId}`)if (status == 'online') {AppStorage.Set('distributedColor', '#ff4fc100')} else if (status == 'offline') {AppStorage.Set('distributedColor', '#ffff0000')}
}
this.mDistributedObject.on("status", globalThis.statusCallback)
(sessionId: string, networkId: string, status: string)為 callback 回調函數返回的值,我們可以使用這些返回值判斷設備上下線狀態,其中 status 參數返回值為 online 或者 offline,表示設備對端設備上下線。
5、開啟分布式數據對象同步監聽
globalThis.changeCallback = (sessionId: string, fields: Array<string>) => {console.info('分布式數據對象發生變化')if (fields != null && fields != undefined) {AppStorage.Set('message', `data change:${fields} sessionId:${sessionId}`)}
}
this.mDistributedObject.on("change", globalThis.changeCallback)
當同一組網內分布式數據對象發生改變時,同一組網中的所有分布式數據對象同步發生變化,變化后的值為某一分布式數據對象改變后的值(sessionId: string, fields: Array)為 callback 回調函數返回值,其中,sessionId 為組網唯一標識符,field 為分布式數據對象的數據變更列表。
此時此刻,分布式數據對象就基本上開發完成啦。
如果有小伙伴想要修改分布式數據對象的屬性,可以直接修改
// @ts-ignore
this.mDistributedObject.name = 'lucy'
// @ts-ignore
this.mDistributedObject.age = 25
注意:根據當前版本 IDE 的編碼插件情況,不能直接寫 this.mDistributedObject.age = 25,此時咱們需要加上// @ts-ignore 就可以啦。
最后,使用完分布式數據對象后大家要記得釋放資源哦(注銷所有監聽,退出組網 sessionId,將分布式數據對象設置為空值)
this.mDistributedObject.off("change")
this.mDistributedObject.off("status")
this.mDistributedObject.setSessionId()
this.mDistributedObject = null
this.mSessionId = null
如果有小伙伴有兩部或兩部以上的華為設備,可以將程序燒錄到設備中,體驗一下分布式數據對象能力的快樂~
為了能讓大家更好的學習鴻蒙 (Harmony OS) 開發技術,這邊特意整理了《鴻蒙 (Harmony OS)開發學習手冊》(共計890頁),希望對大家有所幫助:https://qr21.cn/FV7h05
《鴻蒙 (Harmony OS)開發學習手冊》
入門必看:https://qr21.cn/FV7h05
- 應用開發導讀(ArkTS)
- 應用開發導讀(Java)
HarmonyOS 概念:https://qr21.cn/FV7h05
- 系統定義
- 技術架構
- 技術特性
- 系統安全
如何快速入門:https://qr21.cn/FV7h05
- 基本概念
- 構建第一個ArkTS應用
- 構建第一個JS應用
- ……
開發基礎知識:https://qr21.cn/FV7h05
- 應用基礎知識
- 配置文件
- 應用數據管理
- 應用安全管理
- 應用隱私保護
- 三方應用調用管控機制
- 資源分類與訪問
- 學習ArkTS語言
- ……
基于ArkTS 開發:https://qr21.cn/FV7h05
- Ability開發
- UI開發
- 公共事件與通知
- 窗口管理
- 媒體
- 安全
- 網絡與鏈接
- 電話服務
- 數據管理
- 后臺任務(Background Task)管理
- 設備管理
- 設備使用信息統計
- DFX
- 國際化開發
- 折疊屏系列
- ……