APPLE iOS 远程推送APNS

苹果的远程推送APNS:


原理过程什么的就不说了,这里主要是为了记录一下今天解决推送所遇到的坑。

步骤主要分为四部分:

  • 请求证书
  • 处理证书以及p.12文件等问题
  • 客户端这边根据需要设置一下
  • 测试一下可行性

请求证书 && 处理证书及p.12文件


  1. 创建APP ID
    登录Apple Member Center :https://developer.apple.com/membercenter,选择certificates,identifiers&profiles
    选项,如下图所示:
    APPLE iOS 远程推送APNS_第1张图片
    起始页

    选择identity
    中的APP IDs
    ,如下图所示:
    APPLE iOS 远程推送APNS_第2张图片
    创建id

    注意:创建Explicit App ID
    时,要注意此时设置的Bundle ID要与APP以后的Bundle ID一致,如下图所示:
    APPLE iOS 远程推送APNS_第3张图片
    Bundle ID
    选择
    Push Notification
    来开通Push功能,如下图所示:
    APPLE iOS 远程推送APNS_第4张图片
    开通Push功能
    点击下方的
    register
    按钮,几秒钟之后下方会变成一个Done
    ,表示APP ID已经创建完成,如下图所示:
    APPLE iOS 远程推送APNS_第5张图片
    感谢友盟+
    APPLE iOS 远程推送APNS_第6张图片
    感谢友盟+
    APPLE iOS 远程推送APNS_第7张图片
    感谢友盟+
    注意:
    创建的APP ID要与自己项目的Bundle ID保持一致。如果已经有APP ID,请确保自己的APP ID已经开通了Push功能,如果没有开通,可以点击APP ID,在其底部有一个Edit按钮,点击后选中Push服务并创建,如下图所示:

APPLE iOS 远程推送APNS_第8张图片
感谢友盟+

至此,APP ID创建完毕。

  1. 创建CSR文件
    如果你已经有CSR文件,请继续进行下一步的设置。

CSRCerificate Signing Request的英文缩写,即证书请求文件。证书申请者在申请数字证书时由CSP(加密服务提供者)在生成私钥的同时也生成证书请求文件。证书申请者只要把CSR文件提交给证书颁发机构后,证书颁发机构使用其根证书私钥签名就生成了证书公钥文件,也就是颁发给用户的证书。

在电脑中找到钥匙串----->钥匙串访问------>证书管理------>从证书颁发机构请求证书,如下图所示:

APPLE iOS 远程推送APNS_第9张图片
感谢友盟+

APPLE iOS 远程推送APNS_第10张图片
感谢友盟+

设置完证书信息后,点击“继续”,然后选择存储位置,点击存储, 至此,CSR文件创建成功。

  1. 创建开发调试证书
    如果你已经有开发调试证书,请继续进行下一步的设置。

选择Development(如果是发布上线,需要选择Distribution),如下图所示:

APPLE iOS 远程推送APNS_第11张图片
这里写图片描述
之后,你将看到如下四个证书。这一步,我们选择 iOS App Development证书,如下图所示:
APPLE iOS 远程推送APNS_第12张图片
这里写图片描述

APPLE iOS 远程推送APNS_第13张图片
这里写图片描述

APPLE iOS 远程推送APNS_第14张图片
这里写图片描述

APPLE iOS 远程推送APNS_第15张图片
这里写图片描述

choose file...中选择本地的 CertificateSigningRequest(CSR)文件,然后点击继续,如下图所示:
APPLE iOS 远程推送APNS_第16张图片
感谢友盟+

APPLE iOS 远程推送APNS_第17张图片
这里写图片描述

点击 Download,将证书下载到本地,双击下载的开发调试证书(文件名为: iOS_development.cer),就可以在钥匙串访问中的我的证书中找到。

至此,开发调试证书设置完毕。

  1. 添加测试设备
    测试推送需要添加测试设备,添加方法如下所示:


    APPLE iOS 远程推送APNS_第18张图片
    这里写图片描述
    APPLE iOS 远程推送APNS_第19张图片
    这里写图片描述
    APPLE iOS 远程推送APNS_第20张图片
    这里写图片描述
    APPLE iOS 远程推送APNS_第21张图片
    这里写图片描述
  2. 创建Provisioning Profiles文件
    选择Development,创建开发环境的Provisioning Profiles(如果是发布上线,需要选择Distribution),如下图所示:
    APPLE iOS 远程推送APNS_第22张图片
    这里写图片描述

    APPLE iOS 远程推送APNS_第23张图片
    这里写图片描述

    创建新的Provisioning Profiles,并选择之前生成好的App ID。如下图所示:
    APPLE iOS 远程推送APNS_第24张图片
    这里写图片描述

    选中创建的证书:
    APPLE iOS 远程推送APNS_第25张图片
    这里写图片描述

