推送通知未在 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 应用程序中的多个设备上传递?的主要内容,如果未能解决你的问题,请参考以下文章

推送通知未在 iphone 设备中接收

1 台设备上的多个推送通知 - iPhone

推送通知未在多台设备上接收 - 仅在一台设备上获取推送

颤振推送通知图像未在所有设备上显示

推送通知未在 android 上显示

pushManager 未在移动设备上请求许可