使用NSNotificationCenter通信

NSNotificationCenter实现了观察者模式,允许应用的不同对象之间以松耦合的方式进行通信。

 NSNotification代表Poster与Observer之间的信息载体,该对象包含如下只读属性。

name:该属性代表该通知的名字,程序将Poster注册到指定通知中心时,就是根据该名称进行注册的

object:该属性代表该通知的Poster。

userInfo:该属性是一个NSDictionary对象,用于携带通知的附加信息。

NSNotificationCenter是整个通知系统的中心,Observer向NSNotificationCenter注册自己感兴趣的通知,Poster向NSNotificationCenter发送通知。

- addObserverForName:object:queue:usingBlock:该方法将指定代码块注册为监听者,监听object:参数代表的对象(Poster)发出的通知(由第1个参数指定通知名称)。该方法直接使用指定代码块作为监听者,当Poster向NSNotificationCenter发送通知时,将会触发、执行该代码块。如果object:参数为nil,则用于监听任何对象发出的通知。

示例说明

复制代码
 1 ViewController.m
 2 
 3 @implementation ViewController
 4 
 5 - (void)viewDidLoad
 6 
 7 {
 8 
 9             [super  viewDidLoad];
10 
11             // 监听UIApplicatiob的                  UIApplicationDidFinishLaunchingNotification通知
12 
13             [[NSNotificationCenter  defaultCenter]  addObserver:self
14 
15          selector:@selector(launch:)
16 
17          name:UIApplicationDidFinishLaunchingNotification
18 
19          object:[UIApplication sharedApplication]];
20 
21          // 监听UIApplicatiob的         UIApplicationDidEnterBackgroundNotification通知
22 
23           [[NSNotificationCenter  defaultCenter]  addObserver:self
24 
25          selector:@selector(back:)
26 
27          name:UIApplicationDidEnterBackgroundNotification
28 
29          object:[UIApplication sharedApplication]];
30 
31          // 监听UIApplicatiob的         UIApplicationWillEnterForegroundNotification通知
32 
33             [[NSNotificationCenter  defaultCenter]  addObserver:self
34 
35          selector:@selector(fore:)
36 
37          name:UIApplicationWillEnterForegroundNotification
38 
39          object:[UIApplication  sharedApplication]];
40 
41 }
42 
43 - (void)back: (NSNotification*)Notification
44 
45 {
46 
47             self.showLabel.text = [NSString stringWithFormat:@”应用程序加载完成!”];
48 
49 }
50 
51 - (void)launch: (NSNotification*)Notification
52 
53 {
54 
55             self.showLabel.text = [NSString  stringWithFormat:@”%@\n应用程序进入后台!”,
56 
57          self.showLabel.text];
58 
59 }
60 
61 - (void) fore: (NSNotification*)Notification
62 
63 {
64 
65          self.showLabel.text = [NSString  stringWithFormat:@”%@\n应用程序进入前台!”,
66 
67          self.showLabel.text];
68 
69 }
70 
71 @end
复制代码

 

使用NSNotificationCenter监听自定义通知

使用NSNotificationCenter除了可以监听系统组件发出的通知之外,也可以监听程序自己发出的通知.下面示例将使用异步操作来模拟执行一个耗时任务,并在界面上使用UIProgressView显示耗时任务的执行进度.

示例代码

复制代码
ViewController.m

@import “ViewController.h”

#define  PROGRESS_CHANGED   @”down_progress_changed”

@interface ViewController()

{

       NSNotificationCenter*  nc;

       NSOperationQueue* queue;

}

@end

@implementation ViewController

- (void)viewDidLoad

{

          [super  viewDidLoad];

          nc = [NSNotificationCenter  defaultCenter];

          queue = [[NSOperationQueue  alloc]  init];

          // 设置该队列最多支持10个并发线程

          queue.maxConcurrentOperationCount = 10;

          // 使用视图控制器监听任何对象发出的 PROGRESS_CHANGED 通知

          [nc  addObserver:self  selector:@selector(update:)

       name: PROGRESS_CHANGED  object:nil]; // ①

}

- (IBAction)start: (id)sender