选中测试设备:

APPLE iOS 远程推送APNS_第26张图片
这里写图片描述

APPLE iOS 远程推送APNS_第27张图片
这里写图片描述

把创建的 Provisioning Profiles, 调试证书推送证书下载下来(文件名:umengpushtestdemo.mobileprovision)以后双击证书。
APPLE iOS 远程推送APNS_第28张图片
这里写图片描述

  1. 创建推送证书
    选择Apple Push Notification service SSL(Sandbox)
    APPLE iOS 远程推送APNS_第29张图片
    这里写图片描述

    注意:推送证书分为开发环境和生产环境,如果需要生成生产环境的推送证书请选择: Apple Push Notification service SSL (Sandbox&Production)
    ,如下图所示:
    APPLE iOS 远程推送APNS_第30张图片
    这里写图片描述

选中APP ID后,点击continue,直到上传CRS文件,如下图所示:

APPLE iOS 远程推送APNS_第31张图片
这里写图片描述

APPLE iOS 远程推送APNS_第32张图片
这里写图片描述

APPLE iOS 远程推送APNS_第33张图片
这里写图片描述

APPLE iOS 远程推送APNS_第34张图片
这里写图片描述

点击Download,将证书下载到本地后,双击下载的开发环境推送证书(文件名为:aps_development.cer),就可以在钥匙串访问中的我的证书中找到。

** 这里我要说的坑就是,在双击开发证书之后,在登录选项下,竟然没有发现上述图片所说的那个秘钥!!!!!!!在这里我删了又重来删了有重来好几次了**

最后。。。。我™直接拉进去,竟然可以了~

  1. 导出推送证书的P12文件
    注意:在钥匙串访问(KeyChain)的我的证书中选择刚刚导入的证书,选择导出,注意不要选中私钥,并设置相应密码即可。
APPLE iOS 远程推送APNS_第35张图片
这里写图片描述
APPLE iOS 远程推送APNS_第36张图片
这里写图片描述
APPLE iOS 远程推送APNS_第37张图片
这里写图片描述

注意:此步骤所设置的密码将在之后在U-Push后台上传推送证书时所使用。

APPLE iOS 远程推送APNS_第38张图片
感谢友盟+

生产环境的推送证书也是以同样的方式导出。
至此,P12证书导出完毕。

上面所说的那些,我都是在友盟看回来的,感谢友盟

客户端接收设置


1、注册远程推送以及设置相关选项:

    // 这里其实还有个ios版本区分的,但是项目需求是7.0以上的版本,所以这里没有考虑其他情况。
    UIRemoteNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];

这里还需要对Capabilites进行设置以确保能接受到推送:

APPLE iOS 远程推送APNS_第39张图片
屏幕快照 2016-07-19 20.09.12.png

2、在APPDelegate.m的接收函数


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    if (launchOptions) {
        //如果应用还没启动,则通过push冷启动后,仍能在激动之后获取Dictionary
        NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
        
        if (userInfo) {
            //有推送消息优先处理推送消息
            NSLog(@"Dictionary:%@",userInfo);
        }
        //  当userInfo设置了badge,应用图标上将一直显示一个数字提示,如果要清除数字提示,或者设置成其他数字,调用下面函数就可以完成。
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
        
    }

    return YES;
}

//注册成功回调方法,其中deviceTocken是APNS返回的token
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{

    NSLog(@"Devtocken:%@",deviceToken);
}

//注册失败返回调用方法,处理失败情况
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{

    NSLog(@"获取DeviceTocken失败:%@",error);
    
}

