实现PushKit并测试开发行为

pas*_*i86 21 apple-push-notifications ios ios-frameworks ios8

我想在我的应用程序(Voip应用程序)中实现PushKit服务,但我有以下疑问:我看到我只能生成生产voip证书,如果我尝试在开发设备上测试voip推送通知服务,它是否有效?

这是我的实施测试:

使用这3行代码,我可以在didUpdatePushCredentials回调中获取push令牌,用于保存到我的服务器中.

PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
Run Code Online (Sandbox Code Playgroud)

服务器端我生成一个只有警报文本的"正常"有效负载推送通知,然后我发送到存储在我服务器中的voip令牌.

我使用带有调试日志的回调,但它们永远不会被调用!

- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(NSString *)type {

          NSLog(@"didInvalidatePushTokenForType");

}

-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {

          NSLog(@"didReceiveIncomingPushWithPayload: %@", payload.description);

}

-(void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
     if([credentials.token length] == 0) {
           NSLog(@"voip token NULL");

          return;
     }

      NSLog(@"didUpdatePushCredentials: %@ - Type: %@", credentials.token, type);

}
Run Code Online (Sandbox Code Playgroud)

如果我尝试从我的服务器生成推送通知消息,以便先前上传的voip设备令牌,我从未通知didReceiveIncomingPushWithPayload回调,但是从服务器我得到200 ok消息(消息已成功发送)

M P*_*des 65

为了防止有人对使用Pushkit测试voip推送通知感兴趣,我留下了一个我成功遵循的小程序:

1 -创建,如果你没有它已经,一个CSR与钥匙串访问和保存您的CSR本地.

2 - 访问Apple Developer并获取证书,标识符和配置文件.在会员中心.

  • 内部标识符 - >应用程序ID创建一个新的应用程序ID
  • Inside Devices-> All添加要用于测试voip推送的设备UDID
  • 内部证书 - >全部创建新的生产证书:VoIP服务证书.为您的voip服务证书选择以前创建的应用ID.选择以前创建的CSR(证书签名请求),并在创建后下载新的voip_services.cer

下载后双击voip_services.cer以打开Keychain Access应用程序并导出生成的证书的私钥:右键导出certificate.p12文件.

voip_services.cercertificate.p12文件保存在文件夹中,以便创建服务器推送通知生成器

最后再次访问Apple Developer网站,在Provisioning Profiles-> Distribution内部创建一个新的Ad-Hoc分发配置文件,其中包含您要用于测试voip推送的所有设备UDID.下载此配置文件并拖放到您的xcode,以便在您的应用程序中使用它.

现在让我们创建将接收voip推送通知的iOS应用程序:

  • 从Xcode新项目菜单中创建一个新的单视图应用程序.
  • 根据上一节中创建的应用程序ID填充其捆绑标识符.
  • 在General-> Linked Frameworks and Libraries中添加PushKit.framework.
  • 在功能中启用后台模式并选择Voice over IP选项.
  • 在"构建设置" - >"代码签名"中,选择先前下载的配置文件,然后选择"分发为代码签名标识".

让我们在应用程序中添加Pasquale在他的问题中添加的代码:

在根视图控制器头(ViewController.h )中,PushKit.framework的导入:

#import <PushKit/PushKit.h>
Run Code Online (Sandbox Code Playgroud)

添加委托以实现其功能:

@interface ViewController : UIViewController <PKPushRegistryDelegate>
Run Code Online (Sandbox Code Playgroud)

添加根视图控制器的ViewDidLoad函数(ViewController.m)推送注册:

- (void)viewDidLoad {
    [super viewDidLoad];

    PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
    pushRegistry.delegate = self;
    pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
Run Code Online (Sandbox Code Playgroud)

实现所需的委托功能:

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
    if([credentials.token length] == 0) {
        NSLog(@"voip token NULL");
        return;
    }

    NSLog(@"PushCredentials: %@", credentials.token);
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
    NSLog(@"didReceiveIncomingPushWithPayload");
}
Run Code Online (Sandbox Code Playgroud)

一旦所有内容都编译完成,请归档您的项目并导出您的ipa文件,以便将其安装在测试设备上(您可以使用Testflight来完成这项工作).

执行它并从日志中获取我们将用于发送推送的PushCredentials.

现在让我们去服务器端(我按照这个伟大的raywenderlich教程指南):

如果您放置了三个文件,请返回文件夹:

  • voip_services.cer
  • certificate.p12

1 - 打开终端并从证书文件创建pem文件:

#openssl x509 -in voip_services.cer -inform der -out PushVoipCert.pem
Run Code Online (Sandbox Code Playgroud)

2 - 从导出的私钥文件创建pem文件:

#openssl pkcs12 -nocerts -out PushVoipKey.pem -in certificate.p12
Run Code Online (Sandbox Code Playgroud)

3 - 将两个pem文件合并为一个:

#cat PushVoipCert.pem PushVoipKey.pem > ck.pem
Run Code Online (Sandbox Code Playgroud)

为了发送推送,您可以使用来自raywenderlich教程教程的Pusher或使用简单的PHP脚本:

<?php

// Put your device token here (without spaces):
$deviceToken = '0f744707bebcf74f9b7c25d48e3358945f6aa01da5ddb387462c7eaf61bbad78';

// Put your private key's passphrase here:
$passphrase = 'pushchat';

// Put your alert message here:
$message = 'My first push notification!';

////////////////////////////////////////////////////////////////////////////////

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS' . PHP_EOL;

// Create the payload body
$body['aps'] = array(
    'alert' => $message,
    'sound' => 'default'
    );

// Encode the payload as JSON
$payload = json_encode($body);

// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// Close the connection to the server
fclose($fp);
Run Code Online (Sandbox Code Playgroud)

你应该在脚本中修改:

  • 通过添加PushCredentials(来自应用程序日志)$ deviceToken
  • 您在创建PushVoipKey.pem时在步骤2中添加的密码短语$ passphrase

而已.执行php脚本:

#php simplePushScript.php
Run Code Online (Sandbox Code Playgroud)

你应该收到你的voip推送通知(你应该看到app log:"didReceiveIncomingPushWithPayload")

在那次测试之后,我想知道如何通过pushkit框架接收标准推送通知,但不幸的是我没有回答,因为在注册推送类型时我找不到任何其他PKPushType但PKPushTypeVoIP ...

pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
Run Code Online (Sandbox Code Playgroud)

就这样!谢谢阅读!

  • 我解决了我的问题.我的PKPushRegistry对象被取消分配,因为它是一个局部变量.一旦我把它作为我的AppDelegate的实例变量,它修复了这个问题. (4认同)

Tro*_*roy 7

今天我对此进行了非常详细的探讨。我也想知道当 Apple 只允许我们生成生产 VoIP 推送证书时,如何在开发版本中使用生成的推送令牌。

在服务器上,您必须向 发送生产推送gateway.push.apple.com和开发/沙盒推送gateway.sandbox.push.apple.com。我能够使用gateway.sandbox.push.apple.com. 我还没有尝试过,但假设它也适用于临时或生产构建并使用gateway.push.apple.com.

另请注意,推送通知在模拟器中根本不起作用。