kreait / firebase-php

Unofficial Firebase Admin SDK for PHP
https://firebase-php.readthedocs.io/
MIT License
2.25k stars 430 forks source link

iOS not receiving the topic subscription sending #789

Closed lesliedizon-kano closed 1 year ago

lesliedizon-kano commented 1 year ago

Describe the bug

The code that I have pasted below doesn't work when I am trying to send it to an iOS device through a topic subscription. To be exact, $messaging->send($message); is what I use to trigger this code which is also the same call where my Android config is and my Android device would receive it right away. I can verify and see that my user for the iOS device is subscribed to the topic the same way my android device user is.

Here is the code block I use for sending the topic notification:

$message = CloudMessage::withTarget('topic', $topic);

$notification = Notification::fromArray([
    'title' => $title,
    'body' => $body,
    'image' => $imageUrl,
]);
$message = $message->withNotification($notification);

$configA = AndroidConfig::fromArray([
    "ttl" => "2419200s", // 4 weeks limit of ttl
    "priority" => "normal",
    "notification" => [
        "title" => $title,
        "body" => $body,
        "image" => $imageUrl,
        "event_time" => $epochTime,
    ],
]);
$message = $message->withAndroidConfig($configA);

$configB = ApnsConfig::fromArray([
    "headers" => [
        "apns-push-type" => "alert",
        "apns-priority" => "10",
        "apns-expiration " => $epochTime,
        "apns-topic" => "com.kanoapps.bz.dev",
    ],
    "payload" => [
        "aps" => [
            "timestamp" => $epochTimestamp,
            "event" => "update",
            "alert" => [
                "title" => $title,
                "body" => $body,
            ],
        ],
    ],
]);
$message = $message->withApnsConfig($configB);

$fcmOptions = [
    "analytics_label" => $analyticsLabel
];
$message = $message->withFcmOptions($fcmOptions);

try
{
    $report = $this->messaging->send($message);

    Logger::getLogger()->info("Attempting to send this notification {$topic}: ", ['message' => $message, 'report' => $report]);

    return true;
}
catch (InvalidMessage $e)
{
    Logger::getLogger()->error($e->getMessage() . ' - Trace: ' . $e->getTraceAsString());
}

Installed packages

{
    "require": {
        "php": "7.4.12",
        "ext-dom": "*",
        "ext-mbstring": "*",
        "ext-mongodb": "*",
        "ext-xmlwriter": "*",
        "ext-json": "*",
        "ext-gmp": "*",
        "geoip2/geoip2": "2.7.0",
        "mongodb/mongodb": "1.4.2",
        "monolog/monolog": "1.25.3",
        "slim/slim": "3.12.0",
        "doesntmattr/mongodb-migrations": "dev-master",
        "kreait/firebase-php": "5.26.0",
        "symfony/cache": "4.2.4",
        "slim/php-view": "2.2",
        "aporat/store-receipt-validator": "2.2.0",
        "rlanvin/php-rrule": "1.6.3",
        "web-token/jwt-signature": "1.3.3",
        "web-token/jwt-key-mgmt": "1.3.3",
        "swaggest/json-schema": "0.12.11",
        "symfony/property-access": "5.0.1",
        "amnuts/opcache-gui": "2.5",
        "twisted1919/mailwizz-php-sdk": "1.0.7",
        "opensoft/rollout": "2.3.0",
        "dflydev/fig-cookies": "2.0.1",
        "aws/aws-sdk-php": "^3.208"
    },
    "require-dev": {
        "ext-xdebug":"*",
        "phpunit/phpunit": "9.4.3",
        "friendsofphp/php-cs-fixer": "2.16.6"
    },
    "scripts": {
        "lint": "php-cs-fixer fix --ansi --verbose --dry-run",
        "lint-fix": "php-cs-fixer fix --ansi --verbose",
        "test": "phpunit --colors=always",
        "test-report": "phpunit --coverage-text",
        "test-report-html": "phpunit --coverage-html phpunit-html-report",
        "generate-db-migration":"./bin/migrate-mongo mongodb:migrations:generate --configuration ./bin/migrate-mongo-config.yml --db-configuration ./bin/migrate-mongo-db.php",
        "execute-db-migration":"./bin/migrate-mongo mongodb:migrations:execute --configuration ./bin/migrate-mongo-config.yml --db-configuration ./bin/migrate-mongo-db.php $MIGRATION_TS"
    },
    "config": {
        "allow-plugins": {
            "kylekatarnls/update-helper": true
        }
    }
}

PHP version and extensions

