expo-notifications 1.0.0-canary-20241018-ebd377a → 1.0.0-canary-20241021-c4b5a93

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.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  ### 🐛 Bug fixes
16
16
 
17
+ - [android] fix: allow data message to control notification appearance ([#32162](https://github.com/expo/expo/pull/32162) by [@vonovak](https://github.com/vonovak))
17
18
  - [ios] fix crash if expo-update reload happens while Notifications.requestPermissionsAsync() is showing native dialog ([#32096](https://github.com/expo/expo/pull/32096) by [@mfazekas](https://github.com/mfazekas))
18
19
  - [android] `createNotificationChannel` could return incorrect channel information ([#32000](https://github.com/expo/expo/pull/32000) by [@vonovak](https://github.com/vonovak))
19
20
  - [android] fix notifications with `ChannelAwareTrigger` not being presented ([#31999](https://github.com/expo/expo/pull/31999) by [@vonovak](https://github.com/vonovak))
@@ -0,0 +1,69 @@
1
+ package expo.modules.notifications.notifications.model
2
+
3
+ import org.json.JSONArray
4
+ import org.json.JSONObject
5
+
6
+ /*
7
+ * In some scenarios, data-only push notifications are, in fact, presented.
8
+ * The presentation preferences are taken from the data payload.
9
+ *
10
+ * https://docs.expo.dev/versions/latest/sdk/notifications/#android-push-notification-payload-specification
11
+ * */
12
+ @JvmInline
13
+ value class NotificationData(private val data: Map<String, String>) {
14
+ val title: String?
15
+ get() = data["title"]
16
+
17
+ val message: String?
18
+ get() = data["message"]
19
+
20
+ val body: JSONObject?
21
+ get() = try {
22
+ data["body"]?.let { JSONObject(it) }
23
+ } catch (e: Exception) {
24
+ null
25
+ }
26
+
27
+ val sound: String?
28
+ get() = data["sound"]
29
+
30
+ val shouldPlayDefaultSound: Boolean
31
+ get() = sound == null
32
+
33
+ val shouldUseDefaultVibrationPattern: Boolean
34
+ get() = data["vibrate"]?.toBoolean() == true
35
+
36
+ val isSticky: Boolean
37
+ get() = data["sticky"]?.toBoolean() ?: false
38
+
39
+ val vibrationPattern: LongArray?
40
+ get() = try {
41
+ data["vibrate"]?.let { vibrateString ->
42
+ JSONArray(vibrateString).let { jsonArray ->
43
+ LongArray(jsonArray.length()) { i ->
44
+ jsonArray.getLong(i)
45
+ }
46
+ }
47
+ }
48
+ } catch (e: Exception) {
49
+ // most likely a boolean value that cannot be converted to a longArray
50
+ null
51
+ }
52
+
53
+ val color: String? get() = data["color"]
54
+
55
+ val autoDismiss: Boolean
56
+ get() = data["autoDismiss"]?.toBoolean() ?: true
57
+
58
+ val categoryId: String?
59
+ get() = data["categoryId"]
60
+
61
+ val sticky: Boolean
62
+ get() = data["sticky"]?.toBoolean() ?: false
63
+
64
+ val subText: String?
65
+ get() = data["subtitle"]
66
+
67
+ val badge: Int?
68
+ get() = data["badge"]?.toIntOrNull()
69
+ }
@@ -8,7 +8,6 @@ import com.google.firebase.messaging.RemoteMessage
8
8
  import expo.modules.notifications.notifications.enums.NotificationPriority
9
9
  import expo.modules.notifications.notifications.interfaces.INotificationContent
10
10
  import expo.modules.notifications.notifications.presentation.builders.downloadImage
11
- import org.json.JSONObject
12
11
 
13
12
  /**
14
13
  * A POJO representing a remote notification content: title, message, body, etc.
@@ -21,6 +20,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
21
20
 
22
21
  constructor(parcel: Parcel) : this(parcel.readParcelable<RemoteMessage>(RemoteMessage::class.java.classLoader)!!)
23
22
 
23
+ private val notificationData = NotificationData(remoteMessage.data)
24
+
24
25
  override suspend fun getImage(context: Context): Bitmap? {
25
26
  val uri = remoteMessage.notification?.imageUrl
26
27
  return uri?.let { downloadImage(it) }
@@ -30,30 +31,20 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
30
31
  return remoteMessage.notification?.imageUrl != null
31
32
  }
32
33
 
33
- override val title: String?
34
- get() = remoteMessage.notification?.title
34
+ override val title = remoteMessage.notification?.title ?: notificationData.title
35
35
 
36
- override val text: String?
37
- get() = remoteMessage.notification?.body
36
+ override val text = remoteMessage.notification?.body ?: notificationData.message
38
37
 
39
- override val shouldPlayDefaultSound: Boolean
40
- get() = remoteMessage.notification?.sound == null
38
+ override val shouldPlayDefaultSound = remoteMessage.notification?.sound == null && notificationData.shouldPlayDefaultSound
41
39
 
42
- override val soundName: String?
43
- get() = remoteMessage.notification?.sound
40
+ override val soundName = remoteMessage.notification?.sound ?: notificationData.sound
44
41
 
45
42
  override val shouldUseDefaultVibrationPattern: Boolean
46
- get() = remoteMessage.notification?.defaultVibrateSettings == true
43
+ get() = remoteMessage.notification?.defaultVibrateSettings ?: notificationData.shouldUseDefaultVibrationPattern
47
44
 
48
- override val vibrationPattern: LongArray?
49
- get() = remoteMessage.notification?.vibrateTimings
45
+ override val vibrationPattern = remoteMessage.notification?.vibrateTimings ?: notificationData.vibrationPattern
50
46
 
51
- override val body: JSONObject?
52
- get() = try {
53
- remoteMessage.data["body"]?.let { JSONObject(it) }
54
- } catch (e: Exception) {
55
- null
56
- }
47
+ override val body = notificationData.body
57
48
 
58
49
  override val priority: NotificationPriority
59
50
  get() = when (remoteMessage.priority) {
@@ -62,24 +53,23 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
62
53
  }
63
54
 
64
55
  override val color: Number?
65
- get() = remoteMessage.notification?.color?.let { android.graphics.Color.parseColor(it) }
56
+ get() {
57
+ val colorSource = remoteMessage.notification?.color ?: notificationData.color
58
+ return colorSource?.let { android.graphics.Color.parseColor(it) }
59
+ }
66
60
 
67
61
  // NOTE the following getter functions are here because the local notification content class has them
68
- // and this class conforms to the same interface. They are not supported by FCM.
69
- override val isAutoDismiss: Boolean
70
- get() = remoteMessage.data["autoDismiss"]?.toBoolean() ?: true
62
+ // and this class conforms to the same interface.
63
+ // They are not supported by FCM but were previously implemented by JSONNotificationContentBuilder.java.
64
+ override val isAutoDismiss = notificationData.autoDismiss
71
65
 
72
- override val categoryId: String?
73
- get() = remoteMessage.data["categoryId"]
66
+ override val categoryId = notificationData.categoryId
74
67
 
75
- override val isSticky: Boolean
76
- get() = remoteMessage.data["sticky"]?.toBoolean() ?: false
68
+ override val isSticky = notificationData.isSticky
77
69
 
78
- override val subText: String?
79
- get() = remoteMessage.data["subtitle"]
70
+ override val subText = notificationData.subText
80
71
 
81
- override val badgeCount: Number?
82
- get() = remoteMessage.data["badge"]?.toIntOrNull()
72
+ override val badgeCount = notificationData.badge
83
73
 
84
74
  override fun describeContents(): Int = 0
85
75
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-notifications",
3
- "version": "1.0.0-canary-20241018-ebd377a",
3
+ "version": "1.0.0-canary-20241021-c4b5a93",
4
4
  "description": "Provides an API to fetch push notification tokens and to present, schedule, receive, and respond to notifications.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -38,25 +38,25 @@
38
38
  "preset": "expo-module-scripts/ios"
39
39
  },
40
40
  "dependencies": {
41
- "@expo/image-utils": "0.6.0-canary-20241018-ebd377a",
41
+ "@expo/image-utils": "0.6.0-canary-20241021-c4b5a93",
42
42
  "@ide/backoff": "^1.0.0",
43
43
  "abort-controller": "^3.0.0",
44
44
  "assert": "^2.0.0",
45
45
  "badgin": "^1.1.5",
46
- "expo-application": "6.0.0-canary-20241018-ebd377a",
47
- "expo-constants": "17.0.0-canary-20241018-ebd377a",
46
+ "expo-application": "6.0.0-canary-20241021-c4b5a93",
47
+ "expo-constants": "17.0.0-canary-20241021-c4b5a93",
48
48
  "fs-extra": "^9.1.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node-fetch": "^2.5.7",
52
- "expo-module-scripts": "3.6.0-canary-20241018-ebd377a",
52
+ "expo-module-scripts": "3.6.0-canary-20241021-c4b5a93",
53
53
  "memfs": "^3.2.0",
54
54
  "node-fetch": "^2.6.7"
55
55
  },
56
56
  "peerDependencies": {
57
- "expo": "52.0.0-canary-20241018-ebd377a",
57
+ "expo": "52.0.0-canary-20241021-c4b5a93",
58
58
  "react": "*",
59
59
  "react-native": "*"
60
60
  },
61
- "gitHead": "ebd377a8a9609b3c935bcfe45022f7ad9ecbcd82"
61
+ "gitHead": "c4b5a932011f3dfab7a0302ff32cce7c33aa7c28"
62
62
  }