跳到主要内容

通知订阅扩展能力开发步骤

接口说明

接口名描述
onDestroy(): void通知订阅扩展被销毁时的回调。
onReceiveMessage(notificationInfo: NotificationInfo): void收到通知时的回调。
onCancelMessages(hashCodes: Array<string>): void取消通知时的回调。

前提条件

申请ohos.permission.SUBSCRIBE_NOTIFICATION权限。

开发步骤

开发者在实现NotificationSubscriberExtensionAbility提供方时,需在DevEco Studio工程中新建一个NotificationSubscriberExtensionAbility。具体步骤如下。

  1. 在entry/src/main/ets/创建目录extensionability。

  2. 在entry/src/main/ets/extensionability目录下创建NotificationSubscriberExtAbility.ets,其内容如下。

    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { notificationExtensionSubscription, NotificationSubscriberExtensionAbility } from '@kit.NotificationKit';
    // ...

    const DOMAIN = 0x0000;
    // ...
    export class NotificationSubscriberExtAbility extends NotificationSubscriberExtensionAbility {
    // ...
    onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', 'onDestroy');
    // ...
    }
    // ...
    onReceiveMessage(notificationInfo: notificationExtensionSubscription.NotificationInfo): void {
    hilog.info(DOMAIN, 'testTag', `on receive message ${JSON.stringify(notificationInfo)}`)
    // ...
    }
    // ...
    onCancelMessages(hashCodes: Array<string>): void {
    hilog.info(DOMAIN, 'testTag', `on cancel message ${JSON.stringify(hashCodes)}`)
    // ...
    }
    // ...
    }
  3. 使用蓝牙模块接口与穿戴设备配对(蓝牙处于配对状态)并获取地址,然后通过subscribe/unsubscribe接口订阅或取消订阅通知。

  4. 实现NotificationSubscriberExtensionAbility后,还需要在合适的时机调用openSubscriptionSettings接口,打开通知扩展订阅设置页面,引导用户授予获取本机通知的权限,该页面以半模态弹窗显示。建议在设备管理页面提供一个通知授权的按钮,用户点击按钮则调用openSubscriptionSettings接口。

  5. 在应用的module.json5文件中配置extensionAbilities。

    {
    "name": "NotificationSubscriberExtAbility",
    "srcEntry": "./ets/extensionability/NotificationSubscriberExtAbility.ets",
    "type": "notificationSubscriber",
    "description": "$string:NotificationSubscriberExtAbility_desc",
    "icon": "$media:layered_image",
    "label": "$string:NotificationSubscriberExtAbility_label",
    "exported": true
    }
  6. 在应用的string.json文件中添加

    {
    "name": "NotificationSubscriberExtAbility_desc",
    "value": "description"
    },
    {
    "name": "NotificationSubscriberExtAbility_label",
    "value": "ThirdPartyWearableApp"
    }