composer               2.3.5    Composer package
composer-plugin-api    2.3.0    The Composer Plugin API
composer-runtime-api   2.2.2    The Composer Runtime API
ext-ctype              7.4.12   The ctype PHP extension
ext-curl               7.4.12   The curl PHP extension
ext-date               7.4.12   The date PHP extension
ext-dom                20031129 The dom PHP extension
ext-fileinfo           7.4.12   The fileinfo PHP extension
ext-filter             7.4.12   The filter PHP extension
ext-ftp                7.4.12   The ftp PHP extension
ext-geoip              1.1.1    The geoip PHP extension
ext-gmp                7.4.12   The gmp PHP extension
ext-hash               7.4.12   The hash PHP extension
ext-iconv              7.4.12   The iconv PHP extension
ext-json               7.4.12   The json PHP extension
ext-libxml             7.4.12   The libxml PHP extension
ext-maxminddb          1.4.1    The maxminddb PHP extension
ext-mbstring           7.4.12   The mbstring PHP extension
ext-mongodb            1.5.3    The mongodb PHP extension
ext-mysqlnd            0        The mysqlnd PHP extension (actual version: mysqlnd 7.4.12)
ext-openssl            7.4.12   The openssl PHP extension
ext-pcre               7.4.12   The pcre PHP extension
ext-pdo                7.4.12   The PDO PHP extension
ext-pdo_sqlite         7.4.12   The pdo_sqlite PHP extension
ext-phar               7.4.12   The Phar PHP extension
ext-posix              7.4.12   The posix PHP extension
ext-readline           7.4.12   The readline PHP extension
ext-reflection         7.4.12   The Reflection PHP extension
ext-session            7.4.12   The session PHP extension
ext-simplexml          7.4.12   The SimpleXML PHP extension
ext-sockets            7.4.12   The sockets PHP extension
ext-sodium             7.4.12   The sodium PHP extension
ext-spl                7.4.12   The SPL PHP extension
ext-sqlite3            7.4.12   The sqlite3 PHP extension
ext-tokenizer          7.4.12   The tokenizer PHP extension
ext-xdebug             2.9.1    The xdebug PHP extension
ext-xml                7.4.12   The xml PHP extension
ext-xmlreader          7.4.12   The xmlreader PHP extension
ext-xmlwriter          7.4.12   The xmlwriter PHP extension
ext-zend-opcache       7.4.12   The Zend OPcache PHP extension
ext-zip                1.15.6   The zip PHP extension
ext-zlib               7.4.12   The zlib PHP extension
lib-curl               7.64.0   The curl library
lib-curl-libssh2       1.8.0    curl libssh2 version
lib-curl-openssl       1.1.1.14 curl OpenSSL version (1.1.1.14)
lib-curl-zlib          1.2.11   curl zlib version
lib-date-timelib       2018.04  date timelib version
lib-date-zoneinfo      2020.2   zoneinfo ("Olson") database for date
lib-fileinfo-libmagic  537      fileinfo libmagic version
lib-gmp                6.1.2    The gmp library
lib-iconv              2.28     The iconv library
lib-libsodium          1.0.17   The libsodium library
lib-libxml             2.9.4    libxml library version
lib-mbstring-libmbfl   1.3.2    mbstring libmbfl version
lib-mbstring-oniguruma 6.9.1    mbstring oniguruma version
lib-mongodb-libbson    1.13.0   libbson version of mongodb
lib-mongodb-libmongoc  1.13.0   libmongoc version of mongodb
lib-openssl            1.1.1.4  OpenSSL 1.1.1d  10 Sep 2019
lib-pcre               10.35    The pcre library
lib-pcre-unicode       13.0.0   PCRE Unicode version support
lib-pdo_sqlite-sqlite  3.27.2   The pdo_sqlite-sqlite library
lib-sqlite3-sqlite     3.27.2   The sqlite3-sqlite library
lib-zip-libzip         1.5.1    The zip-libzip library
lib-zlib               1.2.11   The zlib library
php                    7.4.12   The PHP interpreter
php-64bit              7.4.12   The PHP interpreter, 64bit
php-ipv6               7.4.12   The PHP interpreter, with IPv6 support

Steps to reproduce the issue.

$isNotificationSent = CloudMessagingService::getInstance()->SendTopicNotification(
            "test-topic",
            "Server Notification FR",
            "This is a test-topic notification from server",
            "http://via.placeholder.com/640x360",
            "2023-04-20T18:27:35Z",
            "1682029655",
            "test-topic-analytics",
        );
public function SendTopicNotification(string $topic = null, string $title = null, string $body = null, string $imageUrl = null, string $epochTime = null, int $epochTimestamp = 0, string $analyticsLabel = null): ?bool
{
    $message = CloudMessage::withTarget('topic', $topic);

    $notification = Notification::fromArray([
        'title' => $title,
        'body' => $body,
        'image' => $imageUrl,
    ]);
    $message = $message->withNotification($notification);

    $configA = AndroidConfig::fromArray([
        "ttl" => "2419200s", // 4 weeks limit of ttl
        "priority" => "normal",
        "notification" => [
            "title" => $title,
            "body" => $body,
            "image" => $imageUrl,
            "event_time" => $epochTime,
        ],
    ]);
    $message = $message->withAndroidConfig($configA);

    $configB = ApnsConfig::fromArray([
        "headers" => [
            "apns-push-type" => "alert",
            "apns-priority" => "10",
            "apns-expiration " => $epochTime,
            "apns-topic" => "com.kanoapps.bz.dev",
        ],
        "payload" => [
            "aps" => [
                "timestamp" => $epochTimestamp,
                "event" => "update",
                "alert" => [
                    "title" => $title,
                    "body" => $body,
                ],
            ],
        ],
    ]);
    $message = $message->withApnsConfig($configB);

    $fcmOptions = [
        "analytics_label" => $analyticsLabel
    ];
    $message = $message->withFcmOptions($fcmOptions);

    try
    {
        $report = $this->messaging->send($message);

        Logger::getLogger()->info("Attempting to send this notification {$topic}: ", ['message' => $message, 'report' => $report]);

        return true;
    }
    catch (InvalidMessage $e)
    {
        Logger::getLogger()->error($e->getMessage() . ' - Trace: ' . $e->getTraceAsString());
    }

    return false;
}

