diff --git a/README.md b/README.md index 688a5bf..40f6802 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ composer require khrizt/push-notiphications ## Usage example -GCM +FCM ```php use Khrizt\PushNotiphications\Client\Fcm; diff --git a/src/Khrizt/PushNotiphications/Client/Fcm.php b/src/Khrizt/PushNotiphications/Client/Fcm.php index 33dbd7c..e445905 100644 --- a/src/Khrizt/PushNotiphications/Client/Fcm.php +++ b/src/Khrizt/PushNotiphications/Client/Fcm.php @@ -14,7 +14,7 @@ class Fcm extends AbstractClient /** * @const string Firebase Cloud Message URL */ - const GCM_URL = 'https://fcm.googleapis.com/fcm/send'; + const FCM_URL = 'https://fcm.googleapis.com/fcm/send'; /** * FCM Api key. @@ -65,7 +65,7 @@ public function send(MessageInterface $message, Collection $deviceCollection) : 'Content-Type: application/json', ]); curl_setopt($this->handler, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($this->handler, CURLOPT_URL, self::GCM_URL); + curl_setopt($this->handler, CURLOPT_URL, self::FCM_URL); if ($this->debug) { curl_setopt($this->handler, CURLOPT_VERBOSE, true); } diff --git a/src/Khrizt/PushNotiphications/Console/Commands/PushCommand.php b/src/Khrizt/PushNotiphications/Console/Commands/PushCommand.php index 36203be..19eab5a 100644 --- a/src/Khrizt/PushNotiphications/Console/Commands/PushCommand.php +++ b/src/Khrizt/PushNotiphications/Console/Commands/PushCommand.php @@ -37,7 +37,7 @@ protected function configure() ->addArgument( 'adapter', InputArgument::REQUIRED, - 'Adapter (apns, gcm, specific class name, ...)' + 'Adapter (apns, fcm, specific class name, ...)' ) ->addArgument( 'token', @@ -49,6 +49,13 @@ protected function configure() InputArgument::REQUIRED, 'Message' ) + ->addOption( + 'title', + null, + InputOption::VALUE_OPTIONAL, + 'Title', + null + ) ->addOption( 'certificate', null, @@ -68,18 +75,11 @@ protected function configure() 'Topic (for APNS adapter)', null ) - ->addOption( - 'title', - null, - InputOption::VALUE_OPTIONAL, - 'Title (for GCM adapter)', - '' - ) ->addOption( 'apiKey', null, InputOption::VALUE_OPTIONAL, - 'API key (for GCM adapter)' + 'API key (for FCM adapter)' ) ->addOption( 'env', @@ -105,6 +105,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $adapter = $input->getArgument('adapter'); $token = $input->getArgument('token'); $message = $input->getArgument('message'); + $title = $input->getOption('title'); if ($adapter === 'apns') { $env = $input->getOption('env'); @@ -114,20 +115,29 @@ protected function execute(InputInterface $input, OutputInterface $output) } $certificatePassphrase = $input->getOption('certificatePassphrase'); $topic = $input->getOption('topic'); - $this->sendApnsNotification($token, $message, $certificate, $env, $certificatePassphrase, $topic); - } elseif ($adapter === 'gcm') { + $this->sendApnsNotification($token, $title, $message, $certificate, $env, $certificatePassphrase, $topic); + } elseif ($adapter === 'fcm') { $apiKey = $input->getOption('apiKey'); - $title = $input->getOption('title'); $this->sendFcmNotification($token, $title, $message, $apiKey); } else { - throw new \InvalidArgumentException('Adapter '.$adapter.' is not a valid value. Values are: apns and gcm'); + throw new \InvalidArgumentException('Adapter '.$adapter.' is not a valid value. Values are: apns and fcm'); } } - protected function sendApnsNotification(string $token, string $message, string $certificate, string $env, string $certificatePassphrase = null, string $topic = null) - { + protected function sendApnsNotification( + string $token, + ?string $title, + string $message, + string $certificate, + string $env, + string $certificatePassphrase = null, + string $topic = null + ): void { $apnsMessage = new ApnsMessage(); $apnsMessage->setBody($message); + if (!is_null($title)) { + $apnsMessage->setTitle($title); + } if (!is_null($topic)) { $apnsMessage->setTopic($topic); } @@ -140,30 +150,41 @@ protected function sendApnsNotification(string $token, string $message, string $ $responseCollection = $client->send($apnsMessage, $collection); foreach ($responseCollection as $response) { - $this->output->writeLn('Status for notification sent to '.$response->getToken().' was '.($response->isOk() ? 'OK' : '. Error message: '.$response->getErrorMessage())); + $this->output->writeLn( + 'Status for notification sent to '.$response->getToken().' was '. + ($response->isOk() ? 'OK' : '. Error message: '.$response->getErrorMessage()) + ); } } - public function sendFcmNotification(string $token, string $title, string $message, string $apiKey) - { - $gcmMessage = new FcmMessage(); - $gcmMessage->setBody($message) + public function sendFcmNotification( + string $token, + ?string $title, + string $message, + string $apiKey + ): void { + $fcmMessage = new FcmMessage(); + $fcmMessage->setBody($message) ->setData([ - 'custom' => [ - 'notification_title' => $title, - ], + 'title' => $title, 'message' => $message, ]); + if (!is_null($title)) { + $fcmMessage->setTitle($title); + } $device = new Device($token); $collection = new Collection(); $collection->append($device); $client = new Fcm($apiKey); - $responseCollection = $client->send($gcmMessage, $collection); + $responseCollection = $client->send($fcmMessage, $collection); foreach ($responseCollection as $response) { - $this->output->writeLn('Status for notification sent to '.$response->getToken().' was '.($response->isOk() ? 'OK' : ' Error. Error message: '.$response->getErrorMessage())); + $this->output->writeLn( + 'Status for notification sent to '.$response->getToken().' was '. + ($response->isOk() ? 'OK' : ' Error. Error message: '.$response->getErrorMessage()) + ); } } } diff --git a/src/Khrizt/PushNotiphications/Exception/Gcm/AuthenticationException.php b/src/Khrizt/PushNotiphications/Exception/Gcm/AuthenticationException.php index 3c04a14..49125ad 100644 --- a/src/Khrizt/PushNotiphications/Exception/Gcm/AuthenticationException.php +++ b/src/Khrizt/PushNotiphications/Exception/Gcm/AuthenticationException.php @@ -12,7 +12,7 @@ public function __construct() Authorization header missing or with invalid syntax in HTTP request. Invalid project number sent as key. - Key valid but with GCM service disabled. + Key valid but with FCM service disabled. Request originated from a server not whitelisted in the Server Key IPs. Check that the token you\'re sending inside the Authentication header is the correct API key associated with your project. See Checking the validity of an API Key for details.'); diff --git a/src/Khrizt/PushNotiphications/Exception/Gcm/ServerNotAvailableException.php b/src/Khrizt/PushNotiphications/Exception/Gcm/ServerNotAvailableException.php index 897acc2..667114d 100644 --- a/src/Khrizt/PushNotiphications/Exception/Gcm/ServerNotAvailableException.php +++ b/src/Khrizt/PushNotiphications/Exception/Gcm/ServerNotAvailableException.php @@ -12,7 +12,7 @@ public function __construct() Timeout. The server couldn\'t process the request in time. Retry the same request, but you must: - Honor the Retry-After header if it is included in the response from the GCM Connection Server. + Honor the Retry-After header if it is included in the response from the FCM Connection Server. Implement exponential back-off in your retry mechanism. (e.g. if you waited one second before the first retry, wait at least two second before the next one, then 4 seconds and so on). If you\'re sending multiple messages, delay each one independently by an additional random amount to avoid issuing a new request for all messages at the same time. Senders that cause problems risk being blacklisted.'); diff --git a/src/Khrizt/PushNotiphications/Model/Fcm/Message.php b/src/Khrizt/PushNotiphications/Model/Fcm/Message.php index 35dd6bd..cb3ea9c 100644 --- a/src/Khrizt/PushNotiphications/Model/Fcm/Message.php +++ b/src/Khrizt/PushNotiphications/Model/Fcm/Message.php @@ -52,7 +52,7 @@ class Message implements MessageInterface protected $priority; /** - * Field mapping for getting GCM field names. + * Field mapping for getting FCM field names. * * @var array */ diff --git a/src/Khrizt/PushNotiphications/Model/Fcm/Response.php b/src/Khrizt/PushNotiphications/Model/Fcm/Response.php index 5afabb3..b2f017f 100644 --- a/src/Khrizt/PushNotiphications/Model/Fcm/Response.php +++ b/src/Khrizt/PushNotiphications/Model/Fcm/Response.php @@ -7,25 +7,25 @@ class Response implements ResponseInterface { /** - * List of error messages from GCM api. + * List of error messages from FCM api. * * @var array */ protected $errorTexts = [ 'MissingRegistration' => 'Missing Registration Token. Check that the request contains a registration token (in the registration_id in a plain text message, or in the to or registration_ids field in JSON).', - 'InvalidRegistration' => 'Invalid Registration Token. Check the format of the registration token you pass to the server. Make sure it matches the registration token the client app receives from registering with GCM. Do not truncate or add additional characters.', + 'InvalidRegistration' => 'Invalid Registration Token. Check the format of the registration token you pass to the server. Make sure it matches the registration token the client app receives from registering with FCM. Do not truncate or add additional characters.', 'NotRegistered' => 'Unregistered Device. An existing registration token may cease to be valid in a number of scenarios, including: - If the client app unregisters with GCM. + If the client app unregisters with FCM. If the client app is automatically unregistered, which can happen if the user uninstalls the application. For example, on iOS, if the APNS Feedback Service reported the APNS token as invalid. If the registration token expires (for example, Google might decide to refresh registration tokens, or the APNS token has expired for iOS devices). If the client app is updated but the new version is not configured to receive messages. For all these cases, remove this registration token from the app server and stop using it to send messages.', 'InvalidPackageName' => 'Invalid Package Name. Make sure the message was addressed to a registration token whose package name matches the value passed in the request.', - 'MismatchSenderId' => 'Mismatched Sender. A registration token is tied to a certain group of senders. When a client app registers for GCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app. If you switch to a different sender, the existing registration tokens won\'t work.', - 'MessageTooBig' => 'Message too big. Check that the total size of the payload data included in a message does not exceed GCM limits: 4096 bytes for most messages, or 2048 bytes in the case of messages to topics or notification messages on iOS. This includes both the keys and the values.', - 'InvalidDataKey' => 'Invalid data key. Check that the payload data does not contain a key (such as from, or gcm, or any value prefixed by google) that is used internally by GCM. Note that some words (such as collapse_key) are also used by GCM but are allowed in the payload, in which case the payload value will be overridden by the GCM value.', + 'MismatchSenderId' => 'Mismatched Sender. A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app. If you switch to a different sender, the existing registration tokens won\'t work.', + 'MessageTooBig' => 'Message too big. Check that the total size of the payload data included in a message does not exceed FCM limits: 4096 bytes for most messages, or 2048 bytes in the case of messages to topics or notification messages on iOS. This includes both the keys and the values.', + 'InvalidDataKey' => 'Invalid data key. Check that the payload data does not contain a key (such as from, or gcm, or any value prefixed by google) that is used internally by FCM. Note that some words (such as collapse_key) are also used by FCM but are allowed in the payload, in which case the payload value will be overridden by the FCM value.', 'InvalidTtl' => 'Invalid Time to Live. Check that the value used in time_to_live is an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks).', 'DeviceMessageRateExceeded' => 'Device Message Rate Exceeded. The rate of messages to a particular device is too high. Reduce the number of messages sent to this device and do not immediately retry sending to this device.', 'TopicsMessageRateExceeded' => 'Topic Message Rate Exceeded. The rate of messages to subscribers to a particular topic is too high. Reduce the number of messages sent for this topic, and do not immediately retry sending.',