文章目录
- 前言
- 通知渠道:先把地基打好
- 基础通知:一行代码搞定
- 多行文本通知:内容多了用它
- 进度条通知:下载/上传必备
- 图片通知:让通知更直观
- 通知的交互操作:按钮和跳转
- 定时通知:让通知自己"闹钟响"
- 实战:电商 App 通知管理器
- 几点心得
前言
通知这个功能看着简单,不就是弹个消息嘛。但真做起来,里面的门道不少:通知渠道怎么分组、进度条通知怎么更新、按钮点击怎么回调、多条消息怎么聚合……
今天用一篇把 HarmonyOS 的通知系统讲透,结尾搞一个电商 App 的通知方案,直接能用到项目里。
通知渠道:先把地基打好
HarmonyOS 的通知跟 Android 类似,也有渠道(Channel)的概念。渠道决定了通知的分组、重要性级别、是否允许声音震动这些属性。
创建渠道要趁早——最好在 App 启动时就搞定:
import{notificationManager}from'@kit.NotificationKit';asyncfunctioninitNotificationChannels(){// 订单通知渠道constorderChannel:notificationManager.NotificationChannel={name:'订单通知',description:'订单状态变更、物流信息',importance:notificationManager.Importance.HIGH,lockscreenVisibility:notificationManager.LockScreenVisibility.PUBLIC,};// 促销通知渠道constpromoChannel:notificationManager.NotificationChannel={name:'促销活动',description:'优惠信息、限时折扣',importance:notificationManager.Importance.LOW,lockscreenVisibility:notificationManager.LockScreenVisibility.PUBLIC,};awaitnotificationManager.addChannel('order',orderChannel);awaitnotificationManager.addChannel('promo',promoChannel);}重要性级别这个参数很关键。HIGH级别的通知会弹横幅,用户正在操作时也能看到;LOW级别的就安静地躺在通知栏里。别把促销消息设成HIGH,用户会烦死你的。
基础通知:一行代码搞定
最简单的通知就是一行文字:
asyncfunctionsendTextNotification(title:string,text:string){constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'order',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title:title,text:text,additionalText:'刚刚'}}};awaitnotificationManager.publish(request);}多行文本通知:内容多了用它
当你的通知内容比较长(比如物流详情),用多行文本类型:
asyncfunctionsendMultiLineNotification(title:string,lines:string[]){constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'order',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,multiLine:{title:title,text:lines[0],additionalText:'订单详情',multiLine:lines}}};awaitnotificationManager.publish(request);}// 调用sendMultiLineNotification('物流更新',['您的包裹已到达杭州转运中心','预计明天下午送达','快递员:张师傅 138****1234']);进度条通知:下载/上传必备
上篇后台任务里我们用到了进度条通知,这里再详细说说。关键参数是isAlertOnce——设成true后,更新通知不会反复响铃和震动:
asyncfunctionupdateProgressNotification(id:number,title:string,current:number,total:number){constpercent=Math.round((current/total)*100);constrequest:notificationManager.NotificationRequest={id:id,// 固定 id,实现更新而非创建新通知content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_PROGRESS,normal:{title:title,text:`${percent}%`,additionalText:`${current}/${total}`}},isAlertOnce:true,progressBarValue:current,progressBarMaxValue:total};awaitnotificationManager.publish(request);}注意id要保持一致,这样系统会用新通知替换旧通知,而不是创建一堆通知。
图片通知:让通知更直观
电商场景经常需要在通知里放商品图片。HarmonyOS 支持图片类型的通知:
import{image}from'@kit.ImageKit';asyncfunctionsendImageNotification(title:string,text:string,imagePath:string){constpixelMap=awaitimage.createImageSource(imagePath).createPixelMap();constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'promo',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_PICTURE,picture:{title:title,text:text,additionalText:'限时优惠',picture:pixelMap}}};awaitnotificationManager.publish(request);}通知的交互操作:按钮和跳转
通知不只是展示信息,还能让用户直接操作。比如订单通知里加个"确认收货"按钮:
asyncfunctionsendOrderNotification(orderId:string){constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'order',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title:'订单已送达',text:`订单${orderId}已送达,请确认收货`,additionalText:'快递'}},// 点击通知的跳转wantAgent:awaitcreateWantAgent(orderId),// 通知操作按钮actionButtons:[{title:'确认收货',wantAgent:awaitcreateActionAgent('confirm',orderId)},{title:'查看物流',wantAgent:awaitcreateActionAgent('logistics',orderId)}]};awaitnotificationManager.publish(request);}wantAgent是用来处理通知交互的核心。点击通知、点击按钮、滑动删除等操作都会触发对应的 WantAgent:
import{WantAgent,wantAgent}from'@kit.AbilityKit';asyncfunctioncreateWantAgent(orderId:string):Promise<WantAgent>{constwantAgentInfo:wantAgent.WantAgentInfo={wants:[{bundleName:'com.example.shop',abilityName:'OrderDetailAbility',parameters:{orderId:orderId}}],actionType:wantAgent.OperationType.START_ABILITY,requestCode:0,actionFlags:[wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};returnwantAgent.getWantAgent(wantAgentInfo);}asyncfunctioncreateActionAgent(action:string,orderId:string):Promise<WantAgent>{constwantAgentInfo:wantAgent.WantAgentInfo={wants:[{bundleName:'com.example.shop',abilityName:'EntryAbility',parameters:{action:action,orderId:orderId}}],actionType:wantAgent.OperationType.SEND_DATA,requestCode:0,actionFlags:[wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};returnwantAgent.getWantAgent(wantAgentInfo);}定时通知:让通知自己"闹钟响"
有时候你需要通知在指定时间弹出,比如"明天上午 10 点提醒用户付款":
asyncfunctionscheduleNotification(title:string,text:string,triggerTime:Date){constrequest:notificationManager.NotificationRequest={id:Date.now(),content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title,text}},deliveryTime:triggerTime.getTime()// 毫秒时间戳};awaitnotificationManager.publish(request);}// 明天上午 10 点提醒consttomorrow=newDate();tomorrow.setDate(tomorrow.getDate()+1);tomorrow.setHours(10,0,0,0);scheduleNotification('待付款提醒','您有一笔订单即将超时,请及时付款',tomorrow);实战:电商 App 通知管理器
把上面的东西整合成一个完整的电商通知管理器:
import{notificationManager}from'@kit.NotificationKit';import{WantAgent,wantAgent}from'@kit.AbilityKit';import{image}from'@kit.ImageKit';exportclassShopNotificationManager{privatestaticinstance:ShopNotificationManager;staticgetInstance():ShopNotificationManager{if(!ShopNotificationManager.instance){ShopNotificationManager.instance=newShopNotificationManager();}returnShopNotificationManager.instance;}// 初始化渠道asyncinit(){constchannels:notificationManager.NotificationChannel[]=[{name:'订单通知',importance:notificationManager.Importance.HIGH,},{name:'促销通知',importance:notificationManager.Importance.LOW,},{name:'系统消息',importance:notificationManager.Importance.MEDIUM,}];awaitnotificationManager.addChannel('order',channels[0]);awaitnotificationManager.addChannel('promo',channels[1]);awaitnotificationManager.addChannel('system',channels[2]);}// 订单状态推送asyncnotifyOrderStatus(orderId:string,status:string,detail:string){constrequest:notificationManager.NotificationRequest={id:this.hashCode(orderId),channelId:'order',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title:`订单${status}`,text:detail,additionalText:orderId}},actionButtons:status==='已送达'?[{title:'确认收货',wantAgent:awaitthis.buildAgent('confirm',orderId)},{title:'申请售后',wantAgent:awaitthis.buildAgent('refund',orderId)}]:[],wantAgent:awaitthis.buildAgent('detail',orderId)};awaitnotificationManager.publish(request);}// 促销活动(带图片)asyncnotifyPromotion(title:string,desc:string,imgPath:string){letpixelMap:image.PixelMap|undefined;try{pixelMap=awaitimage.createImageSource(imgPath).createPixelMap();}catch(e){// 图片加载失败就降级为文本通知}constcontentType=pixelMap?notificationManager.ContentType.NOTIFICATION_CONTENT_PICTURE:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT;constcontent=pixelMap?{notificationContentType:contentType,picture:{title,text:desc,additionalText:'限时优惠',picture:pixelMap}}:{notificationContentType:contentType,normal:{title,text:desc,additionalText:'限时优惠'}};constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'promo',content:content};awaitnotificationManager.publish(request);}// 消息聚合:多条通知合并展示asyncnotifyMessages(messages:string[],from:string){constrequest:notificationManager.NotificationRequest={id:this.hashCode(from),channelId:'system',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_MULTILINE,multiLine:{title:`${from}(${messages.length}条新消息)`,text:messages[messages.length-1],multiLine:messages}},// 相同分组的通知会自动聚合notificationGroup:{name:from,isAlertOnce:true}};awaitnotificationManager.publish(request);}// 定时提醒asyncscheduleReminder(title:string,text:string,time:Date){constrequest:notificationManager.NotificationRequest={id:Date.now(),channelId:'system',content:{notificationContentType:notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal:{title,text}},deliveryTime:time.getTime()};awaitnotificationManager.publish(request);}privateasyncbuildAgent(action:string,orderId:string):Promise<WantAgent>{constinfo:wantAgent.WantAgentInfo={wants:[{bundleName:'com.example.shop',abilityName:'EntryAbility',parameters:{action,orderId}}],actionType:wantAgent.OperationType.SEND_DATA,requestCode:this.hashCode(orderId+action),actionFlags:[wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};returnwantAgent.getWantAgent(info);}privatehashCode(str:string):number{lethash=0;for(leti=0;i<str.length;i++){hash=((hash<<5)-hash)+str.charCodeAt(i);hash|=0;}returnMath.abs(hash);}// 清除指定订单的所有通知asyncclearOrderNotifications(orderId:string){awaitnotificationManager.cancel(this.hashCode(orderId));}// 清除所有通知asyncclearAll(){awaitnotificationManager.cancelAll();}}用起来就很简洁了:
constnotifier=ShopNotificationManager.getInstance();awaitnotifier.init();// 订单发货了awaitnotifier.notifyOrderStatus('ORD20260623001','已发货','顺丰快递 SF1234567890');// 推送促销awaitnotifier.notifyPromotion('618 大促','全场满 300 减 50','/data/promo.jpg');// 消息聚合awaitnotifier.notifyMessages(['在吗?','这个商品有货吗?','能便宜点不?'],'买家-小明');几点心得
通知这东西,做好了用户觉得贴心,做烂了用户直接卸载。几个经验:
第一,渠道一定要分好。别把所有通知都塞到一个渠道里,用户想关促销通知的时候发现连订单通知也关了,那就尴尬了。
第二,更新类通知(进度条、实时比分)一定用固定 id +isAlertOnce,不然通知栏会疯掉。
第三,通知数量控制一下。超过 5 条就该考虑聚合了,通知栏占满的用户体验很差。
第四,定时通知用deliveryTime比你自己写定时器靠谱得多,系统级别的管理不怕进程被杀。