iOS系统可支持本地通知和远程通知,一个通知在客户端收到的时候可能是一个通知窗体,可能会播放一段通知声音,还有可能在程序图标上增加一个数字,还有可能三者皆有。
本文描述ios系统中计划local notification,注册 remote notification,以及处理 local和remote notification的步骤。本文中客户端API中notification推送指的就是remote notfication的推送
第一个知识点:准备个人定制音频作为提示音,
请注意下面四个小问题-----
1, 系统能播放的四种音频数据格式 Linear PCM MA4 (IMA/ADPCM) µLaw aLaw 对应的后缀名可以是aiff, wav, or caf file. Then, 2, 可以用afconvert来转换音频,例如把16位的线性PCM系统音频格式文件 Submarine.aiff 转换成IMA4音频,存为.CAF文件。 在终端执行即可 afconvert /System/Library/Sounds/Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v 3, 如何确定音频格式呢。 打开QuickTime Player-> Movie menu->Show Movie Inspector 4, 个人定制音频必须是30s以下。否则就播放默认的声音了。
第二个知识点:预定一个Local Notification 需要了解下面5个步骤 1, Allocate 和 initialize 一个 UILocalNotification对象。 2, fireDate属性赋值 3, 设置别的几个体型要素 提示框,提示音,图标上的提示数字。也可以带别的个性化数据:通过userInfo带出去。 4, 然后Schedule这个通知。通过UIApplication.scheduleLocalNotification来预定执行或者立马执行presentLocalNotificationNow: 5, 也可以取消这个通知。用这个方法:cancelLocalNotification和cancelAllLocalNotifications这个方法 看下代码 /
02
- (
void
)scheduleNotificationWithItem:(ToDoItem *)item interval:(
int
)minutesBefore {
03
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
04
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
05
[dateComps setDay:item.day];
06
[dateComps setMonth:item.month];
07
[dateComps setYear:item.year];
08
[dateComps setHour:item.hour];
09
[dateComps setMinute:item.minute];
10
NSDate *itemDate = [calendar dateFromComponents:dateComps];
13
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
14
if
(localNotif == nil)
16
localNotif.fireDate = [itemDate addTimeInterval:-(minutesBefore*60)];
17
localNotif.timeZone = [NSTimeZone defaultTimeZone];
19
localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@
"%@ in %i minutes."
, nil),
20
item.eventName, minutesBefore];
21
localNotif.alertAction = NSLocalizedString(@
"View Details"
, nil);
23
localNotif.soundName = UILocalNotificationDefaultSoundName;
24
localNotif.applicationIconBadgeNumber = 1;
26
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:item.eventName forKey:ToDoItemKey];
27
localNotif.userInfo = infoDict;
29
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
37
- (
void
)applicationDidEnterBackground:(UIApplication *)application {
38
NSLog(@
"Application entered background state."
);
40
NSAssert(self->bgTask == UIInvalidBackgroundTask, nil);
42
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
43
dispatch_async(dispatch_get_main_queue(), ^{
44
[application endBackgroundTask:self->bgTask];
45
self->bgTask = UIInvalidBackgroundTask;
49
dispatch_async(dispatch_get_main_queue(), ^{
50
while
([application backgroundTimeRemaining] > 1.0) {
51
NSString *
friend
= [self checkForIncomingChat];
53
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
55
localNotif.alertBody = [NSString stringWithFormat:
56
NSLocalizedString(@
"%@ has a message for you."
, nil),
friend
];
57
localNotif.alertAction = NSLocalizedString(@
"Read Message"
, nil);
58
localNotif.soundName = @
"alarmsound.caf"
;
59
localNotif.applicationIconBadgeNumber = 1;
60
[application presentLocalNotificationNow:localNotif];
67
[application endBackgroundTask:self->bgTask];
68
self->bgTask = UIInvalidBackgroundTask;
第三个知识点:注册 Remote Notifications
需要注册Apple Push Notification service ,有三步
1,调用 registerForRemoteNotificationTypes:方法
2,通过实现application:didRegisterForRemoteNotificationsWithDeviceToken:这个delegate来接受从APNs传过来的device token。这个token是个binary的值
3,程序启动即需调用theregisterForRemoteNotificationTypes: 方法来注册推送。后期可以调用enabledRemoteNotificationTypes这个方法来改通知类型。
需要注意的事情:
如果网络不通,application:didRegisterForRemoteNotificationsWithDeviceToken这个方法和 application:didFailToRegisterForRemoteNotificationsWithError:都不会被调用哦。 Wifi的时候,通过5223端口链接APNs通常连不上哟因为网管把端口封掉了哟。
建议每次程序启动的时候都调用registerForRemoteNotificationTypes来重新获取设备相关的token,而不要缓存token.
这是因为,如果用户重装了iOS或者用户换了设备并且恢复程序备份到一个新的设备,都将导致这个token值不一样。
那通知就收不到了呗。
看下代码:
01
Listing 2-3 Registering
for
remote notifications
02
- (
void
)applicationDidFinishLaunching:(UIApplication *)app {
04
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
08
- (
void
)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
09
const
void
*devTokenBytes = [devToken bytes];
10
self.registered = YES;
11
[self sendProviderDeviceToken:devTokenBytes];
14
- (
void
)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
15
NSLog(@
"Error in registration. Error: %@"
, err);
第四个知识点:处理 Local and Remote Notifications 一般通知来时,程序有两种状态。 1,后台运行发送,需要窗体,声音和数字 点击窗体,启动程序。程序启动了在application:didFinishLaunchingWithOptions: 方法里面获取传递的数据 notification payload (for remote notifications) or local-notification object (for local notifications).
点击图标,启动程序。同样调用application:didFinishLaunchingWithOptions,但是传参将不会有远程消息的任何信息 2,程序在前台跑着呢。 程序直接就调用application:didReceiveRemoteNotification: (for remote notifications)这个方法了 application:didReceiveLocalNotification: method (for local notifications) 总之要实现UIApplicationDelegate协议 实现application:didFinishLaunchingWithOptions:方法 实现application:didReceiveRemoteNotification:方法 或者实现application:didReceiveLocalNotification:方法 3,那如何判断区别前台还是后台这两种状况呢。 用这个属性applicationState来判断。 若为UIApplicationStateInactive就是用户点击通知框按钮进来的。 若为UIApplicationStateActive,就是前台正跑着呢。
当iOS收到远程消息时, 看下代码
02
- (
BOOL
)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
03
UILocalNotification *localNotif =
04
[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
06
NSString *itemName = [localNotif.userInfo objectForKey:ToDoItemKey];
07
[viewController displayItem:itemName];
08
application.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;
10
[window addSubview:viewController.view];
11
[window makeKeyAndVisible];
这里可以通过UIApplicationLaunchOptionsRemoteNotificationKey来获取通知传递过来的自定义数据
之后即可从provider方下数据了。
01
- (
void
)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)opts {
03
[self startDownloadingDataFromProvider];
04
app.applicationIconBadgeNumber = 0;
09
Listing 2-6 Handling a local notification when an application is already running
10
- (
void
)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif {
11
NSString *itemName = [notif.userInfo objectForKey:ToDoItemKey]
12
[viewController displayItem:itemName];
13
application.applicationIconBadgeNumber = notification.applicationIconBadgeNumber-1;
本文为意译,原文地址:https://developer.apple.com/library/ios/#documentation /NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103-SW1