{

       __block int progStatus = 0;

       [sender  setEnabled:NO];

       // 以传入的代码块作为执行体,创建NSOperation

       NSBlockOperation* operation = [NSBlockOperation 

       blockOperationWithBlock:^{

                for(int I = 0; i < 100;  i++)

               {

                  // 暂停0.5秒模拟耗时任务

                 [NSThread  sleepForTimeInterval: 0.5] ;

               // 创建NSNotification,并指定userInfo信息

                       NSNotification*  noti = [NSNotification                notificationWithName: PROGRESS_CHANGED  object:nil  userInfo: [NSDictionary  dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: ++ progStatus]

,@”prog” ,  nil]];

              // 发送通知

               [nc  postNotification : noti]; // ②

                }

       }];

       // 将NSOperation添加给NSOperationQueue

       [queue  addOperation:  operation];

}

- (void)update: (NSNotification*) noti

{

       // 通过userInfo属性获取耗时任务的进度信息

       NSNumber* progStatus = noti.userInfo[@”prog”];

       NSLog(@”%d”, progStatus.intValue);

       dispatch_async(dispatch_get_main_queue(), ^{

          self.prog.progress = progStatus.intValue  /  100.0;

          // 当任务执行进度执行到100时,启用按钮

          if(100 == progStatus.intValue)

         {

             [self.bn  setEnabled: YES];

          }

      });

}

@end
复制代码

 

    上面程序中的第1行代码将视图控制器注册为通知监听者,用于监听任何对象的PROGRESS_CHANGED通知;接下来的第②行代码先创建了一个NSNotification,并使用NSNotificationCenter发送该通知。当该异步代码块向NSNotificationCenter发送通知之后,通知监听者的方法(update:)将会被触发执行,这个update:方法将会更新界面上UIProgressView的进度.

iOS本地通知

   本地通知属于应用界面编程的内容,本地通知和远程推送通知都可以向不在前台运行的应用发送消息,这种消息既可能是即将发生的事件,也可以是服务器的新数据,都可能显示为一段警告信息信息或应用程序图标上的徽标。

     本地通知和远程推送通知的基本目的都死让应用程序能够通知用户某些事情,而且不需要应用程序在前台运行。二者的区别在于:本地通知由本应用负责调用,只能从当前设备上的 iOS 发出;而远程推送通知由远程服务器上的程序(可由任意语言编写)发送至 Apple Push Notification service(APNs), 再由 APNs 把消息推送至设备上对应的程序.[BL1] 

   

本地通知是一个 UILocalNotification对象,它有如下常用属性.

fireData: 指定通知将在什么时间触发.

 repeatInterval:设置本地通知重复发送的时间间隔.

 alertBody: 设备本地通知的消息体.

 alertAction:  设置当设备处于锁屏状态时,显示通知的警告框下方的 title.

has Action: 设置是否显示 Action.

alertLaunchImage: 当用户通过该通知启动对应的应用时, 该属性设置为加载图片.

 applicatonIconBadgeNumber: 设置显示在应用程序上红色徽标中的数字.

 soundName: 设置通知的声音.

 userInfo: 设置该通知携带的附加信息.

 

创建了 UILocalNotification对象之后,接下来就可以通过 UIApplication 的如下两个方法发送通知了

l  - scheduleLocalNotification: 该方法指定调度通知。通知将会于 fireDate 指定的时间触发,而且会按 repeatInterval 指定的时间间隔重复触发。

l  - presentLocalNotificationNow: 该方法指定立即发送通知。该方法会忽略UILocalNotification的fireDate属性。

如果系统发出通知时,应用程序处于前台运行,系统将会触发应用程序委托类的application:didReceiveLocalNotification:方法。

 

在iOS应用中发送本地通知的步骤很简单,只要如下几步即可。

  1. 创建UILocalNotification对象
  2. 设置UILocalNotification的属性
  3. 调用UIApplication的方法发送或调用通知
  4. 如果希望应用程序在前台运行时可以对通知进行相应的处理,则需要重写应用程序委托类的application:didReceiveLocalNotification:方法。
  5. 当应用需要取消本地通知时,可调用UIApplication的cancelLocalNotification:方法取消指定通知,或调用cancelLocalNotifications方法取消所有通知。

