iOS远程推送原理及实现过程

gzvh8247 9年前
   <p>推送通知,是现在的应用比不可少的功能。那么在 iOS 中,我们是如何实现远程推送的呢?iOS 的远程推送原理又是什么呢?在做 iOS 远程推送时,我们会遇到各种各样的问题。那么首先让我们准备一些做推送需要的东西。我们需要一个付费的苹果开发者账号(免费的不可以做远程推送),有了开发者账号,我们可以去苹果开发者网站,配置自己所需要的推送的相关证书。然后下载证书,供我们后面使用,详细的证书配置过程,我们下面再说。</p>    <p>首先我们要说说iOS推送通知的基本原理:</p>    <p>苹果的推送服务通知是由自己专门的推送服务器APNs (Apple Push Notification service)来完成的,其过程是 APNs 接收到我们自己的应用服务器发出的被推送的消息,将这条消息推送到指定的 iOS 的设备上,然后再由 iOS设备通知到我们的应用程序,我们将会以通知或者声音的形式收到推送回来的消息。 iOS 远程推送的前提是,装有我们应用程序的 iOS 设备,需要向 APNs 服务器注册,注册成功后,APNs 服务器将会给我们返回一个 devicetoken,我们获取到这个 token 后会将这个 token 发送给我们自己的应用服务器。当我们需要推送消息时,我们的应用服务器将消息按照指定的格式进行打包,然后结合 iOS 设备的 devicetoken 一起发给 APNs 服务器。我们的应用会和 APNs 服务器维持一个基于 TCP 的长连接,APNs 服务器将新消息推送到iOS 设备上,然后在设备屏幕上显示出推送的消息。</p>    <p>设备注册APNs的流程图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d1690480a0118ad699cff7ed926375d4.png"></p>    <p>上图完成了如下步骤:</p>    <p>1.Device(设备)连接APNs服务器并携带设备序列号(UUID)</p>    <p>2.连接成功,APNs经过打包和处理产生devicetoken并返回给注册的Device(设备)</p>    <p>3.Device(设备)携带获取的devicetoken发送到我们自己的应用服务器</p>    <p>4.完成需要被推送的Device(设备)在APNs服务器和我们自己的应用服务器的注册</p>    <p>推送过程图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/646ccab84e3de04145c0b327dd45f23a.png"></p>    <p>推送的过程经过如下步骤:</p>    <p>1.首先,我们的设备安装了具有推送功能的应用(应用程序要用代码注册消息推动),我们的 iOS设备在有网络的情况下会连接APNs推送服务器,连接过程中,APNS 服务器会验证devicetoken,连接成功后维持一个基于TCP 的长连接;</p>    <p>2.Provider(我们自己的应用服务器)收到需要被推送的消息并结合被推送的 iOS设备的devicetoken一起打包发送给APNS服务器;</p>    <p>3.APNS服务器将推送信息推送给指定devicetoken的iOS设备;</p>    <p>4.iOS设备收到推送消息后通知我们的应用程序并显示和提示用户(声音、弹出框)</p>    <p>比较直观的流程图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2bb6bdd5c6145b58b26bdad1bba2b083.png"></p>    <p>信息包结构图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/494c8cd9074fa93902a228f37887c57b.png"></p>    <p>上图显示的这个消息体就是我们的应用服务器(Provider)发送给APNs服务器的消息结构,APNs验证这个结构正确并提取其中的信息后,再将消息推送到指定的iOS设备。这个结构体包括五个部分,第一个部分是命令标示符,第二个部分是我们的devicetoken的长度,第三部分是我们的devicetoken字符串,第四部分是推送消 息体(Payload)的长度,最后一部分也就是真正的消息内容了,里面包含了推送消息的基本信息,比如消息内容,应用Icon右上角显示多少数字以及推送消息到达时所播放的声音等</p>    <p>Payload(消息体)的结构:</p>    <pre>  <code class="language-java">{       “aps”:{       “alert”:“听云给您发送了新消息”,       “badge”:1,       “sound”:“default”       },  }</code></pre>    <p>这其实就是个JSON结构体,alert标签的内容就是会显示在用户手机上的推送信息,badge显示的数量(注意是整型)是会在应用Icon右上角显示的数量,提示有多少条未读消息等,sound就是当推送信息送达是手机播放的声音,传defalut就标明使用系统默认声音。</p>    <p>下面就是我们推送通知所需要的证书的推送过程:</p>    <p>1.首先我们要新建一个Certificate Signing Request(也就是CSR)的请求文件</p>    <p>在应用程序里的使用工具中找到钥匙串访问,选择从证书颁发机构请求证书</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2eb41e618824b936b59dae6dcf8215bf.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2ed420c079470ff30cc7e305ba80928d.png"></p>    <p>注意:邮箱地址,填自己的开发者账号,常用名,随便填一个记住就行。然后选择存储到磁盘。继续就行。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/90856014b860622ed08bae107d9c5854.png"></p>    <p>保存位置在 tingyun(指定自己的文件夹,这里我选择的是我的文件夹),点击存储</p>    <p>然后点击完成后我们会在 tingyun 里看到一个CertificateSigningRequest.certSigningRequest的请求文件,也就是我们说的CSR文件。在我们生成CSR文件的同时,会在钥匙串访问中生成一对秘钥,名称为刚才我们填写的常用名</p>    <p>2.配置AppID</p>    <p>到苹果开发者网站https://developer.apple.com</p>    <p>点击Account</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/388e97760524bc7fbdefde0e291cc6cf.png"></p>    <p>选择 Certificates,identifiers&Profiles</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5811d7cfceb0bfc058e11b89be088ddb.png"></p>    <p>选择 Identifiers ->App IDs 点击上方的+号创建一个 App ID.</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6d77ba3871dd140dc84448208879769d.png"></p>    <p>Name: 填写 App 的名字就行</p>    <p>App ID Suffix 选择不用通配符的及 Explicit App ID</p>    <p>Bundle ID:填写自己应用的 Bundle ID 一定要和自己应用的一致.</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/50d78447294070d55c7ba42512bb7338.png"></p>    <p>在下面的 App Services 中选择自己需要的服务</p>    <p>我们需要推送服务,所以在Push Notifications上打勾</p>    <p>然后点击continue</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/aaa12955f1da7a30fe97ebe9b850a5eb.png"></p>    <p>3.创建证书</p>    <p>证书需要创建两种,一种是开发的、一种是发布的,开发的是做测试用的。</p>    <p>选择Development 点击右上角的+号,创建证书,我们首先创建开发证书</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/bb9fe2d0175fab32aee7db867c44cc56.png"></p>    <p>选择Apple Push Notification service SSL (Sandbox),创建推送服务证书点击下一步</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/993375aff95527f22c78c2fc9d66cd6e.png"></p>    <p>这儿的 App ID 选择我们刚才创建的 App ID</p>    <p>然后点击下一步,下一步</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5effa509f790d17a01b618cbad3f9665.png"></p>    <p>这儿点击 Choose File,选择我们刚才创建的 CSR 文件.</p>    <p>然后点击生成(Generate)</p>    <p>最后点击下载,下载证书。将下载的证书,放到指定位置。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/52bc5bc371b3c68729048ea143d30c8b.png"></p>    <p>发布证书的创建和开发证书一样,选择Production->Apple Push Notification service SSL (Production)后面和开发证书一样</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/96f9c631a756364c592d6f0e93c74ec0.png"></p>    <p><img src="https://simg.open-open.com/show/773b31c80d32fed13056218effeb3b20.png"></p>    <p>4.添加 Devices:</p>    <p>首先选中你要添加哪种设备,然后在左上角点击“+”号。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/dd26447fed097c5b91d17e27914036fa.png"></p>    <p>Name 填写一个设备名字。</p>    <p>UDID 填写自己需要加入测试的设备的 UDID。</p>    <p>然后点击下一步</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/65216c8b1332d79732b32f29713d792b.png"></p>    <p>然后点击 Register 即可</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/21eec7189b5f4eeb7a56113df2e2b359.png"></p>    <p>点击Done。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/50fbc9f3c5f660f022db515d7a75912f.png"></p>    <p><img src="https://simg.open-open.com/show/04c58e4e4898766465e933ffafdcda44.png"></p>    <p>5.查找设备的 UDID:</p>    <p>用自己的 iOS 设备连接到电脑上,打开 iTunes。</p>    <p>在设备摘要处可以看见一个序列号,点击序列号就会变成 UDID。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fc8a6943c07dfba3871f1e0d2e6dc6c1.png"></p>    <p>6.生成配置文件</p>    <p>配置文件也有两种,一种是开发的,一种是发布的,开发的使我们做测试需要的,发布的是我们在 Appstore 上发布时需要的,我们都需要生成。</p>    <p>我们先生成开发配置文件,选择Provisioning Profiles->Development点击右上角的+号。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/950fbeb1e57f91372707ca039502d404.png"></p>    <p>选择iOS App Development 点击下一步</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6fb14a8e76bd695bfa1b164d856081cc.png"></p>    <p>这儿的 App ID 仍然选择我们刚才创建的 App ID</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/886fce96f25d1989101ff89862508e9d.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3eefd3f892e55804c4826e2ceecc89c4.png"></p>    <p>这儿选择我们开发者的证书,如果不知道是哪个选择全部即可</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3f3cda118a68e9716801015041be7065.png"></p>    <p>这儿选择我们的测试设备,如果没有则在前面的Devices里面添加即可</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/a0d8bb54fba31ae5ef8051428fdd5048.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ac4230fd151d55330f2356747df4d8b8.png"></p>    <p>随便取个名字即可,然后下载下来</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/18a536e7d0becc8b25a15e37e9b78230.png"></p>    <p>发布配置文件和开发配置文件一样创建,选择Distribution->Ad Hoc即可,后面与发布配置文件一样。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b5b5660b4325abca4ed1a71c5bed050c.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4dc955e6e2e868caf7885d1a18ba3fb9.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4dc955e6e2e868caf7885d1a18ba3fb9.png"></p>    <p>证书配置完成,打开我们创建的应用项目</p>    <p>打开AppDelegate.m 文件,在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中添加下面代码,注册消息推送</p>    <pre>  <code class="language-java">- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      // Override point for customization after application launch.          /** 消息推送注册 */      if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {                    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];          [application registerUserNotificationSettings:settings];          [application registerForRemoteNotifications];      }else {          [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];      }            return YES;  }  下面方法是返回 ANPs 苹果推送服务器生成的唯一标识  /** 接收服务器传回的设备唯一标识 token */  -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{            // 第一次运行获取到DeviceToken时间会比较长!      // 将deviceToken转换成字符串,以便后续使用      NSString *token = [deviceToken description];      NSLog(@"description %@", token);  }    下面方法是当有消息推送回来时,接收推送消息   /** 设备接收到来自苹果推送服务器的消息时触发的,用来显示推送消息 */    -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{        NSLog(@"userInfo == %@",userInfo);  }    上面方法是当注册推送服务失败时,接收错误信息  /** 注册推送服务失败 */  -(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{      NSLog(@"注册失败 %@",error);  }</code></pre>    <p>服务器端(Java服务器)</p>    <p>服务器端我们需要,一个后缀为. p12的证书,以及需要的 jar 包</p>    <p>服务器端的证书生成方式:</p>    <p>打开我们前面下载的证书,在钥匙串中找到它</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b7e14484ced3932adb8466388731a5a7.png"></p>    <p>点击鼠标右键选择导出</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/936ee8f66aa3974b07cd2161eea35ea8.png"></p>    <p>导出后缀为.p12的文件保存到自己的电脑上,需要输入一个密码,在 Java 服务器端要用到</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/601a297b4ba3adf07e483e4372f71b45.png"></p>    <p>Java服务器端需要的 Jar 包</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6d6b9898c2bbf6afe4eb99ae59ddf5af.png"></p>    <p>Java 服务器端代码:</p>    <pre>  <code class="language-java">import javapns.back.PushNotificationManager;  import javapns.back.SSLConnectionHelper;  import javapns.data.Device;  import javapns.data.PayLoad;  public class pushService {   public static void main(String[] args) {                    try {               String deviceToken = "eab6df47eb4f81e0aaa93bb208cffd7dc3884fd346ea0743fcf93288018cfcb6";               //被推送的iphone应用程序标示符                     PayLoad payLoad = new PayLoad();               payLoad.addAlert("测试我的push消息");               payLoad.addBadge(1);               payLoad.addSound("default");                                       PushNotificationManager pushManager = PushNotificationManager.getInstance();               pushManager.addDevice("iphone", deviceToken);                                           //测试推送服务器地址:gateway.sandbox.push.apple.com /2195               //产品推送服务器地址:gateway.push.apple.com / 2195                String host="gateway.sandbox.push.apple.com";  //测试用的苹果推送服务器               int port = 2195;               String certificatePath = "/Users/hsw/Desktop/PushTest/PushTest.p12"; //刚才在mac系统下导出的证书                              String certificatePassword= "123456";                             pushManager.initializeConnection(host, port, certificatePath,certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);                                        //Send Push               Device client = pushManager.getDevice("iphone");               pushManager.sendNotification(client, payLoad); //推送消息               pushManager.stopConnection();               pushManager.removeDevice("iphone");              }              catch (Exception e) {               e.printStackTrace();               System.out.println("push faild!");                return;              }              System.out.println("push succeed!");             }    }</code></pre>    <p>想阅读更多技术文章,请访问听云技术博客,访问听云官方网站感受更多应用性能优化魔力。</p>    <p>via: https://blog.tingyun.com/web/article/detail/571</p>