//当程序在前台运行,接收到消息不会有消息提示(提示框或横幅)。
//当程序运行在后台,接收到消息会有消息提示,点击消息后进入程序,
//AppDelegate的didReceiveRemoteNotification函数会被调用,消息做为此函数的参数传入
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)payload {
    
    NSLog(@"remote notification: %@",[payload description]);
    NSString* alertStr = nil;
    NSDictionary *apsInfo = [payload objectForKey:@"aps"];
    NSObject *alert = [apsInfo objectForKey:@"alert"];
    if ([alert isKindOfClass:[NSString class]])
    {
        alertStr = (NSString*)alert;
    }
    else if ([alert isKindOfClass:[NSDictionary class]])
    {
        NSDictionary* alertDict = (NSDictionary*)alert;
        alertStr = [alertDict objectForKey:@"body"];
    }
    application.applicationIconBadgeNumber = [[apsInfo objectForKey:@"badge"] integerValue];
    
    //当程序存活并受到来自APNS的推送时执行的方法:
    if ([application applicationState] == UIApplicationStateActive && alertStr != nil)
    {
        UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Pushed Message" message:alertStr delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];    
    }
    
    if ([application applicationState] == UIApplicationStateBackground) {
        UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Pushed Message" message:alertStr delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }
}

测试一下


在网上搜罗了一下,有好几种方式可以达到检测的目的,首推的,也是最简单的,在Mac上运行的,直接在github上可以拿到改demo:PushMeBaby

这里只需要简单的在APPdelegate中配置一下DeviceToken以及把推送证书放到项目工程中就可以了。 ** 此处有坑 **:这里需要把这个选项给选上,不然在读取证书路径的时候就会失败。

APPLE iOS 远程推送APNS_第40张图片
屏幕快照 2016-07-19 20.16.30.png

** 同时这里还存在第二个坑:**
在设置deviceToken时,需要保留空格,去掉尖括弧

APPLE iOS 远程推送APNS_第41张图片
屏幕快照 2016-07-19 20.18.28.png

运行一下,push一下就可以了,有时候网络问题也会导致一些延迟。

这里我其实还测试了另外的一种方法:php推送

1 .首先将证书文件和私钥处理成单个方便使用的pem文件,假设CSR、p12和cer文件都放在桌面上。

$ cd ~/Desktop$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
PushKey.p12

2 .将aps_development.cer转换为pem文件。

$ openssl x509 -in aps_development.cer -inform der -out PushCert.pem
$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
PushCert.pem
PushKey.p12

3 .将p12私钥文件转换为pem文件。

$ openssl pkcs12 -nocerts -out PushKey.pem -in PushKey.p12 
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

4 .将两个文件合成同一个。

$ cat PushCert.pem PushKey.pem > ck.pem
$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
ck.pem
PushCert.pem
PushKey.pem 
PushKey.p12

5 .测试证书是否有效。

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushCert.pem -key PushKey.pem

如果有效的话,会输出一堆信息,并且建立连接,否则不会成功建立连接。
6 .使用PHP进行测试,下载SimplePush.php,修改文件并填入deviceToken和密码。在终端运行该代码。

$ php simplepush.php Connected to APNSMessage successfully delivered

成功发送推送消息。
(此方法感谢:戴维营教育原创文章)


** 关于推送json格式的说明 **

  • 推送负载:

远程通知负载的大小根据Provider使用的API不同而不同。当使用HTTP/2 provider API时,负载最大为4096bytes,即4kB;当使用legacy binary interface时,负载最大为2048bytes,即2kB。当负载大小超过规定的负载大小时,APNs会拒绝发送此消息。

  • 远程推送负载内容

内容格式必要要知道的啊,服务端一般会要我们客户端定义好格式给他们的。
每一条通知的消息都会组成一个JSON字典对象,其格式如下所示,示例中的key值为苹果官方所用key。自定义字段的时候要避开这些key值。

每一条通知的消息都会组成一个JSON字典对象,其格式如下所示,示例中的key值为苹果官方所用key。自定义字段的时候要避开这些key值。


{
     "aps" : {  
         "alert"              :              {   // string or dictionary
            "title"          :   "string"
            "body"           :   "string",
            "title-loc-key"  :   "string or null"
            "title-loc-args" :   "array of strings or null"
            "action-loc-key" :   "string or null"
            "loc-key"        :   "string"
            "loc-args"       :   "array of strings"
            "launch-image"   :   "string"
         },
          "badge"             :    number,
          "sound"             :    "string"
          "content-available" :    number;
          "category"          :    "string"
     },
}

aps:推送消息必须有的key
alert:推送消息包含此key值,系统就会根据用户的设置展示标准的推送信息
badge:在app图标上显示消息数量,缺少此key值,消息数量就不会改变,消除标记时把此key对应的value设置为0
sound:设置推送声音的key值,系统默认提示声音对应的value值为default
content-available:此key值设置为1,系统接收到推送消息时就会调用不同的回调方法,iOS7之后配置后台模式
category:UIMutableUserNotificationCategory's identifier 可操作通知类型的key值
title:简短描述此调推送消息的目的,适用系统iOS8.2之后版本
body:推送的内容
title-loc-key:功能类似title,附加功能是国际化,适用系统iOS8.2之后版本
title-loc-args:配合title-loc-key字段使用,适用系统iOS8.2之后版本
action-loc-key:可操作通知类型key值,不详细叙述
loc-key:参考title-loc-key
loc-args:参考title-loc-args
launch-image:点击推送消息或者移动事件滑块时,显示的图片。如果缺少此key值,会加载app默认的启动图片。

后边这一对是自定义的,但是要注意不可以和前面的重复


          "badge"             :    number,
          "sound"             :    "string"
          "content-available" :    number;
          "category"          :    "string"

此处出自TIME_for 的《iOS推送之远程推送(iOS Notification Of Remote Notification》)

搬运工再次感谢各位前辈的付出。谢谢!

你可能感兴趣的:(APPLE iOS 远程推送APNS)