tencent cloud

移动推送

产品动态
公告
产品功能动态
Android SDK 发布动态
iOS SDK 发布动态
macOS SDK 发布动态
产品简介
产品概述
产品优势
应用场景
全球化部署
购买指南
价格总览
购买指引
计费模式
免费试用
欠费说明
快速入门
创建产品和应用
Android 快速接入
iOS 快速接入
创建推送任务
查询推送记录
推送测试方法指引
产品限制说明
操作指南
推送管理
推送高级功能
实践教程
iOS 平台角标功能实践
API 文档
简介
API 概览
调用方式
推送相关接口
标签相关接口
账号相关接口
统计相关接口
用户属性相关接口
服务端错误码
服务端 SDK
API(Java)
SDK 文档
Android 接入指南
iOS 接入指南
客户端集成插件
macOS接入指南
用户及权限
快速入门配置
进阶自定义配置
资源标签
服务协议
服务等级协议
开发者协议
常见问题
iOS 常见问题
Android 常见问题
Flutter 常见问题
其他问题
移动推送政策
移动推送隐私协议
TPNS 数据处理和安全协议
Developer Agreement
联系我们
词汇表
文档移动推送实践教程iOS 平台角标功能实践

iOS 平台角标功能实践

PDF
聚焦模式
字号
最后更新时间: 2024-01-16 17:35:03
移动推送提供一系列角标控制相关方法供您使用,以下列举两个经典场景下的角标实现方法。 本文档为 iOS 平台角标最佳实践,Android 平台角标适配请查看 《Android 角标适配指南》

场景一:打开应用时清空应用的角标数及通知栏消息

场景描述

应用未启动时,角标的数等于当前设备收到该应用的推送条数。
应用进入前台时,将角标的数量设置为0,清空通知栏消息,同时将云端角标数设置为0。

实现方法

此类场景建议使用角标自增方案,如下: 第一步:通过 API 创建推送 时,设置应用角标数 badge_type = -2,角标数字自动加1。 第二步:当 App 启动时,先调用「清空应用角标并清空通知栏」方法来清空本地角标数和通知栏消息,实现代码如下图:
第三步:清空云端角标数,实现代码如下图:
第四步:需要更新云端角标数时,需调用下方接口将角标值同步到移动推送服务器,下次推送时以此值为基准。如当前移动推送服务器角标值同步为 n,则下次收到推送时 App 角标值为 n+1。
//将角标值同步到移动推送服务器,下次推送时以此值为基准
- (void)setBadge:(NSInteger)badgeNumber;
注意:
1. setBadge 方法依赖 移动推送自建通道实现角标同步,应用在退入后台时,移动推送自建通道会断开连接,此时调用 setBadge 会失败,这种情况只能使用自定义角标数方案。
2. 应用进入前台时,移动推送自建通道会尝试恢复连接,在连接恢复之前调用 setBadge 会失败,这种情况只能使用自定义角标数方案。
3. 冷启动应用时需要在注册方法回调中使用 setBadge。
4. 监听移动推送网络连接的状态,详见 如何监听移动推送网络连接的状态?

场景二:角标数包含通知栏消息数与应用内消息数

场景描述

应用的角标数 = 通知栏消息数 + 应用内消息数。用户点击某条通知拉起App时,通知栏消息数会发生变化,此时需要更新App角标数。 在该场景下,开发者需要维护设备的总消息数(包括通知栏消息数和应用内消息数)。

实现方法

1. 获取通知栏消息数,代码如下:
//需要获取通知栏的消息数
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *notifications) {
NSLog(@"notifications count:%d.",notifications.count);
}];
2. 假设通知栏消息数为a,应用内消息数为b,设置App角标数代码如下:
//设置应用角标数
[XGPush defaultManager].xgApplicationBadgeNumber = a + b;
3. 
建议使用自定义角标数方案,方法如下
: 通过 API 创建 推送时,直接设置应用角标数badge_type >= 0,自定义角标数字为总消息数。如总消息数为10,则设置badge_type = 10。

问题答疑

如何只清空角标数,但是在通知中心保留推送通知?

//不在appIcon上显示推送数量,但是在系统通知栏保留推送通知的方法
+ (void)resetBageNumber{
if(APNS_IS_IOS11_LATER){
//iOS 11后,直接设置badgeNumber = -1就生效了
[UIApplication sharedApplication].applicationIconBadgeNumber = -1;
}else{
UILocalNotification *clearEpisodeNotification = [[UILocalNotification alloc] init];
clearEpisodeNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:(0.3)];
clearEpisodeNotification.timeZone = [NSTimeZone defaultTimeZone];
clearEpisodeNotification.applicationIconBadgeNumber = -1;
[[UIApplication sharedApplication] scheduleLocalNotification:clearEpisodeNotification];
}
}

