53

向 iOS 用户发送通知时,对于其中一些用户,我得到响应状态代码 400(BadDeviceToken)或代码 410(未注册)。

来自关于“BadDeviceToken”的 Apple 文档:

指定的设备令牌错误。验证请求是否包含有效令牌并且该令牌与环境匹配。

“坏”是什么意思?我知道设备令牌在早些时候是有效的。用户如何使其设备令牌变坏?

从有关“未注册”的文档中:

指定主题的设备令牌处于非活动状态。

这是否一定意味着该应用程序已被删除?或者此响应可能还有其他一些原因。

4

6 回答 6

80

正如您从APNS 文档中的表 8-6中引用的那样,错误有两个可能的原因:

  1. 设备令牌无效
  2. 设备令牌与环境不匹配

如果是第一种情况,请确保 iOS 应用程序在每次启动应用程序时都为设备注册远程通知,因为设备令牌在启动时发生更改的原因有很多,如配置远程通知支持中所述。

如果是第二种情况,您需要确保:

  • 如果您的应用构建已使用开发APNS 权利进行签名,则后端使用开发配置,并且
  • 如果您的应用构建使用生产APNS 权利进行签名,则后端使用生产配置。

幸运的是,作为 iOS 开发人员,您不需要自己直接更改 APNS 权利。它始终处于开发阶段,只有当您为 App Store 或企业分发生成构建和导出时,Xcode 才会自动将其更改为生产环境。至于后端,您的后端开发人员应该知道如何为开发和生产环境配置后端。对于某些框架,只需切换一些名为isProduction. 最终,根据与 APNs 通信一节中的内容APNs Connections,根据环境是生产环境还是开发环境,推送通知将发送到不同的 APNS 端点。

让我们假设BadDeviceToken错误是由于第二种情况 - 应用程序注册的设备令牌与后端正确配置的开发环境不匹配。首先,在您的 Xcode 项目中,检查您的.entitlements文件并验证APS Environment密钥的值为development. 它应该如下所示:

在此处输入图像描述

接下来,在生成存档后,打开管理器(通过Window菜单 > Organizer),选择存档,然后单击Export...右侧的 。您应该看到四种分发方法:

在此处输入图像描述

如果您选择 App Store 或 Enterprise,您将在后面的对话框中看到 Xcode 将 APNS 权利更改为生产(参见红色箭头的尖端):

在此处输入图像描述

如果您选择 Ad Hoc 或 Development,则aps-environment下的文本将为development,这应该与后端的配置相匹配。

于 2018-02-06T18:07:27.160 回答
15

我正在向“生产”苹果推送服务器发送“开发”设备令牌。api.development.push.apple.com我通过向而不是发送请求来修复它api.push.apple.com

于 2020-04-10T01:26:30.103 回答
13

状态码“400”:当您尝试发送带有错误证书的通知时会收到此错误。确保将生产证书用于生产环境。这很糟糕,因为您使用了错误的配置。

状态代码“410”:是的,使用此代码我们可以理解 App 已删除。在我们的应用程序中,当我们获得此状态代码时,我们会从 db 中删除此令牌。另一种情况可能是用户重新安装了可能会更改其令牌的应用程序。所以最好删除这个令牌。

于 2017-05-31T07:19:20.617 回答
2

错误代码 404:BadDevice 令牌

可能的原因:

  1. 您的 .pem 证书可能有误。
  2. 您的 BundleId 可能是错误的。
  3. 您的设备 ID 可能有误。

注意:使用您的 bundleid 附加 .voip 以发送 voip 推送通知(例如:bundleid.voip)

这是一个可行的 voip 推送通知示例:

<?php
$token = $_REQUEST['tok'];
if (!defined('CURL_HTTP_VERSION_2_0')) {
  define('CURL_HTTP_VERSION_2_0', 3);
}
// open connection 
$http2ch = curl_init();
curl_setopt($http2ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
// send push
$apple_cert = 'certificate_name.pem';
$message = '{"aps":{"action":"message","title":"your_title","body":"your_message_body"}}';
$http2_server = 'https://api.development.push.apple.com'; // or 'api.push.apple.com' if production
$app_bundle_id = 'your bundle id';
$status = sendHTTP2Push($http2ch, $http2_server, $apple_cert, $app_bundle_id, $message, $token);
echo $status;
// close connection
curl_close($http2ch);
function sendHTTP2Push($http2ch, $http2_server, $apple_cert, $app_bundle_id, $message, $token) 
{
    // url (endpoint)
    $url = "{$http2_server}/3/device/{$token}";
    $cert = realpath($apple_cert);
    // headers
    $headers = array(
        "apns-topic: {$app_bundle_id}",
        "User-Agent: My Sender"
    );
    curl_setopt_array($http2ch, array(
        CURLOPT_URL => $url,
        CURLOPT_PORT => 443,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POST => TRUE,
        CURLOPT_POSTFIELDS => $message,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSLCERT => $cert,
        CURLOPT_HEADER => 1
    ));
    $result = curl_exec($http2ch);
    if ($result === FALSE) {
      throw new Exception("Curl failed: " .  curl_error($http2ch));
    }
    // get response
    $status = curl_getinfo($http2ch, CURLINFO_HTTP_CODE);
    if($status=="200")
    echo "SENT|NA";
    else
    echo "FAILED|$status";
}
?> 
于 2018-09-06T09:25:58.953 回答
2

如果使用node-apn. 我发现这里的答案相当混乱,因为 APN 已经转向使用适用于沙盒或生产模式的令牌。我也很困惑,因为编写一个 1 off 脚本来发送通知在生产中工作。

直到我开始怀疑我的服务没有得到process.env.NODE_ENV === 'production'. 所以我将它添加到我的启动日志消息中,并且看到我的服务运行程序forever没有获得任何环境变量。因此,它在沙盒 url 上尝试生产设备 ID。

于 2019-06-19T00:38:44.957 回答
0

410 通知不再是即时反馈。出于隐私考虑,Apple 故意这样做了。现在可能需要长达一周的时间。请参阅https://developer.ibm.com/customer-engagement/2019/05/01/apns-feedback-service-change/

于 2020-04-08T20:21:05.340 回答