向 iOS 用户发送通知时,对于其中一些用户,我得到响应状态代码 400(BadDeviceToken)或代码 410(未注册)。
来自关于“BadDeviceToken”的 Apple 文档:
指定的设备令牌错误。验证请求是否包含有效令牌并且该令牌与环境匹配。
“坏”是什么意思?我知道设备令牌在早些时候是有效的。用户如何使其设备令牌变坏?
从有关“未注册”的文档中:
指定主题的设备令牌处于非活动状态。
这是否一定意味着该应用程序已被删除?或者此响应可能还有其他一些原因。
向 iOS 用户发送通知时,对于其中一些用户,我得到响应状态代码 400(BadDeviceToken)或代码 410(未注册)。
来自关于“BadDeviceToken”的 Apple 文档:
指定的设备令牌错误。验证请求是否包含有效令牌并且该令牌与环境匹配。
“坏”是什么意思?我知道设备令牌在早些时候是有效的。用户如何使其设备令牌变坏?
从有关“未注册”的文档中:
指定主题的设备令牌处于非活动状态。
这是否一定意味着该应用程序已被删除?或者此响应可能还有其他一些原因。
正如您从APNS 文档中的表 8-6中引用的那样,错误有两个可能的原因:
如果是第一种情况,请确保 iOS 应用程序在每次启动应用程序时都为设备注册远程通知,因为设备令牌在启动时发生更改的原因有很多,如配置远程通知支持中所述。
如果是第二种情况,您需要确保:
幸运的是,作为 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,这应该与后端的配置相匹配。
我正在向“生产”苹果推送服务器发送“开发”设备令牌。api.development.push.apple.com我通过向而不是发送请求来修复它api.push.apple.com
状态码“400”:当您尝试发送带有错误证书的通知时会收到此错误。确保将生产证书用于生产环境。这很糟糕,因为您使用了错误的配置。
状态代码“410”:是的,使用此代码我们可以理解 App 已删除。在我们的应用程序中,当我们获得此状态代码时,我们会从 db 中删除此令牌。另一种情况可能是用户重新安装了可能会更改其令牌的应用程序。所以最好删除这个令牌。
错误代码 404:BadDevice 令牌
可能的原因:
注意:使用您的 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";
}
?>
如果使用node-apn. 我发现这里的答案相当混乱,因为 APN 已经转向使用适用于沙盒或生产模式的令牌。我也很困惑,因为编写一个 1 off 脚本来发送通知在生产中工作。
直到我开始怀疑我的服务没有得到process.env.NODE_ENV === 'production'. 所以我将它添加到我的启动日志消息中,并且看到我的服务运行程序forever没有获得任何环境变量。因此,它在沙盒 url 上尝试生产设备 ID。
410 通知不再是即时反馈。出于隐私考虑,Apple 故意这样做了。现在可能需要长达一周的时间。请参阅https://developer.ibm.com/customer-engagement/2019/05/01/apns-feedback-service-change/