示例示范如何开发本地通知

复制代码
ViewController.m

@interface  ViewController()

{

    UIApplication* app;

}

@end

@implementation  ViewController

- (void)viewDidLoad

{

     [super  viewDidLoad];

    app = [UIApplication  sharedApplication];

}

- (IBAction)changed: (id)sender

{

     UISwitch*  sw  = (UISwitch*)sender;

     if(sw.on)

     {

         //  创建一个本地通知

         UILocalNotification*  notification  = [[UILocalNotification  alloc] init]; // ①

         //  设置通知的触发时间

          notification.fireDate  = [NSDate  dateWithTimeIntervalSinceNow:10];

        //  设置通知的时区

       notification.timeZone = [NSTimeZone  defaultTimeZone];

       // 设置通知重复发送的时间间隔

       notification.repeatInterval = kCFCalendarUnitMinute;

          //  设置通知的声音

          notification.soundName  = @”gu.mp3”;

           //  设置当设备处于锁屏状态时, 显示通知的警告框下方的 title

           notification.alertAction =  @”打开”;

           //  设置通知是否显示 Action

           notification.hasAction = YES;

            //  设置通过通知加载应用时显示的图片

           notification.alertLaunchingImage  = @”logo.png”;

              //  设置通知内容

              notification.alertBody = @”轮到你下棋了,  赶快走棋!”;

              // 设置显示在应用程序上红色徽标中的数字

              notification.applicationIconBadgeNumber  =  1;

              //  设置 userInfo, 用于携带额外的附加信息

              NSDictionary*  info = @{@”123456”: @”key”};

              notification.userInfo = info;

              //  调度通知

              [app scheduleLocalNotification:Notification]; // ①

             }

       else

              {

                  // 获取所有处于调度中的本地通知数组

                 NSArray*  localArray = [app  scheduledLocalNotifications];

                 if(localArray)

                 {

                      for(UILocalNotification * noti  in  localArray)

                       {

                         NSDictionary*  dict  = noti.userInfo;

                            if(dict)

                       {

                       //  如果找到要取消的通知

                       NSString*  inKey = [dict  objectForKey:@”key”];

                       if([inKey  isEqualToString:@”123456”])

                       {

                          // 取消调度该通知

                          [app  cancelLocalNotification: noti]; // ②

                         }

                       }

                     }

                   }

             }

}
@end
复制代码

 

   上面程序中的第①段代码创建了一个UILocalNotification对象,并为该对象设置了相关属性,接下来在①号代码处调用了UIApplication的scheduleLocalNotification:方法来调度通知,这样该通知将会在指定事件触发,并按相应的周期重复执行。当用户把UISwitch控件切换到关闭状态时,②号代码将会取消调度该通知。

   为了让程序处于前台运行时也能看到本地通知,还重写了应用程序委托类的application:didReceiveLocalNotification:方法。

 

复制代码
 AppDelegate.m

@implementation  AppDelegate
//  只有当应用程序在前台运行时,该方法才会被调用

- (void)application: (UIApplication*)application

  didReceiveLocalNotification: (UILocalNotification*) notification

{

       // 如果应用程序在前台运行,则将应用程序图标上的红色徽标中的数字设为0

       application.applicationIconBadgeNumber = 0; // ①

       // 使用UIAlertView显示本地通知的信息

       [[[UIAlertView  alloc]  initWithTitle:@” 收到通知  ”

       message:notification.alertBody

       delegate:nil  cancelButtonTitle:@”确定”

       otherButtonTitles: nil]  show];  // ②

}

- (void)applicationWillEnterForeground: (UIApplication*) application

{

               // 当应用程序再次进入前台运行时,将应用程序徽标中数字设为0

              application.applicationIconBadgeNumber = 0;

}
…
@end
复制代码

 

   上面程序中的第①②段代码控制当应用程序处于前台运行时,即使程序收到了本地通知,也依然会将应用程序图标上的红色徽标中数字设为0。

 iOS远程推送通知

 iOS远程推送通知由远程服务器上的程序(可由任意语言编写)发送至APNs,再由APNs把消息推送至设备上对应的程序。

  iOS远程推送通知的过程可用下图进行描述

 

