forked from customerio/customerio-android
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: get current FCM token on SDK startup
- Loading branch information
1 parent
149c922
commit dda443d
Showing
9 changed files
with
239 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
messagingpush/src/main/java/io/customer/messagingpush/ModuleMessagingPushFCM.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package io.customer.messagingpush | ||
|
||
import io.customer.messagingpush.di.fcmTokenProvider | ||
import io.customer.sdk.CustomerIO | ||
import io.customer.sdk.CustomerIOInstance | ||
import io.customer.sdk.CustomerIOModule | ||
import io.customer.sdk.di.CustomerIOComponent | ||
|
||
class ModuleMessagingPushFCM internal constructor( | ||
private val overrideCustomerIO: CustomerIOInstance?, | ||
private val overrideDiGraph: CustomerIOComponent? | ||
) : CustomerIOModule { | ||
|
||
constructor() : this(overrideCustomerIO = null, overrideDiGraph = null) | ||
|
||
private val customerIO: CustomerIOInstance | ||
get() = overrideCustomerIO ?: CustomerIO.instance() | ||
private val diGraph: CustomerIOComponent | ||
get() = overrideDiGraph ?: CustomerIO.instance().diGraph | ||
|
||
private val fcmTokenProvider by lazy { diGraph.fcmTokenProvider } | ||
|
||
override val moduleName: String | ||
get() = "MessagingPushFCM" | ||
|
||
override fun initialize() { | ||
getCurrentFcmToken() | ||
} | ||
|
||
/** | ||
* FCM only provides a push device token once through the [CustomerIOFirebaseMessagingService] when there is a new token assigned to the device. After that, it's up to you to get the device token. | ||
* | ||
* This can cause edge cases where a customer might never get a device token assigned to a profile. https://github.com/customerio/customerio-android/issues/61 | ||
* | ||
* To fix this, it's recommended that each time your app starts up, you get the current push token and register it to the SDK. We do it for you automatically here as long as you initialize the MessagingPush module with the SDK. | ||
*/ | ||
private fun getCurrentFcmToken() { | ||
fcmTokenProvider.getCurrentToken { token -> | ||
token?.let { token -> customerIO.registerDeviceToken(token) } | ||
} | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
messagingpush/src/main/java/io/customer/messagingpush/di/DiGraphMessagingPush.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package io.customer.messagingpush.di | ||
|
||
import io.customer.messagingpush.provider.FCMTokenProvider | ||
import io.customer.messagingpush.provider.FCMTokenProviderImpl | ||
import io.customer.sdk.di.CustomerIOComponent | ||
|
||
/* | ||
This file contains a series of extensions to the common module's Dependency injection (DI) graph. All extensions in this file simply add internal classes for this module into the DI graph. | ||
The use of extensions was chosen over creating a separate graph class for each module. This simplifies the SDK code as well as automated tests code dramatically. | ||
*/ | ||
|
||
internal val CustomerIOComponent.fcmTokenProvider: FCMTokenProvider | ||
get() = override() ?: FCMTokenProviderImpl(logger) |
34 changes: 34 additions & 0 deletions
34
messagingpush/src/main/java/io/customer/messagingpush/provider/FCMTokenProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package io.customer.messagingpush.provider | ||
|
||
import com.google.firebase.messaging.FirebaseMessaging | ||
import io.customer.sdk.util.Logger | ||
|
||
/** | ||
* Wrapper around FCM SDK to make the code base more testable. | ||
*/ | ||
internal interface FCMTokenProvider { | ||
fun getCurrentToken(onComplete: (String?) -> Unit) | ||
} | ||
|
||
/** | ||
* This class should be as small as possible as possible because it can't be tested with automated tests. QA testing, only. | ||
*/ | ||
class FCMTokenProviderImpl(private val logger: Logger) : FCMTokenProvider { | ||
|
||
override fun getCurrentToken(onComplete: (String?) -> Unit) { | ||
logger.debug("getting current FCM device token...") | ||
|
||
FirebaseMessaging.getInstance().token.addOnCompleteListener { task -> | ||
if (task.isSuccessful) { | ||
val existingDeviceToken = task.result | ||
logger.debug("got current FCM token: $existingDeviceToken") | ||
|
||
onComplete(existingDeviceToken) | ||
} else { | ||
logger.debug("got current FCM token: null") | ||
|
||
onComplete(null) | ||
} | ||
} | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
messagingpush/src/sharedTest/java/io/customer/messagingpush/ModuleMessagingPushFCMTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package io.customer.messagingpush | ||
|
||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import io.customer.common_test.BaseTest | ||
import io.customer.messagingpush.provider.FCMTokenProvider | ||
import io.customer.sdk.CustomerIOInstance | ||
import io.customer.sdk.utils.random | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.mockito.kotlin.any | ||
import org.mockito.kotlin.anyOrNull | ||
import org.mockito.kotlin.mock | ||
import org.mockito.kotlin.never | ||
import org.mockito.kotlin.verify | ||
import org.mockito.kotlin.whenever | ||
|
||
@RunWith(AndroidJUnit4::class) | ||
internal class ModuleMessagingPushFCMTest : BaseTest() { | ||
|
||
private val customerIOMock: CustomerIOInstance = mock() | ||
private val fcmTokenProviderMock: FCMTokenProvider = mock() | ||
private lateinit var module: ModuleMessagingPushFCM | ||
|
||
@Before | ||
override fun setup() { | ||
super.setup() | ||
|
||
di.overrideDependency(FCMTokenProvider::class.java, fcmTokenProviderMock) | ||
|
||
module = ModuleMessagingPushFCM(overrideCustomerIO = customerIOMock, overrideDiGraph = di) | ||
} | ||
|
||
@Test | ||
fun initialize_givenNoFCMTokenAvailable_expectDoNotRegisterToken() { | ||
whenever(fcmTokenProviderMock.getCurrentToken(any())).thenAnswer { | ||
val callback = it.getArgument<(String?) -> Unit>(0) | ||
callback(null) | ||
} | ||
|
||
module.initialize() | ||
|
||
verify(customerIOMock, never()).registerDeviceToken(anyOrNull()) | ||
} | ||
|
||
@Test | ||
fun initialize_givenFCMTokenAvailable_expectRegisterToken() { | ||
val givenToken = String.random | ||
|
||
whenever(fcmTokenProviderMock.getCurrentToken(any())).thenAnswer { | ||
val callback = it.getArgument<(String?) -> Unit>(0) | ||
callback(givenToken) | ||
} | ||
|
||
module.initialize() | ||
|
||
verify(customerIOMock).registerDeviceToken(givenToken) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package io.customer.sdk | ||
|
||
/** | ||
* A module is optional Customer.io SDK that you can install in your app. | ||
* | ||
* This interface allows the base SDK to initialize all of the SDKs installed in an app and begin to communicate with them. | ||
*/ | ||
interface CustomerIOModule { | ||
val moduleName: String | ||
fun initialize() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters