1.问题描述:
获取应用是否开启了允许通知权限后,如何引导跳转开启权限通知的设置页面?
解决方案:
- 通过isNotificationEnabled方法查询通知是否授权,参考isNotificationEnabled用法。
2.若申请通知权限被拒绝后,后续调用requestEnableNotification()方法不再弹窗,同时会返回错误,错误码是1600004。具体参考请求通知授权。
3.如果想二次授权,可以调用openNotificationSettings申请授权,拉起通知管理弹窗或者引导用户跳转应用设置页面开启权限。
完整代码示例如下:
import { notificationManager } from '@kit.NotificationKit';import { BusinessError } from '@kit.BasicServicesKit';import { common } from '@kit.AbilityKit';import { Want } from '@kit.AbilityKit';@Entry@Componentstruct 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()来查询应用通知的开启状态。具体实现代码如下:
import { notificationManager } from '@kit.NotificationKit';import { BusinessError } from '@kit.BasicServicesKit';import { common } from '@kit.AbilityKit';@Entry@Componentstruct NotificationManagerDemo {// 组件聚焦状态@State focusState: boolean = truebuild() {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唤起半模态框,如何监听消失并读取最新通知开启状态?
解决方案:
封装通知管理工具类,全局使用。
- 创建通知管理工具类:
// NotificationUtil.tsimport { 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) => void): void {this.focusStateCallbacks.push(callback);}/*** 注销页面聚焦状态回调* @param callback 回调函数*/public unregisterFocusCallback(callback: (isFocused: boolean) => void): void {const index = this.focusStateCallbacks.indexOf(callback);if (index > -1) {this.focusStateCallbacks.splice(index, 1);}}/*** 处理页面聚焦事件(需要在页面onFocus中调用)* @param isFocused 是否聚焦*/public handleFocusChange(isFocused: boolean): void {this.focusStateCallbacks.forEach(callback => {try {callback(isFocused);} catch (err) {console.error('焦点状态回调执行失败:', err);}});}/*** 完整的打开通知设置并监听返回的流程* @param onReturnCallback 返回时的回调函数* @returns Promise<boolean> 是否成功执行*/public async openSettingsAndListenReturn(onReturnCallback?: (isEnabled: boolean) => void): Promise<boolean> {if (!this.context) {console.error('NotificationUtil 未初始化');return false;}const success = await this.openNotificationSettings();if (success && onReturnCallback) {// 注册一次性回调const tempCallback = (isFocused: boolean) => {if (isFocused) {const isEnabled = this.isNotificationEnabled();onReturnCallback(isEnabled);// 执行后立即注销this.unregisterFocusCallback(tempCallback);}};this.registerFocusCallback(tempCallback);}return success;}}// 导出默认实例export default NotificationUtil.getInstance();
- 在应用入口初始化工具类:
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');}
- 使用封装后的工具类:
import NotificationUtil from './NotificationUtil';@Entry@Componentstruct NotificationManagerDemo {@State focusState: boolean = truebuild() {Column() {Button('打开应用通知设置页').onClick(async () => {await NotificationUtil.openSettingsAndListenReturn((isEnabled: boolean) => {console.info('从设置页面返回,通知状态:', isEnabled);this.getUIContext().getPromptAction().showToast({message: `通知状态: ${isEnabled ? '已开启' : '已关闭'}`});});})}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).onFocus(() => {// 将焦点变化传递给工具类NotificationUtil.handleFocusChange(true);}).onBlur(() => {NotificationUtil.handleFocusChange(false);})}}
4.问题描述:
如何直接以弹窗方式打开通知管理页面?
解决方案:
-
通过isNotificationEnabled方法查询通知是否授权,参考isNotificationEnabled用法。
-
若申请通知权限被拒绝后,后续调用requestEnableNotification()方法不再弹窗,同时会返回错误,错误码是1600004。具体参考请求通知授权。
如果想二次授权,可以调用openNotificationSettings申请授权,拉起通知管理弹窗。或者引导用户跳转应用设置页面开启权限,跳转设置页面方法如下:
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(() => {}).catch((err: BusinessError) => {console.error(`Code is ${err.code}, message is ${err.message}`)});
5.问题描述:
notificationManager.requestEnableNotification err.code:1600013,原因是什么?
解决方案:
【背景知识】
应用需要获取用户授权才能发送通知。在通知发布前调用requestEnableNotification()方法,弹窗让用户选择是否允许发送通知,后续再次调用requestEnableNotification()方法时,则不再弹窗。可参考文档请求通知权限。
【问题定位】
-
权限请求时机问题,需要在UI加载后再申请。
-
是否绑定UiAbilityContext,context是否正常初始化。
-
以前有异常弹出的场景,产生了脏数据。
-
检查相关参数HashMap使用是否正确。
【分析结论】
-
1600013,若窗口未加载完成就请求了通知,导致渲染异常,再次请求就会报这个错,尽量在窗口创建并渲染后再调用。
-
建议在entryAbility中调用,或是在对应的页面中调用,不建议在授权时切换页面。
【修改建议】
针对报错code:1600013,可以采用以下两种方案:
- 执行重启手机、删除应用的操作,清理脏数据后再次安装应用尝试。申请通知权限代码改为在ui加载后再申请。代码示例:
windowStage.loadContent('pages/Index', (err) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}notificationManager.requestEnableNotification().then(() => {hilog.info(0x0000, '’testTag', 'requestEnableNotification success');}).catch((error: BusinessError) => {hilog.error(0x0000, 'testTag', 'requestEnableNotification error : %{public}s', JSON.stringify(error))})hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');});
- 绑定UiAbilityContext使用模态弹窗方式,初始化context。代码示例:
let context = getContext(this) as common.UIAbilityContext;notificationManager.isNotificationEnabled().then((data: boolean) => {hilog.info(DOMAIN_NUMBER, TAG, "isNotificationEnabled success, data: " + JSON.stringify(data));if(!data){notificationManager.requestEnableNotification(context).then(() => {hilog.info(DOMAIN_NUMBER, TAG, `[ANS] requestEnableNotification success`);}).catch((err : BusinessError) => {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) => {hilog.error(DOMAIN_NUMBER, TAG, `isNotificationEnabled fail: ${JSON.stringify(err)}`);});
- 不在授权时切换页面,建议在window.loadContent回调中请求权限。