在上面中,Provider指远程服务器上的Push服务端应用,这种Push服务端应用可以使用任意语言编写,如Java、PHP等。

APNs由Apple公司提供,APNs负责把通知发送到对应的iOS设备,该设备再把通知转发给ClientApp-----即我们的iOS应用。

上面所示的过程分为3个阶段

第一个阶段:Provider程序把要发送的通知、目标iPhone的device token (相当于该设备的唯一标识)打包,发给APNs.

第二阶段:APNs通过已注册Push服务的iPhone列表查找具有对应device token的iPhone,并把Push通知发送给对应的iPhone。

第三阶段:iPhone将收到的Push通知传递给相应的应用程序,并且按照设定弹出Push通知。

  实际上,Push服务端程序可以通过APNs将一条通知发送给多个iPhone 上的客户端应用;与此同时,iPhone上的客户端应用也可接收多个Push服务端程序发送过来的推送通知。下图显示了这种示意图

 


对于开发iOSPush服务而言,完整的过程如下。

  1. 应用程序注册远程推送通知。
  2. 当应用程序注册推送通知成功或注册失败时,系统都会触发应用程序委托类的对应方法。可以通过重写应用程序委托类的这些方法来获取该设备注册成功后得到的device token。
  3. 应用程序将device token发送给Push服务端程序
  4. 服务端程序向APNs发送通知。
  5. APNs将通知发送给iOS应用------实际的过程是先发送给指定的iOS设备,再由该设备弹出Push通知。[BL2] 

 

从上图可以看出,Push客户端应用需要3个组件。

  • App ID(应用程序唯一标识,这个必须到Apple网站注册来获得)
  • Provisioning Profile(这个也必须到Apple网站下载)
  • device token(当Push客户端应用注册Push推送通知成功时,APNs将会返回该设备的device  token)。[BL3] 

Push服务端程序则需要如下两个组件

  • SSL Certificate(SSL连接证书,这个必须从Apple网站下载)。
  • Private Key(私钥,这个可用过开发者电脑导出)。

开发Push客户端应用

开发Push客户端应用需要到Apple网站注册一个App ID,而且该App ID不允许使用通配符。通过Apple网站注册App ID的步骤如下。

  1. 打开OS X系统上的”钥匙串访问”应用,单击该应用的主菜单”钥匙串访问” →”证书助理”→”从证书颁发机构请求证书”,如下图所示.

 

  1. 单击”从证书颁发机构请求证书”后,将会显示下图所示的对话框
  2. 输入电子邮件地址和常用名称,并选中“存储到磁盘”单选钮,然后单击“继续”按钮,该程序将会创建一个“Certificate Signing Request”(证书签名请求)文件,系统弹出下图所示的保存文件对话框

 

将证书签名请求文件保存到磁盘上,此处将该文件保存为“Push。cerSigningRequest”。

  1. 使用浏览器打开 https://developer.apple.com/ios/manage/overview/index.action站点, 页面上将会提示用户输入开发者账号\密码. 登录成功后会看到如下说是的页面

 

在上图所示页面中,可以看到在“iOS Apps”栏目下包含了Certificates、Identifiers、Device、ProvisioningProfiles-----这些只有登录账号已经加入iOS Developer Program(iDP)的原因。

  1. 单击“iOS Apps” →“Identifiers”→栏目下的”App IDS” 链接,系统将会显示如下图

  

  1. 单击”从证书颁发机构请求证书”后,将会显示下图所示的对话框
  2. 输入电子邮件地址和常用名称,并选中“存储到磁盘”单选钮,然后单击“继续”按钮,该程序将会创建一个“Certificate Signing Request”(证书签名请求)文件,系统弹出下图所示的保存文件对话框

 

将证书签名请求文件保存到磁盘上,此处将该文件保存为“Push。cerSigningRequest”。

  1. 使用浏览器打开https://developer.apple.com/ios/manage/overview/index.action站点, 页面上将会提示用户输入开发者账号\密码. 登录成功后会看到如下说是的页面

 

