近期发现一个蛋疼的问题,iOS里清程序角标的时候会把通知栏的推送消息也清了。试验了好久得到了一些结论,记录下结果。
推送分为远程推送和本地推送。分开来记录。
在远程推送的协议中,有一个badge字段,这个字段是用来设置程序角标值的。当app处于非运行状态或者在后台时,收到远程推送,app并不会运行任何代码,一切事务都是由系统处理(iOS 7推出的静默推送是特例)。此时收到推送,系统会根据推送消息的aps里的内容执行操作,包括:"sound"-提示音、"alert"-通知栏显示的推送内容、"badge"-程序角标值、"content-available"-静默推送标志。sound、alert和content-available就不提了,单说badge。分为下面几种情况:
- 收到推送前程序角标为零,收到的推送消息badge为0。此时角标一直处于为零的状态(为零时不显示角标)。
- 收到推送前程序角标为零,收到的推送消息badge大于0。此时角标从不显示变为badge的值。
- 收到推送前程序角标不为零,收到的推送消息badge为0。此时角标从显示变为不显示,且清空所有通知栏的消息,包括新收到的推送消息。(此处测试的情况是,当收到推送前角标不为0,收到的推送消息badge为0或小于0时,角标保持不变)。
- 收到推送前程序角标不为零,收到的推送消息badge大于0。此时角标值更新。
本地推送通过UILocalNotification对象发送,UILocalNotification有一个applicationIconBadgeNumber属性,作用与远程推送的badge字段类似,针对上而的四种情况,结果与远程推送相同。但需要注意一点:当applicationIconBadgeNumber设为零(也是默认值)时,意味着不改变程序角标,而不是将程序角标置零。当applicationIconBadgeNumber < 0时,程序角标变为不显示,通知栏通知不清零。顺带说一下UILocalNotification的cancelLocalNotification:和cancelAllLocalNotification方法,这两个方法是清除那些在日程表中尚未推送的本地推送消息,而不是清除通知栏内的推送消息。通知栏内的消息完全由系统控制,程序无法获得。只有当用户点击了通知栏的消息,系统调起app的didReceiveRemoteNotification或者didReceiveLocalNotification方法会将点击的推送内容传递给这两个方法,app才能获得这些数据。
另外,UIApplication也有一个applicationIconBadgeNumber的属性,该属性就是代指程序角标的。可以在代码中直接更改该属性的值,其效果与远程推送的四种情况类似。强调一点,当程序角标为非零时,将UIApplication的applicationIconBadgeNumber属性设为零,会清空通知栏。
综合上面的结论,一旦将程序的角标从非零置为零,就会清空通知栏的所有通知。如果想清除角标但不清空通知栏,有如下方法:
1.发送一条远程推送,推送内容只有badge,并将badge的值设为负数。此时程序角标会消失但是通知栏的推送消息不清除(此处有待确定)。
2.同样的方法,发送一条本地推送。
不能通过直接将UIApplication的applicationIconBadgeNumber设为负数的方法解决问题,实验证明,这种做法一样会清空通知栏。