Error message/Stack trace

There are no error messages generated when trying this

Additional information

No response

jeromegamez commented 1 year ago

I can't see anything wrong with the composition of the message, but you're using 5.26.0 of the SDK, perhaps an update to 5.26.4 (the last version in the 5.x branch) can help.

I recommend upgrading to 7.x, or at least 6.x if you don't have access to PHP 8.1 yet. If there's a bug in the messaging component, there's a chance it might be fixed in the newer releases.

If you have an FCM message payload from somewhere else that you know works, you can json_encode() the the message and compare them.

You can also use a payload you know works in a RawMessageFromArray object and see if that works.

Finally, there's a chance that there's either a server-side problem in the communication between FCM and Apple, or a hiccup in one of the servers which prevent the message from being delivered - in that case, the problem might resolve itself with time.

Aside from that I can't provide free support for older releases than the current one, I hope you can understand 🙏🏻.

lesliedizon-kano commented 1 year ago

Hi Jerome, thank you for your response.

I would like to ask, is it ideal to have both the Android and iOS in one function or should I separate them?

jeromegamez commented 1 year ago

The optimal way should be to include them both in the same message - that saves you one request, and it's officially supported by FCM.

But if the problem doesn't occur if you separate the messages, I(!) would be pragmatic and do it this way if it works 😅. Just keep in mind that you must then include only the specific configuration, not the Notification at the root level of the message.

You should definitely test it this way, let me know how it goes!

lesliedizon-kano commented 1 year ago

I have updated to the 6.9.5 version of kreait/firebase-php and I am getting this error Expected type 'Psr\Cache\CacheItemPoolInterface'. Found 'Psr\SimpleCache\CacheInterface' when trying to use the withVerifierCache method.

<?php

namespace Kano\Fubar\Service;

use Kano\Fubar\FubarApp;
use Kano\Fubar\Singleton;
use Kreait\Firebase;
use Kreait\Firebase\Contract\Database;
use Kreait\Firebase\Factory;
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Simple\FilesystemCache;
use Kano\Fubar\Log\Logger;

/**
 * Manages a few utility components for dealing with Firebase through the kreait/firebase-php library.
 *
 * Primary use of this class is to fetch the $firebase object via FirebaseService::getInstance()->getFirebase();
 */
class FirebaseService extends Singleton
{
    private $firebaseSdk;
    private $keyCache;
    private $serviceAccount;

    public function getFirebaseProjectId(): string
    {
        return getenv('FIREBASE_PRODUCT_ID');
    }

    public function getFirebase(): Database
    {
        if ($this->firebaseSdk == null)
        {
            $this->firebaseSdk = (new Factory())
                ->withServiceAccount($this->getServiceAccount())
                ->withVerifierCache($this->getKeyCache())
                ->createDatabase();
        }

        return $this->firebaseSdk;
    }

    /**
     * Currently returns a FileSystemCache object from the Symfony libraries.
     *
     * @return CacheInterface Cache object for storing public keys
     */
    public function getKeyCache(): CacheInterface
    {
        // @see https://firebase.google.com/docs/auth/admin/verify-id-tokens
        // @see https://symfony.com/doc/current/components/cache/adapters/filesystem_adapter.html
        if ($this->keyCache == null)
        {
            $this->keyCache = new FilesystemCache(getenv('KANO_GAME') . '-firebase');
        }

        return $this->keyCache;
    }

    public function setKeyCache(CacheInterface $cache)
    {
        $this->keyCache = $cache;
    }

    /**
     * @return ServiceAccount object required to deal with Firebase
     */
    public function getServiceAccount(): string
    {
        if ($this->serviceAccount == null)
        {
            // @see https://firebase.google.com/docs/admin/setup for more on the json file required here
            $this->serviceAccount = FubarApp::ROOT_DIR . '/config/' . $this->getFirebaseProjectId() . '-google-service-account.json';
        }

        return $this->serviceAccount;
    }
}
jeromegamez commented 1 year ago

The SDK needs a PSR-6 Cache implementation, but you provided a PSR-16 Cache implementation. This was a change in 6.0 (https://github.com/kreait/firebase-php/blob/6.x/CHANGELOG.md at the bottom). You can wrap the PSR-16 cache in a PSR-6 adapter, for example with the symfony/cache component (https://symfony.com/doc/current/components/cache/psr6_psr16_adapters.html)