在上图所示页面中,可以看到在“iOS Apps”栏目下包含了Certificates、Identifiers、Device、ProvisioningProfiles-----这些只有登录账号已经加入iOS Developer Program(iDP)的原因。

  1. 单击“iOS Apps” →“Identifiers”→栏目下的”App IDS” 链接,系统将会显示如下图

 

上图列出了该开发者账号当前拥有的所有App ID。

  1. 单击页面右上角的“ +”按钮(添加App ID),系统打开如下图所示的页面

 

App ID的描述字符串可以随便填,但该App ID的唯一标识必须要记住,通常采用“公司域名+应用名”的格式

  1. 单击刚刚注册的App ID,可以看到该App ID支持的各种服务,如下图所示

 

  1. 从上图所示页面可以看出,该App ID并不支持Push Notification(推送通知)和iCloud服务。单击“Edit”按钮,进入编辑该App ID的页面如下图所示

 

  1. 勾选Push Notification右边的复选框-----这会启用该App ID的Push通知功能。勾选该复选框之后,Push Notifications下面的两个“Create Certificate…”按钮将会变成可用状态,其中第1个按钮用于创建开发阶段的证书,第2个按钮用于创建产品化阶段的证书。此处只需要创建开发阶段的证书,当需要正式发布该iOS应用时,需要创建产品化阶段的证书。
  2. 单击第1个“Create Certificate…”按钮,系统将会显示一个提示页面,告诉用户去创建一个CSR文件-----也就是前面我们已经创建的“Certificate Signing Request”文件。由于我们已将创建了该文件,因此直接单击“Continue”按钮,系统显示如下图所示的页面
 
  1. 单击“Choose File”按钮选择前面创建的Push.certSigningRequest文件,然后单击”Generate”按钮,系统将会为该App ID生成开发证书。成功生成开发证书之后,可以看到如下图所示的页面

 

  1. 成功生成App ID的开发证书之后,即可通过该页面中的“Download”按钮下载证书,也可返回系统证书列表页面去下载证书。此处先将该证书下载并保存到本地磁盘,该证书的文件名为“app_development.cer”
  2. 双击上一步下载得到的app_development.cer文件,OS X系统将会自动打开“钥匙串访问”应用程序,并将该证书添加到系统中。此时将可以在“钥匙串访问”应用程序中看到如下图所示的一行。

 

  1. 单击上上图所示页面中的“Done”按钮,系统返回证书列表页面,如下图所示

 

通过证书列表页面也可以下载指定的证书(只要点击指定的证书,页面就会显示“Revoke”、“Download”两个按钮,其中“Revoke”按钮用于删除证书,“Download”按钮用于下载证书)。

经过上面步骤,我们已经成功为Push客户端创建了一个支持Push通知的App ID,并下载、安装了该App ID的开发证书

现在开始开发Push‘客户端应用。新建一个Single View Application, 该应用的”Bundle  Identifier”必须与前面注册的App ID完全相同.如下图所示是新建应用对话框.

该对话框的填写非常关键,各位务必保证该用用的“Bundle Identifier”与前面注册的App ID完全相同。

 

接下来通过修改应用程序委托类来注册远程Push通知,并重写对应的方法来处理远程Push通知.

 

 

通过上面介绍不难看出,iOS应用处理远程通知比较简单。

  1. 在应用程序委托类的application:didFinishLaunchingWithOptions:方法中调用UIApplication的registerForRemoteNotificationTypes:注册远程Push通知。
  2. 重写应用程序委托类的如上3个方法

该示例的应用程序委托类实现部分代码

复制代码
AppDelegate.m

- (BOOL)application: (UIApplication*) application 
 didFinishLauchingWithOptions: (NSDictionary*)LaunchingOptions

{

     // 注册远程推送通知 
     [[UIApplication  shareApplication]  registerForRemoteNotificationTypes: 
     UIRemoteNotificationTypeBadge |      UIRemoteNotificationTypeSound  
| UIRemoteNotificationTypeAlert ]; 
     return YES;  // ①

}

- (void)application: (UIApplication *) application 
 didRegisterForRemoteNotificationsWithDeviceToken: (NSData*)pToken 
{

        NSLog(@”注册成功:  %@”,  pToken);

        // 注册成功,应该将该device  token发送给Push服务端程序 
        //  Push服务端程序应该将该token保存到数据库中, 以备以后重复使用

}

