实现PushKit并在开发行为中进行测试。

23

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

这是我的实现测试:

通过这3行代码,我可以在didUpdatePushCredentials回调中获取推送令牌,我将使用它保存到我的服务器。

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

服务器端我生成了一个“普通”的推送通知负载,仅包含警报文本,并将其发送到存储在我的服务器中的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);

}
如果我尝试从我的服务器向之前上传的VoIP设备令牌生成推送通知消息,我永远不会在didReceiveIncomingPushWithPayload回调中收到通知,但是从服务器上我会收到200 OK消息(消息成功发送)。

我没有收到回调被调用的通知,也没有收到未被调用的通知。我不确定如何获取令牌以进行测试。在这方面有任何进展吗? - M Penades
不行,我不能使用这项服务。 - pasqui86
我收到了回调!我忘了检查应用的VoIP后台功能。 - M Penades
你有没有对我发布的代码进行任何更新?你有没有什么例子可以分享? - pasqui86
我逐行复制粘贴了你的代码。你尝试添加后台模式能力了吗?我已经激活了“VoIP”和“远程通知”。 - M Penades
是的,我的应用程序可以做到这一点。非常感谢。 - pasqui86
3个回答

70

如果有人对使用Pushkit测试voip推送通知感兴趣,这里我留下了一个我成功遵循的小流程:

1 - 使用Keychain Access创建CSR(如果您还没有),并将CSR保存到本地。

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

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

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

将voip_services.cer和certificate.p12文件保存在一个文件夹中,以创建您的服务器推送通知生成器。

最后再次进入苹果开发者网站,进入 Provisioning Profiles->Distribution 创建一个新的Ad-Hoc分发配置文件,在其中包括您想用于测试VoIP推送的所有设备UDID。下载此配置文件并将其拖放到您的Xcode中,以便在应用程序上使用它。

现在让我们创建iOS应用程序来接收VoIP推送通知:

  • 从Xcode新项目菜单中创建一个新的Single View Application。
  • 根据上一节中创建的应用程序ID填写其Bundle标识符。
  • 在General->Linked Frameworks and Libraries中添加PushKit.framework。
  • 在Capabilities中启用后台模式并选择Voice over IP选项。
  • 在Build Settings -> Code Signing中选择之前下载的配置文件作为Code Signing Identity,并选择Distribution。

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

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

#import <PushKit/PushKit.h>

添加委托以实现其功能:
@interface ViewController : UIViewController <PKPushRegistryDelegate>

在您的根视图控制器(ViewController.m)的viewDidLoad函数中添加push registration:
- (void)viewDidLoad {
    [super viewDidLoad];

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

实现所需的委托函数:

- (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");
}

一旦所有内容都编译并且正常,归档项目并导出ipa文件以便在测试设备上安装(例如可以使用Testflight进行此操作)。
执行它并从日志中获取PushCredentials,我们将用它来发送推送。
现在让我们进入服务器端(我遵循了raywenderlich教程的指南):
返回到放置三个文件的文件夹:
  • voip_services.cer
  • certificate.p12
1- 打开终端并从证书文件创建pem文件:
#openssl x509 -in voip_services.cer -inform der -out PushVoipCert.pem

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

#openssl pkcs12 -nocerts -out PushVoipKey.pem -in certificate.p12

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

#cat PushVoipCert.pem PushVoipKey.pem > ck.pem

为了发送推送,您可以使用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);

您需要在脚本中进行修改:

  • 通过添加您的PushCredentials(从应用程序日志中获取),修改$deviceToken
  • 通过添加在创建PushVoipKey.pem时步骤2中添加的密码,修改$passphrase

就这样。执行php脚本:

#php simplePushScript.php

并且您应该会收到VoIP推送通知(您应该看到应用程序日志:“didReceiveIncomingPushWithPayload”)

在那个测试之后,我想知道如何通过PushKit框架接收标准的推送通知,但很遗憾,当我注册推送类型时,除了PKPushTypeVoIP之外,我找不到任何其他的PKPushType...

pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];

就这些了!谢谢阅读!


我按照这个做了,但是 didUpdatePushCredentials 方法从未被调用。我需要使用 [UIApplication registerForRemoteNotificationTypes:] 注册远程通知吗? - Liron Yahdav
我无法编辑那个评论,但是我尝试通过调用registerUserNotificationSettingsregisterForRemoteNotifications来注册推送通知,但我仍然没有收到didUpdatePushCredentialsdidReceiveIncomingPushWithPayload的调用。 - Liron Yahdav
4
我解决了我的问题。我的PKPushRegistry对象被释放了,因为它是一个局部变量。一旦我将它变成AppDelegate的实例变量,问题就解决了。 - Liron Yahdav
非常好的答案,除了它链接到一个不再可用的脚本。 - Andy Dent
谢谢@AndyDent,我编辑了回复并包含了脚本,但是我在raywenderlich教程中看到他们更新了如何使用名为Pusher的应用程序发送推送(虽然我没有尝试过)。 - M Penades
显示剩余6条评论

7
今天我详细探讨了这个问题。我也在想当我们只能生成生产VoIP推送证书时如何在开发构建中使用生成的推送令牌。在服务器上,您必须将生产推送发送到gateway.push.apple.com,将开发/沙盒推送发送到gateway.sandbox.push.apple.com。我能够使用生成的生产VoIP证书在gateway.sandbox.push.apple.com上生成和接收VoIP推送。我还没有尝试过ad hoc或生产构建,并使用gateway.push.apple.com,但我认为也可以使用。另外,请注意,推送通知在模拟器中根本不起作用。

1

即使您不使用远程通知,也需要启用远程通知:

  • 在开发者门户网站上的App ID标识符中
  • 重新创建开发配置文件
  • 在XCode -> 首选项... -> 账户 -> 您的账户中点击下载全部
  • 在“能力” -> “后台模式”中启用远程通知

完成此操作后,您将在调试和发布模式下均收到委托回调。


在“能力 -> 后台模式”中启用远程通知并不是必须的。这是为了请求后台时间以下载内容。我们的PushKit通知完全可以正常工作,而无需设置这个选项。 - chadbag
如果您希望在应用程序处于后台时处理推送通知,则需要在“功能”->“后台模式”中“启用远程通知”,否则不正确。您所讨论的行为是在“功能”->“后台模式”中的“后台获取”。 - Shebuka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接