传统蓝牙连接示例

  1. 示例仅为传统蓝牙连接示例,开发者也可选用低功耗蓝牙连接方式。

  2. 用户收到消息后,假如蓝牙连接是无效的,则建立蓝牙连接。

  3. 假如蓝牙连接已经存在,则直接使用这个连接发送消息。

  4. 如果使用该连接发送消息失败,则重新建立连接,如果连接能建立成功则发送消息。

  5. 需要申请权限ohos.permission.ACCESS_BLUETOOTH。如何配置和申请权限,具体操作请参考声明权限向用户申请授权

    import { hilog } from '@kit.PerformanceAnalysisKit';
    import { notificationExtensionSubscription, NotificationSubscriberExtensionAbility } from '@kit.NotificationKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    import { socket } from '@kit.ConnectivityKit'
    import { util } from '@kit.ArkTS';

    const DOMAIN = 0x0000;
    class TransferInfo {
    public type: string = ''
    public info: notificationExtensionSubscription.NotificationInfo | undefined
    public cancelHashCodes: Array<string> | undefined
    }
    // Spp means Serial Port Profile
    class SppClientManager {
    private clientNumber: number = -1;
    private peerDevice: string = '';

    constructor(peerDevice: string) {
    this.peerDevice = peerDevice
    }

    public isConnect(): boolean {
    return this.clientNumber !== -1;
    }

    public async startConnect(): Promise<boolean> {
    let option: socket.SppOptions = {
    uuid: '00009999-0000-1000-8000-00805F9B34FB',
    secure: false,
    type: socket.SppType.SPP_RFCOMM
    };
    socket.sppConnect(this.peerDevice, option, (err: BusinessError, num: number) => {
    if (err) {
    hilog.error(DOMAIN, 'testTag', `cpp connect failed, errCode: ${err.code}, errMessage: ${err.message}`);
    } else {
    hilog.info(DOMAIN, 'testTag', `spp connect success clientNumber: ${num}`);
    this.clientNumber = num;
    }
    });
    return true
    }

    private sendData(jsonStr: string) {
    if (!this.isConnect()) {
    hilog.error(DOMAIN, 'testTag', `server is not connected`);
    return;
    }
    if (!jsonStr) {
    hilog.error(DOMAIN, 'testTag', 'json is empty');
    return;
    }
    hilog.info(DOMAIN, 'testTag', `prepare sending data to client ${this.clientNumber}`);
    const textEncoder:util.TextEncoder = new util.TextEncoder();
    const uint8Array: Uint8Array = textEncoder.encodeInto(jsonStr);
    const arrayBuffer = uint8Array.buffer;

    socket.sppWrite(this.clientNumber, arrayBuffer);
    hilog.info(DOMAIN, 'testTag', `sending success size: ${arrayBuffer.byteLength} bytes, data: ${jsonStr}`);
    }

    public sendNotificationData(notificationInfo: notificationExtensionSubscription.NotificationInfo) {
    let info: TransferInfo = {
    type: 'publish',
    info: notificationInfo,
    cancelHashCodes: undefined
    };

    let jsonStr = JSON.stringify(info);
    this.sendData(jsonStr);
    }

    public sendCancelNotificationData(cancelHashCodes: Array<string>) {
    let info: TransferInfo = {
    type: 'cancel',
    cancelHashCodes: cancelHashCodes,
    info: undefined
    };

    let jsonStr = JSON.stringify(info);
    this.sendData(jsonStr);
    }

    public read = (dataBuffer: ArrayBuffer) => {
    let data = new Uint8Array(dataBuffer);
    hilog.info(DOMAIN, 'testTag', `client data: ${JSON.stringify(data)}`);
    };

    public stopConnect() {
    hilog.info(DOMAIN, 'testTag', `closeSppClient ${this.clientNumber}`);
    try {
    socket.off('sppRead', this.clientNumber, this.read);
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `off sppRead errCode: ${err.code}, errMessage: ${err.message}`);
    }
    try {
    socket.sppCloseClientSocket(this.clientNumber);
    this.clientNumber = -1;
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `stopConnect errCode: ${err.code}, errMessage: ${err.message}`);
    }
    }
    }

    // export SppClientManager;
    export class NotificationSubscriberExtAbility extends NotificationSubscriberExtensionAbility {
    private sppClientManager: SppClientManager | undefined;
    onDestroy(): void {
    hilog.info(DOMAIN, 'testTag', 'onDestroy');
    this.sppClientManager!.stopConnect();
    }
    // Called back when a notification is published.
    onReceiveMessage(notificationInfo: notificationExtensionSubscription.NotificationInfo): void {
    hilog.info(DOMAIN, 'testTag', `on receive message ${JSON.stringify(notificationInfo)}`)
    notificationExtensionSubscription.getSubscribeInfo()
    .then(async (info) => {
    if (this.sppClientManager == undefined) {
    this.sppClientManager = new SppClientManager(info[0].addr);
    }
    if (this.sppClientManager.isConnect()) {
    this.sendPublishWithRetry(notificationInfo);
    } else {
    try {
    await this.sppClientManager.startConnect().then(() => {
    hilog.info(DOMAIN, 'testTag', `startConnect success`);
    });
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `Failed to start connect: ${JSON.stringify(err)}`);
    }
    setTimeout(() => {
    this.sendPublishWithRetry(notificationInfo);
    }, 3000)
    }
    }).catch((err: BusinessError) => {
    hilog.error(DOMAIN, 'testTag',
    `notificationExtensionSubscription failed, errCode ${err.code}, errorMessage ${err.message}`);
    });
    }
    // Sends a publish notification and retries once upon failure.
    private async sendPublishWithRetry(notificationInfo: notificationExtensionSubscription.NotificationInfo) {
    try {
    this.sppClientManager!.sendNotificationData(notificationInfo);
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `send failed, errCode ${err.code}, errorMessage ${err.message}, and retry one times`);
    try {
    await this.sppClientManager!.startConnect().then(() => {
    hilog.info(DOMAIN, 'testTag', `startConnect success`);
    });
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `Failed to start connect: ${JSON.stringify(err)}`);
    }
    setTimeout(() => {
    this.sppClientManager!.sendNotificationData(notificationInfo);
    }, 3000);
    }
    }

    // Called back when notifications are cancelled.
    onCancelMessages(hashCodes: Array<string>): void {
    hilog.info(DOMAIN, 'testTag', `on cancel message ${JSON.stringify(hashCodes)}`)
    notificationExtensionSubscription.getSubscribeInfo()
    .then(async (info) => {
    if (this.sppClientManager == undefined) {
    this.sppClientManager = new SppClientManager(info[0].addr);
    }
    if (this.sppClientManager.isConnect()) {
    this.sendCancelWithRetry(hashCodes);
    } else {
    try {
    await this.sppClientManager.startConnect().then(() => {
    hilog.info(DOMAIN, 'testTag', `startConnect success`);
    });
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `Failed to start connect: ${JSON.stringify(err)}`);
    }
    setTimeout(() => {
    this.sendCancelWithRetry(hashCodes);
    }, 3000)
    }
    }).catch((err: BusinessError) => {
    hilog.error(DOMAIN, 'testTag', `notificationExtensionSubscription failed, errCode ${err.code}, errorMessage ${err.message}`);
    });
    }
    // Retries a cancel operation if it fails.
    private async sendCancelWithRetry(hashCodes: string[]) {
    try {
    this.sppClientManager!.sendCancelNotificationData(hashCodes);
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `send failed, errCode ${err.code}, errorMessage ${err.message}, and retry one times`);
    try {
    await this.sppClientManager!.startConnect().then(() => {
    hilog.info(DOMAIN, 'testTag', `startConnect success`);
    });
    } catch (err) {
    hilog.error(DOMAIN, 'testTag', `Failed to start connect: ${JSON.stringify(err)}`);
    }
    setTimeout(() => {
    this.sppClientManager!.sendCancelNotificationData(hashCodes);
    }, 3000);
    }
    }
    }

注意:请勿频繁建立连接,可能会影响功能。