- (void)application: (UIApplication*)application  didFailToRegisterForRemoteNotifications 
WithError: (NSError*) error

{

          NSLog(@”注册失败:  %@”,  error);

}

- (void)application: (UIApplication*)application didReceiveRemoteNotification: (NSDictionary*) userInfo 
{

     // 处理推送消息

     UIAlertView* alert = [[UIAlertView  alloc]  initWithTitle:@” 通 知 ” 
message:@”我的消息”  delegate:self  cancelButtonTitle:@”取消 ” 
otherButtontitles: nil]; 
       [alert  show]; 
       NSLog(@”%@”,  userInfo);

}

…

@end
复制代码

 

  上面程序的第1行代码注册了远程Push通知,接下来程序实现了UIApplicationDelegate协议中与远程推送通知相关的3个方法-----注册Push通知成功、失败时激发的方法,以及收到远程Push通知时激发的方法

   远程推送通知的应用必须在真机上测试,而且客户端应用还需要Provisioning  Profile,这个东西也必须通过Apple网站创建、下载。为远程推送通知应用创建、下载Provisioning Profile请按如下步骤进行。

  1. 将真机接入电脑
  2. 再次登录 https://developer.apple.com/ios/manage/overview/index.action站点,单击”Provisioning  Profiles”链接, 此时看到如下图所示的页面.

 

其中第1个Provisioning Profile是测试其他普通程序的Provisioning Profile,由于其他程序所谓App ID可支持通配符, 因此只要一个Provisioning Profile即可。但远程推送通知应用的App ID不能使用通配符,因此此处必须重新创建一个Provisioning Profile。

  1. 单击页面右上角的“ +”按钮,系统将会显示如下图所示的页面。

 

  1. 让用户选择Provisioning Profile的类型,此处支持创建开发阶段的Provisioning Profile,因此选中“Development” 分类下的“iOS App Development”单选钮。然后单击页面下方的“Continue”按钮,系统将会显示如下图所示的页面。

 

  1. 让用户选择需要为哪个应用创建Provisioning Profile,此处选择前面刚刚创建的org.crazyit.PushTest应用。然后单击页面下方的”Continue”按钮,系统将会显示下图所示的页面

 

  1. 为Provisioning Profile选择证书,我们可根据需要选择相应的证书,此处我们直接勾选“Selector  All”复选框来选择两个证书。然后单击页面下方的“Continue”按钮,系统将会显示如下图所示的页面。
  2. 为Provisioning Profile 选择调试手机,我们可根据需要选择相应的调试手机,此处我们勾选“yeeku的iPhone”------这是我的调试手机,然后单击页面下方的“Continue”按钮,系统将会显示如下图所示的页面

 

 

  1. 为Provisioning Profile输入名称,然后单击页面下方的“Generate”按钮,喜用将会为我们选中的iOS应用生成Provisioning Profile,将可以看到如下图所示的页面
  2. 单击“Download”按钮,系统将会把刚刚创建的Provisioning Profile下载到本地磁盘。仅保存到磁盘上将会得到一个PushTest.mobileprovision文件(该文件的扩展名是.mobileprovision, 但主文件名就是我们在上图中输入的名称)。
  3. 单击本地磁盘上的PushTest.mobileprovision文件,OS X系统将会自动把该Provisioning Profile添加到对应的调试手机上。如果打开Xcode 的Organizer窗口(在Xcode中按“command+shift+2”快捷键即可),然后在该窗口的左边选中对应调试手机下面的Provisioning Profiles项,将可以看到如下图所示的界面。

 

  1. 在“查看调试手机”图片中可以看到两个Provisioning Profile,其中第1个Provisioning Profile就是刚刚创建并添加的Provisioning Profile;第2个Provisioning Profile是调试其他普通程序的Provisioning Profile,该Provisioning Profile对应的App Identifier使用了通配符,因此适用于其他所有的普通应用。
  2. 经过上面步骤,我们已经为该远程推送应用准备了Provisioning Profile,接下来在Xcode中设置此Provisioning Profile即可。通过Xcode打开如下图所示界面,并按图所示的提示设置Provisioning Profile。

 

