@capacitor/background-runner 2.0.0 → 2.2.0

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.
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.author = package['author']
12
12
  s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
13
  s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'packages/capacitor-plugin/ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}', 'packages/ios-engine/Sources/RunnerEngine/*.swift'
14
- s.ios.deployment_target = '13.0'
14
+ s.ios.deployment_target = '14.0'
15
15
  s.dependency 'Capacitor'
16
16
  s.swift_version = '5.1'
17
17
  end
package/README.md CHANGED
@@ -269,7 +269,7 @@ Visit [Don't kill my app!](https://dontkillmyapp.com) for more information on th
269
269
 
270
270
  ## Limitations of Background Tasks
271
271
 
272
- It’s not possible to run persistent, always running background services on mobile operating systems. Due to the limitations imposed by iOS and Android designed to reduce battery and data consumption, background tasks are constrained with various limitations that you must keep in mind while designing and implementing your background task.
272
+ It's not possible to run persistent, always running background services on mobile operating systems. Due to the limitations imposed by iOS and Android designed to reduce battery and data consumption, background tasks are constrained with various limitations that you must keep in mind while designing and implementing your background task.
273
273
 
274
274
  ### iOS
275
275
 
@@ -289,6 +289,8 @@ It’s not possible to run persistent, always running background services on mob
289
289
  * [`checkPermissions()`](#checkpermissions)
290
290
  * [`requestPermissions(...)`](#requestpermissions)
291
291
  * [`dispatchEvent(...)`](#dispatchevent)
292
+ * [`addListener('backgroundRunnerNotificationReceived', ...)`](#addlistenerbackgroundrunnernotificationreceived-)
293
+ * [`removeNotificationListeners()`](#removenotificationlisteners)
292
294
  * [Interfaces](#interfaces)
293
295
  * [Type Aliases](#type-aliases)
294
296
 
@@ -350,6 +352,41 @@ Dispatches an event to the configured runner.
350
352
  --------------------
351
353
 
352
354
 
355
+ ### addListener('backgroundRunnerNotificationReceived', ...)
356
+
357
+ ```typescript
358
+ addListener(eventName: 'backgroundRunnerNotificationReceived', listenerFunc: (event: NotificationActionEvent) => void) => any
359
+ ```
360
+
361
+ Add a listener for notification actions.
362
+
363
+ | Param | Type |
364
+ | ------------------ | ----------------------------------------------------------------------------------------------- |
365
+ | **`eventName`** | <code>'backgroundRunnerNotificationReceived'</code> |
366
+ | **`listenerFunc`** | <code>(event: <a href="#notificationactionevent">NotificationActionEvent</a>) =&gt; void</code> |
367
+
368
+ **Returns:** <code>any</code>
369
+
370
+ **Since:** 2.1.1
371
+
372
+ --------------------
373
+
374
+
375
+ ### removeNotificationListeners()
376
+
377
+ ```typescript
378
+ removeNotificationListeners() => any
379
+ ```
380
+
381
+ Remove notification action listeners for this plugin.
382
+
383
+ **Returns:** <code>any</code>
384
+
385
+ **Since:** 2.1.1
386
+
387
+ --------------------
388
+
389
+
353
390
  ### Interfaces
354
391
 
355
392
 
@@ -377,6 +414,21 @@ Dispatches an event to the configured runner.
377
414
  | **`details`** | <code>{ [key: string]: any; }</code> | | |
378
415
 
379
416
 
417
+ #### NotificationActionEvent
418
+
419
+ | Prop | Type |
420
+ | -------------------- | ------------------- |
421
+ | **`actionTypeId`** | <code>string</code> |
422
+ | **`notificationId`** | <code>number</code> |
423
+
424
+
425
+ #### PluginListenerHandle
426
+
427
+ | Prop | Type |
428
+ | ------------ | ------------------------- |
429
+ | **`remove`** | <code>() =&gt; any</code> |
430
+
431
+
380
432
  ### Type Aliases
381
433
 
382
434
 
@@ -1,21 +1,21 @@
1
1
  ext {
2
2
  junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
- androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
4
4
  androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.12.0'
5
- androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
6
- androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
5
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
6
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
7
7
  workManagerVersion = project.hasProperty('workManagerVersion') ? rootProject.ext.workManagerVersion : '2.8.1'
8
8
 
9
9
  }
10
10
 
11
11
  buildscript {
12
- ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.10'
12
+ ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '1.9.25'
13
13
  repositories {
14
14
  google()
15
15
  mavenCentral()
16
16
  }
17
17
  dependencies {
18
- classpath 'com.android.tools.build:gradle:8.2.1'
18
+ classpath 'com.android.tools.build:gradle:8.7.2'
19
19
  classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
20
20
 
21
21
  }
@@ -26,10 +26,10 @@ apply plugin: 'org.jetbrains.kotlin.android'
26
26
 
27
27
  android {
28
28
  namespace "com.capacitorjs.plugins.backgroundrunner"
29
- compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
29
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
30
30
  defaultConfig {
31
- minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
32
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
31
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
32
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
33
33
  versionCode 1
34
34
  versionName "1.0"
35
35
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -44,8 +44,8 @@ android {
44
44
  abortOnError false
45
45
  }
46
46
  compileOptions {
47
- sourceCompatibility JavaVersion.VERSION_17
48
- targetCompatibility JavaVersion.VERSION_17
47
+ sourceCompatibility JavaVersion.VERSION_21
48
+ targetCompatibility JavaVersion.VERSION_21
49
49
  }
50
50
  }
51
51
 
@@ -14,6 +14,8 @@ import kotlinx.coroutines.Dispatchers
14
14
  import kotlinx.coroutines.GlobalScope
15
15
  import kotlinx.coroutines.launch
16
16
  import kotlinx.coroutines.runBlocking
17
+ import android.content.Intent
18
+ import com.getcapacitor.Bridge
17
19
 
18
20
 
19
21
  @CapacitorPlugin(
@@ -125,4 +127,46 @@ class BackgroundRunnerPlugin: Plugin() {
125
127
  fun registerBackgroundTask(call: PluginCall) {
126
128
  call.resolve()
127
129
  }
130
+
131
+ override fun handleOnNewIntent(intent: Intent) {
132
+ super.handleOnNewIntent(intent)
133
+
134
+ Log.d("BackgroundRunner", "handleOnNewIntent with action: ${intent.action}")
135
+
136
+ if (intent.action == ".NOTIFICATION_CLICKED") {
137
+ val actionTypeId = intent.getStringExtra("actionTypeId")
138
+ val notificationId = intent.getIntExtra("notificationId", -1)
139
+
140
+ // Create notification action data
141
+ val notificationAction = if (actionTypeId != null) {
142
+ JSObject().apply {
143
+ put("actionTypeId", actionTypeId)
144
+ put("notificationId", notificationId)
145
+ }
146
+ } else null
147
+
148
+ // Launch the app using proper intent flags
149
+ val packageName = context.packageName
150
+ val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)?.apply {
151
+ action = Intent.ACTION_MAIN
152
+ addCategory(Intent.CATEGORY_LAUNCHER)
153
+ flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
154
+ }
155
+
156
+ if (launchIntent != null) {
157
+ context.startActivity(launchIntent)
158
+
159
+ // Notify listeners about the action with retention
160
+ notificationAction?.let {
161
+ notifyListeners("backgroundRunnerNotificationReceived", it, true)
162
+ }
163
+ }
164
+ }
165
+ }
166
+
167
+ @PluginMethod
168
+ fun removeNotificationListeners(call: PluginCall) {
169
+ notifyListeners("backgroundRunnerNotificationReceived", null)
170
+ call.resolve()
171
+ }
128
172
  }
@@ -20,7 +20,7 @@ class Notification(jsonObject: JSONObject) {
20
20
  var sound: String? = null
21
21
  var smallIcon: String? = null
22
22
  var largeIcon: String? = null
23
- var actionTypeID: String? = null
23
+ var actionTypeId: String? = null
24
24
  var extra: HashMap<String, Any>? = null
25
25
  var group: String? = null
26
26
  var groupSummary: String? = null
@@ -32,8 +32,10 @@ class Notification(jsonObject: JSONObject) {
32
32
  id = jsonObject.optInt("id", -1)
33
33
  title = jsonObject.optString("title", "")
34
34
  body = jsonObject.optString("body", "")
35
+ smallIcon = jsonObject.optString("smallIcon", "")
35
36
  ongoing = jsonObject.optBoolean("ongoing", false)
36
37
  autoCancel = jsonObject.optBoolean("autoCancel", false)
38
+ actionTypeId = jsonObject.optString("actionTypeId", null)
37
39
 
38
40
  val scheduleDateString = jsonObject.optString("scheduleAt", "")
39
41
  if (scheduleDateString.isNotEmpty()) {
@@ -59,4 +61,4 @@ class Notification(jsonObject: JSONObject) {
59
61
 
60
62
  return resId
61
63
  }
62
- }
64
+ }
@@ -92,6 +92,27 @@ class Notifications(context: Context) : NotificationsAPI {
92
92
  builder.setGroupSummary(it.groupSummary != null)
93
93
  builder.setSmallIcon(it.smallIcon(this.context, getDefaultSmallIcon()))
94
94
 
95
+ // Add action intent handling
96
+ val actionIntent = Intent(".NOTIFICATION_CLICKED").apply {
97
+ `package` = context.packageName
98
+ putExtra("actionTypeId", it.actionTypeId)
99
+ putExtra("notificationId", it.id)
100
+ }
101
+
102
+ val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
103
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
104
+ } else {
105
+ PendingIntent.FLAG_UPDATE_CURRENT
106
+ }
107
+
108
+ val pendingActionIntent = PendingIntent.getActivity(
109
+ context,
110
+ it.id,
111
+ actionIntent,
112
+ flags
113
+ )
114
+ builder.setContentIntent(pendingActionIntent)
115
+
95
116
  val largeBody = it.largeBody
96
117
  if (largeBody != null) {
97
118
  val style = NotificationCompat.BigTextStyle()
package/dist/docs.json CHANGED
@@ -73,6 +73,50 @@
73
73
  "T"
74
74
  ],
75
75
  "slug": "dispatchevent"
76
+ },
77
+ {
78
+ "name": "addListener",
79
+ "signature": "(eventName: 'backgroundRunnerNotificationReceived', listenerFunc: (event: NotificationActionEvent) => void) => any",
80
+ "parameters": [
81
+ {
82
+ "name": "eventName",
83
+ "docs": "",
84
+ "type": "'backgroundRunnerNotificationReceived'"
85
+ },
86
+ {
87
+ "name": "listenerFunc",
88
+ "docs": "",
89
+ "type": "(event: NotificationActionEvent) => void"
90
+ }
91
+ ],
92
+ "returns": "any",
93
+ "tags": [
94
+ {
95
+ "name": "since",
96
+ "text": "2.1.1"
97
+ }
98
+ ],
99
+ "docs": "Add a listener for notification actions.",
100
+ "complexTypes": [
101
+ "NotificationActionEvent",
102
+ "PluginListenerHandle"
103
+ ],
104
+ "slug": "addlistenerbackgroundrunnernotificationreceived-"
105
+ },
106
+ {
107
+ "name": "removeNotificationListeners",
108
+ "signature": "() => any",
109
+ "parameters": [],
110
+ "returns": "any",
111
+ "tags": [
112
+ {
113
+ "name": "since",
114
+ "text": "2.1.1"
115
+ }
116
+ ],
117
+ "docs": "Remove notification action listeners for this plugin.",
118
+ "complexTypes": [],
119
+ "slug": "removenotificationlisteners"
76
120
  }
77
121
  ],
78
122
  "properties": []
@@ -162,6 +206,45 @@
162
206
  "type": "{ [key: string]: any; }"
163
207
  }
164
208
  ]
209
+ },
210
+ {
211
+ "name": "NotificationActionEvent",
212
+ "slug": "notificationactionevent",
213
+ "docs": "",
214
+ "tags": [],
215
+ "methods": [],
216
+ "properties": [
217
+ {
218
+ "name": "actionTypeId",
219
+ "tags": [],
220
+ "docs": "",
221
+ "complexTypes": [],
222
+ "type": "string"
223
+ },
224
+ {
225
+ "name": "notificationId",
226
+ "tags": [],
227
+ "docs": "",
228
+ "complexTypes": [],
229
+ "type": "number"
230
+ }
231
+ ]
232
+ },
233
+ {
234
+ "name": "PluginListenerHandle",
235
+ "slug": "pluginlistenerhandle",
236
+ "docs": "",
237
+ "tags": [],
238
+ "methods": [],
239
+ "properties": [
240
+ {
241
+ "name": "remove",
242
+ "tags": [],
243
+ "docs": "",
244
+ "complexTypes": [],
245
+ "type": "() => any"
246
+ }
247
+ ]
165
248
  }
166
249
  ],
167
250
  "enums": [],
@@ -1,4 +1,4 @@
1
- import type { PermissionState } from '@capacitor/core';
1
+ import type { PermissionState, PluginListenerHandle } from '@capacitor/core';
2
2
  export interface BackgroundRunnerConfig {
3
3
  /**
4
4
  * The name of the runner, used in logs.
@@ -122,6 +122,10 @@ export interface RequestPermissionOptions {
122
122
  export interface RegisterBackgroundTaskOptions {
123
123
  runner: BackgroundRunnerConfig;
124
124
  }
125
+ export interface NotificationActionEvent {
126
+ actionTypeId: string;
127
+ notificationId: number;
128
+ }
125
129
  export interface BackgroundRunnerPlugin {
126
130
  /**
127
131
  * Check permissions for the various Capacitor device APIs.
@@ -141,6 +145,18 @@ export interface BackgroundRunnerPlugin {
141
145
  * @since 1.0.0
142
146
  */
143
147
  dispatchEvent<T = void>(options: DispatchEventOptions): Promise<T>;
148
+ /**
149
+ * Add a listener for notification actions.
150
+ *
151
+ * @since 2.1.1
152
+ */
153
+ addListener(eventName: 'backgroundRunnerNotificationReceived', listenerFunc: (event: NotificationActionEvent) => void): Promise<PluginListenerHandle>;
154
+ /**
155
+ * Remove notification action listeners for this plugin.
156
+ *
157
+ * @since 2.1.1
158
+ */
159
+ removeNotificationListeners(): Promise<void>;
144
160
  }
145
161
  declare module '@capacitor/cli' {
146
162
  interface PluginsConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\nimport type { PermissionState } from '@capacitor/core';\n\nexport interface BackgroundRunnerConfig {\n /**\n * The name of the runner, used in logs.\n *\n * @since 1.0.0\n */\n label: string;\n /**\n * The path to the runner JavaScript file, relative to the app bundle.\n *\n * @since 1.0.0\n */\n src: string;\n /**\n * The name of the event that will be called when the OS executes the background task.\n *\n * @since 1.0.0\n */\n event: string;\n /**\n * If background task should repeat based on the interval set in `interval`.\n *\n * @since 1.0.0\n */\n repeat: boolean;\n /**\n * The number of minutes after the the app is put into the background in which the background task should begin.\n *\n * If `repeat` is true, this also specifies the number of minutes between each execution.\n *\n * @since 1.0.0\n */\n interval: number;\n /**\n * Automatically register and schedule background task on app load.\n *\n * @since 1.0.0\n */\n autoStart?: boolean;\n}\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * On load, Background Runner will automatically register a\n * background task that will be scheduled and run once your app is\n * backgrounded.\n */\n BackgroundRunner?: {\n /**\n * The name of the runner, used in logs.\n *\n * @since 1.0.0\n * @example \"com.example.background.task\"\n */\n label: string;\n /**\n * The path to the runner JavaScript file, relative to the app bundle.\n *\n * @since 1.0.0\n * @example \"runners/background.js\"\n */\n src: string;\n /**\n * The name of the event that will be called when the OS executes the background task.\n *\n * @since 1.0.0\n * @example \"myCustomEvent\"\n */\n event: string;\n /**\n * If background task should repeat based on the interval set in `interval`.\n *\n * @since 1.0.0\n * @example true\n */\n repeat: boolean;\n /**\n * The number of minutes after the the app is put into the background in which the background task should begin.\n *\n * If `repeat` is true, this also specifies the number of minutes between each execution.\n *\n * @since 1.0.0\n * @example 15\n */\n interval: number;\n /**\n * Automatically register and schedule background task on app load.\n *\n * @since 1.0.0\n * @example true\n */\n autoStart?: boolean;\n };\n }\n}\n\nexport type API = 'geolocation' | 'notifications';\n\nexport interface PermissionStatus {\n geolocation: PermissionState;\n notifications: PermissionState;\n}\n\nexport interface DispatchEventOptions {\n /**\n * The runner label to dispatch the event to\n *\n * @since 1.0.0\n */\n label: string;\n /**\n * The name of the registered event listener.\n *\n * @since 1.0.0\n */\n event: string;\n details: { [key: string]: any };\n}\n\nexport interface RequestPermissionOptions {\n apis: API[];\n}\n\nexport interface RegisterBackgroundTaskOptions {\n runner: BackgroundRunnerConfig;\n}\n\nexport interface BackgroundRunnerPlugin {\n /**\n * Check permissions for the various Capacitor device APIs.\n *\n * @since 1.0.0\n */\n checkPermissions(): Promise<PermissionStatus>;\n /**\n * Request permission to display local notifications.\n *\n * @since 1.0.0\n */\n requestPermissions(\n options: RequestPermissionOptions,\n ): Promise<PermissionStatus>;\n /**\n * Dispatches an event to the configured runner.\n * @param options\n * @since 1.0.0\n */\n dispatchEvent<T = void>(options: DispatchEventOptions): Promise<T>;\n}\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n BackgroundRunner?: BackgroundRunnerConfig;\n }\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\nimport type { PermissionState, PluginListenerHandle } from '@capacitor/core';\n\nexport interface BackgroundRunnerConfig {\n /**\n * The name of the runner, used in logs.\n *\n * @since 1.0.0\n */\n label: string;\n /**\n * The path to the runner JavaScript file, relative to the app bundle.\n *\n * @since 1.0.0\n */\n src: string;\n /**\n * The name of the event that will be called when the OS executes the background task.\n *\n * @since 1.0.0\n */\n event: string;\n /**\n * If background task should repeat based on the interval set in `interval`.\n *\n * @since 1.0.0\n */\n repeat: boolean;\n /**\n * The number of minutes after the the app is put into the background in which the background task should begin.\n *\n * If `repeat` is true, this also specifies the number of minutes between each execution.\n *\n * @since 1.0.0\n */\n interval: number;\n /**\n * Automatically register and schedule background task on app load.\n *\n * @since 1.0.0\n */\n autoStart?: boolean;\n}\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * On load, Background Runner will automatically register a\n * background task that will be scheduled and run once your app is\n * backgrounded.\n */\n BackgroundRunner?: {\n /**\n * The name of the runner, used in logs.\n *\n * @since 1.0.0\n * @example \"com.example.background.task\"\n */\n label: string;\n /**\n * The path to the runner JavaScript file, relative to the app bundle.\n *\n * @since 1.0.0\n * @example \"runners/background.js\"\n */\n src: string;\n /**\n * The name of the event that will be called when the OS executes the background task.\n *\n * @since 1.0.0\n * @example \"myCustomEvent\"\n */\n event: string;\n /**\n * If background task should repeat based on the interval set in `interval`.\n *\n * @since 1.0.0\n * @example true\n */\n repeat: boolean;\n /**\n * The number of minutes after the the app is put into the background in which the background task should begin.\n *\n * If `repeat` is true, this also specifies the number of minutes between each execution.\n *\n * @since 1.0.0\n * @example 15\n */\n interval: number;\n /**\n * Automatically register and schedule background task on app load.\n *\n * @since 1.0.0\n * @example true\n */\n autoStart?: boolean;\n };\n }\n}\n\nexport type API = 'geolocation' | 'notifications';\n\nexport interface PermissionStatus {\n geolocation: PermissionState;\n notifications: PermissionState;\n}\n\nexport interface DispatchEventOptions {\n /**\n * The runner label to dispatch the event to\n *\n * @since 1.0.0\n */\n label: string;\n /**\n * The name of the registered event listener.\n *\n * @since 1.0.0\n */\n event: string;\n details: { [key: string]: any };\n}\n\nexport interface RequestPermissionOptions {\n apis: API[];\n}\n\nexport interface RegisterBackgroundTaskOptions {\n runner: BackgroundRunnerConfig;\n}\n\nexport interface NotificationActionEvent {\n actionTypeId: string;\n notificationId: number;\n}\n\nexport interface BackgroundRunnerPlugin {\n /**\n * Check permissions for the various Capacitor device APIs.\n *\n * @since 1.0.0\n */\n checkPermissions(): Promise<PermissionStatus>;\n /**\n * Request permission to display local notifications.\n *\n * @since 1.0.0\n */\n requestPermissions(\n options: RequestPermissionOptions,\n ): Promise<PermissionStatus>;\n /**\n * Dispatches an event to the configured runner.\n * @param options\n * @since 1.0.0\n */\n dispatchEvent<T = void>(options: DispatchEventOptions): Promise<T>;\n /**\n * Add a listener for notification actions.\n *\n * @since 2.1.1\n */\n addListener(\n eventName: 'backgroundRunnerNotificationReceived',\n listenerFunc: (event: NotificationActionEvent) => void,\n ): Promise<PluginListenerHandle>;\n /**\n * Remove notification action listeners for this plugin.\n *\n * @since 2.1.1\n */\n removeNotificationListeners(): Promise<void>;\n}\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n BackgroundRunner?: BackgroundRunnerConfig;\n }\n}\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,8 +1,11 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core';
