【FAQ】HarmonyOS SDK 闭源开放能力 — Notification Kit

1.问题描述:

获取应用是否开启了允许通知权限后,如何引导跳转开启权限通知的设置页面?

解决方案:

  1. 通过isNotificationEnabled方法查询通知是否授权,参考isNotificationEnabled用法。

2.若申请通知权限被拒绝后,后续调用requestEnableNotification()方法不再弹窗,同时会返回错误,错误码是1600004。具体参考请求通知授权。

3.如果想二次授权,可以调用openNotificationSettings申请授权,拉起通知管理弹窗或者引导用户跳转应用设置页面开启权限。

完整代码示例如下:

ts 复制代码
import { notificationManager } from '@kit.NotificationKit';

import { BusinessError } from '@kit.BasicServicesKit';

import { common } from '@kit.AbilityKit';

import { Want } from '@kit.AbilityKit';


@Entry

@Component

struct NotificationPage {

  aboutToAppear(): void {

    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;

    notificationManager.isNotificationEnabled().then((data: boolean) => {

      console.info("isNotificationEnabled success, data: " + data);

      if (!data) {

        let requestEnableNotificationCallback = (err: BusinessError): void => {

          if (err) {

            console.error(`requestEnableNotification failed, code is ${err.code}, message is ${err.message}`);

          } else {

            console.info(`requestEnableNotification success`);

          }

        };

        notificationManager.requestEnableNotification(context, requestEnableNotificationCallback);

      }

    }).catch((err: BusinessError) => {

      console.error(`isNotificationEnabled fail, code is ${err.code}, message is ${err.message}`);

    });

  }


  // 发布基本类型通知

  publishBasicNotification() {


    let notificationRequest: notificationManager.NotificationRequest = {

      id: 1,

      notificationSlotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,

      content: {

        notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, // 普通文本类型通知

        normal: {

          title: '基本型消息通知',

          text: '通知内容XXXXXXX',

          additionalText: 'TextXXXXXXX',

        }

      }

    };


    notificationManager.publish(notificationRequest, (err: BusinessError) => {

      if (err) {

        console.error(`Failed to publish notification. Code is ${err.code}, message is ${err.message}`);

        return;

      }

      console.info('Succeeded in publishing notification.');

    });

    notificationManager.setBadgeNumber(1)

  }


  build() {

    Column() {

      Button('基本通知')

        .onClick(() => {

          this.publishBasicNotification()

        })

      Button('二次授权')

        .margin({ top: 20 })

        .onClick(() => {

          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;

          notificationManager.openNotificationSettings(context).then(() => {

            console.info(`openNotificationSettings success`);

          }).catch((err: BusinessError) => {

            console.error(`openNotificationSettings failed, code is ${err.code}, message is ${err.message}`);

          });

        })

      Button('点击进入应用设置页面')

        .margin({ top: 20 })

        .onClick(() => {

          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;

          let want: Want = {

            bundleName: 'com.huawei.hmos.settings',

            abilityName: 'com.huawei.hmos.settings.MainAbility',

            uri: 'application_info_entry',

            parameters: {

              pushParams: "com.example.myapplication" // 配置应用包名

            }

          };

          context.startAbility(want).then(() => {

          }).catch((err: BusinessError) => {

            console.error(`Code is ${err.code}, message is ${err.message}`)

          });

        })


    }

    .alignItems(HorizontalAlign.Center)

    .width('100%')

    .height('100%')

  }

}

2.问题描述:

使用notificationManager.openNotificationSettings接口打开的弹窗,如何监听弹窗关闭事件?

解决方案:

在页面打开应用通知设置页。

openNotificationSettings接口拉起的设置页面,页面关闭的时候没有回调方法可以直接使用,但是该接口拉起的页面关闭的时候,会触发其他页面聚焦的回调,在这个页面的根组件上注册的onfocus事件,在该回调内自定义一些操作,比如调用isNotificationEnabledSync()来查询应用通知的开启状态。具体实现代码如下:

TypeScript 复制代码
import { notificationManager } from '@kit.NotificationKit';