编译运行该应用(在真机上运行该应用),将可以看到如下图所示的提示框。

 

用户单击“好”按钮,将可以在Xcode的底部看到如下图所示的输出

 

此处iOS应用成功注册了远程推送通知,APNs返回了该设备的device token.在实际应用中, iOS应用应该通过网络将该device token发送给Push服务端程序, 此处我们为了简化编程就不增加网络传输的代理代码了,而是直接将该device token复制到Push服务端程序.

 

开发Push服务端程序

Push服务端程序需要包含SSL连接证书和私钥。因此在开发Push服务端程序之前,需要先将它们准备好。

导入远程推送通知应用的私钥

  1. 打开OS X系统上的“钥匙串访问”应用,在该应用中找到名为“Push”的专用密钥----这就是私钥。然后右击该项,在弹出的快捷菜单单击“导出Push”菜单项,如下图所示

 

 此处之所以列有名为“Push”的公用密钥和专用密钥,是因为前面开发iOS客户端应用时使用证书助理创建了名字为Push的Certificate Signing Request文件,如果之前没有创建该Certificate Signing Request文件,或创建Certificate Signing Request时指定的名称不同,那么此处将不会显示名为“Push”的公用密钥和专用密钥。

  1. 单击“导出Push”菜单项后,将会开始导出Push私钥,系统显示如下图所示的对话框。

 

  1. 为导出的Push私钥指定文件名(通常无须修改,直接就命名为Push.p12即可),并将该导出文件保存在本地磁盘的指定路径下。然后单击“存储”按钮,系统将会显示如下图所示的密码输入框----此处输入的密码就是该私钥文件的密码。

 

  1. 为Push私钥输入密码(此处输入user)后,单击“好”按钮,即可成功导出Push私钥。

此时我们已经得到了Push服务端程序所需要的私钥和SSL连接证书(前面开发推送通知客户端时已经从Apple网站下载过开发证书,当时保存的开发证书名为aps_development.ver)。

接下来还需要将两个文件合并为一个文件,请按如下步骤进行:

  1. 进入app_development.cer文件所在的路径,执行如下命令:
  • opensel x509 –in aps_development.cer – inform der – out PushCert.pem – outform PEM  // ①

上面命令的作用是将aps_development.cer证书文件转换为PEM格式的证书文件,该命令将会生成一个PushCert.pem文件.

  1. 进入Push.p12文件所在的路径,执行如下命令:
  • opensel pkcs12 –nocerts – in Push.p12 – out PushKey.pem  // ②

上面命令的作用是将Push.p12私钥文件转换为PEM格式的私钥文件,该命令将会生成一个PushKey.pem文件。

运行上面命令一共会提示输入3次密码:第1次输入Push.p12私钥文件的密码(也就是我们在“为Push输入密码”图片中输入的密码),只有输入该密码才可让openssl命令读取该Push.p12私钥文件的内容;第2次输入的密码将会作为PushKey.pem文件的密码;第3次输入的密码用于确认第2次输入的密码-----此处依然输入”user”.

  1. 进入PushCert.pem、PushKey.pem文件所在的路径,执行如下命令:
  • openssl pkcs12 –export –in PushCert.pem –inkey PushKey.pem –out aps_developer_identity.p12 // ③

上面命令的作用是将PushCert.pem、PushKey.pem 合并为一个aps_developer_identity.p12

     运行上面命令一共会提示输入3次密码:第1次输入PushKey.pem文件的密码(也就是我们在第2 步中为PushKey.pem文件输入的密码),只有输入该密码才可让openssl命令读取该PushKey.pem文件的内容;第2次输入的密码将会作为aps_developer_identity.p12文件的密码;第3次输入的密码用于确认第 2次输入的密码-----此处依然输入“user”。

 整个运行过程如下图所示

 

 Java领域有一个JavaPNS开源项目用于开发Apple Push Notification Service Provider,借助于该项目即可非常方便地开发远程推送通知的服务端程序。下载和安装JavaPNS的步骤如下:

  1. 登录该项目的官网:http://code.google.com/p/javapns/,选择页面上的“Downloads”标签页。此标签页中包含3个下载项。

        JavaPNS_2.2.jar:  该选项只是下载JavaPNS项目的核心JAR包.

        JavaPNS_2.2_javadoc.zip: 该选项只是下载JavaPNS项目的API文档

        JavaPNS_2.2_complete.zip: 该选项下载JavaPNS的完整压缩包,包括JavaPNS的核心JAR包、API文档和示例。

  1. 下载JavaPNS_2.2_complete.zip压缩包,解压该压缩包即可得到如下文件结构。

        doc:该文件夹下包含JavaPNS项目的各种文档。

        lib:该文件下包含bcprov-jdk15-146.jar、log4j-1.2.15.jar两个JAR包。这两个JAR包是

