本篇文章主要是整理一下有关通知的相关知识。主要介绍:
- 本地通知
- 远程通知
本文参考:
- 编写push notification之获取device token
- 编写push notification之服务器端发送通知
- iOS实现本地通知
- iOS实现本地通知
本地通知
本地通知,local notification,用于基于时间行为的通知,比如有关日历或者todo列表的小应用。另外,应用如果在后台执行,iOS允许它在受限的时间内运行,它也会发现本地通知有用。比如,一个应用,在后台运行,向应用的服务器端获取消息,当消息到达时,比如下载更新版本的提示消息,通过本地通知机制通知用户。
本地通知是UILocalNotification的实例,主要有三类属性:
- scheduled time,时间周期,用来指定iOS系统发送通知的日期和时间;
- notification type,通知类型,包括警告信息、动作按钮的标题、应用图标上的badge(数字标记)和播放的声音;
- 自定义数据,本地通知可以包含一个dictionary类型的本地数据。
对本地通知的数量限制,iOS最多允许最近本地通知数量是64个,超过限制的本地通知将被iOS忽略。
如果就写个简单的定时提醒,是很简单的,比如这样:
示例写的很简单,启动应用后,就发出一个定时通知,10秒后启动。这时按Home键退出,一会儿就会提示上图的提示信息。如果应用不退出则无效。
代码如下:
UILocalNotification *notification=[[UILocalNotification alloc] init];
if (notification!=nil) {
NSLog(@">> support local notification");
NSDate *now=[NSDate new];
notification.fireDate=[now addTimeInterval:10];
notification.timeZone=[NSTimeZone defaultTimeZone];
notification.alertBody=@"该去吃晚饭了!";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
更详细的代码见官方文档:《Scheduling, Registering, and Handling Notifications》,可以设置比如声音,比如用户定义数据等。
设置更多本地通知的信息:
- 设置icon上数字。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
/////////////
application.applicationIconBadgeNumber = 0;
// Add the view controller’s view to the window and display.
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];return YES;
}
- 添加通知时间,通知类型,取消通知
#pragma mark –
#pragma mark onChageValue
-(IBAction)onChangeValue:(id)sender
{
UISwitch *switch1=(UISwitch *)sender;
if (switch1.on) {
UILocalNotification *notification=[[UILocalNotification alloc] init];
NSDate *now1=[NSDate date];
notification.timeZone=[NSTimeZone defaultTimeZone];
notification.repeatInterval=NSDayCalendarUnit;
notification.applicationIconBadgeNumber = 1;
notification.alertAction = NSLocalizedString(@"显示", nil);
switch (switch1.tag) {
case 0:
{
notification.fireDate=[now1 dateByAddingTimeInterval:10];
notification.alertBody=self.myLable1.text;
}
break;
case 1:
{
notification.fireDate=[now1 dateByAddingTimeInterval:20];
notification.alertBody=self.myLable2.text;
}
break;
case 2:
{
notification.fireDate=[now1 dateByAddingTimeInterval:30];
notification.alertBody=self.myLable3.text;
}
break;
default:
break;
}
[notification setSoundName:UILocalNotificationDefaultSoundName];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"%d",switch1.tag], @"key1", nil];
[notification setUserInfo:dict];
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}else {
NSArray *myArray=[[UIApplication sharedApplication] scheduledLocalNotifications];
for (int i=0; i<[myArray count]; i++) {
UILocalNotification *myUILocalNotification=[myArray objectAtIndex:i];
if ([[[myUILocalNotification userInfo] objectForKey:@"key1"] intValue]==switch1.tag) {
[[UIApplication sharedApplication] cancelLocalNotification:myUILocalNotification];
}
}
}
}
远程通知
远程通知的原理:《偷窥iPhone Push Notification的幕后》和《iPhone的Push(推送通知)功能原理浅析》。
- 设备的准备
首先要知道,push notification只能在真机上运行的,无法在模拟器上使用,如果在模拟器上运行,在注册设备的时候会有类似如下报错:
Error in registration. Error: Error Domain=NSCocoaErrorDomain Code=3010 "remote notifications are not supported in the simulator" UserInfo=0x5d249d0 {NSLocalizedDescription=remote notifications are not supported in the simulator}
真机也要注意,如果没有越狱,没有问题。越狱的话,比如通过blacksnOw,因为没有经过iTunes,无法生成有效的设备证书(device certificate),因此注册的时候不会成功。
检查越狱版本是否可用,可以ssh到设备上,执行命令:
ls /var/mobile/Library/Preferences/com.apple.apsd.plist -l
-rw——- 1 mobile mobile 119 Aug 24 19:21 /var/mobile/Library/Preferences/com.apple.apsd.plist
返回的文件大小是119,就没有问题。
2.获取device token的原理
在说操作步骤之前,先说一下获取device token的一些原理方面的事情。
device token,即设备令牌,不是系统唯一标识(见获取iOS设备的基本信息),需要在应用启动时发起到apple服务器请求,注册自己的设备和应用,并获得这个device token。
device token有什么用?如果应用需要push notification给手机,那么它要有个服务器端(provider),但是它发出的信息不是直接给手机的,而是必须统一交给apple的服务器,这个服务器就是apple push notification server(apns)。apple服务器通过这个token,知道应用要发的消息是给哪个手机设备的,并转发该消息给手机,手机再通知应用程序。
3.获取device token的操作步骤
这里主要参照了这篇文章:Programming Apple Push Notification Services
该文档很详细,照做就应该没有问题。
需要注意的是identifier一定要和provision portal profile中的app id一致,即:
要和:
一致。
另外,要确保设备绑定的是唯一的profile:
编写代码,是在AppDelegate中增加两个方法:
- didRegisterForRemoteNotificationsWithDeviceToken:当应用第一次运行的时候,ios获取到device token后调用,用于注册设备到apns上之后的操作(比如将device token通知应用的服务器端provider)
- didFailToRegisterForRemoteNotificationsWithError:如果注册的时候失败,ios会调用这个方法,可以打印一些报错日志或者提醒用户通知不可用
另外,有一个方法需要增加内容,主要是打印日志,说明是否已经注册:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
NSLog(@"Initiating remoteNoticationssAreActive");
if(!application.enabledRemoteNotificationTypes){
NSLog(@"Initiating remoteNoticationssAreActive1");
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
}
UIApplication* myapp = [UIApplication sharedApplication];
myapp.idleTimerDisabled = YES;
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
第一次运行带注册方法的应用,会看到类似这样的提示窗口:
然后,在日志中看到类似下面的日志,主要是看到打印出device token的64位字符串,就说明成功了。
5.获得证书
苹果提供两种接入方式的证书:
- developer,用于测试
- production,用于产品
如果是内部测试,使用developer方式即可。
下载证书,通过ios provisioning portal:
这要求:
- 登录的apple developer program帐号必须是级别最高的agent(这是针对企业帐号来说的,如果是个人帐号就无所谓了),agent帐号即创始帐号,否则看不到configure链接;
- 必须经过configure操作,已经enable了developer和product。
然后进入configure链接,点击download按钮即可:
6.处理证书
如果是编写在mac下跑的objc程序,无需对证书做处理,可跳过这一步。
如果是在java下使用,需要把打证书用的私有专用密钥和上述的支持通知的证书(注意,不是iphone developer证书)合并导出。
生成证书:
点击存储的时候,会提示生成一个文件密码:
当然可以密码为空。
之后会提示:
这里需要输入mac登录用户的密码。
文件生成。
7.编写发送通知的实例
如果是编写mac代码,有一个现成的项目可用:http://stefan.hafeneger.name/download/PushMeBabySource.zip
导入到xcode中,只需将:
deviceToken填写成设备的token字符串,另外,pathForResource改为上面图中的:
aps_developer_identity
另外,要把刚才获得证书步骤中下载的证书复制到xcode项目Resources目录下:
可以看到文件名和上面的pathForResource的参数一致。
之后运行程序就可以在设备上收到推送通知。
如果是用java编写,可以用第三方库,见:
http://code.google.com/p/javapns/
编写简单的发送通知代码:
import org.json.JSONException;
import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;public class Main {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
PayLoad simplePayLoad = new PayLoad();
// Get PushNotification Instance
PushNotificationManager pushManager = PushNotificationManager.getInstance();
// Link iPhone’s UDID (64-char device token) to a stringName
pushManager.addDevice("iPhone", "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ");
simplePayLoad.addAlert("My alert message测试");
simplePayLoad.addBadge(1);
simplePayLoad.addSound("default");
Device client = PushNotificationManager.getInstance().getDevice("iPhone");
PushNotificationManager.getInstance().initializeConnection("gateway.sandbox.push.apple.com", 2195, "/home/ubuntu/mypush.p12", "password", SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
PushNotificationManager.getInstance().sendNotification(client, simplePayLoad);
测试中文没有乱码问题。
编写比较复杂的使用示例(可以控制通知是否有提示窗口、是否有提醒声音):
- aPayload.addBadge( 2),显示在手机应用图标上的数字
- aPayload.addAlert("软件版本有更新"),显示提示窗口文字
- aPayload.addSound("default.wav"),指定提示声音
另外,也可以使用php的第三方实现,比如:
http://code.google.com/p/php-apns
基本原理是启动一个php服务,监控memcacheq队列,如果有消息就发送给苹果服务器。
Programming Apple Push Notification Services
One of the key limitations of the iPhone is its constraint on running applications in the background. Because of this, applications cannot keep running in the background when the user switches to another application. So, applications that require a constant state of connectivity (such as social networking applications) will not be able to receive timely updates.
To remedy this limitation, Apple released the Apple Push Notification Service (APNs). The APNs is a service that allows your device to be constantly connected to Apple's push notification server. When you want to send a push notification to an application installed on the users' devices, you (the provider) can contact the APNs so that it can deliver a push message to the particular application installed on the intended device.
In this article, you will learn how to perform the various steps needed to create an iPhone application that uses the APNs.
Generating a Certificate Request
The first step to using the APNs is to generate a certificate request file so that you can use it to request for a development SSL certificate later on.
1. Launch the Keychain Access application in your Mac OS X.
2. Select Keychain Access'Certificate Assistant'Request a Certificate From a Certificate Authority (see Figure 1):
3. Enter the information required and check the Saved to disk option. Click Continue (see Figure 2).
4. Save the certificate request using the suggested name and click Save (see Figure 3): Click Done in the next screen.
Creating an App ID
Each iPhone applications that uses the APNs must have a unique application ID that uniquely identifies itself. In this step, you will learn how to create an App ID for push notification.
1. Sign in to the iPhone Developer Program at: http://developer.apple.com/iphone/. Click on the iPhone Developer Program Portal on the right of the page (see Figure 4).
2. You should see the welcome page (see Figure 5).
3. Click on the App IDs tab on the left and then click on the New App ID button (see Figure 6).
4. Enter "PushAppID" for the Description and select Generate New for the Bundle Seed ID. For the Bundle Identifier, enter net.learn2develop.MyPushApp
. Click Submit (see Figure 7).
5. You should now see the App ID that you have created (together with those you have previously created) (see Figure 8).
Configuring an App ID for Push Notifications
Once an App ID is created, you need to configure it for push notifications.
1. To configure an App ID for push notification, you need to click the Configure link displayed to the right of the App ID. You will now see the option (see Figure 9).
Check the Enable for Apple Push Notification service option and click the Configure button displayed to the right of the Development Push SSL Certificate.
2. You will now see the Apple Push Notification service SSL Certificate Assistant screen. Click Continue (see Figure 10).
3. Click the Choose File button to locate the Certificate Request file that you have saved earlier. Click Generate (see Figure 11).
4. Your SSL Certificate will now be generated. Click Continue (see Figure 12).
5. Click the Download Now button to download the SSL Certificate. Click Done (see Figure 13).
6. The SSL Certificate that you download is named aps.developer.identity.cer
. Double-click on it to install it in the Keychain Access application (see Figure 14). The SSL certificate will be used by your provider application so that it can contact the APNs to send push notifications to your applications.
Creating a Provisioning Profile
The next step is to create a provisioning profile so that your application can be installed onto a real device.
1. Back in the iPhone Development Program Portal, click on the Provisioning tab and click on the New Profile button (see Figure 15).
2. Type in MyDevicesProfile
as the profile name. Select PushAppID as the App ID. Finally, check all the devices that you want to provision (you can register these devices with the iPhone Developer Program Portal through the Devices tab). Click Submit (see Figure 16).
3. The provisioning profile will now be pending approval. After a while, you will see it appear. Click on the Download button to download the provisioning profile (see Figure 17).
4. The downloaded provisioning profile is named MyDevicesProfile.mobileprovision.
Provisioning a Device
With the provision profile created, you will now install it onto a real device.
1. Connect your iPhone or iPod Touch to your Mac.
2. Drag and drop the downloaded MyDevicesProfile.mobileprovision
file onto the Xcode icon on the Dock.
3. Launch the Organizer application from within Xcode and select the device currently connected to your Mac. You should see the MyDevicesProfile
installed on the device (see Figure 18).
Creating the iPhone Application
1. In Xcode, create a new View-Based Application project and name it as ApplePushNotification.
2. Drag and drop a WAV file (shown as beep.wav
in this example) onto the Resources folder in Xcode (see Figure 19).
3. Expand on the Targets item in Xcode and select the ApplePushNotification item. Press Command-I. In the Info window, click the Properties tab (see Figure 20).
In the Identifier textbox, type <net.learn2develop.MyPushApp
.
4. Click on the Build tab and type "Code Signing" in the search box. In the Any iPhone OS Device item, select the profile as shown in Figure 21:
5. In the ApplePushNotificationAppDelegate.m
file, type the following code in bold:
#import "ApplePushNotificationAppDelegate.h" #import "ApplePushNotificationViewController.h" @implementation ApplePushNotificationAppDelegate @synthesize window; @synthesize viewController; - (void)applicationDidFinishLaunching:(UIApplication *)application { [window addSubview:viewController.view]; [window makeKeyAndVisible]; NSLog(@"Registering for push notifications..."); [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)]; } - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *str = [NSString stringWithFormat:@"Device Token=%@",deviceToken]; NSLog(str); } - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { NSString *str = [NSString stringWithFormat: @"Error: %@", err]; NSLog(str); } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { for (id key in userInfo) { NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]); } } - (void)dealloc { [viewController release]; [window release]; [super dealloc]; } @end
6. Press Command-R
to test the application on a real device. Press Shift-Command-R
in Xcode to display the Debugger Console window. Observe carefully the device token that is printed (see Figure 22). In the figure below, the token is:38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7c e90d56e9 fe145bcc 6c2c594b
. Record down this device token (you might want to cut and paste it into a text file).
7. If you go to the Settings application on your iPhone/iPod Touch, you will notice that you now have the Notifications item (see Figure 23).
Creating the Push Notification Provider
A Push Notification provider is an application written by the application's developer to send push notifications to the iPhone application through the APNs.
Here are the basic steps to send push notifications to your applications via the Apple Push Notification Service (APNs):
1. Communicate with the APNs using the SSL certificate you have created earlier.
2. Construct the payload for the message you want to send.
3. Send the push notification containing the payload to the APNs.
The APNs is a stream TCP socket that your provider can communicate using a SSL secured communication channel. You send the push notification (containing the payload) as a binary stream. Once connected to the APNs, you should maintain the connection and send as many push notifications as you want within the duration of the connection.
Tip: Refrain from opening and closing the connections to the APNs for each push notification that you want to send. Rapid opening and closing of connections to the APNs will be deemed as a Denial-of-Service (DOS) attack and may prevent your provider from sending push notifications to your applications.
The format of a push notification message looks like Figure 24 (figure from Apple's documentation):
For more details, please refer to Apple Push Notification Service Programming Guide.
The payload is a JSON formatted string (maximum 256 bytes) carrying the information you want to send to your application. An example of a payload looks like this:
{ "aps": { "alert" : "You got a new message!" , "badge" : 5, "sound" : "beep.wav"}, "acme1" : "bar", "acme2" : 42 }
To save yourself the trouble in developing a push notification provider from scratch, you can use the PushMeBabyapplication (for Mac OS X) written by Stefan Hafeneger (Get it here).
1. Open the PushMeBaby application in Xcode.
2. Right-click
on the Resources folder in Xcode and select Add Existing Files…. Select theaps.developer.identity.cer
file that you have downloaded earlier (see Figure 25).
3. In the ApplicationDelegate.m
file, modify the code as shown in bold below:
- (id)init { self = [super init]; if(self != nil) { self.deviceToken = @"38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7c e90d56e9 fe145bcc 6c2c594b"; self.payload = @"{\"aps\":{\"alert\":\"You got a new message!\",\"badge\":5,\"sound\":\"beep.wav\"},\"acme1\":\"bar\",\"acme2\":42}"; self.certificate = [[NSBundle mainBundle] pathForResource:@"aps_developer_identity" ofType:@"cer"]; } return self; }
4. Press Command-R to test the application. You will be asked to grant access to the certificate. Click Always Allow (see Figure 26):
On the iPhone/iPod Touch, ensure that the ApplePushNotification application is not running. To send a message to the device, click the Push button. The server essentially sends the following message to the Apple Push Notification server:
{ "aps": { "alert" : "You got a new message!" , "badge" : 5, "sound" : "beep.wav"}, "acme1" : "bar", "acme2" : 42 }
5. If the message is pushed correctly, you should see the notification as shown in Figure 27.
6. If you now debug the ApplePushNotification application by pressing Command-R
and send a push message from the PushMeBaby application, the Debugger Console window will display the following outputs:
2009-11-24 21:11:49.182 ApplePushNotification[1461:207] key: acme1, value: bar 2009-11-24 21:11:49.187 ApplePushNotification[1461:207] key: aps, value: { alert = "You got a new message!"; badge = 5; sound = "beep.wav"; } 2009-11-24 21:11:49.191 ApplePushNotification[1461:207] key: acme2, value: 42