@capacitor/local-notifications 1.0.10 → 4.0.0-beta.2

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 (27) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/CapacitorLocalNotifications.podspec +1 -1
  3. package/README.md +126 -30
  4. package/android/build.gradle +10 -11
  5. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/DateMatch.java +45 -10
  6. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationManager.java +48 -32
  7. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationRestoreReceiver.java +2 -1
  8. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationSchedule.java +3 -1
  9. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/LocalNotificationsPlugin.java +79 -0
  10. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/NotificationChannelManager.java +2 -6
  11. package/android/src/main/java/com/capacitorjs/plugins/localnotifications/TimedNotificationPublisher.java +6 -1
  12. package/android/src/main/res/drawable/ic_transparent.xml +12 -0
  13. package/dist/docs.json +305 -23
  14. package/dist/esm/definitions.d.ts +141 -4
  15. package/dist/esm/definitions.js +13 -1
  16. package/dist/esm/definitions.js.map +1 -1
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/web.d.ts +5 -1
  19. package/dist/esm/web.js +33 -0
  20. package/dist/esm/web.js.map +1 -1
  21. package/dist/plugin.cjs.js +48 -0
  22. package/dist/plugin.cjs.js.map +1 -1
  23. package/dist/plugin.js +48 -0
  24. package/dist/plugin.js.map +1 -1
  25. package/ios/Plugin/LocalNotificationsPlugin.m +4 -1
  26. package/ios/Plugin/LocalNotificationsPlugin.swift +43 -1
  27. package/package.json +8 -8
@@ -22,7 +22,7 @@ import com.getcapacitor.CapConfig;
22
22
  import com.getcapacitor.JSObject;
23
23
  import com.getcapacitor.Logger;
24
24
  import com.getcapacitor.PluginCall;
25
- import com.getcapacitor.android.R;
25
+ import com.getcapacitor.PluginConfig;
26
26
  import com.getcapacitor.plugin.util.AssetUtil;
27
27
  import java.text.SimpleDateFormat;
28
28
  import java.util.Date;
@@ -36,7 +36,6 @@ import org.json.JSONObject;
36
36
  */