JavaPNS所依赖的JAR包。

        src:该文件夹下包含JavaPNS项目的源代码。

        JavaPNS_2.2.jar:这是JavaPNS项目的核心JAR包。

  1. 将JavaPNS解压路径下的JavaPNS_2.2.jar、bcprov-jdk15-146.jar、log4j-1.2.15.jar这3个JAR包添加到系统的类加载路径中即可完成JavaPNS的安装。
复制代码
如下编写简单的Java源文件,即可实现远程推送通知的服务端程序

PushSever.java

import  javapns.Push;

import  javapns.notification.PushNotificationPayload;

public  class  PushServer

{
     public static  void  main (String[]  args)
     {

         // 向执行设备发送Push通知的device token

           // 不同设备的device token应该由iOS应用通过网络发送给服务端程序

         //  服务端程序应该将这些device  token保存在服务器中

         //  然后通过循环向每个device  token发送Push通知

         String deviceToken = “60c70bb185cd50edfaa430”; // ①

         try

         {

             // 创建PushNotificationPayload 
                   PushNotificationPayload  payload = new PushNotificationPayload(); 

// 设置推送消息体 payload.addCustomAlertBody(“推送通知\n happy new year。\n” + “2016年顺顺利利,平平安安”); // 设置应用程序图标的小红圈中的数值 payload.addBadg(2); // 设置推送通知的提示声音 payload.addSound(“default”); // 发送推送通知 Push.payload(payload, “../aps_developer_identity.p12”, // 指定包含证书和私钥的文件 “user”, // 设置aps_developer_identity.p12文件的导出密码 false, // 是否为产品化阶段 deviceToken ); // ② } catch(Exception e) { e.printStackTrace(); } } }
复制代码

 

上面程序中的第1行红色字代码就是指定iOS设备的device token----在实际应用中, 该device token应该由iOS客户端通过网络发送给服务端程序,此处为了简单起见,我们直接将iOS设备的device token复制、粘贴到此处。

上面程序中的第2段红色字代码使用了Push类的payload()类方法来发送远程推送通知,发送推送通知指定了包含证书和私钥的文件、aps_developer_identity.p12文件的导出密码。

将JavaPNS解压路径中包含的JavaPNS_2.2.jar、bcprov-jdk15-146.jar、log4j-1.2.15.jar复制到该Java源文件的同一路径下,然后使用如下命令来编译该Java源文件:

java –encoding utf-8 –cp JavaPNS_2.2.jar PushServer.java  // ①

上面命令用于编译PushServer.java文件,该命令使用了-cp选项将JavaPNS_2.2.jar临时添加到类加载路径中.

使用如下命令运行PushServer:

java –cp .: JavaPNS_2.2.jar:bcprov-jdk15-146.jar:log4j-1.2.15.jar PushServer  // ②

上面命令用于运行PushServer,并使用了-cp选项将JavaPNS_2.2.jar、bcprov-jdk15-146.jar和log4j-1.2.15.jar临时添加到类加载路径中

/*

注意:

   若在UNIX、Linux、OS X系统上执行上面的java命令,-cp选项值中的各JAR包的分隔符为英文冒号;如果在Windows系统中执行上面的java命令,则应将-cp选项值中的各JAR包的分隔符改为英文分号。而且,不要忘记了-cp选项值开始的一点(.),这个点(.)代表了当前路径,用于告诉系统在当前路径下搜索PushServer类文件。

*/

posted on 2016-01-08 22:15  贾富阳  阅读(258)  评论(0)    收藏  举报