介紹
通過(guò)AbilityAccessCtrl動(dòng)態(tài)向用戶申請(qǐng)“允許不同設(shè)備間的數(shù)據(jù)交換”的權(quán)限,使用設(shè)備管理實(shí)例獲取周邊不可信設(shè)備列表。
說(shuō)明: 查詢周邊不可信設(shè)備之前,請(qǐng)確保本設(shè)備與周邊設(shè)備未進(jìn)行配對(duì)。如果已配對(duì),則恢復(fù)出廠設(shè)置之后重新查詢。
相關(guān)概念
- [訪問(wèn)控制權(quán)限申請(qǐng)]:應(yīng)用的APL(Ability Privilege Level)等級(jí)分為normal、system_basic和system_core三個(gè)等級(jí),默認(rèn)情況下,應(yīng)用的APL等級(jí)都為normal等級(jí)。權(quán)限類型分為system_grant和user_grant兩種類型。應(yīng)用可申請(qǐng)的權(quán)限項(xiàng)參見(jiàn)應(yīng)用權(quán)限列表。
- [權(quán)限類型說(shuō)明]:根據(jù)授權(quán)方式的不同,權(quán)限類型可分為system_grant(系統(tǒng)授權(quán))和user_grant(用戶授權(quán))。
- [應(yīng)用ALP等級(jí)說(shuō)明]:元能力權(quán)限等級(jí)APL(Ability Privilege Level)指的是應(yīng)用的權(quán)限申請(qǐng)優(yōu)先級(jí)的定義,不同APL等級(jí)的應(yīng)用能夠申請(qǐng)的權(quán)限等級(jí)不同。
- [應(yīng)用權(quán)限列表]:在申請(qǐng)目標(biāo)權(quán)限前,建議開(kāi)發(fā)者先閱讀訪問(wèn)控制開(kāi)發(fā)概述-權(quán)限的工作流程。對(duì)權(quán)限的工作流程有基本的了解后,再結(jié)合以下權(quán)限的具體說(shuō)明,判斷應(yīng)用能否申請(qǐng)目標(biāo)權(quán)限,提高開(kāi)發(fā)效率。
- [設(shè)備管理實(shí)例]:用于獲取可信設(shè)備和本地設(shè)備的相關(guān)信息。在調(diào)用DeviceManager的方法前,需要先通過(guò)createDeviceManager構(gòu)建一個(gè)DeviceManager實(shí)例dmInstance。
約束與限制
通過(guò)DevEco Studio自動(dòng)下載的SDK均為public版本,public-SDK不支持開(kāi)發(fā)者使用系統(tǒng)API。本篇Codelab使用的DeviceManager(設(shè)備管理實(shí)例)依賴于系統(tǒng)API,需下載full-SDK并替換工具自動(dòng)下載的public-SDK。
相關(guān)權(quán)限
本篇Codelab需要在配置文件module.json5里添加允許不同設(shè)備間的數(shù)據(jù)交換權(quán)限:ohos.permission.DISTRIBUTED_DATASYNC。
環(huán)境搭建
軟件要求
- [DevEco Studio]版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
硬件要求
- 開(kāi)發(fā)板類型:[潤(rùn)和RK3568開(kāi)發(fā)板]。
- OpenHarmony系統(tǒng):3.2 Release。
環(huán)境搭建
完成本篇Codelab我們首先要完成開(kāi)發(fā)環(huán)境的搭建,本示例以RK3568開(kāi)發(fā)板為例,參照以下步驟進(jìn)行:
- [獲取OpenHarmony系統(tǒng)版本]:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)。以3.2 Release版本為例:
- 搭建燒錄環(huán)境。
- [完成DevEco Device Tool的安裝]
- [完成RK3568開(kāi)發(fā)板的燒錄](méi)
- 搭建開(kāi)發(fā)環(huán)境。
代碼結(jié)構(gòu)解讀
本篇Codelab只對(duì)核心代碼進(jìn)行講解,對(duì)于完整代碼,我們會(huì)在gitee中提供。
├──entry/src/main/ets // 代碼區(qū)
│ ├──common
│ │ ├──constants
│ │ │ └──CommonConstants.ets // 公共常量類
│ │ └──util
│ │ ├──DeviceListUtil.ets // 設(shè)備查詢工具類
│ │ ├──Logger.ets // 日志管理工具類
│ │ └──PermissionUtil.ets // 權(quán)限申請(qǐng)工具類
│ ├──entryability
│ │ └──EntryAbility.ts // 程序入口類
│ ├──pages
│ │ └──HomePage.ets // 主頁(yè)面
│ └──view
│ ├──DeviceBean.ets // 設(shè)備信息類
│ ├──DeviceItem.ets // 設(shè)備信息對(duì)象
│ ├──DeviceListDialog.ets // 設(shè)備列表展示彈框
│ └──NoPermissionDialog.ets // 無(wú)權(quán)限彈框
└──entry/src/main/resource // 應(yīng)用靜態(tài)資源目錄
頁(yè)面設(shè)計(jì)
頁(yè)面分為授權(quán)圖片、授權(quán)說(shuō)明、查詢內(nèi)網(wǎng)設(shè)備按鈕三部分,效果如圖所示:
// HomePage.ets
struct HomePage {
@State authorizedImage: Resource = $r('app.media.ic_unauthorized');
@State permissionDescribe: Resource = $r('app.string.no_permission');
noPermissionDialog: CustomDialogController = new CustomDialogController({
builder: NoPermissionDialog(),
autoCancel: false,
alignment: DialogAlignment.Bottom,
offset: {
dx: CommonConstants.DIALOG_OFFSET_X,
dy: CommonConstants.DIALOG_OFFSET_Y
}
});
deviceListDialog: CustomDialogController = new CustomDialogController({
builder: DeviceListDialog(),
autoCancel: false,
alignment: DialogAlignment.Bottom,
offset: {
dx: CommonConstants.DIALOG_OFFSET_X,
dy: CommonConstants.DIALOG_OFFSET_Y
}
})
...
build() {
Column() {
Image(this.authorizedImage)
...
Text(this.permissionDescribe)
...
Column() {
Button($r('app.string.button_text'), { type: ButtonType.Capsule, stateEffect: true })
...
}
...
}
...
}
}
授權(quán)狀態(tài)為未授權(quán)時(shí),點(diǎn)擊查詢內(nèi)網(wǎng)設(shè)備按鈕打開(kāi)未申請(qǐng)權(quán)限提示的彈框,效果如圖所示:
// NoPermissionDialog.ets
@CustomDialog
export struct NoPermissionDialog {
controller: CustomDialogController;
build() {
Column() {
Text($r('app.string.no_permission_title'))
...
Text($r('app.string.clear_permission'))
...
Text($r('app.string.dialog_confirm'))
...
.onClick(() = > {
this.controller.close();
})
}
...
}
}
授權(quán)狀態(tài)為已授權(quán)時(shí),點(diǎn)擊查詢內(nèi)網(wǎng)設(shè)備按鈕打開(kāi)設(shè)備查詢列表彈框,效果如圖所示:
// DeviceListDialog.ets
@CustomDialog
export struct DeviceListDialog {
private deviceListUtil: DeviceListUtil = new DeviceListUtil();
@State deviceList: Array< DeviceBean > = [];
controller: CustomDialogController;
...
build() {
Column() {
Text($r('app.string.device_list'))
...
Column() {
if (this.deviceList.length === 0) {
Text($r('app.string.no_device'))
...
} else {
Column() {
List() {
ForEach(this.deviceList, (item: DeviceBean, index: number) = > {
ListItem() {
DeviceItem({item: item, index: index});
}
}, (item: DeviceBean) = > JSON.stringify(item))
}
}
...
}
}
...
Text($r('app.string.dialog_confirm'))
...
.onClick(() = > {
this.deviceListUtil.stopDeviceDiscovery();
this.controller.close();
})
}
...
}
}
權(quán)限申請(qǐng)
首次進(jìn)入主頁(yè)面彈出授權(quán)彈框,點(diǎn)擊禁止按鈕不會(huì)授權(quán),點(diǎn)擊允許按鈕進(jìn)行授權(quán),再次進(jìn)入首頁(yè)不會(huì)出現(xiàn)授權(quán)彈框。
// HomePage.ets
struct HomePage {
...
async aboutToAppear() {
let result = await PermissionUtil.applyPermission();
if (result === 0) {
this.permissionDescribe = $r('app.string.has_permission');
this.authorizedImage = $r('app.media.ic_authorized');
} else {
this.permissionDescribe = $r('app.string.no_permission');
}
}
...
}
// PermissionUtil.ets
async applyPermission() {
let atManager = abilityAccessCtrl.createAtManager();
let data = await atManager.requestPermissionsFromUser(getContext(this), [CommonConstants.PERMISSION]);
let grantStatus: Array< number > = data.authResults;
let length: number = grantStatus.length;
if (length === 0) {
return 1;
}
return grantStatus[0];
}
主頁(yè)面點(diǎn)擊查詢內(nèi)網(wǎng)設(shè)備按鈕時(shí),先查詢是否授權(quán),根據(jù)授權(quán)狀態(tài)打開(kāi)對(duì)應(yīng)的彈框(未授權(quán):打開(kāi)未授權(quán)彈框;已授權(quán):打開(kāi)設(shè)備查詢列表彈框)。
// HomePage.ets
struct HomePage {
...
build() {
Column() {
...
Column() {
Button($r('app.string.button_text'), { type: ButtonType.Capsule, stateEffect: true })
...
.onClick(async () = > {
let result = await PermissionUtil.checkPermission();
if(result === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
this.deviceListDialog.open();
} else {
this.noPermissionDialog.open();
}
})
}
...
}
...
}
}
// PermissionUtil.ets
async checkPermission() {
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
let tokenId: number = 0;
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) {
Logger.error(TAG, 'getBundleInfoForSelf failed, code is ${err.code}, message is ${err.message}');
}
try {
grantStatus = await atManager.checkAccessToken(tokenId, CommonConstants.PERMISSION);
} catch (err) {
Logger.error(TAG, 'checkAccessToken failed, code is ${err.code}, message is ${err.message}');
}
return grantStatus;
}
設(shè)備查詢
先創(chuàng)建dmInstance實(shí)例,再注冊(cè)發(fā)現(xiàn)設(shè)備(deviceFoundOn)的回調(diào)方法,最后調(diào)用startDeviceDiscovery方法查詢周邊設(shè)備;當(dāng)查詢到設(shè)備之后調(diào)用deviceFoundOn方法處理設(shè)備信息。
//DeviceListDialog.ets
export struct DeviceListDialog {
...
aboutToAppear() {
this.deviceListUtil.initDmInstance((data: DeviceInfoInterface) = > {
...
});
}
...
}
// DeviceListUtil.ets
// 創(chuàng)建dmInstance實(shí)例
initDmInstance(dealDeviceInfo: Function) {
this.dealDeviceInfo = dealDeviceInfo;
try {
deviceManager.createDeviceManager(getContext(this).applicationInfo.name, (err, data) = > {
if (err) {
Logger.error(TAG, 'createDeviceManager errCode:' + err.code + ',errMessage:' + err.message);
return;
}
this.dmInstance = data;
this.deviceFoundOn();
this.startDeviceDiscovery();
});
} catch (err) {
Logger.error(TAG, 'createDeviceManager err=' + JSON.stringify(err));
}
}
// DeviceListUtil.ets
// 注冊(cè)發(fā)現(xiàn)設(shè)備回調(diào)方法
deviceFoundOn() {
try {
if (this.dmInstance !== undefined) {
this.dmInstance.on('deviceFound', (data) = > {
if (this.dealDeviceInfo !== undefined) {
this.dealDeviceInfo(data);
}
});
}
} catch (err) {
Logger.error(TAG, 'deviceFoundOn err:' + JSON.stringify(err));
}
}
// DeviceListUtil.ets
// 發(fā)現(xiàn)周邊設(shè)備方法
startDeviceDiscovery() {
this.subscribeId = Math.floor(Math.random() * CommonConstants.RANDOM_ONE + CommonConstants.RANDOM_TWO);
let subscribeInfo: SubscribeInfoInterface = {
subscribeId: this.subscribeId,
mode: CommonConstants.MODE,
medium: 0,
freq: CommonConstants.FREQ,
isSameAccount: false,
isWakeRemote: true,
capability: 1
};
try {
if (this.dmInstance !== undefined) {
this.dmInstance.startDeviceDiscovery(subscribeInfo);
}
} catch (err) {
Logger.error(TAG, 'startDeviceDiscovery err:' + JSON.stringify(err));
}
}
審核編輯 黃宇
-
鴻蒙
+關(guān)注
關(guān)注
57文章
2397瀏覽量
43098 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1983瀏覽量
30640 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3753瀏覽量
16669
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
如何縮短Vivado的運(yùn)行時(shí)間
![如何縮短Vivado的<b class='flag-5'>運(yùn)行時(shí)</b>間](https://file.elecfans.com/web1/M00/94/F1/pIYBAFzuKWmACRntAAAPzPfTtK4564.png)
在運(yùn)行時(shí)添加100個(gè)項(xiàng)目
HarmonyOS應(yīng)用開(kāi)發(fā)-應(yīng)用權(quán)限安全
如何TouchGFX運(yùn)行時(shí)添加小部件、行等?
運(yùn)行時(shí)軟件故障注入器的設(shè)計(jì)與實(shí)現(xiàn)
FPGA運(yùn)行時(shí)重構(gòu)的延遲隱藏機(jī)制研究與實(shí)現(xiàn)
紫金橋組態(tài)軟件新的功能_運(yùn)行時(shí)組態(tài)
![紫金橋組態(tài)軟件新的功能_<b class='flag-5'>運(yùn)行時(shí)</b>組態(tài)](https://file.elecfans.com/web2/M00/4A/04/pYYBAGKhvImAf6BOAAAwEeaeZnk806.png)
華為開(kāi)發(fā)者分論壇HarmonyOS學(xué)生公開(kāi)課-OpenHarmony Codelabs開(kāi)發(fā)案例
![華為<b class='flag-5'>開(kāi)發(fā)</b>者分論壇<b class='flag-5'>HarmonyOS</b>學(xué)生公開(kāi)課-OpenHarmony Codelabs<b class='flag-5'>開(kāi)發(fā)案</b>例](https://file.elecfans.com/web2/M00/19/8E/pYYBAGF00USAR-78AAD-2dnL6jM191.jpg)
如何高效測(cè)量ECU的運(yùn)行時(shí)間
Go運(yùn)行時(shí):4年之后
什么是Kubernetes容器運(yùn)行時(shí)CRI
![什么是Kubernetes容器<b class='flag-5'>運(yùn)行時(shí)</b>CRI](https://file.elecfans.com/web2/M00/92/8F/poYBAGPzLaGAL_oFAAB-zswhwHk864.jpg)
ch32v307記錄程序運(yùn)行時(shí)間
Xilinx運(yùn)行時(shí)(XRT)發(fā)行說(shuō)明
![Xilinx<b class='flag-5'>運(yùn)行時(shí)</b>(XRT)發(fā)行說(shuō)明](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評(píng)論