鸿蒙应用服务开发【自定义通知角标】

自定义通知角标

介绍

本示例主要展示了设定应用的桌面图标角标的功能,使用@ohos.notificationManager接口,进行桌面角标的设置,通知的发送,获取等。

效果预览

使用说明

  1. 在主界面,可以看到当前应用的所有消息通知;
  2. 点击右下角Tab页签进入通知发送页面,点击对应的通知即可发送相应类型的通知,点击几次发送几条;
  3. 点击左下角Tab页签进入消息列表,可以查看刚才发送的消息,消息右边会显示消息数量,点击相应的消息可进行消息读取,取消相应通知;
  4. 下拉通知栏,可以看到角标数量,对应消息数量。

具体实现

  • 允许发送通知,发送通知的功能接口封装在NotificationUtil,源码参考:[NotificationUtil.ets]

    /*

    • Copyright (c) 2023 Huawei Device Co., Ltd.
    • Licensed under the Apache License, Version 2.0 (the "License");
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • http://www.apache.org/licenses/LICENSE-2.0
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */

    import { notificationManager } from '@kit.NotificationKit';
    import { logger } from '../util/Logger';
    import { notificationManagement } from '../notification/NotificationManagementUtil';
    import { BusinessError } from '@kit.BasicServicesKit';

    const TAG: string = 'NotificationUtilModel';

    class NotificationUtil {
    /**
    * enable notification
    */
    private id: number = 0

    async enableNotification() {
      try {
        notificationManager.requestEnableNotification(AppStorage.get('context'), (err: BusinessError): void => {
          if (err) {
            logger.error(TAG, `requestEnableNotification failed, code is ${err.code}, message is ${err.message}`);
          } else {
            logger.info(TAG, 'requestEnableNotification success');
          }
        });
        logger.info(TAG, `enableNotification success`);
      } catch (err) {
        logger.info(TAG, `enableNotification err ${JSON.stringify(err)}`);
      }
    }
    
    /**
     *
     * @param notificationRequest
     * @param id, Support specifying notification id when publishing notifications
     */
    async publishNotification(notificationRequest: notificationManager.NotificationRequest, group?: string) {
      notificationRequest.id = this.id;
      this.id++;
      if (group) {
        notificationRequest.groupName = group;
      }
    
      try {
        await notificationManager.publish(notificationRequest);
        logger.info(TAG, `publish notification success`);
        // 通知管理器添加新通知
        await notificationManagement.addNotification(notificationRequest);
      } catch (err) {
        if (err) {
          logger.info(TAG, `publishNotification err ${JSON.stringify(err)}`);
        }
      }
    }
    
    /**
     * cancel notification by id
     */
    async cancelNotificationById(id: number) {
      try {
        await notificationManager.cancel(id);
        logger.info(TAG, `cancel success`);
      } catch (err) {
        if (err) {
          logger.info(TAG, `cancel err ${JSON.stringify(err)}`);
        }
      }
    }
    
    /**
     * cancel all notification
     */
    async cancelAllNotifications() {
      try {
        await notificationManager.cancelAll();
        logger.info(TAG, `cancel all success`);
      } catch (err) {
        if (err) {
          logger.info(TAG, `cancel all err ${JSON.stringify(err)}`);
        }
      }
    }
    

    }

    export let notificationUtil = new NotificationUtil();

  • 允许发送通知:在进入[Index.ets] 前通过notificationUtil.enableNotification()调用notification.requestEnableNotification()接口向用户请求发送通知;

    /*

    • Copyright (c) 2023 Huawei Device Co., Ltd.
    • Licensed under the Apache License, Version 2.0 (the "License")
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • http://www.apache.org/licenses/LICENSE-2.0
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */

    import { NotificationList } from '../components/NotificationList';
    import { NoticePublish } from '../components/NotificationPublish';

    export interface TabImage {
    selectedImage: Resource,
    unselectedImage: Resource,
    }

    const MESSAGE_TAB: TabImage = {
    selectedImage: $r('app.media.ic_messages_filled'),
    unselectedImage: $r('app.media.ic_messages'),
    }
    const NOTIFICATION_TAB: TabImage = {
    selectedImage: $r('app.media.ic_public_send_filled'),
    unselectedImage: $r('app.media.ic_public_send'),
    }

    interface TAB_INDEX_TYPE {
    MESSAGE_TAB: number
    NOTIFICATION_TAB: number
    }

    const TAB_INDEX: TAB_INDEX_TYPE = {
    MESSAGE_TAB: 0,
    NOTIFICATION_TAB: 1
    }

    @Entry
    @Component
    struct Index {
    @State tabsIndex: number = 0

    @Builder TabBarBuilder(index: number, item: TabImage, tabBarName: Resource) {
    
      Column() {
        Image(this.tabsIndex === index ? item.selectedImage : item.unselectedImage)
          .width(24)
          .height(24)
          .margin({ bottom: 10 })
        Text(tabBarName)
          .fontSize(10)
    
      }
      .width('100%')
      .padding({ top: 0, bottom: 0 })
      .alignItems(HorizontalAlign.Center)
      .id(`tabBar${index}`)
    }
    
    build() {
      Column() {
        Tabs({ barPosition: BarPosition.End }) {
          TabContent() {
            Column() {
              if (this.tabsIndex === TAB_INDEX.MESSAGE_TAB) {
                NotificationList()
              }
              Blank()
            }
            .height('100%')
          }
          .tabBar(this.TabBarBuilder(TAB_INDEX.MESSAGE_TAB, MESSAGE_TAB, $r('app.string.messages_list_title')))
    
          TabContent() {
            Column() {
              NoticePublish()
              Blank()
            }
            .height('100%')
          }
          .tabBar(this.TabBarBuilder(TAB_INDEX.NOTIFICATION_TAB, NOTIFICATION_TAB, $r('app.string.notification_publish_title')),)
        }
        .barHeight(74)
        .barWidth('100%')
        .vertical(false)
        .onChange((index: number) => {
          this.tabsIndex = index
        })
    
      }.width('100%').height('100%')
      .backgroundColor($r('app.color.background_light_gray'))
    }
    

    }

  • 发送通知:通过publishNotification()封装发布通知的接口;

  • 获取应用所有消息通知、取消相关类型通知,角标管理接口封装在NotificationManagementUtil,源码参考:[NotificationManagementUtil.ets]

    /*

    • Copyright (c) 2023 Huawei Device Co., Ltd.
    • Licensed under the Apache License, Version 2.0 (the "License");
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • http://www.apache.org/licenses/LICENSE-2.0
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */
      import { notificationManager } from '@kit.NotificationKit';
      import { logger } from '../util/Logger';

    const NOTIFICATION_TYPE_SIZE = 5;

    export interface getAllNotificationsResultType {
    groupNotifications: Array<Array<notificationManager.NotificationRequest>>
    countsByType: Array<number>
    }

    // 通知管理
    class NotificationManagementUtil {
    typeNotifications: Array<Array<notificationManager.NotificationRequest>> = new Array(NOTIFICATION_TYPE_SIZE + 1);
    countsByType: Array<number> = new Array(NOTIFICATION_TYPE_SIZE + 1);
    badgeNum: number = 0;

    constructor() {
      this.countsByType.fill(0);
      for (let i = 0; i < NOTIFICATION_TYPE_SIZE + 1; i++) {
        this.typeNotifications[i] = new Array();
      }
      // 获取当前应用所有通知
      notificationManager.getActiveNotifications().then((notifications) => {
        for (let i = 0; i < notifications.length; i++) {
          let typeId = notifications[i].content.notificationContentType;
          this.countsByType[typeId as number] += 1;
          this.typeNotifications[typeId as number].push(notifications[i]);
        }
        logger.info(`getAllActiveNotifications success, data: ${JSON.stringify(notifications)}`)
        // 计算角标数量
        this.countsByType.forEach((num: number) => {
          this.badgeNum += num;
        })
      })
    }
    
    // 取消属于该类型的通知
    cancelNotificationType(typeId: number) {
      this.typeNotifications[typeId].forEach(item => {
        notificationManager.cancel(item.id);
      })
    }
    
    // 设置角标
    async setBadgeNumber(num: number) {
      await notificationManager.setBadgeNumber(num).then(() => {
        this.badgeNum = num;
        logger.info("displayBadge success");
      });
    }
    
    // 获取角标数量
    getBadgeNumber(): number {
      return this.badgeNum;
    }
    
    // 添加一条消息
    async addNotification(notification: notificationManager.NotificationRequest) {
      const typeId: notificationManager.ContentType = notification.content.notificationContentType as notificationManager.ContentType;
      this.typeNotifications[typeId].push(notification);
      this.countsByType[typeId] += 1;
      this.badgeNum += 1;
      await notificationManagement.setBadgeNumber(this.badgeNum);
      logger.info("add Message success");
    }
    
    // 获取当前所有消息及数量
    async getAllNotifications() {
      let result: getAllNotificationsResultType = {
        groupNotifications: this.typeNotifications,
        countsByType: this.countsByType
      }
      return result;
    }
    

    }

    export let notificationManagement = new NotificationManagementUtil();

  • 获取应用所有消息通知:在constructor()构造函数中调用@ohos.notificationManager中的getActiveNotifications接口获取所有通知及相应类型通知数量,通过封装getAllNotifications()对外提供接口获取当前消息及消息数量。

  • 取消相关类型通知:通过cancelNotificationType()封装取消相关通知类型的接口;

  • 角标管理接口:通过setBadgeNumber()封装设置应用角标数量的接口,通过getBadgeNumber()封装获取当前应用角标数量的接口。

    • 添加一条通知:通过addNotification()封装接口添加一条通知到消息管理器,当发送通知的时候进行调用。
  • NotificationOperations向外提供接口,在页面中调用它们来实现功能,源码参考:[NotificationOperations.ets]

    /*

    • Copyright (c) 2023 Huawei Device Co., Ltd.
    • Licensed under the Apache License, Version 2.0 (the "License")
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • http://www.apache.org/licenses/LICENSE-2.0
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */

    import { image } from '@kit.ImageKit';
    import { notificationManager } from '@kit.NotificationKit';
    import { logger, notificationUtil, notificationContentUtil, notificationRequestUtil } from '@ohos/notification';

    const TAG: string = 'Sample_Notification';
    const MULTI_LINE_CONTENT: Array<string> = ['line0', 'line1', 'line2', 'line3']; // 多行文本通知的多行文本内容

    interface NOTIFICATION_GROUP_TYPE {
    BASIC: string
    LONG_TEXT: string
    MULTI_LINE: string
    PICTURE: string
    CONVERSATION: string
    }

    const NOTIFICATION_GROUP: NOTIFICATION_GROUP_TYPE = { // 定义不同类型通知的通知组
    BASIC: 'BASIC',
    LONG_TEXT: 'LONG_TEXT',
    MULTI_LINE: 'MULTI_LINE',
    PICTURE: 'PICTURE',
    CONVERSATION: 'CONVERSATION'
    }

    export default class NotificationOperations {
    private context: Context;
    private basicContent: notificationManager.NotificationBasicContent;

    // 在初始化函数初始化基本通知类型的参数
    constructor(context: Context) {
      this.context = context;
      let notificationTitle = '';
      let notificationText = this.context.resourceManager.getStringSync($r('app.string.notification_content'));
      let notificationAdditional = this.context.resourceManager.getStringSync($r('app.string.notification_additional'));
      this.basicContent = {
        title: notificationTitle,
        text: notificationText,
        additionalText: notificationAdditional
      }
    }
    
    // 发布基本类型通知
    publishBasicNotification = () => {
      try {
        logger.info(TAG, 'publishBasicNotification');
        this.basicContent.title = this.context.resourceManager.getStringSync($r('app.string.basic_notification'));
        let notificationContent = notificationContentUtil.initBasicNotificationContent(this.basicContent);
        notificationUtil.publishNotification(notificationRequestUtil.initBasicNotificationRequest(notificationContent as notificationManager.NotificationContent) as notificationManager.NotificationRequest);
      } catch (error) {
        logger.info(TAG, `publishBasicNotification error, error = ${JSON.stringify(error)}`);
      }
    }
    // 发布长文本类型通知
    publishLongTextNotification = () => {
      try {
        logger.info(TAG, 'publishLongTextNotification');
        this.basicContent.title = this.context.resourceManager.getStringSync($r('app.string.long_text_notification'));
        let notificationLongText = this.context.resourceManager.getStringSync($r('app.string.notification_long_text'));
        let notificationBriefText = this.context.resourceManager.getStringSync($r('app.string.notification_brief_text'));
        let notificationExpandedText = this.context.resourceManager.getStringSync($r('app.string.notification_expanded_title'));
        let notificationContent = notificationContentUtil.initNotificationLongTextContent(this.basicContent, notificationLongText, notificationBriefText, notificationExpandedText);
        notificationUtil.publishNotification(notificationRequestUtil.initBasicNotificationRequest(notificationContent as notificationManager.NotificationContent) as notificationManager.NotificationRequest);
      } catch (error) {
        logger.info(TAG, `publishLongTextNotification error, error = ${JSON.stringify(error)}`);
      }
    }
    // 发布多行文本类型通知
    publishMultiLineNotification = () => {
      try {
        logger.info(TAG, 'publishMultiLineNotification');
        this.basicContent.title = this.context.resourceManager.getStringSync($r('app.string.multiline_notification'));
        let notificationBriefText = this.context.resourceManager.getStringSync($r('app.string.notification_brief_text'));
        let notificationLongTitle = this.context.resourceManager.getStringSync($r('app.string.notification_expanded_title'));
        let notificationContent = notificationContentUtil.initNotificationMultiLineContent(this.basicContent, notificationBriefText, notificationLongTitle, MULTI_LINE_CONTENT);
        notificationUtil.publishNotification(notificationRequestUtil.initBasicNotificationRequest(notificationContent as notificationManager.NotificationContent) as notificationManager.NotificationRequest);
      } catch (error) {
        logger.info(TAG, `publishMultiLineNotification error, error = ${JSON.stringify(error)}`);
      }
    }
    // 发布图片类型通知
    publishPictureNotification = async () => {
      try {
        logger.info(TAG, 'publishPictureNotification');
        this.basicContent.title = this.context.resourceManager.getStringSync($r('app.string.picture_notification'));
        let notificationBriefText = this.context.resourceManager.getStringSync($r('app.string.notification_brief_text'));
        let notificationExpandedText = this.context.resourceManager.getStringSync($r('app.string.notification_expanded_title'));
        let imageArray = await this.context.resourceManager.getMediaContent($r('app.media.notification_icon').id);
        let imageResource = image.createImageSource(imageArray.buffer as ArrayBuffer);
        let picture = await imageResource.createPixelMap();
        let notificationContent = notificationContentUtil.initNotificationPictureContent(this.basicContent, notificationBriefText, notificationExpandedText, picture);
        notificationUtil.publishNotification(notificationRequestUtil.initBasicNotificationRequest(notificationContent as notificationManager.NotificationContent) as notificationManager.NotificationRequest);
      } catch (error) {
        logger.info(TAG, `publishPictureNotification error, error = ${JSON.stringify(error)}`);
      }
    }
    // 发布社交类型的通知
    publishConversationNotification = async () => {
      try {
        logger.info(TAG, 'publishConversationNotification');
        this.basicContent.title = this.context.resourceManager.getStringSync($r('app.string.conversation_notification'));
        let notificationContent = notificationContentUtil.initNotificationConversationContent(this.basicContent);
        notificationUtil.publishNotification(notificationRequestUtil.initBasicNotificationRequest(notificationContent as notificationManager.NotificationContent) as notificationManager.NotificationRequest, NOTIFICATION_GROUP.CONVERSATION);
      } catch (error) {
        logger.info(TAG, `publishNotificationWithWantAgent error, error = ${JSON.stringify(error)}`);
      }
    }
    

    }

  • 发布通知:在[Index.ets]页面中进入发送通知Tab页签,通过点击事件调用NotificationOperations中封装的对应的方法,然后从NotificationContentUtil中获取对应的主体内容content,将 content传递给NotificationRequestUtil得到完整的发布信息,最后调用NotificationUtil.publishNotification()发布内容,并调用NotificationManagementUtil的addNotification()添加一条消息;

    /*

    • Copyright (c) 2023 Huawei Device Co., Ltd.
    • Licensed under the Apache License, Version 2.0 (the "License")
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • http://www.apache.org/licenses/LICENSE-2.0
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */

    import { NotificationList } from '../components/NotificationList';
    import { NoticePublish } from '../components/NotificationPublish';

    export interface TabImage {
    selectedImage: Resource,
    unselectedImage: Resource,
    }

    const MESSAGE_TAB: TabImage = {
    selectedImage: $r('app.media.ic_messages_filled'),
    unselectedImage: $r('app.media.ic_messages'),
    }
    const NOTIFICATION_TAB: TabImage = {
    selectedImage: $r('app.media.ic_public_send_filled'),
    unselectedImage: $r('app.media.ic_public_send'),
    }

    interface TAB_INDEX_TYPE {
    MESSAGE_TAB: number
    NOTIFICATION_TAB: number
    }

    const TAB_INDEX: TAB_INDEX_TYPE = {
    MESSAGE_TAB: 0,
    NOTIFICATION_TAB: 1
    }

    @Entry
    @Component
    struct Index {
    @State tabsIndex: number = 0

    @Builder TabBarBuilder(index: number, item: TabImage, tabBarName: Resource) {
    
      Column() {
        Image(this.tabsIndex === index ? item.selectedImage : item.unselectedImage)
          .width(24)
          .height(24)
          .margin({ bottom: 10 })
        Text(tabBarName)
          .fontSize(10)
    
      }
      .width('100%')
      .padding({ top: 0, bottom: 0 })
      .alignItems(HorizontalAlign.Center)
      .id(`tabBar${index}`)
    }
    
    build() {
      Column() {
        Tabs({ barPosition: BarPosition.End }) {
          TabContent() {
            Column() {
              if (this.tabsIndex === TAB_INDEX.MESSAGE_TAB) {
                NotificationList()
              }
              Blank()
            }
            .height('100%')
          }
          .tabBar(this.TabBarBuilder(TAB_INDEX.MESSAGE_TAB, MESSAGE_TAB, $r('app.string.messages_list_title')))
    
          TabContent() {
            Column() {
              NoticePublish()
              Blank()
            }
            .height('100%')
          }
          .tabBar(this.TabBarBuilder(TAB_INDEX.NOTIFICATION_TAB, NOTIFICATION_TAB, $r('app.string.notification_publish_title')),)
        }
        .barHeight(74)
        .barWidth('100%')
        .vertical(false)
        .onChange((index: number) => {
          this.tabsIndex = index
        })
    
      }.width('100%').height('100%')
      .backgroundColor($r('app.color.background_light_gray'))
    }
    

    }

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!

下面是鸿蒙的完整学习路线 ,展示如下:

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

相关推荐
xo198820111 小时前
鸿蒙人脸识别
redis·华为·harmonyos
塞尔维亚大汉2 小时前
【OpenHarmony】 鸿蒙 UI开发之CircleIndicator
harmonyos·arkui
BisonLiu2 小时前
华为仓颉鸿蒙HarmonyOS NEXT仓颉原生数据网络HTTP请求(ohos.net.http)
harmonyos
BisonLiu2 小时前
华为仓颉鸿蒙NEXT原生加解密算法库框架
harmonyos
变色龙云2 小时前
网页生成鸿蒙App
华为·harmonyos
BisonLiu2 小时前
华为仓颉鸿蒙HarmonyOS NEXT仓颉原生ohos.request(上传下载)
harmonyos
s_daqing2 小时前
华为手机鸿蒙4.2连接不上adb
华为·智能手机·harmonyos
Lucky me.2 小时前
鸿蒙开发使用axios请求后端网络服务出现该错误
华为·harmonyos
_Shirley3 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
大土豆的bug记录6 小时前
关于鸿蒙架构feature
华为·arkts·鸿蒙·arkui