【问题标题】:how to properly send push notifications如何正确发送推送通知
【发布时间】:2013-06-14 15:34:47
【问题描述】:

这不是我第一个发送推送通知的应用,但它是我第一个同时向所有用户发送通知的应用。

我遇到的是,并非所有用户都收到通知,只有部分用户收到通知,即使他们的设置正确(即启用我的应用程序的通知),代码也是正确的,因为它已发送给其中一些用户,所以我的猜测是代码“错过”了一些执行,因为与 APNS 的连接是异步的,所以不知何故(如果我错了,你告诉我)它弄乱了发送通知的队列。

代码如下:

function sendNotification(){

$sql = "SELECT * FROM users WHERE phone = 'iPhone' AND pushID != ''";
try {
    $db = getConnection();
    $stmt = $db->prepare($sql);  
    $stmt->execute();
    $users = $stmt->fetchAll(PDO::FETCH_OBJ);

    $request = Slim::getInstance()->request();
    $content = json_decode($request->getBody());
    $message = $content->message;

    foreach($users as $user){

            // Put your device token here (without spaces):
            $deviceToken = $user->pushID;


            // Put your private key's passphrase here:
            $passphrase = 'xxxxxxx';

            ////////////////////////////////////////////////////////////////////////////////

            $ctx = stream_context_create();
            stream_context_set_option($ctx, 'ssl', 'local_cert', 'xxxxx.pem');
            stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

            // Open a connection to the APNS server
            $fp = stream_socket_client(
                'ssl://gateway.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);

    }
    $db = null;
} catch(PDOException $e) {
    echo '{"error":{"text":'. $e->getMessage() .'}}'; 
}
}

如您所见,我使用 iPhone 获取所有用户并向他们发送通知。我的手机是该列表中的最后一个用户,我没有得到它,我知道的另一个用户是第一个用户,她得到了它。 它要么错过了数组中的一些用户,要么只做了前半部分,没有显示错误。

我为此使用 Slim。

希望你能帮助我,谢谢!

【问题讨论】:

    标签: php ios push-notification apple-push-notifications


    【解决方案1】:

    您发送到的某些设备令牌可能无效。即使是一台无效的设备也可以解释您所遇到的情况。当您发送带有无效设备令牌的通知时,Apple 会返回错误响应并关闭套接字。

    当您的代码检测到套接字已关闭时,您可能已经在无效通知之后发送了许多通知(甚至有可能您在检测到套接字已关闭之前完成了所有通知的发送),这会导致所有通知在无效的被丢弃之后发送。创建新套接字后,此类通知必须重新发送给 Apple。

    我建议您阅读this document 中的Push Notification Throughput and Error Checking 部分以了解更多详细信息。

    确保您的数据库不包含生产设备令牌和沙盒设备令牌的混合,因为生产令牌在沙盒环境中无效,反之亦然。

    【讨论】:

    • 我在这里遇到了同样的问题 - stackoverflow.com/questions/17116249/… 。这确实是我的数据库表顶部的一个错误设备令牌,它正在停止向每个设备发送通知。
    • 我刚才尝试向我的所有用户发送通知,但是通过 Sandox 模式,这应该会出错,因为我的令牌都不是开发的,不幸的是,我得到的是“消息已成功发送”,苹果真的会回答“一切都好”吗?
    • @subharb 这取决于您发送的通知数量和速度。例如,如果您同时发送 10 条通知(其中一些带有无效的设备令牌),您可能不会看到任何异常,并且在您看来它们都已成功发送。下次您尝试通过同一个套接字发送通知时,您将收到异常。苹果从不回答“一切正常”。它仅在发生错误时并且仅在您使用增强的二进制格式时才发送响应。阅读我在回答中提供的链接了解更多详情。
    • @Eran 好的,现在我明白发生了什么。如果您看到我的代码,我将 Apple 的答案保存在 $result 中,我想这将是一个整数或布尔值。现在我打印 $result 的值,如果可以,则为 138,如果有问题,则为 139,但从 Apple 的文档中我看到他们实际上发送了一个二进制数,但我找不到使结果成为的方法一个像文档中的二进制数,你能帮我得到那个二进制数吗?谢谢!
    • @subharb 根据您的代码 (chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;),您使用的是基本二进制格式,其中 Apple 不返回任何内容。我不知道 PHP,所以我不知道 fwrite 返回什么,但如果它返回写入的字节数,我不会感到惊讶,它只会告诉你字节是否发送到 Apple。它不会告诉您您发送的消息是否有效。如果您想要 Apple 的响应,您必须切换到增强格式并尝试从套接字读取。
    【解决方案2】:

    您可以使用此方法通过以下代码向多个用户发送通知。以下代码可帮助您发送Firebase push notification android。您需要将您的服务器密钥和消息传递给此函数。

    <?php
    $target = ["TARGET_ID"];
    
    $notificationBody['data'] = [
        'type' => 1,
        'url' => "https://trinitytuts.com/wp-content/uploads/2018/07/macaw.png",
        'title' => "title",
        "msg" => "Message"
    ];
    
    $response = sendMessage($notificationBody, $target, $_POST['serverKey']);
    
    function sendMessage($data, $target, $serverKey){
        //FCM api URL
        $rsp = [];
        $url = 'https://fcm.googleapis.com/fcm/send';
        //api_key available in Firebase Console -> Project Settings -> CLOUD MESSAGING -> Server key
        $server_key = $serverKey;
        $fields = array();
        $fields['data'] = $data;
        if(is_array($target)){
                $fields['registration_ids'] = $target;
            }else{
                $fields['to'] = $target;
        }
        //header with content_type api key
        $headers = array(
            'Content-Type:application/json',
            'Authorization:key='.$server_key
        );
    
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        $result = curl_exec($ch);
        if ($result === FALSE) {
            //die('FCM Send Error: ' . curl_error($ch));
        }
        curl_close($ch);
    
        //print_r($result);
        return $result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-18
      • 2018-11-27
      • 1970-01-01
      相关资源
      最近更新 更多