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唤起半模态框,如何监听消失并读取最新通知开启状态?
解决方案:
封装通知管理工具类,全局使用。
- 创建通知管理工具类:
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) => 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();
- 在应用入口初始化工具类:
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');
}
- 使用封装后的工具类:
TypeScript
import NotificationUtil from './NotificationUtil';
@Entry
@Component
struct NotificationManagerDemo {
@State focusState: boolean = true
build() {
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申请授权,拉起通知管理弹窗。或者引导用户跳转应用设置页面开启权限,跳转设置页面方法如下:
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(() => {
}).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加载后再申请。代码示例:
TypeScript
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。代码示例:
TypeScript
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回调中请求权限。