如何设置角标数,但是在通知中心保留推送通知?

#define APNS_IS_IOS11_LATER ([UIDevice currentDevice].systemVersion.floatValue >= 11.0f)
//在appIcon上推送角标数量逻辑,但是在系统通知栏保留推送通知的方法
+ (void)resetBageNumber:(int) number{
/// 如果是非0数,直接设置
if(number){
[XGPush defaultManager].xgApplicationBadgeNumber = number;
return;
}
/// 如果是0,则通过如下逻辑设置
if(APNS_IS_IOS11_LATER){
//iOS 11后,直接设置badgeNumber = -1就生效了
[UIApplication sharedApplication].applicationIconBadgeNumber = -1;
}else{
UILocalNotification *clearEpisodeNotification = [[UILocalNotificationalloc] init];
clearEpisodeNotification.fireDate = [NSDatedateWithTimeIntervalSinceNow:(0.3)];
clearEpisodeNotification.timeZone = [NSTimeZonedefaultTimeZone];
clearEpisodeNotification.applicationIconBadgeNumber = -1;
[[UIApplication sharedApplication] scheduleLocalNotification:clearEpisodeNotification];
}
}

如何在通知中心删除特定通知?

//objectID:通知下发的消息id,用以辨识通知
- (void)removeNotificationsForObjectID:(ObjectID *)objectID {
__weak __typeof(self) weakSelf = self;
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *notifications) {
__strong __typeof(weakSelf) self = weakSelf;
NSMutableArray <NSString *> *identifiersToRemove = [@[] mutableCopy];
for (UNNotification *notification in notifications) {
//筛选符合删除条件的通知
ObjectID *objectIDFromNotification = [self marshalNotification:notification];
if ([objectID isEqual:objectIDFromNotification]) {
[identifiersToRemove addObject:notification.request.identifier];
}
}
[[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:identifiersToRemove];
}];
}
注意:
此方法仅支持 iOS 10 及以上的操作系统版本。

如何在 App 没有启动时,只更新应用角标?

使用 自定义角标数方案,创建没有内容,只有角标数的推送。

如何监听移动推送网络连接的状态?

建议使用 v1.3.1.0 及以上版本 SDK 的如下方法:
// TPNS网络连接成功
- (void)xgPushNetworkConnected;
// TPNS网络连接断开
- (void)xgPushNetworkDisconnected;

通过 API 创建推送 时,如何让角标数不变?

badge_type = -1:角标数字不变。

如何查询App的角标修改方法的函数堆栈?

可以通过hook系统类UIApplication的setApplicationIconBadgeNumber:方法打印函数调用堆栈,从而发现调用者信息,代码如下: UIApplication+ApplicationIconBadgeNumber.h文件
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIApplication (ApplicationIconBadgeNumber)

@end

NS_ASSUME_NONNULL_END

UIApplication+ApplicationIconBadgeNumber.m文件
#import "UIApplication+ApplicationIconBadgeNumber.h"
#import <objc/runtime.h>

@implementation UIApplication (ApplicationIconBadgeNumber)

//load类方法(当某个类的代码被读到内存后调用)
+ (void)load
{
SEL origSel = @selector(setApplicationIconBadgeNumber:);
SEL swizSel = @selector(swiz_setApplicationIconBadgeNumber:);
[UIApplication swizzleMethods:[self class] originalSelector:origSel swizzledSelector:swizSel];
}

//交换两个方法的实现
+ (void)swizzleMethods:(Class)class originalSelector:(SEL)origSel swizzledSelector:(SEL)swizSel
{
Method origMethod = class_getInstanceMethod(class, origSel);
Method swizMethod = class_getInstanceMethod(class, swizSel);
BOOL didAddMethod = class_addMethod(class, origSel, method_getImplementation(swizMethod), method_getTypeEncoding(swizMethod));
if (didAddMethod){
class_replaceMethod(class, swizSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}else{
method_exchangeImplementations(origMethod, swizMethod);
}
}

/// hook设置角标
- (void)swiz_setApplicationIconBadgeNumber:(NSInteger)number
{
NSLog(@"调用了swiz_setApplicationIconBadgeNumber方法");
/// 打印当前函数调用堆栈
NSArray *syms = [NSThread  callStackSymbols];
for(int i = 0 ; i < [syms count]; i++){
NSLog(@"<%@ %p> %@ - caller: %@ ", [self class], self, NSStringFromSelector(_cmd),[syms objectAtIndex:i]);
}
//执行这句的时候跳转到setApplicationIconBadgeNumber方法中
[self swiz_setApplicationIconBadgeNumber:number];
}

@end

将上面的两个文件加入到自己的工程中使用。 下图是加入到移动推送 Demo示例:



帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