expo-notifications 0.28.7 → 0.28.9

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
@@ -10,6 +10,16 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.28.9 — 2024-06-12
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 0.28.8 — 2024-06-10
18
+
19
+ ### 🐛 Bug fixes
20
+
21
+ - [Android] Add default channel plugin prop, restore legacy icon and color. ([#29491](https://github.com/expo/expo/pull/29491) by [@douglowder](https://github.com/douglowder))
22
+
13
23
  ## 0.28.7 — 2024-06-05
14
24
 
15
25
  ### 🐛 Bug fixes
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'host.exp.exponent'
4
- version = '0.28.7'
4
+ version = '0.28.9'
5
5
 
6
6
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
7
7
  apply from: expoModulesCorePlugin
@@ -14,7 +14,7 @@ android {
14
14
  namespace "expo.modules.notifications"
15
15
  defaultConfig {
16
16
  versionCode 21
17
- versionName '0.28.7'
17
+ versionName '0.28.9'
18
18
  }
19
19
 
20
20
  buildFeatures {
@@ -12,7 +12,12 @@ object BadgeHelper {
12
12
 
13
13
  fun setBadgeCount(context: Context, badgeCount: Int): Boolean {
14
14
  return try {
15
- ShortcutBadger.applyCountOrThrow(context.applicationContext, badgeCount)
15
+ if (badgeCount == 0) {
16
+ val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager
17
+ notificationManager.cancelAll()
18
+ } else {
19
+ ShortcutBadger.applyCountOrThrow(context.applicationContext, badgeCount)
20
+ }
16
21
  BadgeHelper.badgeCount = badgeCount
17
22
  true
18
23
  } catch (e: ShortcutBadgeException) {
@@ -126,16 +126,27 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
126
126
  }
127
127
  }
128
128
 
129
- public void onNotificationResponseFromExtras(Bundle extras) {
130
- if (mPendingNotificationResponsesFromExtras.isEmpty()) {
131
- mPendingNotificationResponsesFromExtras.add(extras);
132
- } else {
129
+ public void onNotificationResponseFromExtras(Bundle extras) {
130
+ // We're going to be passed in extras from either
131
+ // a killed state (ExpoNotificationLifecycleListener::onCreate)
132
+ // OR a background state (ExpoNotificationLifecycleListener::onNewIntent)
133
+
134
+ // If we've just come from a background state, we'll have listeners set up
135
+ // pass on the notification to them
136
+ if (!mListenerReferenceMap.isEmpty()) {
133
137
  for (WeakReference<NotificationListener> listenerReference : mListenerReferenceMap.values()) {
134
138
  NotificationListener listener = listenerReference.get();
135
139
  if (listener != null) {
136
140
  listener.onNotificationResponseIntentReceived(extras);
137
141
  }
138
142
  }
143
+ } else {
144
+ // Otherwise, the app has been launched from a killed state, and our listeners
145
+ // haven't yet been setup. We'll add this to a list of pending notifications
146
+ // for them to process once they've been initialized.
147
+ if (mPendingNotificationResponsesFromExtras.isEmpty()) {
148
+ mPendingNotificationResponsesFromExtras.add(extras);
149
+ }
139
150
  }
140
151
  }
141
152
  }
@@ -41,6 +41,10 @@ public class ExpoNotificationLifecycleListener implements ReactActivityLifecycle
41
41
  if (intent != null) {
42
42
  Bundle extras = intent.getExtras();
43
43
  if (extras != null) {
44
+ if (extras.containsKey("notificationResponse")) {
45
+ Log.d("ReactNativeJS", "[native] ExpoNotificationLifecycleListener contains an unmarshaled notification response. Skipping.");
46
+ return;
47
+ }
44
48
  mNotificationManager.onNotificationResponseFromExtras(extras);
45
49
  }
46
50
  }
@@ -59,6 +63,11 @@ public class ExpoNotificationLifecycleListener implements ReactActivityLifecycle
59
63
  public boolean onNewIntent(Intent intent) {
60
64
  Bundle extras = intent.getExtras();
61
65
  if (extras != null) {
66
+ if (extras.containsKey("notificationResponse")) {
67
+ Log.d("ReactNativeJS", "[native] ExpoNotificationLifecycleListener contains an unmarshaled notification response. Skipping.");
68
+ intent.removeExtra("notificationResponse");
69
+ return ReactActivityLifecycleListener.super.onNewIntent(intent);
70
+ }
62
71
  mNotificationManager.onNotificationResponseFromExtras(extras);
63
72
  }
64
73
  return ReactActivityLifecycleListener.super.onNewIntent(intent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-notifications",
3
- "version": "0.28.7",
3
+ "version": "0.28.9",
4
4
  "description": "Notifications module",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -55,5 +55,5 @@
55
55
  "peerDependencies": {
56
56
  "expo": "*"
57
57
  },
58
- "gitHead": "01afaad3852d3af00238b2e28ea6e13db6f0a1f8"
58
+ "gitHead": "247b0bf49d46697632665ef49660fea7a34ec174"
59
59
  }
@@ -13,6 +13,11 @@ export type NotificationsPluginProps = {
13
13
  * @platform android
14
14
  */
15
15
  color?: string;
16
+ /**
17
+ * Default channel for FCMv1 notifications.
18
+ * @platform android
19
+ */
20
+ defaultChannel?: string;
16
21
  /**
17
22
  * Array of local paths to sound files (.wav recommended) that can be used as custom notification sounds.
18
23
  */
@@ -10,6 +10,9 @@ export declare const ANDROID_RES_PATH = "android/app/src/main/res/";
10
10
  export declare const dpiValues: dpiMap;
11
11
  export declare const META_DATA_NOTIFICATION_ICON = "com.google.firebase.messaging.default_notification_icon";
12
12
  export declare const META_DATA_NOTIFICATION_ICON_COLOR = "com.google.firebase.messaging.default_notification_color";
13
+ export declare const META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID = "com.google.firebase.messaging.default_notification_channel_id";
14
+ export declare const META_DATA_LEGACY_NOTIFICATION_ICON = "expo.modules.notifications.default_notification_icon";
15
+ export declare const META_DATA_LEGACY_NOTIFICATION_ICON_COLOR = "expo.modules.notifications.default_notification_color";
13
16
  export declare const NOTIFICATION_ICON = "notification_icon";
14
17
  export declare const NOTIFICATION_ICON_RESOURCE: string;
15
18
  export declare const NOTIFICATION_ICON_COLOR = "notification_icon_color";
@@ -23,6 +26,7 @@ export declare const withNotificationIconColor: ConfigPlugin<{
23
26
  export declare const withNotificationManifest: ConfigPlugin<{
24
27
  icon: string | null;
25
28
  color: string | null;
29
+ defaultChannel: string | null;
26
30
  }>;
27
31
  export declare const withNotificationSounds: ConfigPlugin<{
28
32
  sounds: string[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withNotificationsAndroid = exports.setNotificationSounds = exports.setNotificationIconAsync = exports.setNotificationIconColor = exports.getNotificationColor = exports.getNotificationIcon = exports.withNotificationSounds = exports.withNotificationManifest = exports.withNotificationIconColor = exports.withNotificationIcons = exports.NOTIFICATION_ICON_COLOR_RESOURCE = exports.NOTIFICATION_ICON_COLOR = exports.NOTIFICATION_ICON_RESOURCE = exports.NOTIFICATION_ICON = exports.META_DATA_NOTIFICATION_ICON_COLOR = exports.META_DATA_NOTIFICATION_ICON = exports.dpiValues = exports.ANDROID_RES_PATH = void 0;
3
+ exports.withNotificationsAndroid = exports.setNotificationSounds = exports.setNotificationIconAsync = exports.setNotificationIconColor = exports.getNotificationColor = exports.getNotificationIcon = exports.withNotificationSounds = exports.withNotificationManifest = exports.withNotificationIconColor = exports.withNotificationIcons = exports.NOTIFICATION_ICON_COLOR_RESOURCE = exports.NOTIFICATION_ICON_COLOR = exports.NOTIFICATION_ICON_RESOURCE = exports.NOTIFICATION_ICON = exports.META_DATA_LEGACY_NOTIFICATION_ICON_COLOR = exports.META_DATA_LEGACY_NOTIFICATION_ICON = exports.META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID = exports.META_DATA_NOTIFICATION_ICON_COLOR = exports.META_DATA_NOTIFICATION_ICON = exports.dpiValues = exports.ANDROID_RES_PATH = void 0;
4
4
  const image_utils_1 = require("@expo/image-utils");
5
5
  const config_plugins_1 = require("expo/config-plugins");
6
6
  const fs_1 = require("fs");
@@ -19,6 +19,9 @@ const BASELINE_PIXEL_SIZE = 24;
19
19
  const ERROR_MSG_PREFIX = 'An error occurred while configuring Android notifications. ';
20
20
  exports.META_DATA_NOTIFICATION_ICON = 'com.google.firebase.messaging.default_notification_icon';
21
21
  exports.META_DATA_NOTIFICATION_ICON_COLOR = 'com.google.firebase.messaging.default_notification_color';
22
+ exports.META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID = 'com.google.firebase.messaging.default_notification_channel_id';
23
+ exports.META_DATA_LEGACY_NOTIFICATION_ICON = 'expo.modules.notifications.default_notification_icon';
24
+ exports.META_DATA_LEGACY_NOTIFICATION_ICON_COLOR = 'expo.modules.notifications.default_notification_color';
22
25
  exports.NOTIFICATION_ICON = 'notification_icon';
23
26
  exports.NOTIFICATION_ICON_RESOURCE = `@drawable/${exports.NOTIFICATION_ICON}`;
24
27
  exports.NOTIFICATION_ICON_COLOR = 'notification_icon_color';
@@ -44,12 +47,13 @@ const withNotificationIconColor = (config, { color }) => {
44
47
  });
45
48
  };
46
49
  exports.withNotificationIconColor = withNotificationIconColor;
47
- const withNotificationManifest = (config, { icon, color }) => {
50
+ const withNotificationManifest = (config, { icon, color, defaultChannel }) => {
48
51
  // If no icon or color provided in the config plugin props, fallback to value from app.json
49
52
  icon = icon || getNotificationIcon(config);
50
53
  color = color || getNotificationColor(config);
54
+ defaultChannel = defaultChannel || null;
51
55
  return (0, config_plugins_1.withAndroidManifest)(config, (config) => {
52
- config.modResults = setNotificationConfig({ icon, color }, config.modResults);
56
+ config.modResults = setNotificationConfig({ icon, color, defaultChannel }, config.modResults);
53
57
  return config;
54
58
  });
55
59
  };
@@ -95,15 +99,25 @@ function setNotificationConfig(props, manifest) {
95
99
  const mainApplication = getMainApplicationOrThrow(manifest);
96
100
  if (props.icon) {
97
101
  addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON, exports.NOTIFICATION_ICON_RESOURCE, 'resource');
102
+ addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_LEGACY_NOTIFICATION_ICON, exports.NOTIFICATION_ICON_RESOURCE, 'resource');
98
103
  }
99
104
  else {
100
105
  removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON);
106
+ removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_LEGACY_NOTIFICATION_ICON);
101
107
  }
102
108
  if (props.color) {
103
109
  addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON_COLOR, exports.NOTIFICATION_ICON_COLOR_RESOURCE, 'resource');
110
+ addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_LEGACY_NOTIFICATION_ICON_COLOR, exports.NOTIFICATION_ICON_COLOR_RESOURCE, 'resource');
104
111
  }
105
112
  else {
106
113
  removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON_COLOR);
114
+ removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_LEGACY_NOTIFICATION_ICON_COLOR);
115
+ }
116
+ if (props.defaultChannel) {
117
+ addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID, props.defaultChannel, 'value');
118
+ }
119
+ else {
120
+ removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID);
107
121
  }
108
122
  return manifest;
109
123
  }