37
37
  public class LocalNotificationManager {
38
38
 
39
- private static final String CONFIG_KEY_PREFIX = "plugins.LocalNotifications.";
40
39
  private static int defaultSoundID = AssetUtil.RESOURCE_ID_ZERO_VALUE;
41
40
  private static int defaultSmallIconID = AssetUtil.RESOURCE_ID_ZERO_VALUE;
42
41
  // Action constants
@@ -52,13 +51,13 @@ public class LocalNotificationManager {
52
51
  private Context context;
53
52
  private Activity activity;
54
53
  private NotificationStorage storage;
55
- private CapConfig config;
54
+ private PluginConfig config;
56
55
 
57
56
  public LocalNotificationManager(NotificationStorage notificationStorage, Activity activity, Context context, CapConfig config) {
58
57
  storage = notificationStorage;
59
58
  this.activity = activity;
60
59
  this.context = context;
61
- this.config = config;
60
+ this.config = config.getPluginConfiguration("LocalNotifications");
62
61
  }
63
62
 
64
63
  /**
@@ -223,7 +222,7 @@ public class LocalNotificationManager {
223
222
  mBuilder.setSmallIcon(localNotification.getSmallIcon(context, getDefaultSmallIcon(context)));
224
223
  mBuilder.setLargeIcon(localNotification.getLargeIcon(context));
225
224
 
226
- String iconColor = localNotification.getIconColor(config.getString(CONFIG_KEY_PREFIX + "iconColor"));
225
+ String iconColor = localNotification.getIconColor(config.getString("iconColor"));
227
226
  if (iconColor != null) {
228
227
  try {
229
228
  mBuilder.setColor(Color.parseColor(iconColor));
@@ -253,13 +252,11 @@ public class LocalNotificationManager {
253
252
  private void createActionIntents(LocalNotification localNotification, NotificationCompat.Builder mBuilder) {
254
253
  // Open intent
255
254
  Intent intent = buildIntent(localNotification, DEFAULT_PRESS_ACTION);
256
-
257
- PendingIntent pendingIntent = PendingIntent.getActivity(
258
- context,
259
- localNotification.getId(),
260
- intent,
261
- PendingIntent.FLAG_CANCEL_CURRENT
262
- );
255
+ int flags = PendingIntent.FLAG_CANCEL_CURRENT;
256
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
257
+ flags = flags | PendingIntent.FLAG_MUTABLE;
258
+ }
259
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, localNotification.getId(), intent, flags);
263
260
  mBuilder.setContentIntent(pendingIntent);
264
261
 
265
262
  // Build action types
@@ -273,7 +270,7 @@ public class LocalNotificationManager {
273
270
  context,
274
271
  localNotification.getId() + notificationAction.getId().hashCode(),
275
272
  actionIntent,
276
- PendingIntent.FLAG_CANCEL_CURRENT
273
+ flags
277
274
  );
278
275
  NotificationCompat.Action.Builder actionBuilder = new NotificationCompat.Action.Builder(
279
276
  R.drawable.ic_transparent,
@@ -295,7 +292,11 @@ public class LocalNotificationManager {
295
292
  dissmissIntent.putExtra(ACTION_INTENT_KEY, "dismiss");
296
293
  LocalNotificationSchedule schedule = localNotification.getSchedule();
297
294
  dissmissIntent.putExtra(NOTIFICATION_IS_REMOVABLE_KEY, schedule == null || schedule.isRemovable());
298
- PendingIntent deleteIntent = PendingIntent.getBroadcast(context, localNotification.getId(), dissmissIntent, 0);
295
+ flags = 0;
296
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
297
+ flags = PendingIntent.FLAG_MUTABLE;
298
+ }
299
+ PendingIntent deleteIntent = PendingIntent.getBroadcast(context, localNotification.getId(), dissmissIntent, flags);
299
300
  mBuilder.setDeleteIntent(deleteIntent);
300
301
  }
301
302
 
@@ -330,12 +331,11 @@ public class LocalNotificationManager {
330
331
  Intent notificationIntent = new Intent(context, TimedNotificationPublisher.class);
331
332
  notificationIntent.putExtra(NOTIFICATION_INTENT_KEY, request.getId());
332
333
  notificationIntent.putExtra(TimedNotificationPublisher.NOTIFICATION_KEY, notification);
333
- PendingIntent pendingIntent = PendingIntent.getBroadcast(
334
- context,
335
- request.getId(),
336
- notificationIntent,
337
- PendingIntent.FLAG_CANCEL_CURRENT
338
- );
334
+ int flags = PendingIntent.FLAG_CANCEL_CURRENT;
335
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
336
+ flags = flags | PendingIntent.FLAG_MUTABLE;
337
+ }
338
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, flags);
339
339
 
340
340
  // Schedule at specific time (with repeating support)
341
341
  Date at = schedule.getAt();
@@ -348,11 +348,7 @@ public class LocalNotificationManager {
348
348
  long interval = at.getTime() - new Date().getTime();
349
349
  alarmManager.setRepeating(AlarmManager.RTC, at.getTime(), interval, pendingIntent);
350
350
  } else {
351
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) {
352
- alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC, at.getTime(), pendingIntent);
353
- } else {
354
- alarmManager.setExact(AlarmManager.RTC, at.getTime(), pendingIntent);
355
- }
351
+ setExactIfPossible(alarmManager, schedule, at.getTime(), pendingIntent);
356
352
  }
357
353
  return;
358
354
  }
@@ -373,15 +369,31 @@ public class LocalNotificationManager {
373
369
  if (on != null) {
374
370
  long trigger = on.nextTrigger(new Date());
375
371
  notificationIntent.putExtra(TimedNotificationPublisher.CRON_KEY, on.toMatchString());
376
- pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
372
+ pendingIntent = PendingIntent.getBroadcast(context, request.getId(), notificationIntent, flags);
373
+ setExactIfPossible(alarmManager, schedule, trigger, pendingIntent);
374
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
375
+ Logger.debug(Logger.tags("LN"), "notification " + request.getId() + " will next fire at " + sdf.format(new Date(trigger)));
376
+ }
377
+ }
378
+
379
+ private void setExactIfPossible(
380
+ AlarmManager alarmManager,
381
+ LocalNotificationSchedule schedule,
382
+ long trigger,
383
+ PendingIntent pendingIntent
384
+ ) {
385
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
386
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) {
387
+ alarmManager.setAndAllowWhileIdle(AlarmManager.RTC, trigger, pendingIntent);
388
+ } else {
389
+ alarmManager.set(AlarmManager.RTC, trigger, pendingIntent);
390
+ }
391
+ } else {
377
392
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) {
378
393
  alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC, trigger, pendingIntent);
379
394
  } else {
380
395
  alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent);
381
396
  }
382
-
383
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
384
- Logger.debug(Logger.tags("LN"), "notification " + request.getId() + " will next fire at " + sdf.format(new Date(trigger)));
385
397
  }
386
398
  }
387
399
 
@@ -399,7 +411,11 @@ public class LocalNotificationManager {
399
411
 
400
412
  private void cancelTimerForNotification(Integer notificationId) {
401
413
  Intent intent = new Intent(context, TimedNotificationPublisher.class);
402
- PendingIntent pi = PendingIntent.getBroadcast(context, notificationId, intent, 0);
414
+ int flags = 0;
415
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
416
+ flags = PendingIntent.FLAG_MUTABLE;
417
+ }
418
+ PendingIntent pi = PendingIntent.getBroadcast(context, notificationId, intent, flags);
403
419
  if (pi != null) {
404
420
  AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
405
421
  alarmManager.cancel(pi);
@@ -428,7 +444,7 @@ public class LocalNotificationManager {
428
444
  if (defaultSoundID != AssetUtil.RESOURCE_ID_ZERO_VALUE) return defaultSoundID;
429
445
 
430
446
  int resId = AssetUtil.RESOURCE_ID_ZERO_VALUE;
431
- String soundConfigResourceName = config.getString(CONFIG_KEY_PREFIX + "sound");
447
+ String soundConfigResourceName = config.getString("sound");
432
448
  soundConfigResourceName = AssetUtil.getResourceBaseName(soundConfigResourceName);
433
449
 
434
450
  if (soundConfigResourceName != null) {
@@ -443,7 +459,7 @@ public class LocalNotificationManager {
443
459
  if (defaultSmallIconID != AssetUtil.RESOURCE_ID_ZERO_VALUE) return defaultSmallIconID;
444
460
 
445
461
  int resId = AssetUtil.RESOURCE_ID_ZERO_VALUE;
446
- String smallIconConfigResourceName = config.getString(CONFIG_KEY_PREFIX + "smallIcon");
462
+ String smallIconConfigResourceName = config.getString("smallIcon");
447
463
  smallIconConfigResourceName = AssetUtil.getResourceBaseName(smallIconConfigResourceName);
448
464
 
449
465
  if (smallIconConfigResourceName != null) {
@@ -5,6 +5,7 @@ import static android.os.Build.VERSION.SDK_INT;
5
5
  import android.content.BroadcastReceiver;
6
6
  import android.content.Context;
7
7
  import android.content.Intent;
8
+ import android.os.Build;
8
9
  import android.os.UserManager;
9
10
  import com.getcapacitor.CapConfig;
10
11
  import java.util.ArrayList;
@@ -15,7 +16,7 @@ public class LocalNotificationRestoreReceiver extends BroadcastReceiver {
15
16
 
16
17
  @Override
17
18
  public void onReceive(Context context, Intent intent) {
18
- if (SDK_INT >= 24) {
19
+ if (SDK_INT >= Build.VERSION_CODES.N) {
19
20
  UserManager um = context.getSystemService(UserManager.class);
20
21
  if (um == null || !um.isUserUnlocked()) return;
21
22
  }
@@ -65,6 +65,7 @@ public class LocalNotificationSchedule {
65
65
  on.setYear(onJson.getInteger("year"));
66
66
  on.setMonth(onJson.getInteger("month"));
67
67
  on.setDay(onJson.getInteger("day"));
68
+ on.setWeekday(onJson.getInteger("weekday"));
68
69
  on.setHour(onJson.getInteger("hour"));
69
70
  on.setMinute(onJson.getInteger("minute"));
70
71
  on.setSecond(onJson.getInteger("second"));
@@ -140,7 +141,8 @@ public class LocalNotificationSchedule {
140
141
  public Long getEveryInterval() {
141
142
  switch (every) {
142
143
  case "year":
143
- return count * DateUtils.YEAR_IN_MILLIS;
144
+ // This case is just approximation as not all years have the same number of days
145
+ return count * DateUtils.WEEK_IN_MILLIS * 52;
144
146
  case "month":
145
147
  // This case is just approximation as months have different number of days
146
148
  return count * 30 * DateUtils.DAY_IN_MILLIS;
@@ -1,6 +1,11 @@
1
1
  package com.capacitorjs.plugins.localnotifications;
2
2
 
3
+ import android.app.Notification;
4
+ import android.app.NotificationManager;
5
+ import android.content.Context;
3
6
  import android.content.Intent;
7
+ import android.os.Build;
8
+ import android.service.notification.StatusBarNotification;
4
9
  import com.getcapacitor.Bridge;
5
10
  import com.getcapacitor.JSArray;
6
11
  import com.getcapacitor.JSObject;
@@ -13,12 +18,15 @@ import com.getcapacitor.annotation.Permission;
13
18
  import java.util.List;
14
19
  import java.util.Map;
15
20
  import org.json.JSONArray;
21
+ import org.json.JSONException;
22
+ import org.json.JSONObject;
16
23
 
17
24
  @CapacitorPlugin(name = "LocalNotifications", permissions = @Permission(strings = {}, alias = "display"))
18
25
  public class LocalNotificationsPlugin extends Plugin {
19
26
 
20
27
  private static Bridge staticBridge = null;
21
28
  private LocalNotificationManager manager;
29
+ public NotificationManager notificationManager;
22
30
  private NotificationStorage notificationStorage;
23
31
  private NotificationChannelManager notificationChannelManager;
24
32
 
@@ -29,6 +37,7 @@ public class LocalNotificationsPlugin extends Plugin {
29
37
  manager = new LocalNotificationManager(notificationStorage, getActivity(), getContext(), this.bridge.getConfig());
30
38
  manager.createNotificationChannel();
31
39
  notificationChannelManager = new NotificationChannelManager(getActivity());
40
+ notificationManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
32
41
  staticBridge = this.bridge;
33
42
  }
34
43
 
@@ -97,6 +106,76 @@ public class LocalNotificationsPlugin extends Plugin {
97
106
  call.resolve(data);
98
107
  }
99
108
 
109
+ @PluginMethod
110
+ public void getDeliveredNotifications(PluginCall call) {
111
+ JSArray notifications = new JSArray();
112
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
113
+ StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications();
114
+
115
+ for (StatusBarNotification notif : activeNotifications) {
116
+ JSObject jsNotif = new JSObject();
117
+
118
+ jsNotif.put("id", notif.getId());
119
+ jsNotif.put("tag", notif.getTag());
120
+
121
+ Notification notification = notif.getNotification();
122
+ if (notification != null) {
123
+ jsNotif.put("title", notification.extras.getCharSequence(Notification.EXTRA_TITLE));
124
+ jsNotif.put("body", notification.extras.getCharSequence(Notification.EXTRA_TEXT));
125
+ jsNotif.put("group", notification.getGroup());
126
+ jsNotif.put("groupSummary", 0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY));
127
+
128
+ JSObject extras = new JSObject();
129
+
130
+ for (String key : notification.extras.keySet()) {
131
+ extras.put(key, notification.extras.get(key));
132
+ }
133
+
134
+ jsNotif.put("data", extras);
135
+ }
136
+
137
+ notifications.put(jsNotif);
138
+ }
139
+ }
140
+
141
+ JSObject result = new JSObject();
142
+ result.put("notifications", notifications);
143
+ call.resolve(result);
144
+ }
145
+
146
+ @PluginMethod
147
+ public void removeDeliveredNotifications(PluginCall call) {
148
+ JSArray notifications = call.getArray("notifications");
149
+
150
+ try {
151
+ for (Object o : notifications.toList()) {
152
+ if (o instanceof JSONObject) {
153
+ JSObject notif = JSObject.fromJSONObject((JSONObject) o);
154
+ String tag = notif.getString("tag");
155
+ Integer id = notif.getInteger("id");
156
+
157
+ if (tag == null) {
158
+ notificationManager.cancel(id);
159
+ } else {
160
+ notificationManager.cancel(tag, id);
161
+ }
162
+ } else {
163
+ call.reject("Expected notifications to be a list of notification objects");
164
+ }
165
+ }
166
+ } catch (JSONException e) {
167
+ call.reject(e.getMessage());
168
+ }
169
+
170
+ call.resolve();
171
+ }
172
+
173
+ @PluginMethod
174
+ public void removeAllDeliveredNotifications(PluginCall call) {
175
+ notificationManager.cancelAll();
176
+ call.resolve();
177
+ }
178
+
100
179
  @PluginMethod
101
180
  public void createChannel(PluginCall call) {
102
181
  notificationChannelManager.createChannel(call);
@@ -54,12 +54,8 @@ public class NotificationChannelManager {
54
54
  call.reject("Channel missing name");
55
55
  return;
56
56
  }
57
- if (call.getInt(CHANNEL_IMPORTANCE) != null) {
58
- channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE));
59
- } else {
60
- call.reject("Channel missing importance");
61
- return;
62
- }
57
+
58
+ channel.put(CHANNEL_IMPORTANCE, call.getInt(CHANNEL_IMPORTANCE, NotificationManager.IMPORTANCE_DEFAULT));
63
59
  channel.put(CHANNEL_DESCRIPTION, call.getString(CHANNEL_DESCRIPTION, ""));
64
60
  channel.put(CHANNEL_VISIBILITY, call.getInt(CHANNEL_VISIBILITY, NotificationCompat.VISIBILITY_PUBLIC));
65
61
  channel.put(CHANNEL_SOUND, call.getString(CHANNEL_SOUND, null));
@@ -7,6 +7,7 @@ import android.app.PendingIntent;
7
7
  import android.content.BroadcastReceiver;
8
8
  import android.content.Context;
9
9
  import android.content.Intent;
10
+ import android.os.Build;
10
11
  import com.getcapacitor.JSObject;
11
12
  import com.getcapacitor.Logger;
12
13
  import java.text.SimpleDateFormat;
@@ -49,7 +50,11 @@ public class TimedNotificationPublisher extends BroadcastReceiver {
49
50
  long trigger = date.nextTrigger(new Date());
50
51
  Intent clone = (Intent) intent.clone();
51
52
  PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, clone, PendingIntent.FLAG_CANCEL_CURRENT);
52
- alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent);
53
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
54
+ alarmManager.set(AlarmManager.RTC, trigger, pendingIntent);
55
+ } else {
56
+ alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent);
57
+ }
53
58
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
54
59
  Logger.debug(Logger.tags("LN"), "notification " + id + " will next fire at " + sdf.format(new Date(trigger)));
55
60
  return true;
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:width="16dp"
4
+ android:height="16dp"
5
+ android:viewportHeight="108"
6
+ android:viewportWidth="108">
7
+
8
+ <path
9
+ android:width="1dp"
10
+ android:color="@android:color/transparent" />
11
+
12
+ </vector>