推送通知未在 iPhone 应用程序中的多个设备上传递?
Posted
技术标签:
【中文标题】推送通知未在 iPhone 应用程序中的多个设备上传递?【英文标题】:push notification not delivering on multiple devices in iphone app? 【发布时间】:2013-01-06 19:25:11 【问题描述】:我想将推送消息广播到多个设备。目前,如果数据库表中仅存储 2 个(可能是 1 个或 2 个)设备令牌,我可以发送消息。对于 3 个或更多设备令牌,我无法发送推送消息。它甚至不会向之前添加的 2 个设备发送消息。在服务器端,我可以看到消息已送达,但实际上并未送达。
我在开发人员配置文件和分发配置文件上都对其进行了测试,但是如果数据库表中仅保存 1 或 2 台设备,我只能在两者上发送消息。
在这两种情况下,我都使用了一个为开发和分发而配置的应用 ID。
我的服务器端php代码如下:
<?php
error_reporting(0);
include 'classfiles/Tokens.php';
if(isset($_POST))
$sender = $_POST['sender'];
$message = $_POST['message'];
$token = new Tokens;
$arrtokens = $token->getTokens();
$devicetoken = $_POST['device_token'];
// Settings
$apnsCert = 'test.pem';//To be changed
$apnsHost = 'gateway.push.apple.com';//To be changed
$apnsPort = 2195;
// Connect to Apple Push Notification server
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
stream_context_set_option($streamContext, 'ssl', 'passphrase', 'test123');
//60 -> timeout in seconds
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $streamContext);
if (!$apns)
die('Error creating ssl socket');
stream_set_blocking ($apns, 0);
echo 'Connected to APNS' . PHP_EOL;
if(is_array($arrtokens))
//foreach($arrtokens as $key=>$deviceToken)
for($i=0;$i<count($arrtokens);$i++)
$incrementcount = 0;
$tokenid = $arrtokens[$i][0];
$badgecount = $arrtokens[$i][1];
$incrementcount = $badgecount+1;
// Prepare payload
$payload =
array(
'aps' => array(
'alert' => $message,
'badge' => $incrementcount,
'sound' => 'default',
'sender' => $sender
)
);
$payload = json_encode($payload);
/*
// this was also working
$apnsMessage =
chr(1)
. pack('N', 88)
. pack('N', time() + 86400)
. chr(0) . chr(32)
. pack('H*', str_replace(' ', '', $tokenid))
. chr(0) . chr(strlen($payload))
. $payload . $payload;
*/
$apnsMessage = chr(0) .pack('n',32) . pack('H*', str_replace(' ', '', $tokenid)) . chr(0) . chr(strlen($payload)) . $payload;
// this was also working
// $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $tokenid)) . chr(0) . chr(strlen($payload)) . $payload;
// this was also working
// $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $device_tokens_array[i])) . chr(0) . chr(strlen($payload)) . $payload;
// $result =fwrite($apns, $apnsMessage);
$result = fwrite($apns, $apnsMessage, strlen($apnsMessage));
if(!$result)
echo 'Message to the device ' . $arrtokens[$i][0] . ' not delivered' . '<br/>';
else
$token->updateToken($tokenid,$incrementcount);
echo 'Message to the device ' . $arrtokens[$i][0] . ' successfully delivered' . '<br/>';
// sleep(10);
else if($devicetoken != "")
$apnsMessage =
chr(1)
. pack('N', 88)
. pack('N', time() + 86400)
. chr(0) . chr(32)
. pack('H*', str_replace(' ', '', $deviceToken))
. chr(0) . chr(strlen($payload))
. $payload . $payload;
$result = fwrite($apns, $apnsMessage);
if(!$result)
echo 'Message to the device ' . $token . ' not delivered' . PHP_EOL;
else
echo 'Message to the device ' . $token . ' successfully delivered' . PHP_EOL;
usleep(500000);
fclose($apns);
function checkAppleErrorResponse($apns)
$responseBinary = fread($apns, 6);
if ($responseBinary !== false && strlen($responseBinary) == 6)
print(
"\n"
.'Error message recieved from Apple.'."\n"
.'For the meaning, refer to: "Provider Communication with Apple Push Notification Service"'."\n"
);
$response = unpack('Ccommand/Cstatus_code/Nidentifier', $responseBinary);
var_dump($response);
?>
我的客户端代码在这里:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
NSLog(@"error : %@", [error description]);
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
NSLog(@"deviceToken : %@", deviceToken);
NSString *myDeviceToken = [[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""];
NSLog(@"%@",myDeviceToken);
[[NSUserDefaults standardUserDefaults] setObject:myDeviceToken forKey:@"myDeviceToken"];
[[NSUserDefaults standardUserDefaults] synchronize];
receivedData = [[NSMutableData alloc] initWithLength:0];
NSString *urlString = [NSString stringWithFormat:@"%@%@", tokenApi, myDeviceToken];//deviceToken
urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
NSLog(@"URL : %@", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone)
NSLog(@"UIRemoteNotificationTypeNone");
else if (types == UIRemoteNotificationTypeAlert)
NSLog(@"UIRemoteNotificationTypeAlert");
else if (types == UIRemoteNotificationTypeBadge)
NSLog(@"UIRemoteNotificationTypeBadge");
else if (types == UIRemoteNotificationTypeSound)
NSLog(@"UIRemoteNotificationTypeSound");
UIApplicationState state = [application applicationState];
int batchNo = [[UIApplication sharedApplication] applicationIconBadgeNumber];
if (state == UIApplicationStateActive)
NSLog(@"applicationIconBadgeNumber : %d", [[UIApplication sharedApplication] applicationIconBadgeNumber]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[[userInfo objectForKey:@"aps"] objectForKey:@"sender"]
message:[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
batchNo = 0;
else
NSLog(@"applicationIconBadgeNumber : %d", [[UIApplication sharedApplication] applicationIconBadgeNumber]);
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:batchNo - 1];
batchNo = [[UIApplication sharedApplication] applicationIconBadgeNumber];
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:@"myDeviceToken"];
receivedData = [[NSMutableData alloc] initWithLength:0];
NSString *urlString = [NSString stringWithFormat:@"%@%@&count=% d", updateTokenApi, token,batchNo];//deviceToken
urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
NSLog(@"URL : %@", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
// NSLog(@"userInfo : %@", userInfo);
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"alerts"]];
// NSLog(@"Before : %@", array);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MM/dd/YYYY hh:mm a"];
NSMutableArray *alertarray = [[NSMutableArray alloc] initWithCapacity:0];
[alertarray addObject:[dateFormatter stringFromDate:[NSDate date]]];
[alertarray addObject:[[userInfo objectForKey:@"aps"] objectForKey:@"sender"]];
[alertarray addObject:[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]];
[array addObject:alertarray];
NSArray *alertsArray = [[NSArray alloc] initWithArray:array];
[[NSUserDefaults standardUserDefaults] setObject:alertsArray forKey:@"alerts"];
[[NSUserDefaults standardUserDefaults] synchronize];
[[[[self accountPage] accountHistoryPage] alertsArray] removeAllObjects];
[[[[self accountPage] accountHistoryPage] alertsArray] addObjectsFromArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"alerts"]];
[[[[self accountPage] accountHistoryPage] accountDetailTableView] reloadData];
// NSLog(@"After : %@", [[NSUserDefaults standardUserDefaults] objectForKey:@"alerts"]);
【问题讨论】:
您应该返回并接受您之前提出的问题的答案。关于这个问题,所有注册的设备是否都处于生产模式(他们是否从 App Store 下载了应用程序)? 其中1个处于开发模式,其他4个设备处于生产模式。并且该应用不是从应用商店下载的,我们正在测试该应用。 【参考方案1】:最可能的解释是第三个设备令牌无效。如果您首先发送到此设备令牌,Apple 会关闭套接字,并且忽略发送到其他两个设备的消息,即使它们似乎在服务器端已成功传递。 如果您正在混合开发和生产设备令牌,那就可以解释为什么其中一些是无效的。如果您使用生产证书打开到 APNS 服务器的套接字,则只有生产设备令牌对该连接有效(反之亦然)。
【讨论】:
现在我已经创建了新证书、新开发者资料、新应用程序 ID,现在我正在 4 台设备上进行测试,它表示已分发到所有设备,但它只发送到第一个设备。跨度> 您使用的是增强格式吗?您是否尝试阅读 Apple 返回的错误响应?您使用的设备令牌之一可能无效。仍然有可能 4 个设备令牌中的一些是开发令牌,而其他是生产令牌,这可以解释问题。也许您应该从数据库中删除设备令牌并从 4 个设备中获取新令牌,以确保它们都是有效的。 我创建了新的应用程序 ID、新的开发人员配置文件和服务器端的一些更改,它现在可以正常工作(我未注释的注释行)。我认为您适合开发人员和分发令牌 ID。我还删除了表中的所有条目。谢谢伊兰。 谢谢!你拯救了我的一天!以上是关于推送通知未在 iPhone 应用程序中的多个设备上传递?的主要内容,如果未能解决你的问题,请参考以下文章