import { BusinessError } from '@kit.BasicServicesKit';

import { common } from '@kit.AbilityKit';


@Entry

@Component

struct NotificationManagerDemo {

  // 组件聚焦状态

  @State focusState: boolean = true


  build() {

    Column() {

      Button('打开弹窗')

        .onClick(() => {

          let context = this.getUIContext().getHostContext() as common.UIAbilityContext;

          // 拉起应用通知设置页面

          notificationManager.openNotificationSettings(context).then(() => {

            console.info('页面拉起成功')

            // 拉起成功,改变页面聚焦状态

            this.focusState = false

          }).catch((err: BusinessError) => {

            console.info('页面拉起失败')

          });

        })

    }

    .onFocus(() => {

      // 组件聚焦的回调

      if (!this.focusState) {

        // 做一些自己的操作

        console.info('应用通知页面关闭')

        // 查询通知开关是否开启

        let res = notificationManager.isNotificationEnabledSync()

        console.info(`是否开启应用通知:${res}`)

        this.getUIContext().getPromptAction().showToast({ message: `是否开启应用通知:${res}` })


        // 重置组件聚焦状态

        this.focusState = !this.focusState

      }

    })

  }

}

3.问题描述:

notificationManager.openNotificationSettings唤起半模态框,如何监听消失并读取最新通知开启状态?

解决方案:

封装通知管理工具类,全局使用。

  1. 创建通知管理工具类:
TypeScript 复制代码
// NotificationUtil.ts

import { notificationManager } from '@kit.NotificationKit';

import { BusinessError } from '@kit.BasicServicesKit';

import { common } from '@kit.AbilityKit';

 

/**

 * 通知管理工具类

 */

export class NotificationUtil {

  private static instance: NotificationUtil;

  private context: common.UIAbilityContext | null = null;

  private focusStateCallbacks: Array<(isFocused: boolean) => void> = [];

 

  private constructor() {

  }

 

  /**

   * 获取单例实例

   */

  public static getInstance(): NotificationUtil {

    if (!NotificationUtil.instance) {

      NotificationUtil.instance = new NotificationUtil();

    }

    return NotificationUtil.instance;

  }

 

  /**

   * 初始化工具类(必须在应用启动时调用)

   * @param context UIAbility上下文

   */

  public initialize(context: common.UIAbilityContext): void {

    this.context = context;

  }

 

  /**

   * 打开通知设置页面

   * @returns Promise<boolean> 是否成功打开

   */

  public async openNotificationSettings(): Promise<boolean> {

    if (!this.context) {

      console.error('NotificationUtil 未初始化,请先调用 initialize 方法');

      return false;

    }

 

    try {

      await notificationManager.openNotificationSettings(this.context);

      console.info('通知设置页面拉起成功');

      return true;

    } catch (err) {

      const error = err as BusinessError;

      console.error(`通知设置页面拉起失败: ${error.code} - ${error.message}`);

      return false;

    }

  }

 

  /**

   * 检查通知是否开启(同步)

   * @returns boolean 通知是否开启

   */

  public isNotificationEnabled(): boolean {

    try {

      return notificationManager.isNotificationEnabledSync();

    } catch (err) {

      const error = err as BusinessError;

      console.error(`检查通知状态失败: ${error.code} - ${error.message}`);

      return false;

    }

  }

 

  /**

   * 检查通知是否开启(异步)

   * @returns Promise<boolean> 通知是否开启

   */

  public async isNotificationEnabledAsync(): Promise<boolean> {

    try {

      return await notificationManager.isNotificationEnabled();

    } catch (err) {

      const error = err as BusinessError;

      console.error(`异步检查通知状态失败: ${error.code} - ${error.message}`);

      return false;

    }

  }

 

  /**

   * 注册页面聚焦状态回调

   * @param callback 回调函数

   */

  public registerFocusCallback(callback: (isFocused: boolean) =&gt; void): void {

    this.focusStateCallbacks.push(callback);

  }

 