1
2
  import { WebPlugin } from '@capacitor/core';
2
- import type { BackgroundRunnerPlugin, DispatchEventOptions, PermissionStatus } from './definitions';
3
+ import type { BackgroundRunnerPlugin, DispatchEventOptions, PermissionStatus, NotificationActionEvent } from './definitions';
3
4
  export declare class BackgroundRunnerWeb extends WebPlugin implements BackgroundRunnerPlugin {
4
5
  checkPermissions(): Promise<PermissionStatus>;
5
6
  requestPermissions(): Promise<PermissionStatus>;
6
7
  registerBackgroundTask(): Promise<void>;
7
8
  dispatchEvent<T = void>(_options: DispatchEventOptions): Promise<T>;
9
+ addListener(_eventName: 'backgroundRunnerNotificationReceived', _listenerFunc: (event: NotificationActionEvent) => void): Promise<PluginListenerHandle>;
10
+ removeNotificationListeners(): Promise<void>;
8
11
  }
package/dist/esm/web.js CHANGED
@@ -12,5 +12,11 @@ export class BackgroundRunnerWeb extends WebPlugin {
12
12
  dispatchEvent(_options) {
13
13
  throw new Error('not available on web');
14
14
  }
15
+ async addListener(_eventName, _listenerFunc) {
16
+ throw new Error('not available on web');
17
+ }
18
+ async removeNotificationListeners() {
19
+ throw new Error('not available on web');
20
+ }
15
21
  }
16
22
  //# sourceMappingURL=web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQ5C,MAAM,OAAO,mBACX,SAAQ,SAAS;IAGjB,gBAAgB;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,kBAAkB;QAChB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,sBAAsB;QACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,aAAa,CAAW,QAA8B;QACpD,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n BackgroundRunnerPlugin,\n DispatchEventOptions,\n PermissionStatus,\n} from './definitions';\n\nexport class BackgroundRunnerWeb\n extends WebPlugin\n implements BackgroundRunnerPlugin\n{\n checkPermissions(): Promise<PermissionStatus> {\n throw new Error('not available on web');\n }\n\n requestPermissions(): Promise<PermissionStatus> {\n throw new Error('not available on web');\n }\n\n registerBackgroundTask(): Promise<void> {\n throw new Error('not available on web');\n }\n\n dispatchEvent<T = void>(_options: DispatchEventOptions): Promise<T> {\n throw new Error('not available on web');\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,MAAM,OAAO,mBACX,SAAQ,SAAS;IAGjB,gBAAgB;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,kBAAkB;QAChB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,sBAAsB;QACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,aAAa,CAAW,QAA8B;QACpD,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,WAAW,CACf,UAAkD,EAClD,aAAuD;QAEvD,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,2BAA2B;QAC/B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\nimport { WebPlugin } from '@capacitor/core';\n\nimport type {\n BackgroundRunnerPlugin,\n DispatchEventOptions,\n PermissionStatus,\n NotificationActionEvent,\n} from './definitions';\n\nexport class BackgroundRunnerWeb\n extends WebPlugin\n implements BackgroundRunnerPlugin\n{\n checkPermissions(): Promise<PermissionStatus> {\n throw new Error('not available on web');\n }\n\n requestPermissions(): Promise<PermissionStatus> {\n throw new Error('not available on web');\n }\n\n registerBackgroundTask(): Promise<void> {\n throw new Error('not available on web');\n }\n\n dispatchEvent<T = void>(_options: DispatchEventOptions): Promise<T> {\n throw new Error('not available on web');\n }\n\n async addListener(\n _eventName: 'backgroundRunnerNotificationReceived',\n _listenerFunc: (event: NotificationActionEvent) => void,\n ): Promise<PluginListenerHandle> {\n throw new Error('not available on web');\n }\n\n async removeNotificationListeners(): Promise<void> {\n throw new Error('not available on web');\n }\n}\n"]}