@@ -174,10 +188,10 @@ function writeNotificationSoundFile(soundFileRelativePath, projectRoot) {
174
188
  }
175
189
  }
176
190
  }
177
- const withNotificationsAndroid = (config, { icon = null, color = null, sounds = [] }) => {
191
+ const withNotificationsAndroid = (config, { icon = null, color = null, sounds = [], defaultChannel = null }) => {
178
192
  config = (0, exports.withNotificationIconColor)(config, { color });
179
193
  config = (0, exports.withNotificationIcons)(config, { icon });
180
- config = (0, exports.withNotificationManifest)(config, { icon, color });
194
+ config = (0, exports.withNotificationManifest)(config, { icon, color, defaultChannel });
181
195
  config = (0, exports.withNotificationSounds)(config, { sounds });
182
196
  return config;
183
197
  };
@@ -19,6 +19,11 @@ export type NotificationsPluginProps = {
19
19
  * @platform android
20
20
  */
21
21
  color?: string;
22
+ /**
23
+ * Default channel for FCMv1 notifications.
24
+ * @platform android
25
+ */
26
+ defaultChannel?: string;
22
27
  /**
23
28
  * Array of local paths to sound files (.wav recommended) that can be used as custom notification sounds.
24
29
  */
@@ -32,10 +32,19 @@ const {
32
32
  } = AndroidConfig.Manifest;
33
33
  const BASELINE_PIXEL_SIZE = 24;
34
34
  const ERROR_MSG_PREFIX = 'An error occurred while configuring Android notifications. ';
35
+
35
36
  export const META_DATA_NOTIFICATION_ICON =
36
37
  'com.google.firebase.messaging.default_notification_icon';
37
38
  export const META_DATA_NOTIFICATION_ICON_COLOR =
38
39
  'com.google.firebase.messaging.default_notification_color';
40
+ export const META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID =
41
+ 'com.google.firebase.messaging.default_notification_channel_id';
42
+
43
+ export const META_DATA_LEGACY_NOTIFICATION_ICON =
44
+ 'expo.modules.notifications.default_notification_icon';
45
+ export const META_DATA_LEGACY_NOTIFICATION_ICON_COLOR =
46
+ 'expo.modules.notifications.default_notification_color';
47
+
39
48
  export const NOTIFICATION_ICON = 'notification_icon';
40
49
  export const NOTIFICATION_ICON_RESOURCE = `@drawable/${NOTIFICATION_ICON}`;
41
50
  export const NOTIFICATION_ICON_COLOR = 'notification_icon_color';
@@ -68,12 +77,14 @@ export const withNotificationIconColor: ConfigPlugin<{ color: string | null }> =
68
77
  export const withNotificationManifest: ConfigPlugin<{
69
78
  icon: string | null;
70
79
  color: string | null;
71
- }> = (config, { icon, color }) => {
80
+ defaultChannel: string | null;
81
+ }> = (config, { icon, color, defaultChannel }) => {
72
82
  // If no icon or color provided in the config plugin props, fallback to value from app.json
73
83
  icon = icon || getNotificationIcon(config);
74
84
  color = color || getNotificationColor(config);
85
+ defaultChannel = defaultChannel || null;
75
86
  return withAndroidManifest(config, (config) => {
76
- config.modResults = setNotificationConfig({ icon, color }, config.modResults);
87
+ config.modResults = setNotificationConfig({ icon, color, defaultChannel }, config.modResults);
77
88
  return config;
78
89
  });
79
90
  };
@@ -118,7 +129,7 @@ export async function setNotificationIconAsync(projectRoot: string, icon: string
118
129
  }
119
130
 
120
131
  function setNotificationConfig(
121
- props: { icon: string | null; color: string | null },
132
+ props: { icon: string | null; color: string | null; defaultChannel?: string | null },
122
133
  manifest: AndroidConfig.Manifest.AndroidManifest
123
134
  ) {
124
135
  const mainApplication = getMainApplicationOrThrow(manifest);
@@ -129,8 +140,15 @@ function setNotificationConfig(
129
140
  NOTIFICATION_ICON_RESOURCE,
130
141
  'resource'
131
142
  );
143
+ addMetaDataItemToMainApplication(
144
+ mainApplication,
145
+ META_DATA_LEGACY_NOTIFICATION_ICON,
146
+ NOTIFICATION_ICON_RESOURCE,
147
+ 'resource'
148
+ );
132
149
  } else {
133
150
  removeMetaDataItemFromMainApplication(mainApplication, META_DATA_NOTIFICATION_ICON);
151
+ removeMetaDataItemFromMainApplication(mainApplication, META_DATA_LEGACY_NOTIFICATION_ICON);
134
152
  }
135
153
  if (props.color) {
136
154
  addMetaDataItemToMainApplication(
@@ -139,8 +157,32 @@ function setNotificationConfig(
139
157
  NOTIFICATION_ICON_COLOR_RESOURCE,
140
158
  'resource'
141
159
  );
160
+ addMetaDataItemToMainApplication(
161
+ mainApplication,
162
+ META_DATA_LEGACY_NOTIFICATION_ICON_COLOR,
163
+ NOTIFICATION_ICON_COLOR_RESOURCE,
164
+ 'resource'
165
+ );
142
166
  } else {
143
167
  removeMetaDataItemFromMainApplication(mainApplication, META_DATA_NOTIFICATION_ICON_COLOR);
168
+ removeMetaDataItemFromMainApplication(
169
+ mainApplication,
170
+ META_DATA_LEGACY_NOTIFICATION_ICON_COLOR
171
+ );
172
+ }
173
+
174
+ if (props.defaultChannel) {
175
+ addMetaDataItemToMainApplication(
176
+ mainApplication,
177
+ META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID,
178
+ props.defaultChannel,
179
+ 'value'
180
+ );
181
+ } else {
182
+ removeMetaDataItemFromMainApplication(
183
+ mainApplication,
184
+ META_DATA_NOTIFICATION_DEFAULT_CHANNEL_ID
185
+ );
144
186
  }
145
187
  return manifest;
146
188
  }
@@ -230,11 +272,11 @@ function writeNotificationSoundFile(soundFileRelativePath: string, projectRoot:
230
272
 
231
273
  export const withNotificationsAndroid: ConfigPlugin<NotificationsPluginProps> = (
232
274
  config,
233
- { icon = null, color = null, sounds = [] }
275
+ { icon = null, color = null, sounds = [], defaultChannel = null }
234
276
  ) => {
235
277
  config = withNotificationIconColor(config, { color });
236
278
  config = withNotificationIcons(config, { icon });
237
- config = withNotificationManifest(config, { icon, color });
279
+ config = withNotificationManifest(config, { icon, color, defaultChannel });
238
280
  config = withNotificationSounds(config, { sounds });
239
281
  return config;
240
282
  };