@aws-amplify/rtn-push-notification 1.0.1-push-notification-dryrun.7810

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/AmplifyRTNPushNotification.podspec +36 -0
  2. package/LICENSE +201 -0
  3. package/android/build.gradle +76 -0
  4. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  6. package/android/gradle.properties +23 -0
  7. package/android/gradlew +234 -0
  8. package/android/gradlew.bat +89 -0
  9. package/android/src/main/AndroidManifest.xml +22 -0
  10. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationAWSPinpointUtils.kt +159 -0
  11. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationEventManager.kt +49 -0
  12. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationFirebaseMessagingService.kt +74 -0
  13. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationHeadlessTaskService.kt +28 -0
  14. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationLaunchActivity.kt +27 -0
  15. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationModule.kt +188 -0
  16. package/android/src/main/kotlin/com/amazonaws/amplify/rtnpushnotification/PushNotificationPackage.kt +22 -0
  17. package/android/src/test/kotlin/PushNotificationAWSPinpointUtilsTest.kt +326 -0
  18. package/android/src/test/kotlin/PushNotificationEventManagerTest.kt +45 -0
  19. package/android/src/test/kotlin/PushNotificationFirebaseMessagingServiceTest.kt +92 -0
  20. package/android/src/test/kotlin/PushNotificationLaunchActivityTest.kt +45 -0
  21. package/android/src/test/kotlin/PushNotificationModuleTest.kt +201 -0
  22. package/ios/AmplifyPushNotification.h +17 -0
  23. package/ios/AmplifyPushNotification.m +21 -0
  24. package/ios/AmplifyPushNotificationAppDelegateHelper.swift +31 -0
  25. package/ios/AmplifyRTNEventManager.swift +73 -0
  26. package/ios/AmplifyRTNPushNotification-Bridging-Header.h +7 -0
  27. package/ios/AmplifyRTNPushNotification.m +26 -0
  28. package/ios/AmplifyRTNPushNotification.swift +121 -0
  29. package/ios/AmplifyRTNPushNotification.xcworkspace/contents.xcworkspacedata +28 -0
  30. package/ios/AmplifyRTNPushNotification.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  31. package/ios/AmplifyRTNPushNotificationManager.swift +258 -0
  32. package/lib/.tsbuildinfo +3 -0
  33. package/lib/index.d.ts +3 -0
  34. package/lib/index.js +7 -0
  35. package/lib/index.js.map +1 -0
  36. package/lib/types.d.ts +18 -0
  37. package/lib/types.js +5 -0
  38. package/lib/types.js.map +1 -0
  39. package/lib-esm/.tsbuildinfo +3 -0
  40. package/lib-esm/index.d.ts +3 -0
  41. package/lib-esm/index.js +5 -0
  42. package/lib-esm/index.js.map +1 -0
  43. package/lib-esm/types.d.ts +18 -0
  44. package/lib-esm/types.js +3 -0
  45. package/lib-esm/types.js.map +1 -0
  46. package/package.json +48 -0
  47. package/src/index.ts +10 -0
  48. package/src/types.ts +23 -0
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ package="com.amazonaws.amplify.rtnpushnotification">
4
+
5
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
6
+ <application>
7
+ <activity
8
+ android:name=".PushNotificationLaunchActivity"
9
+ android:launchMode="singleInstance"
10
+ android:exported="false" />
11
+
12
+ <service android:name=".PushNotificationHeadlessTaskService" />
13
+
14
+ <service
15
+ android:name=".PushNotificationFirebaseMessagingService"
16
+ android:exported="false">
17
+ <intent-filter>
18
+ <action android:name="com.google.firebase.MESSAGING_EVENT" />
19
+ </intent-filter>
20
+ </service>
21
+ </application>
22
+ </manifest>
@@ -0,0 +1,159 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import android.content.Context
7
+ import android.content.Intent
8
+ import android.net.Uri
9
+ import android.os.Bundle
10
+ import android.util.Log
11
+ import com.amplifyframework.annotations.InternalAmplifyApi
12
+ import com.amplifyframework.notifications.pushnotifications.NotificationContentProvider
13
+ import com.amplifyframework.notifications.pushnotifications.NotificationPayload
14
+ import com.amplifyframework.pushnotifications.pinpoint.PinpointNotificationPayload
15
+ import com.amplifyframework.pushnotifications.pinpoint.PushNotificationsConstants
16
+ import com.amplifyframework.pushnotifications.pinpoint.PushNotificationsUtils
17
+ import com.amplifyframework.pushnotifications.pinpoint.permissions.PermissionRequestResult
18
+ import com.amplifyframework.pushnotifications.pinpoint.permissions.PushNotificationPermission
19
+ import com.facebook.react.bridge.Arguments
20
+ import com.facebook.react.bridge.WritableMap
21
+ import com.google.firebase.messaging.RemoteMessage
22
+ import kotlinx.serialization.decodeFromString
23
+ import kotlinx.serialization.json.Json
24
+ import kotlin.random.Random
25
+
26
+ private const val TAG = "PushNotificationAWSPinpointUtils"
27
+
28
+ class PushNotificationPermission(context: Context) {
29
+ private val permission = PushNotificationPermission(context)
30
+
31
+ val hasRequiredPermission = permission.hasRequiredPermission
32
+
33
+ suspend fun requestPermission(): Boolean {
34
+ return permission.requestPermission() is PermissionRequestResult.Granted
35
+ }
36
+ }
37
+
38
+ @InternalAmplifyApi
39
+ class PushNotificationUtils(context: Context) {
40
+ private val utils = PushNotificationsUtils(context)
41
+
42
+ fun showNotification(
43
+ payload: NotificationPayload
44
+ ) {
45
+ PinpointNotificationPayload.fromNotificationPayload(payload)?.let {
46
+ if (utils.areNotificationsEnabled() && !it.silentPush) {
47
+ utils.showNotification(
48
+ payload.notificationId, it, PushNotificationLaunchActivity::class.java
49
+ )
50
+ }
51
+ }
52
+ }
53
+
54
+ fun isAppInForeground(): Boolean {
55
+ return utils.isAppInForeground()
56
+ }
57
+ }
58
+
59
+ @InternalAmplifyApi
60
+ fun Bundle.getNotificationPayload(): NotificationPayload? {
61
+ val payload = NotificationPayload(NotificationContentProvider.FCM(RemoteMessage(this).data))
62
+ return PinpointNotificationPayload.fromNotificationPayload(payload)
63
+ }
64
+
65
+ @InternalAmplifyApi
66
+ fun NotificationPayload?.getProcessedIntent(
67
+ context: Context,
68
+ ): Intent? {
69
+ // Always launch app
70
+ val notificationIntent: Intent? =
71
+ context.packageManager.getLaunchIntentForPackage(context.packageName)
72
+ this?.let {
73
+ PinpointNotificationPayload.fromNotificationPayload(it)?.action?.let { action ->
74
+ when {
75
+ // Attach action to open url
76
+ action[PushNotificationsConstants.URL] != null -> {
77
+ notificationIntent?.action = Intent.ACTION_VIEW
78
+ notificationIntent?.data = Uri.parse(action[PushNotificationsConstants.URL])
79
+ }
80
+ // Attach action to open deep link
81
+ action[PushNotificationsConstants.DEEPLINK] != null -> {
82
+ notificationIntent?.action = Intent.ACTION_VIEW
83
+ notificationIntent?.data =
84
+ Uri.parse(action[PushNotificationsConstants.DEEPLINK])
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return notificationIntent
90
+ }
91
+
92
+ @InternalAmplifyApi
93
+ fun NotificationPayload.toWritableMap(): WritableMap {
94
+ val payload = PinpointNotificationPayload.fromNotificationPayload(this)
95
+
96
+ // Build actions map
97
+ val action = payload?.action?.let { action ->
98
+ Arguments.createMap().apply {
99
+ action[PushNotificationsConstants.OPENAPP]?.let {
100
+ putString(PushNotificationsConstants.OPENAPP, it)
101
+ }
102
+ action[PushNotificationsConstants.URL]?.let {
103
+ putString(PushNotificationsConstants.URL, it)
104
+ }
105
+ action[PushNotificationsConstants.DEEPLINK]?.let {
106
+ putString(PushNotificationsConstants.DEEPLINK, it)
107
+ }
108
+ }
109
+ }
110
+
111
+ // Build rawData map
112
+ val rawData = Arguments.createMap()
113
+ this.rawData.entries.forEach {
114
+ rawData.putString(it.key, it.value)
115
+ }
116
+
117
+ // Build and return final map
118
+ return Arguments.createMap().apply {
119
+ payload?.title?.let { putString("title", it) }
120
+ payload?.body?.let { putString("body", it) }
121
+ payload?.imageUrl?.let { putString("imageUrl", it) }
122
+ payload?.channelId?.let { putString("channelId", it) }
123
+ action?.let { putMap("action", action) }
124
+ putMap("rawData", rawData)
125
+ }
126
+ }
127
+
128
+ @InternalAmplifyApi
129
+ private val NotificationPayload.notificationId: Int
130
+ get() {
131
+ var sourceId: String?
132
+ var activityId: String?
133
+
134
+ // Assign campaign attributes
135
+ sourceId = this.rawData[PushNotificationsConstants.PINPOINT_CAMPAIGN_CAMPAIGN_ID]
136
+ activityId = this.rawData[PushNotificationsConstants.PINPOINT_CAMPAIGN_CAMPAIGN_ACTIVITY_ID]
137
+
138
+ // If no campaign id, try to assign journey attributes
139
+ if (sourceId.isNullOrEmpty()) {
140
+ val journeyAttributes = this.rawData[PushNotificationsConstants.PINPOINT_PREFIX]?.let {
141
+ try {
142
+ Json.decodeFromString<Map<String, Map<String, String>>>(it)[PushNotificationsConstants.JOURNEY]
143
+ } catch (e: Exception) {
144
+ Log.e(TAG, "Error parsing journey attribute", e)
145
+ null
146
+ }
147
+ }
148
+ journeyAttributes?.let {
149
+ sourceId = it[PushNotificationsConstants.JOURNEY_ID]
150
+ activityId = it[PushNotificationsConstants.JOURNEY_ACTIVITY_ID]
151
+ }
152
+ }
153
+
154
+ // If no activity id (even if campaign was direct send), use a random id, otherwise hash
155
+ // attributes to prevent displaying duplicate notifications from an activity
156
+ return activityId?.let {
157
+ "$sourceId:$activityId".hashCode()
158
+ } ?: Random.nextInt()
159
+ }
@@ -0,0 +1,49 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.WritableMap
8
+ import com.facebook.react.modules.core.DeviceEventManagerModule
9
+
10
+ enum class PushNotificationEventType(val value: String) {
11
+ FOREGROUND_MESSAGE_RECEIVED("ForegroundMessageReceived"),
12
+ LAUNCH_NOTIFICATION_OPENED("LaunchNotificationOpened"),
13
+ NOTIFICATION_OPENED("NotificationOpened"),
14
+ TOKEN_RECEIVED("TokenReceived")
15
+ }
16
+
17
+ class PushNotificationEvent(val type: PushNotificationEventType, val params: WritableMap?)
18
+
19
+ object PushNotificationEventManager {
20
+ private lateinit var reactContext: ReactApplicationContext
21
+ private var isInitialized: Boolean = false
22
+ private val eventQueue: MutableList<PushNotificationEvent> = mutableListOf()
23
+
24
+ fun init(reactContext: ReactApplicationContext) {
25
+ this.reactContext = reactContext
26
+ isInitialized = true
27
+ flushEventQueue()
28
+ }
29
+
30
+ fun sendEvent(type: PushNotificationEventType, params: WritableMap?) {
31
+ if (!isInitialized) {
32
+ eventQueue.add(PushNotificationEvent(type, params))
33
+ } else {
34
+ sendJSEvent(type, params)
35
+ }
36
+ }
37
+
38
+ private fun sendJSEvent(type: PushNotificationEventType, params: WritableMap?) {
39
+ reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
40
+ ?.emit(type.value, params)
41
+ }
42
+
43
+ private fun flushEventQueue() {
44
+ eventQueue.forEach {
45
+ sendJSEvent(it.type, it.params)
46
+ }
47
+ eventQueue.clear()
48
+ }
49
+ }
@@ -0,0 +1,74 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import android.content.Intent
7
+ import android.os.Bundle
8
+ import android.util.Log
9
+ import com.amplifyframework.annotations.InternalAmplifyApi
10
+ import com.amplifyframework.notifications.pushnotifications.NotificationPayload
11
+ import com.facebook.react.HeadlessJsTaskService
12
+ import com.facebook.react.bridge.Arguments
13
+ import com.google.firebase.messaging.FirebaseMessagingService
14
+
15
+ @InternalAmplifyApi
16
+ private val TAG = PushNotificationFirebaseMessagingService::class.java.simpleName
17
+
18
+ @InternalAmplifyApi
19
+ class PushNotificationFirebaseMessagingService : FirebaseMessagingService() {
20
+
21
+ private lateinit var utils: PushNotificationUtils
22
+
23
+ override fun onCreate() {
24
+ super.onCreate()
25
+ utils = PushNotificationUtils(baseContext)
26
+ }
27
+
28
+ override fun onNewToken(token: String) {
29
+ super.onNewToken(token)
30
+ val params = Arguments.createMap()
31
+ params.putString("token", token)
32
+ Log.d(TAG, "Send device token event")
33
+ PushNotificationEventManager.sendEvent(PushNotificationEventType.TOKEN_RECEIVED, params)
34
+ }
35
+
36
+ override fun handleIntent(intent: Intent) {
37
+ val extras = intent.extras ?: Bundle()
38
+ extras.getNotificationPayload()?.let {
39
+ // message contains push notification payload, show notification
40
+ onMessageReceived(it)
41
+ } ?: run {
42
+ Log.d(TAG, "Ignore intents that don't contain push notification payload")
43
+ super.handleIntent(intent)
44
+ }
45
+ }
46
+
47
+ private fun onMessageReceived(payload: NotificationPayload) {
48
+ if (utils.isAppInForeground()) {
49
+ Log.d(TAG, "Send foreground message received event")
50
+ PushNotificationEventManager.sendEvent(
51
+ PushNotificationEventType.FOREGROUND_MESSAGE_RECEIVED, payload.toWritableMap()
52
+ )
53
+ } else {
54
+ Log.d(
55
+ TAG, "App is in background, try to create notification and start headless service"
56
+ )
57
+
58
+ utils.showNotification(payload)
59
+
60
+ try {
61
+ val serviceIntent =
62
+ Intent(baseContext, PushNotificationHeadlessTaskService::class.java)
63
+ serviceIntent.putExtra("amplifyNotificationPayload", payload)
64
+ if (baseContext.startService(serviceIntent) != null) {
65
+ HeadlessJsTaskService.acquireWakeLockNow(baseContext)
66
+ }
67
+ } catch (exception: Exception) {
68
+ Log.e(
69
+ TAG, "Something went wrong while starting headless task: ${exception.message}"
70
+ )
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,28 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import android.content.Intent
7
+ import com.amplifyframework.annotations.InternalAmplifyApi
8
+ import com.amplifyframework.notifications.pushnotifications.NotificationPayload
9
+ import com.facebook.react.HeadlessJsTaskService
10
+ import com.facebook.react.jstasks.HeadlessJsTaskConfig
11
+
12
+ class PushNotificationHeadlessTaskService : HeadlessJsTaskService() {
13
+
14
+ private val defaultTimeout: Long = 10000 // 10 seconds
15
+
16
+ @InternalAmplifyApi
17
+ override fun getTaskConfig(intent: Intent): HeadlessJsTaskConfig? {
18
+ return NotificationPayload.fromIntent(intent)?.let {
19
+ HeadlessJsTaskConfig(
20
+ HEADLESS_TASK_KEY, it.toWritableMap(), defaultTimeout, true
21
+ )
22
+ }
23
+ }
24
+
25
+ companion object {
26
+ const val HEADLESS_TASK_KEY = "PushNotificationHeadlessTaskKey"
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ package com.amazonaws.amplify.rtnpushnotification
2
+
3
+ import android.app.Activity
4
+ import android.content.ActivityNotFoundException
5
+ import android.os.Bundle
6
+ import android.util.Log
7
+ import com.amplifyframework.annotations.InternalAmplifyApi
8
+ import com.amplifyframework.notifications.pushnotifications.NotificationPayload
9
+
10
+ private val TAG = PushNotificationLaunchActivity::class.java.simpleName
11
+
12
+ class PushNotificationLaunchActivity : Activity() {
13
+ @Override
14
+ @InternalAmplifyApi
15
+ override fun onCreate(savedInstanceState: Bundle?) {
16
+ super.onCreate(savedInstanceState)
17
+ val payload = NotificationPayload.fromIntent(intent)
18
+ val notificationIntent = payload.getProcessedIntent(applicationContext)
19
+ notificationIntent?.putExtras(intent)
20
+ try {
21
+ startActivity(notificationIntent)
22
+ } catch (e: ActivityNotFoundException) {
23
+ Log.e(TAG, "Unable to launch intent.", e)
24
+ }
25
+ finish()
26
+ }
27
+ }
@@ -0,0 +1,188 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import android.app.Activity
7
+ import android.content.Context.MODE_PRIVATE
8
+ import android.content.Intent
9
+ import android.util.Log
10
+ import androidx.core.app.ActivityCompat
11
+ import com.amplifyframework.annotations.InternalAmplifyApi
12
+ import com.amplifyframework.notifications.pushnotifications.NotificationPayload
13
+ import com.facebook.react.bridge.*
14
+ import com.google.android.gms.tasks.OnCompleteListener
15
+ import com.google.firebase.messaging.FirebaseMessaging
16
+ import kotlinx.coroutines.*
17
+
18
+
19
+ private val TAG = PushNotificationModule::class.java.simpleName
20
+ private const val PERMISSION = "android.permission.POST_NOTIFICATIONS"
21
+ private const val PREF_FILE_KEY = "com.amazonaws.amplify.rtnpushnotification"
22
+ private const val PREF_PREVIOUSLY_DENIED = "wasPermissionPreviouslyDenied"
23
+
24
+ enum class PushNotificationPermissionStatus {
25
+ ShouldRequest,
26
+ ShouldExplainThenRequest,
27
+ Granted,
28
+ Denied,
29
+ }
30
+
31
+ class PushNotificationModule(
32
+ reactContext: ReactApplicationContext,
33
+ dispatcher: CoroutineDispatcher = Dispatchers.Main
34
+ ) : ReactContextBaseJavaModule(reactContext), ActivityEventListener, LifecycleEventListener {
35
+
36
+ private var isAppLaunch: Boolean = true
37
+ private var launchNotification: WritableMap? = null
38
+ private val sharedPreferences = reactContext.getSharedPreferences(PREF_FILE_KEY, MODE_PRIVATE)
39
+ private val scope = CoroutineScope(dispatcher)
40
+
41
+ init {
42
+ reactContext.addActivityEventListener(this)
43
+ reactContext.addLifecycleEventListener(this)
44
+ }
45
+
46
+ @ReactMethod
47
+ fun getLaunchNotification(promise: Promise) {
48
+ launchNotification?.let {
49
+ promise.resolve(launchNotification)
50
+ launchNotification = null
51
+ } ?: promise.resolve(null)
52
+ }
53
+
54
+ @ReactMethod
55
+ fun getPermissionStatus(promise: Promise) {
56
+ val permission = PushNotificationPermission(reactApplicationContext)
57
+ // If permission has already been granted
58
+ if (permission.hasRequiredPermission) {
59
+ return promise.resolve(PushNotificationPermissionStatus.Granted.name)
60
+ }
61
+ // If the shouldShowRequestPermissionRationale flag is true, permission must have been
62
+ // denied once (and only once) previously
63
+ if (shouldShowRequestPermissionRationale()) {
64
+ return promise.resolve(PushNotificationPermissionStatus.ShouldExplainThenRequest.name)
65
+ }
66
+ // If the shouldShowRequestPermissionRationale flag is false and the permission was
67
+ // already previously denied then user has denied permissions twice
68
+ if (sharedPreferences.getBoolean(PREF_PREVIOUSLY_DENIED, false)) {
69
+ return promise.resolve(PushNotificationPermissionStatus.Denied.name)
70
+ }
71
+ // Otherwise it's never been requested (or user could have dismissed the request without
72
+ // explicitly denying)
73
+ promise.resolve(PushNotificationPermissionStatus.ShouldRequest.name)
74
+ }
75
+
76
+ @ReactMethod
77
+ fun requestPermissions(
78
+ @Suppress("UNUSED_PARAMETER") permissions: ReadableMap,
79
+ promise: Promise
80
+ ) {
81
+ scope.launch {
82
+ val permission = PushNotificationPermission(reactApplicationContext)
83
+ if (permission.requestPermission()) {
84
+ promise.resolve(true)
85
+ } else {
86
+ // If permission was not granted and the shouldShowRequestPermissionRationale flag
87
+ // is true then user must have denied for the first time. We will set the
88
+ // wasPermissionPreviouslyDenied value to true only in this scenario since it's
89
+ // possible to dismiss the permission request without explicitly denying as well.
90
+ if (shouldShowRequestPermissionRationale()) {
91
+ with(sharedPreferences.edit()) {
92
+ putBoolean(PREF_PREVIOUSLY_DENIED, true)
93
+ apply()
94
+ }
95
+ }
96
+ promise.resolve(false)
97
+ }
98
+ }
99
+ }
100
+
101
+ @ReactMethod
102
+ fun addListener(@Suppress("UNUSED_PARAMETER") eventName: String) {
103
+ // noop - only required for RN NativeEventEmitter
104
+ }
105
+
106
+ @ReactMethod
107
+ fun removeListeners(@Suppress("UNUSED_PARAMETER") count: Int) {
108
+ // noop - only required for RN NativeEventEmitter
109
+ }
110
+
111
+ override fun getName() = "AmplifyRTNPushNotification"
112
+
113
+ override fun getConstants(): MutableMap<String, Any> = hashMapOf(
114
+ "NativeEvent" to PushNotificationEventType.values()
115
+ .associateBy({ it.name }, { it.value }),
116
+ "NativeHeadlessTaskKey" to PushNotificationHeadlessTaskService.HEADLESS_TASK_KEY
117
+ )
118
+
119
+ override fun onActivityResult(p0: Activity?, p1: Int, p2: Int, p3: Intent?) {
120
+ // noop - only overridden as this class implements ActivityEventListener
121
+ }
122
+
123
+ /**
124
+ * Send notification opened app event to JS layer if the app is in a background state
125
+ */
126
+ @InternalAmplifyApi
127
+ override fun onNewIntent(intent: Intent) {
128
+ val payload = NotificationPayload.fromIntent(intent)
129
+ if (payload != null) {
130
+ PushNotificationEventManager.sendEvent(
131
+ PushNotificationEventType.NOTIFICATION_OPENED, payload.toWritableMap()
132
+ )
133
+ }
134
+ }
135
+
136
+ /**
137
+ * On every app resume (including launch), send the current device token to JS layer. Also
138
+ * store the app launching notification if app is in a quit state
139
+ */
140
+ @InternalAmplifyApi
141
+ override fun onHostResume() {
142
+ if (isAppLaunch) {
143
+ isAppLaunch = false
144
+ PushNotificationEventManager.init(reactApplicationContext)
145
+ val firebaseInstance = FirebaseMessaging.getInstance()
146
+ firebaseInstance.token.addOnCompleteListener(OnCompleteListener { task ->
147
+ if (!task.isSuccessful) {
148
+ Log.w(TAG, "Fetching FCM registration token failed")
149
+ return@OnCompleteListener
150
+ }
151
+ val params = Arguments.createMap().apply {
152
+ putString("token", task.result)
153
+ }
154
+ Log.d(TAG, "Send device token event")
155
+ PushNotificationEventManager.sendEvent(
156
+ PushNotificationEventType.TOKEN_RECEIVED,
157
+ params
158
+ )
159
+ })
160
+ currentActivity?.intent?.let {
161
+ val payload = NotificationPayload.fromIntent(it)
162
+ if (payload != null) {
163
+ launchNotification = payload.toWritableMap()
164
+ // Launch notification opened event is emitted for internal use only
165
+ PushNotificationEventManager.sendEvent(
166
+ PushNotificationEventType.LAUNCH_NOTIFICATION_OPENED,
167
+ payload.toWritableMap()
168
+ )
169
+ }
170
+ }
171
+ } else {
172
+ // Wipe the launching notification as app was re-opened by some other means
173
+ launchNotification = null
174
+ }
175
+ }
176
+
177
+ override fun onHostPause() {
178
+ // noop - only overridden as this class implements LifecycleEventListener
179
+ }
180
+
181
+ override fun onHostDestroy() {
182
+ scope.cancel()
183
+ }
184
+
185
+ private fun shouldShowRequestPermissionRationale(): Boolean {
186
+ return ActivityCompat.shouldShowRequestPermissionRationale(currentActivity!!, PERMISSION)
187
+ }
188
+ }
@@ -0,0 +1,22 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ package com.amazonaws.amplify.rtnpushnotification
5
+
6
+ import android.view.View
7
+ import com.facebook.react.ReactPackage
8
+ import com.facebook.react.bridge.NativeModule
9
+ import com.facebook.react.bridge.ReactApplicationContext
10
+ import com.facebook.react.uimanager.ReactShadowNode
11
+ import com.facebook.react.uimanager.ViewManager
12
+
13
+ class PushNotificationPackage : ReactPackage {
14
+
15
+ override fun createViewManagers(
16
+ reactContext: ReactApplicationContext
17
+ ): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()
18
+
19
+ override fun createNativeModules(
20
+ reactContext: ReactApplicationContext
21
+ ): MutableList<NativeModule> = listOf(PushNotificationModule(reactContext)).toMutableList()
22
+ }