@@ -21,6 +21,12 @@ class BackgroundRunnerWeb extends core.WebPlugin {
21
21
  dispatchEvent(_options) {
22
22
  throw new Error('not available on web');
23
23
  }
24
+ async addListener(_eventName, _listenerFunc) {
25
+ throw new Error('not available on web');
26
+ }
27
+ async removeNotificationListeners() {
28
+ throw new Error('not available on web');
29
+ }
24
30
  }
25
31
 
26
32
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('BackgroundRunner', {\n web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),\n});\nexport * from './definitions';\nexport * from './apis';\nexport { BackgroundRunner };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class BackgroundRunnerWeb extends WebPlugin {\n checkPermissions() {\n throw new Error('not available on web');\n }\n requestPermissions() {\n throw new Error('not available on web');\n }\n registerBackgroundTask() {\n throw new Error('not available on web');\n }\n dispatchEvent(_options) {\n throw new Error('not available on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,gBAAgB,GAAGA,mBAAc,CAAC,kBAAkB,EAAE;AAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;AACrE,CAAC;;ACFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;AACnD,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,kBAAkB,GAAG;AACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,sBAAsB,GAAG;AAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,aAAa,CAAC,QAAQ,EAAE;AAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('BackgroundRunner', {\n web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),\n});\nexport * from './definitions';\nexport * from './apis';\nexport { BackgroundRunner };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class BackgroundRunnerWeb extends WebPlugin {\n checkPermissions() {\n throw new Error('not available on web');\n }\n requestPermissions() {\n throw new Error('not available on web');\n }\n registerBackgroundTask() {\n throw new Error('not available on web');\n }\n dispatchEvent(_options) {\n throw new Error('not available on web');\n }\n async addListener(_eventName, _listenerFunc) {\n throw new Error('not available on web');\n }\n async removeNotificationListeners() {\n throw new Error('not available on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,gBAAgB,GAAGA,mBAAc,CAAC,kBAAkB,EAAE;AAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;AACrE,CAAC;;ACFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;AACnD,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,kBAAkB,GAAG;AACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,sBAAsB,GAAG;AAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,aAAa,CAAC,QAAQ,EAAE;AAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,MAAM,WAAW,CAAC,UAAU,EAAE,aAAa,EAAE;AACjD,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL,IAAI,MAAM,2BAA2B,GAAG;AACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAChD,KAAK;AACL;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -18,6 +18,12 @@ var capacitorBackgroundRunner = (function (exports, core) {
18
18
  dispatchEvent(_options) {
19
19
  throw new Error('not available on web');
20
20
  }
21
+ async addListener(_eventName, _listenerFunc) {
22
+ throw new Error('not available on web');
23
+ }
24
+ async removeNotificationListeners() {
25
+ throw new Error('not available on web');
26
+ }
21
27
  }
22
28
 
23
29
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('BackgroundRunner', {\n web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),\n});\nexport * from './definitions';\nexport * from './apis';\nexport { BackgroundRunner };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class BackgroundRunnerWeb extends WebPlugin {\n checkPermissions() {\n throw new Error('not available on web');\n }\n requestPermissions() {\n throw new Error('not available on web');\n }\n registerBackgroundTask() {\n throw new Error('not available on web');\n }\n dispatchEvent(_options) {\n throw new Error('not available on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,gBAAgB,GAAGA,mBAAc,CAAC,kBAAkB,EAAE;IAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;IACrE,CAAC;;ICFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;IACnD,IAAI,gBAAgB,GAAG;IACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,kBAAkB,GAAG;IACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,sBAAsB,GAAG;IAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,aAAa,CAAC,QAAQ,EAAE;IAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('BackgroundRunner', {\n web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),\n});\nexport * from './definitions';\nexport * from './apis';\nexport { BackgroundRunner };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class BackgroundRunnerWeb extends WebPlugin {\n checkPermissions() {\n throw new Error('not available on web');\n }\n requestPermissions() {\n throw new Error('not available on web');\n }\n registerBackgroundTask() {\n throw new Error('not available on web');\n }\n dispatchEvent(_options) {\n throw new Error('not available on web');\n }\n async addListener(_eventName, _listenerFunc) {\n throw new Error('not available on web');\n }\n async removeNotificationListeners() {\n throw new Error('not available on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,gBAAgB,GAAGA,mBAAc,CAAC,kBAAkB,EAAE;IAC5D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;IACrE,CAAC;;ICFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;IACnD,IAAI,gBAAgB,GAAG;IACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,kBAAkB,GAAG;IACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,sBAAsB,GAAG;IAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,aAAa,CAAC,QAAQ,EAAE;IAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,MAAM,WAAW,CAAC,UAAU,EAAE,aAAa,EAAE;IACjD,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL,IAAI,MAAM,2BAA2B,GAAG;IACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAChD,KAAK;IACL;;;;;;;;;;;;;;;;;"}
@@ -8,4 +8,5 @@ CAP_PLUGIN(BackgroundRunnerPlugin, "BackgroundRunner",
8
8
  CAP_PLUGIN_METHOD(registerBackgroundTask, CAPPluginReturnPromise);
9
9
  CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise);
10
10
  CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
11
+ CAP_PLUGIN_METHOD(removeNotificationListeners, CAPPluginReturnPromise);
11
12
  )
@@ -1,6 +1,7 @@
1
1
  import Foundation
2
2
  import Capacitor
3
3
  import WatchConnectivity
4
+ import UserNotifications
4
5
 
5
6
  @objc(BackgroundRunnerPlugin)
6
7
  public class BackgroundRunnerPlugin: CAPPlugin {
@@ -14,6 +15,9 @@ public class BackgroundRunnerPlugin: CAPPlugin {
14
15
  object: nil
15
16
  )
16
17
 
18
+ // Register as notification delegate
19
+ registerNotificationCategories()
20
+
17
21
  initWatchConnectivity()
18
22
  }
19
23
 
@@ -95,6 +99,11 @@ public class BackgroundRunnerPlugin: CAPPlugin {
95
99
  call.resolve()
96
100
  }
97
101
 
102
+ @objc func removeNotificationListeners(_ call: CAPPluginCall) {
103
+ notifyListeners("backgroundRunnerNotificationReceived", data: nil)
104
+ call.resolve()
105
+ }
106
+
98
107
  @objc private func didEnterBackground() {
99
108
  do {
100
109
  try impl.scheduleBackgroundTasks()
@@ -175,4 +184,45 @@ public class BackgroundRunnerPlugin: CAPPlugin {
175
184
 
176
185
  print("Watch Connectivity Enabled")
177
186
  }
187
+
188
+ @objc func registerNotificationCategories() {
189
+ let notificationCenter = UNUserNotificationCenter.current()
190
+
191
+ // Set the plugin as the notification delegate
192
+ notificationCenter.delegate = self
193
+ }
194
+ }
195
+
196
+ // MARK: - UNUserNotificationCenterDelegate
197
+ extension BackgroundRunnerPlugin: UNUserNotificationCenterDelegate {
198
+ // This method will be called when a notification is tapped
199
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
200
+ didReceive response: UNNotificationResponse,
201
+ withCompletionHandler completionHandler: @escaping () -> Void) {
202
+ let actionTypeId = response.notification.request.content.categoryIdentifier
203
+ let notificationId = Int(response.notification.request.identifier) ?? -1
204
+
205
+ // Create event data
206
+ let eventData: [String: Any] = [
207
+ "actionTypeId": actionTypeId,
208
+ "notificationId": notificationId
209
+ ]
210
+
211
+ // Notify listeners with the action data - the 'true' parameter is for retaining the event
212
+ notifyListeners("backgroundRunnerNotificationReceived", data: eventData, retainUntilConsumed: true)
213
+
214
+ completionHandler()
215
+ }
216
+
217
+ // This is needed to present notifications when the app is in the foreground
218
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
219
+ willPresent notification: UNNotification,
220
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
221
+ // Show the notification even when the app is in foreground
222
+ if #available(iOS 14.0, *) {
223
+ completionHandler([.banner, .sound, .badge])
224
+ } else {
225
+ completionHandler([.alert, .sound, .badge])
226
+ }
227
+ }
178
228
  }
@@ -195,7 +195,7 @@ class CapacitorNotifications: NSObject, CapacitorNotificationsExports {
195
195
 
196
196
  let badgeOptions = SetBadgeOption(from: jsonDict)
197
197
 
198
- DispatchQueue.main.sync {
198
+ DispatchQueue.main.async {
199
199
  if #available(iOS 16.0, *) {
200
200
  UNUserNotificationCenter.current().setBadgeCount(badgeOptions.count)
201
201
  } else {
@@ -213,7 +213,7 @@ class CapacitorNotifications: NSObject, CapacitorNotificationsExports {
213
213
  throw CapacitorNotificationsErrors.permissionDenied
214
214
  }
215
215
 
216
- DispatchQueue.main.sync {
216
+ DispatchQueue.main.async {
217
217
  if #available(iOS 16.0, *) {
218
218
  UNUserNotificationCenter.current().setBadgeCount(0)
219
219
  } else {
@@ -191,7 +191,7 @@ public extension Reachability {
191
191
  _ = unmanagedWeakifiedReachability.retain()
192
192
  return UnsafeRawPointer(unmanagedWeakifiedReachability.toOpaque())
193
193
  },
194
- release: { (info: UnsafeRawPointer) -> Void in
194
+ release: { (info: UnsafeRawPointer) in
195
195
  let unmanagedWeakifiedReachability = Unmanaged<ReachabilityWeakifier>.fromOpaque(info)
196
196
  unmanagedWeakifiedReachability.release()
197
197
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/background-runner",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Capacitor Background Runner",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -66,7 +66,7 @@
66
66
  "typescript": "^5.1.6"
67
67
  },
68
68
  "peerDependencies": {
69
- "@capacitor/core": "^6.0.0"
69
+ "@capacitor/core": "^6.0.0 || ^7.0.0"
70
70
  },
71
71
  "prettier": "@ionic/prettier-config",
72
72
  "swiftlint": "@ionic/swiftlint-config",
@@ -81,5 +81,5 @@
81
81
  "src": "android"
82
82
  }
83
83
  },
84
- "gitHead": "c290f3cd6372453b2679a4255f822fc91664fe77"
84
+ "gitHead": "9bd41296af96580537f63bb51a64f37a6e76a645"
85
85
  }