  /**

   * 注销页面聚焦状态回调

   * @param callback 回调函数

   */

  public unregisterFocusCallback(callback: (isFocused: boolean) =&gt; void): void {

    const index = this.focusStateCallbacks.indexOf(callback);

    if (index &gt; -1) {

      this.focusStateCallbacks.splice(index, 1);

    }

  }

 

  /**

   * 处理页面聚焦事件(需要在页面onFocus中调用)

   * @param isFocused 是否聚焦

   */

  public handleFocusChange(isFocused: boolean): void {

    this.focusStateCallbacks.forEach(callback =&gt; {

      try {

        callback(isFocused);

      } catch (err) {

        console.error('焦点状态回调执行失败:', err);

      }

    });

  }

 

  /**

   * 完整的打开通知设置并监听返回的流程

   * @param onReturnCallback 返回时的回调函数

   * @returns Promise<boolean> 是否成功执行

   */

  public async openSettingsAndListenReturn(onReturnCallback?: (isEnabled: boolean) =&gt; void): Promise<boolean> {

    if (!this.context) {

      console.error('NotificationUtil 未初始化');

      return false;

    }

 

    const success = await this.openNotificationSettings();

    if (success &amp;&amp; onReturnCallback) {

      // 注册一次性回调

      const tempCallback = (isFocused: boolean) =&gt; {

        if (isFocused) {

          const isEnabled = this.isNotificationEnabled();

          onReturnCallback(isEnabled);

          // 执行后立即注销

          this.unregisterFocusCallback(tempCallback);

        }

      };

 

      this.registerFocusCallback(tempCallback);

    }

 

    return success;

  }

}

 

// 导出默认实例

export default NotificationUtil.getInstance();

 
  1. 在应用入口初始化工具类:
TypeScript 复制代码
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

    try {

      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);

 

      // 初始化通知工具类

      NotificationUtil.initialize(this.context);

 

    } catch (err) {

      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));

    }

    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

  }
  1. 使用封装后的工具类:
TypeScript 复制代码
import NotificationUtil from './NotificationUtil';

 

@Entry

@Component

struct NotificationManagerDemo {

  @State focusState: boolean = true

 

  build() {

    Column() {

 

      Button('打开应用通知设置页')

        .onClick(async () =&gt; {

          await NotificationUtil.openSettingsAndListenReturn((isEnabled: boolean) =&gt; {

            console.info('从设置页面返回,通知状态:', isEnabled);

            this.getUIContext().getPromptAction().showToast({

              message: `通知状态: ${isEnabled ? '已开启' : '已关闭'}`

            });

          });

        })

 

    }

    .width('100%')

    .height('100%')

    .justifyContent(FlexAlign.Center)

    .alignItems(HorizontalAlign.Center)

    .onFocus(() =&gt; {

      // 将焦点变化传递给工具类

      NotificationUtil.handleFocusChange(true);

    })

    .onBlur(() =&gt; {

      NotificationUtil.handleFocusChange(false);

    })

  }

}

4.问题描述:

如何直接以弹窗方式打开通知管理页面?

解决方案:

  1. 通过isNotificationEnabled方法查询通知是否授权,参考isNotificationEnabled用法

  2. 若申请通知权限被拒绝后,后续调用requestEnableNotification()方法不再弹窗,同时会返回错误,错误码是1600004。具体参考请求通知授权

如果想二次授权,可以调用openNotificationSettings申请授权,拉起通知管理弹窗。或者引导用户跳转应用设置页面开启权限,跳转设置页面方法如下:

typescript 复制代码
let context = getContext(this) as common.UIAbilityContext;

let want: Want = {

  bundleName: 'com.huawei.hmos.settings',

  abilityName: 'com.huawei.hmos.settings.MainAbility',

  uri: 'application_info_entry',

  parameters: {

    pushParams: "bundleName" // 配置应用包名

  }

};

context.startAbility(want).then(() =&gt; {

}).catch((err: BusinessError) =&gt; {

  console.error(`Code is ${err.code}, message is ${err.message}`)

});

5.问题描述:

notificationManager.requestEnableNotification err.code:1600013,原因是什么?

解决方案:

【背景知识】

应用需要获取用户授权才能发送通知。在通知发布前调用requestEnableNotification()方法,弹窗让用户选择是否允许发送通知,后续再次调用requestEnableNotification()方法时,则不再弹窗。可参考文档请求通知权限

【问题定位】

  1. 权限请求时机问题,需要在UI加载后再申请。

  2. 是否绑定UiAbilityContext,context是否正常初始化。

  3. 以前有异常弹出的场景,产生了脏数据。

  4. 检查相关参数HashMap使用是否正确。

【分析结论】

  1. 1600013,若窗口未加载完成就请求了通知,导致渲染异常,再次请求就会报这个错,尽量在窗口创建并渲染后再调用。

  2. 建议在entryAbility中调用,或是在对应的页面中调用,不建议在授权时切换页面。

【修改建议】

针对报错code:1600013,可以采用以下两种方案:

  1. 执行重启手机、删除应用的操作,清理脏数据后再次安装应用尝试。申请通知权限代码改为在ui加载后再申请。代码示例:
TypeScript 复制代码
windowStage.loadContent('pages/Index', (err) =&gt; {

     if (err.code) {

       hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');

       return;

     }

 

     notificationManager.requestEnableNotification().then(() =&gt; {

       hilog.info(0x0000, ''testTag', 'requestEnableNotification success');

     })

       .catch((error: BusinessError) =&gt; {

         hilog.error(0x0000, 'testTag', 'requestEnableNotification error : %{public}s', JSON.stringify(error))

       })

     hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');

   });
  1. 绑定UiAbilityContext使用模态弹窗方式,初始化context。代码示例:
TypeScript 复制代码
let context = getContext(this) as common.UIAbilityContext;

notificationManager.isNotificationEnabled().then((data: boolean) =&gt; {

  hilog.info(DOMAIN_NUMBER, TAG, "isNotificationEnabled success, data: " + JSON.stringify(data));

  if(!data){

    notificationManager.requestEnableNotification(context).then(() =&gt; {

      hilog.info(DOMAIN_NUMBER, TAG, `[ANS] requestEnableNotification success`);

    }).catch((err : BusinessError) =&gt; {

      if(1600004 == err.code){

        hilog.error(DOMAIN_NUMBER, TAG, `[ANS] requestEnableNotification refused, code is ${err.code}, message is ${err.message}`);

      } else {

        hilog.error(DOMAIN_NUMBER, TAG, `[ANS] requestEnableNotification failed, code is ${err.code}, message is ${err.message}`);

      }

    });

  }

}).catch((err : BusinessError) =&gt; {

  hilog.error(DOMAIN_NUMBER, TAG, `isNotificationEnabled fail: ${JSON.stringify(err)}`);

});
  • 不在授权时切换页面,建议在window.loadContent回调中请求权限。
相关推荐
HarmonyOS_SDK2 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 — Account Kit
harmonyos
ifeng09184 小时前
HarmonyOS功耗优化实战:减少冗余计算与传感器合理调用
pytorch·华为·harmonyos
爱笑的眼睛114 小时前
HarmonyOS WebSocket实时通信:从基础原理到复杂场景实践
华为·harmonyos
二流小码农8 小时前
鸿蒙开发:支持自定义组件的跑马灯
android·ios·harmonyos
2013编程爱好者10 小时前
【HUAWEI】HUAWEI Mate 70 Air详解
华为·harmonyos
爱笑的眼睛1114 小时前
HarmonyOS USB设备管理深度探索:从基础到高级应用
华为·harmonyos
爱笑的眼睛1116 小时前
HarmonyOS文件压缩与解压缩API深度解析与实践
华为·harmonyos
柒儿吖19 小时前
Qt for HarmonyOS 水平进度条组件开发实战
开发语言·qt·harmonyos
xiaocao_102321 小时前
鸿蒙手机上有没有轻便好用的备忘录APP?
华为·智能手机·harmonyos