Google FCM
Google Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages at no cost.
Using FCM, you can notify a client app that new email or other data is available to sync. You can send notification messages to drive user re-engagement and retention. For use cases such as instant messaging, a message can transfer a payload of up to 4KB to a client app.
The Alpakka Google Firebase Cloud Messaging connector provides a way to send notifications with Firebase Cloud Messaging.
Project Info: Alpakka Google Firebase Cloud Messaging (FCM) | |
---|---|
Artifact | com.lightbend.akka
akka-stream-alpakka-google-fcm
9.0.0
|
JDK versions | Eclipse Temurin JDK 11 Eclipse Temurin JDK 17 |
Scala versions | 2.13.12 |
JPMS module name | akka.stream.alpakka.google.firebase.fcm |
License | |
Readiness level |
Since 0.18, 2018-03-28
|
Home page | https://doc.akka.io/libraries/alpakka/current |
API documentation | |
Forums | |
Release notes | GitHub releases |
Issues | Github issues |
Sources | https://github.com/akka/alpakka |
Artifacts
The Akka dependencies are available from Akka’s library repository. To access them there, you need to configure the URL for this repository.
- sbt
resolvers += "Akka library repository".at("https://repo.akka.io/maven")
- Maven
<project> ... <repositories> <repository> <id>akka-repository</id> <name>Akka library repository</name> <url>https://repo.akka.io/maven</url> </repository> </repositories> </project>
- Gradle
repositories { mavenCentral() maven { url "https://repo.akka.io/maven" } }
Additionally, add the dependencies as below.
- sbt
val AkkaVersion = "2.10.0" val AkkaHttpVersion = "10.7.0" libraryDependencies ++= Seq( "com.lightbend.akka" %% "akka-stream-alpakka-google-fcm" % "9.0.0", "com.typesafe.akka" %% "akka-stream" % AkkaVersion, "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion )
- Maven
<properties> <akka.version>2.10.0</akka.version> <akka.http.version>10.7.0</akka.http.version> <scala.binary.version>2.13</scala.binary.version> </properties> <dependencies> <dependency> <groupId>com.lightbend.akka</groupId> <artifactId>akka-stream-alpakka-google-fcm_${scala.binary.version}</artifactId> <version>9.0.0</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-stream_${scala.binary.version}</artifactId> <version>${akka.version}</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-http_${scala.binary.version}</artifactId> <version>${akka.http.version}</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-http-spray-json_${scala.binary.version}</artifactId> <version>${akka.http.version}</version> </dependency> </dependencies>
- Gradle
def versions = [ AkkaVersion: "2.10.0", AkkaHttpVersion: "10.7.0", ScalaBinary: "2.13" ] dependencies { implementation "com.lightbend.akka:akka-stream-alpakka-google-fcm_${versions.ScalaBinary}:9.0.0" implementation "com.typesafe.akka:akka-stream_${versions.ScalaBinary}:${versions.AkkaVersion}" implementation "com.typesafe.akka:akka-http_${versions.ScalaBinary}:${versions.AkkaHttpVersion}" implementation "com.typesafe.akka:akka-http-spray-json_${versions.ScalaBinary}:${versions.AkkaHttpVersion}" }
The table below shows direct dependencies of this module and the second tab shows all libraries it depends on transitively.
- Direct dependencies
Organization Artifact Version com.lightbend.akka akka-stream-alpakka-google-common_2.13 9.0.0 com.typesafe.akka akka-http-spray-json_2.13 10.7.0 com.typesafe.akka akka-http_2.13 10.7.0 com.typesafe.akka akka-stream_2.13 2.10.0 org.scala-lang scala-library 2.13.12 - Dependency tree
com.lightbend.akka akka-stream-alpakka-google-common_2.13 9.0.0 com.github.jwt-scala jwt-json-common_2.13 9.4.6 Apache-2.0 com.github.jwt-scala jwt-core_2.13 9.4.6 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.google.auth google-auth-library-credentials 1.24.1 com.typesafe.akka akka-http-spray-json_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http-core_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-parsing_2.13 10.7.0 BUSL-1.1 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-pki_2.13 2.10.0 BUSL-1.1 com.hierynomus asn-one 0.6.0 The Apache License, Version 2.0 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.slf4j slf4j-api 2.0.16 org.scala-lang scala-library 2.13.12 Apache-2.0 io.spray spray-json_2.13 1.3.6 Apache 2 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-http_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http-core_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-parsing_2.13 10.7.0 BUSL-1.1 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-pki_2.13 2.10.0 BUSL-1.1 com.hierynomus asn-one 0.6.0 The Apache License, Version 2.0 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.slf4j slf4j-api 2.0.16 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-stream_2.13 2.10.0 BUSL-1.1 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-protobuf-v3_2.13 2.10.0 BUSL-1.1 org.reactivestreams reactive-streams 1.0.4 MIT-0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-http-spray-json_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http-core_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-parsing_2.13 10.7.0 BUSL-1.1 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-pki_2.13 2.10.0 BUSL-1.1 com.hierynomus asn-one 0.6.0 The Apache License, Version 2.0 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.slf4j slf4j-api 2.0.16 org.scala-lang scala-library 2.13.12 Apache-2.0 io.spray spray-json_2.13 1.3.6 Apache 2 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-http_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-http-core_2.13 10.7.0 BUSL-1.1 com.typesafe.akka akka-parsing_2.13 10.7.0 BUSL-1.1 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-pki_2.13 2.10.0 BUSL-1.1 com.hierynomus asn-one 0.6.0 The Apache License, Version 2.0 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.slf4j slf4j-api 2.0.16 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-stream_2.13 2.10.0 BUSL-1.1 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-protobuf-v3_2.13 2.10.0 BUSL-1.1 org.reactivestreams reactive-streams 1.0.4 MIT-0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0
Settings
The FCM connector shares its basic configuration with all the Google connectors in Alpakka. Additional FCM-specific configuration settings can be found in its own reference.conf. You can send test notifications (so called validate only). And you can set the number of maximum concurrent connections. There is a limitation in the docs; from one IP you can have maximum 1k pending connections, and you may need to configure akka.http.host-connection-pool.max-open-requests
in your application.conf.
Sending notifications
To send a notification message create your notification object, and send it!
- Scala
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings import akka.stream.alpakka.google.firebase.fcm.v1.models._ import akka.stream.alpakka.google.firebase.fcm.v1.scaladsl.GoogleFcm val result1: Future[immutable.Seq[FcmResponse]] = Source .single(notification) .via(GoogleFcm.send(fcmConfig)) .map { case res @ FcmSuccessResponse(name) => println(s"Successful $name") res case res @ FcmErrorResponse(errorMessage) => println(s"Send error $errorMessage") res } .runWith(Sink.seq)
- Java
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings; import akka.stream.alpakka.google.firebase.fcm.v1.models.*; import akka.stream.alpakka.google.firebase.fcm.v1.javadsl.GoogleFcm; CompletionStage<List<FcmResponse>> result1 = Source.single(notification) .via(GoogleFcm.send(fcmConfig)) .map( res -> { if (res.isSuccess()) { FcmSuccessResponse response = (FcmSuccessResponse) res; System.out.println("Successful " + response.getName()); } else { FcmErrorResponse response = (FcmErrorResponse) res; System.out.println("Send error " + response.getRawError()); } return res; }) .runWith(Sink.seq(), system);
With this type of send you can get responses from the server. These responses can be FcmSuccessResponse
or FcmErrorResponse
. You can choose what you want to do with this information, but keep in mind if you try to resend the failed messages you will need to use exponential backoff! (see Akka docs RestartFlow.onFailuresWithBackoff
)
If you don’t care if the notification was sent successfully, you may use fireAndForget
.
- Scala
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings import akka.stream.alpakka.google.firebase.fcm.v1.models._ import akka.stream.alpakka.google.firebase.fcm.v1.scaladsl.GoogleFcm val fcmConfig = FcmSettings() val notification = FcmNotification("Test", "This is a test notification!", Token("token")) Source .single(notification) .runWith(GoogleFcm.fireAndForget(fcmConfig))
- Java
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings; import akka.stream.alpakka.google.firebase.fcm.v1.models.*; import akka.stream.alpakka.google.firebase.fcm.v1.javadsl.GoogleFcm; FcmSettings fcmConfig = FcmSettings.create(); FcmNotification notification = FcmNotification.basic("Test", "This is a test notification!", new Token("token")); Source.single(notification).runWith(GoogleFcm.fireAndForget(fcmConfig), system);
With fire and forget you will just send messages and ignore all the errors.
To help the integration and error handling or logging, there is a variation of the flow where you can send data beside your notification.
- Scala
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings import akka.stream.alpakka.google.firebase.fcm.v1.models._ import akka.stream.alpakka.google.firebase.fcm.v1.scaladsl.GoogleFcm val result2: Future[immutable.Seq[(FcmResponse, String)]] = Source .single((notification, "superData")) .via(GoogleFcm.sendWithPassThrough(fcmConfig)) .runWith(Sink.seq)
- Java
-
source
import akka.stream.alpakka.google.firebase.fcm.FcmSettings; import akka.stream.alpakka.google.firebase.fcm.v1.models.*; import akka.stream.alpakka.google.firebase.fcm.v1.javadsl.GoogleFcm; CompletionStage<List<Pair<FcmResponse, String>>> result2 = Source.single(Pair.create(notification, "superData")) .via(GoogleFcm.sendWithPassThrough(fcmConfig)) .runWith(Sink.seq(), system);
Here I send a simple string, but you could use any type.
Scala only
You can build any notification described in the original documentation. It can be done by hand, or using some builder method. If you build your notification from scratch with options (and not with the provided builders), worth to check isSendable before sending.
- Scala
-
source
val buildedNotification = FcmNotification.empty .withTarget(Topic("testers")) .withBasicNotification("title", "body") //.withAndroidConfig(AndroidConfig(...)) //.withApnsConfig(ApnsConfig(...)) .withWebPushConfig( WebPushConfig( headers = Option(Map.empty), data = Option(Map.empty), notification = Option("{\"title\": \"web-title\", \"body\": \"web-body\", \"icon\": \"http://example.com/icon.png\"}") ) ) val sendable = buildedNotification.isSendable
There is a condition builder too.
- Scala
-
source
import Condition.{Topic => CTopic} val condition = Condition(CTopic("TopicA") && (CTopic("TopicB") || (CTopic("TopicC") && !CTopic("TopicD")))) val conditioneddNotification = FcmNotification("Test", "This is a test notification!", condition)