ServiceExtensionAbility
概述
[ServiceExtensionAbility]是SERVICE類型的ExtensionAbility組件,提供后臺服務能力,其內部持有了一個[ServiceExtensionContext],通過[ServiceExtensionContext]提供了豐富的接口供外部使用。
本文描述中稱被啟動的ServiceExtensionAbility為服務端,稱啟動ServiceExtensionAbility的組件為客戶端。
[ServiceExtensionAbility]可以被其他組件啟動或連接,并根據調用者的請求信息在后臺處理相關事務。[ServiceExtensionAbility]支持以啟動和連接兩種形式運行,系統應用可以調用[startServiceExtensionAbility()]方法啟動后臺服務,也可以調用[connectServiceExtensionAbility()]方法連接后臺服務,而三方應用只能調用[connectServiceExtensionAbility()]方法連接后臺服務。啟動和連接后臺服務的差別:
- 啟動 :AbilityA啟動ServiceB,啟動后AbilityA和ServiceB為弱關聯,AbilityA退出后,ServiceB可以繼續存在。
- 連接 :AbilityA連接ServiceB,連接后AbilityA和ServiceB為強關聯,AbilityA退出后,ServiceB也一起退出。
此處有如下細節需要注意:
- 若Service只通過connect的方式被拉起,那么該Service的生命周期將受客戶端控制,當客戶端調用一次[connectServiceExtensionAbility()]方法,將建立一個連接,當客戶端退出或者調用[disconnectServiceExtensionAbility()]方法,該連接將斷開。當所有連接都斷開后,Service將自動退出。
- Service一旦通過start的方式被拉起,將不會自動退出,系統應用可以調用[stopServiceExtensionAbility()]方法將Service退出。
- 只能在主線程線程中執行connect/disconnect操作,不要在Worker、TaskPool等子線程中執行connect/disconnect操作。
說明:
開發前請熟悉鴻蒙開發指導文檔 :gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
點擊或者復制轉到。
- 當前不支持三方應用實現ServiceExtensionAbility。如果三方開發者想要實現后臺處理相關事務的功能,可以使用后臺任務,具體請參見[后臺任務]。
- 三方應用的UIAbility組件可以通過Context連接系統提供的ServiceExtensionAbility。
- 三方應用需要在前臺獲焦的情況下才能連接系統提供的ServiceExtensionAbility。
生命周期
[ServiceExtensionAbility]提供了onCreate()、onRequest()、onConnect()、onDisconnect()和onDestroy()生命周期回調,根據需要重寫對應的回調方法。下圖展示了ServiceExtensionAbility的生命周期。
圖1 ServiceExtensionAbility生命周期
- onCreate 服務被首次創建時觸發該回調,開發者可以在此進行一些初始化的操作,例如注冊公共事件監聽等。
說明: 如果服務已創建,再次啟動該ServiceExtensionAbility不會觸發onCreate()回調。
- onRequest 當另一個組件調用[startServiceExtensionAbility()]方法啟動該服務組件時,觸發該回調。執行此方法后,服務會啟動并在后臺運行。每調用一次[startServiceExtensionAbility()]方法均會觸發該回調。
- onConnect 當另一個組件調用[connectServiceExtensionAbility()]方法與該服務連接時,觸發該回調。開發者在此方法中,返回一個遠端代理對象(IRemoteObject),客戶端拿到這個對象后可以通過這個對象與服務端進行RPC通信,同時系統側也會將該遠端代理對象(IRemoteObject)儲存。后續若有組件再調用[connectServiceExtensionAbility()]方法,系統側會直接將所保存的遠端代理對象(IRemoteObject)返回,而不再觸發該回調。
- onDisconnect 當最后一個連接斷開時,將觸發該回調。客戶端死亡或者調用[disconnectServiceExtensionAbility()]方法可以使連接斷開。
- onDestroy 當不再使用服務且準備將其銷毀該實例時,觸發該回調。開發者可以在該回調中清理資源,如注銷監聽等。
實現一個后臺服務(僅對系統應用開放)
開發準備
只有系統應用才允許實現ServiceExtensionAbility,因此開發者在開發之前需做如下準備:
- 替換Full SDK :ServiceExtensionAbility相關接口都被標記為System-API,默認對開發者隱藏,因此需要手動從鏡像站點獲取Full SDK,并在DevEco Studio中替換,具體操作可參考[替換指南]。
- 申請AllowAppUsePrivilegeExtension特權 :只有具有AllowAppUsePrivilegeExtension特權的應用才允許開發ServiceExtensionAbility,具體申請方式可參考[應用特權配置指南])。
定義IDL接口
ServiceExtensionAbility作為后臺服務,需要向外部提供可調用的接口,開發者可將接口定義在idl文件中,并使用[IDL工具]生成對應的proxy、stub文件。此處定義一個名為IIdlServiceExt.idl的文件作為示例:
interface OHOS.IIdlServiceExt {
int ProcessData([in] int data);
void InsertDataToMap([in] String key, [in] int val);
}
在DevEco Studio工程Module對應的ets目錄下手動新建名為IdlServiceExt的目錄,將[IDL工具]生成的文件復制到該目錄下,并創建一個名為idl_service_ext_impl.ts的文件,作為idl接口的實現:
├── ets
│ ├── IdlServiceExt
│ │ ├── i_idl_service_ext.ts # 生成文件
│ │ ├── idl_service_ext_proxy.ts # 生成文件
│ │ ├── idl_service_ext_stub.ts # 生成文件
│ │ ├── idl_service_ext_impl.ts # 開發者自定義文件,對idl接口的具體實現
│ └
└
idl_service_ext_impl.ts實現如下:
import IdlServiceExtStub from './idl_service_ext_stub';
import hilog from '@ohos.hilog';
import type { insertDataToMapCallback } from './i_idl_service_ext';
import type { processDataCallback } from './i_idl_service_ext';
const ERR_OK = 0;
const TAG: string = "[IdlServiceExtImpl]";
const DOMAIN_NUMBER: number = 0xFF00;
// 開發者需要在這個類型里對接口進行實現
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: processDataCallback): void {
// 開發者自行實現業務邏輯
hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`);
callback(ERR_OK, data + 1); // 鑒權通過,執行正常業務邏輯
}
insertDataToMap(key: string, val: number, callback: insertDataToMapCallback): void {
// 開發者自行實現業務邏輯
hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key} val: ${val}`);
callback(ERR_OK);
}
}
創建ServiceExtensionAbility
在DevEco Studio工程中手動新建一個ServiceExtensionAbility,具體步驟如下:
- 在工程Module對應的ets目錄下,右鍵選擇“New > Directory”,新建一個目錄并命名為ServiceExtAbility。
- 在ServiceExtAbility目錄,右鍵選擇“New > ArkTS File”,新建一個文件并命名為ServiceExtAbility.ets。
├── ets │ ├── IdlServiceExt │ │ ├── i_idl_service_ext.ets # 生成文件 │ │ ├── idl_service_ext_proxy.ets # 生成文件 │ │ ├── idl_service_ext_stub.ets # 生成文件 │ │ ├── idl_service_ext_impl.ets # 開發者自定義文件,對idl接口的具體實現 │ ├── ServiceExtAbility │ │ ├── ServiceExtAbility.ets └
- 在ServiceExtAbility.ets文件中,增加導入ServiceExtensionAbility的依賴包,自定義類繼承ServiceExtensionAbility并實現生命周期回調,在onConnect生命周期回調里,需要將之前定義的ServiceExtImpl對象返回。
import hilog from '@ohos.hilog'; import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'; import ServiceExtImpl from '../IdlServiceExt/idl_service_ext_impl'; import type Want from '@ohos.app.ability.Want'; import type rpc from '@ohos.rpc'; const TAG: string = '[ServiceExtAbility]'; const DOMAIN_NUMBER: number = 0xFF00; export default class ServiceExtAbility extends ServiceExtensionAbility { serviceExtImpl: ServiceExtImpl = new ServiceExtImpl('ExtImpl'); onCreate(want: Want): void { let serviceExtensionContext = this.context; hilog.info(DOMAIN_NUMBER, TAG, `onCreate, want: ${want.abilityName}`); }; onRequest(want: Want, startId: number): void { hilog.info(DOMAIN_NUMBER, TAG, `onRequest, want: ${want.abilityName}`); }; onConnect(want: Want): rpc.RemoteObject { hilog.info(DOMAIN_NUMBER, TAG, `onConnect, want: ${want.abilityName}`); // 返回ServiceExtImpl對象,客戶端獲取后便可以與ServiceExtensionAbility進行通信 return this.serviceExtImpl as rpc.RemoteObject; }; onDisconnect(want: Want): void { hilog.info(DOMAIN_NUMBER, TAG, `onDisconnect, want: ${want.abilityName}`); }; onDestroy(): void { hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy'); }; };
- 在工程Module對應的[module.json5配置文件]中注冊ServiceExtensionAbility,type標簽需要設置為“service”,srcEntry標簽表示當前ExtensionAbility組件所對應的代碼路徑。
{ "module": { ... "extensionAbilities": [ { "name": "ServiceExtAbility", "icon": "$media:icon", "description": "service", "type": "service", "exported": true, "srcEntry": "./ets/ServiceExtAbility/ServiceExtAbility.ets" } ] } }
啟動一個后臺服務(僅對系統應用開放)
系統應用通過[startServiceExtensionAbility()]方法啟動一個后臺服務,服務的[onRequest()]回調就會被調用,并在該回調方法中接收到調用者傳遞過來的want對象。后臺服務啟動后,其生命周期獨立于客戶端,即使客戶端已經銷毀,該后臺服務仍可繼續運行。因此,后臺服務需要在其工作完成時通過調用ServiceExtensionContext的[terminateSelf()]來自行停止,或者由另一個組件調用[stopServiceExtensionAbility()]來將其停止。
說明: ServiceExtensionContext的[startServiceExtensionAbility()]、[stopServiceExtensionAbility()]和[terminateSelf()]為系統接口,三方應用不支持調用。
- 在系統應用中啟動一個新的ServiceExtensionAbility。示例中的context的獲取方式請參見[獲取UIAbility的上下文信息]。
import common from '@ohos.app.ability.common'; import Want from '@ohos.app.ability.Want'; import { BusinessError } from '@ohos.base'; import promptAction from '@ohos.promptAction'; import hilog from '@ohos.hilog'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; @Entry @Component struct Page_ServiceExtensionAbility { build() { Column() { //... List({ initialIndex: 0 }) { ListItem() { Row() { //... } .onClick(() = > { let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext let want: Want = { deviceId: '', bundleName: 'com.samples.stagemodelabilitydevelop', abilityName: 'ServiceExtAbility' }; context.startServiceExtensionAbility(want).then(() = > { hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in starting ServiceExtensionAbility.'); // 成功啟動后臺服務 promptAction.showToast({ message: $r('app.string.SuccessfullyStartBackendService') }); }).catch((err: BusinessError) = > { hilog.error(DOMAIN_NUMBER, TAG, `Failed to start ServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`); }); }) } //... } //... } //... } }
- 在系統應用中停止一個已啟動的ServiceExtensionAbility。
import common from '@ohos.app.ability.common'; import hilog from '@ohos.hilog'; import promptAction from '@ohos.promptAction'; import Want from '@ohos.app.ability.Want'; import { BusinessError } from '@ohos.base'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; @Entry @Component struct Page_ServiceExtensionAbility { build() { Column() { //... List({ initialIndex: 0 }) { ListItem() { Row() { //... } .onClick(() = > { let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext let want: Want = { deviceId: '', bundleName: 'com.samples.stagemodelabilitydevelop', abilityName: 'ServiceExtAbility' }; context.stopServiceExtensionAbility(want).then(() = > { hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in stopping ServiceExtensionAbility.'); promptAction.showToast({ message: $r('app.string.SuccessfullyStoppedAStartedBackendService') }); }).catch((err: BusinessError) = > { hilog.error(DOMAIN_NUMBER, TAG, `Failed to stop ServiceExtensionAbility. Code is ${err.code}, message is ${err.message}`); }); }) } //... } //... } //... } }
- 已啟動的ServiceExtensionAbility停止自身。
import common from '@ohos.app.ability.common'; import { BusinessError } from '@ohos.base'; import promptAction from '@ohos.promptAction'; import hilog from '@ohos.hilog'; import Want from '@ohos.app.ability.Want'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; @Entry @Component struct Page_ServiceExtensionAbility { build() { Column() { //... List({ initialIndex: 0 }) { ListItem() { Row() { //... } .onClick(() = > { let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext context.terminateSelf().then(() = > { hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in terminating self.'); // 成功停止當前后臺服務 promptAction.showToast({ message: $r('app.string.SuccessfullyStopStartedBackendService') }); }).catch((err: BusinessError) = > { hilog.error(DOMAIN_NUMBER, TAG, `Failed to terminate self. Code is ${err.code}, message is ${err.message}`); }); }) } //... } //... } //... } }
說明: 后臺服務可以在后臺長期運行,為了避免資源浪費,需要對后臺服務的生命周期進行管理。即一個后臺服務完成了請求方的任務,需要及時銷毀。銷毀已啟動的后臺服務有兩種方式:
- 后臺服務自身調用[terminateSelf()]方法來自行停止。
- 由其他組件調用[stopServiceExtensionAbility()]方法來停止。 調用[terminateSelf()]或[stopServiceExtensionAbility()]方法之后,系統將銷毀后臺服務。
連接一個后臺服務
系統應用或者三方應用可以通過[connectServiceExtensionAbility()]連接一個服務(在Want對象中指定啟動的目標服務),服務的[onConnect()]就會被調用,并在該回調方法中接收到調用者傳遞過來的Want對象,從而建立長連接。
ServiceExtensionAbility服務組件在[onConnect()]中返回IRemoteObject對象,開發者通過該IRemoteObject定義通信接口,用于客戶端與服務端進行RPC交互。多個客戶端可以同時連接到同一個后臺服務,客戶端完成與服務的交互后,客戶端需要通過調用[disconnectServiceExtensionAbility()]來斷開連接。如果所有連接到某個后臺服務的客戶端均已斷開連接,則系統會銷毀該服務。
- 使用connectServiceExtensionAbility()建立與后臺服務的連接。示例中的context的獲取方式請參見[獲取UIAbility的上下文信息]。
import common from '@ohos.app.ability.common'; import deviceManager from '@ohos.distributedDeviceManager'; import hilog from '@ohos.hilog'; import promptAction from '@ohos.promptAction'; import rpc from '@ohos.rpc'; import Want from '@ohos.app.ability.Want'; // 客戶端需要將服務端對外提供的idl_service_ext_proxy.ts導入到本地工程中 import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; let connectionId: number; let want: Want = { deviceId: '', bundleName: 'com.samples.stagemodelabilitydevelop', abilityName: 'ServiceExtAbility' }; let options: common.ConnectOptions = { onConnect(elementName, remote: rpc.IRemoteObject): void { hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback'); if (remote === null) { hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`); return; } let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote); // 通過接口調用的方式進行通信,屏蔽了RPC通信的細節,簡潔明了 serviceExtProxy.processData(1, (errorCode: number, retVal: number) = > { hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`); }); serviceExtProxy.insertDataToMap('theKey', 1, (errorCode: number) = > { hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, errorCode: ${errorCode}`); }) }, onDisconnect(elementName): void { hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback'); }, onFailed(code: number): void { hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code)); } }; @Entry @Component struct Page_ServiceExtensionAbility { build() { Column() { //... List({ initialIndex: 0 }) { ListItem() { Row() { //... } .onClick(() = > { let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext // 建立連接后返回的Id需要保存下來,在解綁服務時需要作為參數傳入 connectionId = context.connectServiceExtensionAbility(want, options); // 成功連接后臺服務 promptAction.showToast({ message: $r('app.string.SuccessfullyConnectBackendService') }); // connectionId = context.connectAbility(want, options); hilog.info(DOMAIN_NUMBER, TAG, `connectionId is : ${connectionId}`); }) } //... } //... } //... } }
- 使用disconnectServiceExtensionAbility()斷開與后臺服務的連接。
import hilog from '@ohos.hilog'; import promptAction from '@ohos.promptAction'; import common from '@ohos.app.ability.common'; import { BusinessError } from '@ohos.base'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; let connectionId: number; @Entry @Component struct Page_ServiceExtensionAbility { build() { Column() { //... List({ initialIndex: 0 }) { ListItem() { Row() { //... } .onClick(() = > { let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; // UIAbilityContext // connectionId為調用connectServiceExtensionAbility接口時的返回值,需開發者自行維護 context.disconnectServiceExtensionAbility(connectionId).then(() = > { hilog.info(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility success'); // 成功斷連后臺服務 promptAction.showToast({ message: $r('app.string.SuccessfullyDisconnectBackendService') }); }).catch((error: BusinessError) = > { hilog.error(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility failed'); }); }) } //... } //... } //... } }
客戶端與服務端通信
客戶端在onConnect()中獲取到[rpc.RemoteObject]對象后便可與Service進行通信,有如下兩種方式:
- 使用服務端提供的IDL接口進行通信(推薦)
// 客戶端需要將服務端對外提供的idl_service_ext_proxy.ts導入到本地工程中 import common from '@ohos.app.ability.common'; import hilog from '@ohos.hilog'; import rpc from '@ohos.rpc'; import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy'; const TAG: string = '[Page_ServiceExtensionAbility]'; const DOMAIN_NUMBER: number = 0xFF00; let options: common.ConnectOptions = { onConnect(elementName, remote: rpc.IRemoteObject): void { hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback'); if (remote === null) { hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`); return; } let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote); // 通過接口調用的方式進行通信,屏蔽了RPC通信的細節,簡潔明了 serviceExtProxy.processData(1, (errorCode: number, retVal: number) = > { hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`); }); serviceExtProxy.insertDataToMap('theKey', 1, (errorCode: number) = > { hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, errorCode: ${errorCode}`); }) }, onDisconnect(elementName): void { hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback'); }, onFailed(code: number): void { hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback', JSON.stringify(code)); } };
- 直接使用[sendMessageRequest]接口向服務端發送消息(不推薦)
import hilog from '@ohos.hilog'; import promptAction from '@ohos.promptAction'; import rpc from '@ohos.rpc'; import common from '@ohos.app.ability.common'; import { BusinessError } from '@ohos.base'; const TAG: string = '[Page_CollaborateAbility]'; const DOMAIN_NUMBER: number = 0xFF00; const REQUEST_CODE = 1; let options: common.ConnectOptions = { onConnect(elementName, remote): void { hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback'); if (remote === null) { hilog.info(DOMAIN_NUMBER, TAG, `onConnect remote is null`); return; } let option = new rpc.MessageOption(); let data = new rpc.MessageSequence(); let reply = new rpc.MessageSequence(); data.writeInt(99); // 開發者可發送data到目標端應用進行相應操作 // @param code 表示客戶端發送的服務請求代碼。 // @param data 表示客戶端發送的{@link MessageSequence}對象。 // @param reply 表示遠程服務發送的響應消息對象。 // @param options 指示操作是同步的還是異步的。 // @return 如果操作成功返回{@code true}; 否則返回 {@code false}。 remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) = > { let errCode = reply.readInt(); // 在成功連接的情況下,會收到來自目標端返回的信息(100) let msg: number = 0; if (errCode === 0) { msg = reply.readInt(); } hilog.info(DOMAIN_NUMBER, TAG, `sendRequest msg:${msg}`); // 成功連接后臺服務 promptAction.showToast({ message: `sendRequest msg:${msg}` }); }).catch((error: BusinessError) = > { hilog.info(DOMAIN_NUMBER, TAG, `sendRequest failed, ${JSON.stringify(error)}`); }); }, onDisconnect(elementName): void { hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback'); }, onFailed(code): void { hilog.info(DOMAIN_NUMBER, TAG, 'onFailed callback'); } }; //...
服務端對客戶端身份校驗
部分開發者需要使用ServiceExtension提供一些較為敏感的服務,因此需要對客戶端身份進行校驗,開發者可在IDL接口的stub端進行校驗,IDL接口實現詳見上文[定義IDL接口],此處推薦兩種校驗方式:
- 通過callerUid識別客戶端應用
通過調用[getCallingUid()]接口獲取客戶端的uid,再調用[getBundleNameByUid()]接口獲取uid對應的bundleName,從而識別客戶端身份。此處需要注意的是[getBundleNameByUid()]是一個異步接口,因此服務端無法將校驗結果返回給客戶端,這種校驗方式適合客戶端向服務端發起執行異步任務請求的場景,示例代碼如下:import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import bundleManager from '@ohos.bundle.bundleManager'; import IdlServiceExtStub from './idl_service_ext_stub'; import hilog from '@ohos.hilog'; import rpc from '@ohos.rpc'; import type { BusinessError } from '@ohos.base'; import type { InsertDataToMapCallback } from './i_idl_service_ext'; import type { ProcessDataCallback } from './i_idl_service_ext'; const ERR_OK = 0; const ERR_DENY = -1; const TAG: string = "[IdlServiceExtImpl]"; const DOMAIN_NUMBER: number = 0xFF00; // 開發者需要在這個類型里對接口進行實現 export default class ServiceExtImpl extends IdlServiceExtStub { processData(data: number, callback: ProcessDataCallback): void { // 開發者自行實現業務邏輯 hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`); let callerUid = rpc.IPCSkeleton.getCallingUid(); bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) = > { hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName); // 對客戶端包名進行識別 if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // 識別不通過 hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject'); return; } // 識別通過,執行正常業務邏輯 }).catch((err: BusinessError) = > { hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message); }); //... }; insertDataToMap(key: string, val: number, callback: InsertDataToMapCallback): void { // 開發者自行實現業務邏輯 hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key} val: ${val}`); callback(ERR_OK); }; };
- 通過callerTokenId對客戶端進行鑒權
通過調用[getCallingTokenId()]接口獲取客戶端的tokenID,再調用[verifyAccessTokenSync()]接口判斷客戶端是否有某個具體權限,由于當前不支持自定義權限,因此只能校驗當前[系統所定義的權限]。示例代碼如下:import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import bundleManager from '@ohos.bundle.bundleManager'; import IdlServiceExtStub from './idl_service_ext_stub'; import hilog from '@ohos.hilog'; import rpc from '@ohos.rpc'; import type { BusinessError } from '@ohos.base'; import type { InsertDataToMapCallback } from './i_idl_service_ext'; import type { ProcessDataCallback } from './i_idl_service_ext'; const ERR_OK = 0; const ERR_DENY = -1; const TAG: string = '[IdlServiceExtImpl]'; const DOMAIN_NUMBER: number = 0xFF00; // 開發者需要在這個類型里對接口進行實現 export default class ServiceExtImpl extends IdlServiceExtStub { processData(data: number, callback: ProcessDataCallback): void { // 開發者自行實現業務邏輯 hilog.info(DOMAIN_NUMBER, TAG, `processData: ${data}`); let callerUid = rpc.IPCSkeleton.getCallingUid(); bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) = > { hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName); // 對客戶端包名進行識別 if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') { // 識別不通過 hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject'); return; } // 識別通過,執行正常業務邏輯 }).catch((err: BusinessError) = > { hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message); }); let callerTokenId = rpc.IPCSkeleton.getCallingTokenId(); let accessManger = abilityAccessCtrl.createAtManager(); // 所校驗的具體權限由開發者自行選擇,此處ohos.permission.GET_BUNDLE_INFO_PRIVILEGED只作為示例 let grantStatus = accessManger.verifyAccessTokenSync(callerTokenId, 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED'); if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) { hilog.info(DOMAIN_NUMBER, TAG, 'PERMISSION_DENIED'); callback(ERR_DENY, data); // 鑒權失敗,返回錯誤 return; } hilog.info(DOMAIN_NUMBER, TAG, 'verify access token success.'); callback(ERR_OK, data + 1); // 鑒權通過,執行正常業務邏輯 }; insertDataToMap(key: string, val: number, callback: InsertDataToMapCallback): void { // 開發者自行實現業務邏輯 hilog.info(DOMAIN_NUMBER, TAG, `insertDataToMap, key: ${key} val: ${val}`); callback(ERR_OK); }; };
審核編輯 黃宇
-
框架
+關注
關注
0文章
403瀏覽量
17527 -
程序
+關注
關注
117文章
3795瀏覽量
81303 -
鴻蒙
+關注
關注
57文章
2392瀏覽量
42980
發布評論請先 登錄
相關推薦
評論