0

Google App Engine サーバーにプッシュ通知を追加しようとしていますが、デバイスが毎秒プッシュ通知しか受信しないという奇妙な問題が発生しています。

バックエンドで通知を送信するプッシュ キューを設定しました。インスタンスごとの最初のリクエストは、プッシュをキューに入れて送信するバックグラウンド スレッドを作成します。次に、各プッシュ要求は要求をキューに追加し、プッシュが送信されるのを待ってから、成功の場合はコード 200、失敗の場合はコード 500 で応答します。バックグラウンドスレッドのコードは次のとおりです。

void doSendThread() {

    // Open certificate (certificate is a class URL var)
    InputStream cert = certificate.openStream();

    // Connect to Apple Push service (password and apnsManager are class vars)
    AppleNotificationServer appleServer = new AppleNotificationServerBasicImpl(cert, password, ConnectionToAppleServer.KEYSTORE_TYPE_PKCS12, "gateway.push.apple.com", 2195);
    apnsManager = new PushNotificationManager();
    apnsManager.initializeConnection(appleServer);

    // Send loop
    while (true) {

        // Wait for a bit
        Thread.sleep(500);

        // Check for new pushes in queue (pushQueue is a class ArrayDequeue var)
        while (!pushQueue.isEmpty()) {

            // Get next push data (PushData is a custom class that holds the push notification state)
            PushData data = pushQueue.poll();

            // Send data (the HTTP request thread stops waiting when data.done is true)
            sendPushData(data);
            data.done = true;

        }

    }

    // There's also some feedback checking stuff here which I've left out
    ...

}

void sendPushData(PushData) {

    try {

        // Get tokens
        Logger.getLogger(PushManager.class.getName()).log(Level.INFO, "Sending push...");
        List<Device> devices = Devices.asDevices(data.tokens);

        // Create payload
        PushNotificationPayload payload = PushNotificationPayload.complex();
        if (data.text.length() > 0)
            payload.addAlert(data.text);
        if (data.badge > 0)
            payload.addBadge(data.badge);
        if (data.sound.length() > 0)
            payload.addSound(data.sound);

        // Go through devices and send each push
        for (Device dev : devices) {

            // Send payload and don't close the connection
            PushedNotification pn = apnsManager.sendNotification(dev, payload, false);

            // Check for error (HTTP thread returns 500 if data.error is true)
            if (!pn.isSuccessful())
                data.error = true;

            // Log error
            if (pn.getException() != null)
                Logger.getLogger(PushManager.class.getName()).log(Level.SEVERE, "Push error: " + pn.getException().getMessage());

        }

    } catch (Exception e) {
        Logger.getLogger(PushManager.class.getName()).log(Level.SEVERE, "Push error: " + e.getMessage());
        e.printStackTrace();
        disconnect(); // <- Disconnects the apnsManager and shuts down the thread, the next push request will create a new thread and reconnect
        data.error = true;
    }

}

ログはインスタンスがシャットダウンされるとバックグラウンド スレッドに対してのみ取得されるため、GAE でのログ記録は困難ですが、アプリを使用して 5 回のプッシュを送信してからインスタンスをシャットダウンすると、これが私のログになります。

W 2014-01-13 13:41:18.028 [s~*****chat/push-notification-worker.373021320690690677].<stderr>: log4j:WARN No appenders could be found for logger (javapns.communication.Connecti
W 2014-01-13 13:41:18.028 [s~*****chat/push-notification-worker.373021320690690677].<stderr>: log4j:WARN Please initialize the log4j system properly.
W 2014-01-13 13:41:18.028 [s~*****chat/push-notification-worker.373021320690690677].<stderr>: log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more inf
I 2014-01-13 13:41:19.222 com.*****apps.*****Server.Push.PushManager sendPushData: Sending push...
I 2014-01-13 13:41:23.027 com.*****apps.*****Server.Push.PushManager sendPushData: Sending push...
I 2014-01-13 13:41:23.663 com.*****apps.*****Server.Push.PushManager sendPushData: Sending push...
I 2014-01-13 13:41:24.225 com.*****apps.*****Server.Push.PushManager sendPushData: Sending push...
I 2014-01-13 13:41:24.790 com.*****apps.*****Server.Push.PushManager sendPushData: Sending push...
I 2014-01-13 13:42:25.022 com.*****apps.*****Server.Push.PushManager disconnect: Shutting down push manager...

... 5 つすべてを送信しているように見えますが、デバイスで 2 番目と 4 番目のものしか受信できません。本当に奇妙なのは、私は 2 つのデバイスを持っているため、各プッシュが実際には 2 つのプッシュを送信し (つまり、実際には 10 個のプッシュ通知が Apple に送信された)、両方でメッセージを受信するか、1 つだけではなく、両方でメッセージを受信することです。

4

1 に答える 1

0

短期間に同じデバイスに複数の通知を送信すると、一部の通知のみが配信される場合があります。同じデバイスへのメッセージ間に任意の遅延 (十分である場合もあれば十分でない場合もあります) を強制することはお勧めできません。アプリは、(サーバーと同期することによって) 送信したすべての通知を受信しないことを処理できる必要があります。

これについて、Apple のテクニカル ノートには次のように書かれています。

一部の通知を受信しましたが、すべてではありません

短期間に同じデバイスまたはコンピューターに複数の通知を送信している場合、プッシュ サービスは最後の通知のみを送信します。

理由は次のとおりです。デバイスまたはコンピューターは、各通知の受信を確認します。プッシュ サービスは、その受信確認を受信するまで、デバイスまたはコンピューターが何らかの理由でオフラインになったと想定し、将来の再配信のためにサービスの品質 (QoS) キューに通知を格納します。もちろん、ここでの往復ネットワーク遅延は主要な要因です。

Local and Push Notification Programming Guide で説明されているように、QoS キューは、デバイスまたはコンピューターごとにアプリごとに 1 つの通知を保持します。キュー内の通知が送信される前にサービスが別の通知を受信した場合、新しい通知によって前の通知が上書きされます。

これらはすべて、プロバイダーで重要な変更があったことを通知がアプリに示すことを意図していることを示しており、アプリはプロバイダーにチェックインして詳細を取得する必要があります。通知には、他の場所では利用できないデータを含めるべきではなく、ステートフルであってはなりません。

すぐに配信されないプッシュ通知は、デバイスがサービスに接続されていなかったため、将来の再配信のためにキューに入れられました。もちろん、「すぐに」では、接続の待ち時間を考慮する必要があります。その時点で APN がタイムアウトするため、範囲外のケースは 60 秒を超えます。

于 2014-01-13T13:59:38.960 に答える