@capacitor/background-runner 2.2.0 → 2.3.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.
Files changed (44) hide show
  1. package/CapacitorBackgroundRunner.podspec +1 -1
  2. package/Package.swift +45 -0
  3. package/README.md +12 -2
  4. package/android/src/main/java/io/ionic/backgroundrunner/plugin/BackgroundRunnerPlugin.kt +1 -1
  5. package/android/src/main/libs/android-js-engine-release.aar +0 -0
  6. package/dist/esm/definitions.js.map +1 -1
  7. package/dist/esm/index.js +2 -2
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/web.js.map +1 -1
  10. package/dist/plugin.cjs.js +2 -4
  11. package/dist/plugin.cjs.js.map +1 -1
  12. package/dist/plugin.js +2 -4
  13. package/dist/plugin.js.map +1 -1
  14. package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/BackgroundRunner.swift +26 -11
  15. package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Geolocation.swift +21 -9
  16. package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Notifications.swift +2 -1
  17. package/ios/{Plugin/BackgroundRunnerPlugin.swift → Sources/CapacitorBackgroundRunner/CapacitorBackgroundRunner.swift} +62 -9
  18. package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/Context+CapacitorAPI.swift +8 -2
  19. package/ios/{Plugin → Sources}/RunnerEngine/Context.swift +1 -1
  20. package/ios/{Plugin → Sources}/RunnerEngine/JSCrypto.swift +3 -3
  21. package/ios/{Plugin → Sources}/RunnerEngine/JSError.swift +1 -1
  22. package/ios/{Plugin → Sources}/RunnerEngine/Runner.swift +1 -1
  23. package/ios/Tests/CapacitorBackgroundRunnerTests/CapacitorBackgroundRunnerTests.swift +21 -0
  24. package/ios/Tests/RunnerEngineTests/ContextTests.swift +393 -0
  25. package/ios/Tests/RunnerEngineTests/RunnerTests.swift +32 -0
  26. package/package.json +24 -22
  27. package/scripts/install_libs.js +4 -12
  28. package/ios/Plugin/BackgroundRunnerPlugin.h +0 -10
  29. package/ios/Plugin/BackgroundRunnerPlugin.m +0 -12
  30. package/ios/Plugin/Info.plist +0 -24
  31. /package/ios/{Plugin/BackgroundRunnerErrors.swift → Sources/CapacitorBackgroundRunner/BackgroundRunnerPluginError.swift} +0 -0
  32. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/App.swift +0 -0
  33. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Device.swift +0 -0
  34. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/KV.swift +0 -0
  35. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Reachability.swift +0 -0
  36. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/CapacitorAPI/Watch.swift +0 -0
  37. /package/ios/{Plugin → Sources/CapacitorBackgroundRunner}/RunnerConfig.swift +0 -0
  38. /package/ios/{Plugin/WatchConnectivtySessionDelegate.swift → Sources/CapacitorBackgroundRunner/WatchConnectivitySessionDelegate.swift} +0 -0
  39. /package/ios/{Plugin → Sources}/RunnerEngine/Errors.swift +0 -0
  40. /package/ios/{Plugin → Sources}/RunnerEngine/JSConsole.swift +0 -0
  41. /package/ios/{Plugin → Sources}/RunnerEngine/JSFetch.swift +0 -0
  42. /package/ios/{Plugin → Sources}/RunnerEngine/JSResponse.swift +0 -0
  43. /package/ios/{Plugin → Sources}/RunnerEngine/JSTextDecoder.swift +0 -0
  44. /package/ios/{Plugin → Sources}/RunnerEngine/JSTextEncoder.swift +0 -0
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
10
10
  s.homepage = package['repository']['url']
11
11
  s.author = package['author']
12
12
  s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
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'
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
14
  s.ios.deployment_target = '14.0'
15
15
  s.dependency 'Capacitor'
16
16
  s.swift_version = '5.1'
package/Package.swift ADDED
@@ -0,0 +1,45 @@
1
+ // swift-tools-version: 5.7
2
+ // The swift-tools-version declares the minimum version of Swift required to build this package.
3
+
4
+ import PackageDescription
5
+
6
+ let package = Package(
7
+ name: "CapacitorBackgroundRunner",
8
+ platforms: [.iOS(.v14), .macOS(.v13)],
9
+ products: [
10
+ // Products define the executables and libraries a package produces, making them visible to other packages.
11
+ .library(
12
+ name: "CapacitorBackgroundRunner",
13
+ targets: ["CapacitorBackgroundRunner"]
14
+ )
15
+ ],
16
+ dependencies: [
17
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
18
+ ],
19
+ targets: [
20
+ // Targets are the basic building blocks of a package, defining a module or a test suite.
21
+ // Targets can depend on other targets in this package and products from dependencies.
22
+ .target(
23
+ name: "CapacitorBackgroundRunner",
24
+ dependencies: [
25
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
26
+ .product(name: "Cordova", package: "capacitor-swift-pm"),
27
+ "RunnerEngine"
28
+ ],
29
+ path: "ios/Sources/CapacitorBackgroundRunner"
30
+ ),
31
+ .target(
32
+ name: "RunnerEngine",
33
+ dependencies: [],
34
+ path: "ios/Sources/RunnerEngine"),
35
+ .testTarget(
36
+ name: "RunnerEngineTests",
37
+ dependencies: ["RunnerEngine"],
38
+ path: "ios/Tests/RunnerEngineTests"),
39
+ .testTarget(
40
+ name: "CapacitorBackgroundRunnerTests",
41
+ dependencies: ["CapacitorBackgroundRunner"],
42
+ path: "ios/Tests/CapacitorBackgroundRunnerTests"
43
+ )
44
+ ]
45
+ )
package/README.md CHANGED
@@ -23,6 +23,18 @@ If you will be making use of Geolocation or Push Notifications, enable `Location
23
23
 
24
24
  ![Configure Background Modes in Xcode](https://github.com/ionic-team/capacitor-background-runner/raw/main/docs/configure_background_modes.png)
25
25
 
26
+ You will also need to add the following entry into your `Info.plist` file:
27
+ ```
28
+ <key>BGTaskSchedulerPermittedIdentifiers</key>
29
+ <array>
30
+ <string>com.example.background.task</string>
31
+ </array>
32
+ ```
33
+
34
+ Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode.
35
+
36
+ Make sure you use the same id that you use for `BGTaskSchedulerPermittedIdentifiers` (for example "com.example.background.task") in the `label` field in the plugin configuration.
37
+
26
38
  After enabling the Background Modes capability, add the following to your app's `AppDelegate.swift`:
27
39
 
28
40
  At the top of the file, under `import Capacitor` add:
@@ -65,8 +77,6 @@ Apple requires privacy descriptions to be specified in `Info.plist` for location
65
77
  - `NSLocationAlwaysUsageDescription` (`Privacy - Location Always Usage Description`)
66
78
  - `NSLocationWhenInUseUsageDescription` (`Privacy - Location When In Use Usage Description`)
67
79
 
68
- Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode
69
-
70
80
  ## Android
71
81
 
72
82
  Insert the following line to `android/app/build.gradle`:
@@ -19,7 +19,7 @@ import com.getcapacitor.Bridge
19
19
 
20
20
 
21
21
  @CapacitorPlugin(
22
- name = "BackgroundRunner",
22
+ name = "CapacitorBackgroundRunner",
23
23
  permissions = [
24
24
  Permission(
25
25
  strings = [Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION],
@@ -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, 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"]}
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(options: RequestPermissionOptions): 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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { registerPlugin } from '@capacitor/core';
2
- const BackgroundRunner = registerPlugin('BackgroundRunner', {
3
- web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),
2
+ const BackgroundRunner = registerPlugin('CapacitorBackgroundRunner', {
3
+ web: () => import('./web').then((m) => new m.BackgroundRunnerWeb()),
4
4
  });
5
5
  export * from './definitions';
6
6
  export * from './apis';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,gBAAgB,GAAG,cAAc,CACrC,kBAAkB,EAClB;IACE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;CAClE,CACF,CAAC;AAEF,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { BackgroundRunnerPlugin } from './definitions';\n\nconst BackgroundRunner = registerPlugin<BackgroundRunnerPlugin>(\n 'BackgroundRunner',\n {\n web: () => import('./web').then(m => new m.BackgroundRunnerWeb()),\n },\n);\n\nexport * from './definitions';\nexport * from './apis';\n\nexport { BackgroundRunner };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,gBAAgB,GAAG,cAAc,CAAyB,2BAA2B,EAAE;IAC3F,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;CACpE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { BackgroundRunnerPlugin } from './definitions';\n\nconst BackgroundRunner = registerPlugin<BackgroundRunnerPlugin>('CapacitorBackgroundRunner', {\n web: () => import('./web').then((m) => new m.BackgroundRunnerWeb()),\n});\n\nexport * from './definitions';\nexport * from './apis';\n\nexport { BackgroundRunner };\n"]}
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS5C,MAAM,OAAO,mBAAoB,SAAQ,SAAS;IAChD,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 extends WebPlugin implements BackgroundRunnerPlugin {\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"]}
@@ -1,11 +1,9 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var core = require('@capacitor/core');
6
4
 
7
- const BackgroundRunner = core.registerPlugin('BackgroundRunner', {
8
- web: () => Promise.resolve().then(function () { return web; }).then(m => new m.BackgroundRunnerWeb()),
5
+ const BackgroundRunner = core.registerPlugin('CapacitorBackgroundRunner', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.BackgroundRunnerWeb()),
9
7
  });
10
8
 
11
9
  class BackgroundRunnerWeb extends core.WebPlugin {
@@ -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 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;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('CapacitorBackgroundRunner', {\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,2BAA2B,EAAE;AACrE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;AACvE,CAAC;;ACFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;AACnD,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ,IAAI,kBAAkB,GAAG;AACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ,IAAI,sBAAsB,GAAG;AAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ,IAAI,aAAa,CAAC,QAAQ,EAAE;AAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,UAAU,EAAE,aAAa,EAAE;AACjD,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ,IAAI,MAAM,2BAA2B,GAAG;AACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AAC/C,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  var capacitorBackgroundRunner = (function (exports, core) {
2
2
  'use strict';
3
3
 
4
- const BackgroundRunner = core.registerPlugin('BackgroundRunner', {
5
- web: () => Promise.resolve().then(function () { return web; }).then(m => new m.BackgroundRunnerWeb()),
4
+ const BackgroundRunner = core.registerPlugin('CapacitorBackgroundRunner', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.BackgroundRunnerWeb()),
6
6
  });
7
7
 
8
8
  class BackgroundRunnerWeb extends core.WebPlugin {
@@ -33,8 +33,6 @@ var capacitorBackgroundRunner = (function (exports, core) {
33
33
 
34
34
  exports.BackgroundRunner = BackgroundRunner;
35
35
 
36
- Object.defineProperty(exports, '__esModule', { value: true });
37
-
38
36
  return exports;
39
37
 
40
38
  })({}, capacitorExports);
@@ -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 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;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst BackgroundRunner = registerPlugin('CapacitorBackgroundRunner', {\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,2BAA2B,EAAE;IACrE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;IACvE,CAAC;;ICFM,MAAM,mBAAmB,SAASC,cAAS,CAAC;IACnD,IAAI,gBAAgB,GAAG;IACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ,IAAI,kBAAkB,GAAG;IACzB,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ,IAAI,sBAAsB,GAAG;IAC7B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ,IAAI,aAAa,CAAC,QAAQ,EAAE;IAC5B,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,UAAU,EAAE,aAAa,EAAE;IACjD,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ,IAAI,MAAM,2BAA2B,GAAG;IACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAC/C,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -1,8 +1,12 @@
1
- import Foundation
2
- import Capacitor
3
1
  import BackgroundTasks
2
+ import Capacitor
3
+ import Foundation
4
4
  import JavaScriptCore
5
5
 
6
+ #if canImport(RunnerEngine)
7
+ import RunnerEngine
8
+ #endif
9
+
6
10
  public class BackgroundRunner {
7
11
  public static let shared = BackgroundRunner()
8
12
  public var config: RunnerConfig?
@@ -27,7 +31,8 @@ public class BackgroundRunner {
27
31
  }
28
32
 
29
33
  guard let interval = config.interval else {
30
- throw BackgroundRunnerPluginError.invalidRunnerConfig(reason: "cannot register background task without a configured interval")
34
+ throw BackgroundRunnerPluginError.invalidRunnerConfig(
35
+ reason: "cannot register background task without a configured interval")
31
36
  }
32
37
 
33
38
  let request = BGAppRefreshTaskRequest(identifier: config.label)
@@ -64,7 +69,9 @@ public class BackgroundRunner {
64
69
  }
65
70
 
66
71
  // swiftlint:disable:next cyclomatic_complexity function_body_length
67
- public func execute(config: RunnerConfig, inputArgs: [String: Any]? = nil, callbackId: String? = nil) throws -> [String: Any]? {
72
+ public func execute(
73
+ config: RunnerConfig, inputArgs: [String: Any]? = nil, callbackId: String? = nil
74
+ ) throws -> [String: Any]? {
68
75
  do {
69
76
  let context = try initContext(config: config, callbackId: callbackId)
70
77
 
@@ -73,7 +80,7 @@ public class BackgroundRunner {
73
80
  var result: [String: Any]?
74
81
  var rejectionErr: JSError?
75
82
 
76
- let resolveFunc: @convention(block)(JavaScriptCore.JSValue) -> Void = { returnObj in
83
+ let resolveFunc: @convention(block) (JavaScriptCore.JSValue) -> Void = { returnObj in
77
84
  if !returnObj.isUndefined && !returnObj.isNull {
78
85
  var dict: [String: Any] = [:]
79
86
 
@@ -88,7 +95,7 @@ public class BackgroundRunner {
88
95
  return
89
96
  }
90
97
 
91
- let rejectFunc: @convention(block)(JavaScriptCore.JSValue) -> Void = { rejectObj in
98
+ let rejectFunc: @convention(block) (JavaScriptCore.JSValue) -> Void = { rejectObj in
92
99
  var rejectionTitle = "Error"
93
100
  var rejectionMessage = ""
94
101
 
@@ -136,7 +143,7 @@ public class BackgroundRunner {
136
143
  waitGroup.wait()
137
144
 
138
145
  if let rejection = rejectionErr {
139
- throw EngineError.jsException(details: rejection.message)
146
+ throw EngineError.jsException(details: rejection.toString())
140
147
  }
141
148
 
142
149
  return result
@@ -146,7 +153,8 @@ public class BackgroundRunner {
146
153
  }
147
154
  }
148
155
 
149
- public func dispatchEvent(event: String, inputArgs: [String: Any]?, callbackId: String? = nil) throws {
156
+ public func dispatchEvent(event: String, inputArgs: [String: Any]?, callbackId: String? = nil)
157
+ throws {
150
158
  if let config = config {
151
159
  let waitGroup = DispatchGroup()
152
160
  waitGroup.enter()
@@ -174,13 +182,17 @@ public class BackgroundRunner {
174
182
  }
175
183
 
176
184
  private func loadRunnerConfig() throws -> RunnerConfig? {
177
- guard let capacitorConfigFileURL = Bundle.main.url(forResource: "capacitor.config.json", withExtension: nil) else {
185
+ guard
186
+ let capacitorConfigFileURL = Bundle.main.url(
187
+ forResource: "capacitor.config.json", withExtension: nil)
188
+ else {
178
189
  throw BackgroundRunnerPluginError.runnerError(reason: "capacitor.config.json file not found")
179
190
  }
180
191
 
181
192
  let capacitorConfigFileData = try Data(contentsOf: capacitorConfigFileURL)
182
193
 
183
- if let capConfig = JSTypes.coerceDictionaryToJSObject(try JSONSerialization.jsonObject(with: capacitorConfigFileData) as? [String: Any]) {
194
+ if let capConfig = JSTypes.coerceDictionaryToJSObject(
195
+ try JSONSerialization.jsonObject(with: capacitorConfigFileData) as? [String: Any]) {
184
196
  if let jsonConfig = capConfig[keyPath: "plugins.BackgroundRunner"] as? JSObject {
185
197
  return try RunnerConfig(from: jsonConfig)
186
198
  }
@@ -190,7 +202,10 @@ public class BackgroundRunner {
190
202
  }
191
203
 
192
204
  private func initContext(config: RunnerConfig, callbackId: String?) throws -> Context {
193
- guard let srcFileURL = Bundle.main.url(forResource: config.src, withExtension: nil, subdirectory: "public") else {
205
+ guard
206
+ let srcFileURL = Bundle.main.url(
207
+ forResource: config.src, withExtension: nil, subdirectory: "public")
208
+ else {
194
209
  throw BackgroundRunnerPluginError.runnerError(reason: "source file not found")
195
210
  }
196
211
 
@@ -1,6 +1,10 @@
1
+ import CoreLocation
1
2
  import Foundation
2
3
  import JavaScriptCore
3
- import CoreLocation
4
+
5
+ #if canImport(RunnerEngine)
6
+ import RunnerEngine
7
+ #endif
4
8
 
5
9
  @objc protocol CapacitorGeolocationExports: JSExport {
6
10
  var isWatchingPosition: Bool { get }
@@ -32,9 +36,12 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
32
36
  self.context = context
33
37
  self.locationManager.delegate = self
34
38
 
35
- self.locationManager.allowsBackgroundLocationUpdates = true
36
- self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
37
- self.locationManager.pausesLocationUpdatesAutomatically = false
39
+ if CLLocationManager.authorizationStatus() == .authorizedAlways {
40
+ self.locationManager.allowsBackgroundLocationUpdates = true
41
+ self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
42
+ self.locationManager.pausesLocationUpdatesAutomatically = false
43
+ }
44
+
38
45
  }
39
46
 
40
47
  static func getCurrentKnownLocation() -> CLLocation? {
@@ -71,7 +78,8 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
71
78
  return
72
79
  }
73
80
 
74
- return try await withCheckedThrowingContinuation({ (continuation: CheckedContinuation<Void, Error>) in
81
+ return try await withCheckedThrowingContinuation({
82
+ (continuation: CheckedContinuation<Void, Error>) in
75
83
  permissionContinuation = continuation
76
84
 
77
85
  DispatchQueue.main.async {
@@ -96,7 +104,8 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
96
104
 
97
105
  self.isWatchingLocation = true
98
106
  } catch {
99
- JSContext.current().exception = JSValue(newErrorFromMessage: "\(error)", in: JSContext.current())
107
+ JSContext.current().exception = JSValue(
108
+ newErrorFromMessage: "\(error)", in: JSContext.current())
100
109
  }
101
110
  }
102
111
 
@@ -121,7 +130,8 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
121
130
 
122
131
  return buildLocationDict(location: lastLocation)
123
132
  } catch {
124
- JSContext.current().exception = JSValue(newErrorFromMessage: "\(error)", in: JSContext.current())
133
+ JSContext.current().exception = JSValue(
134
+ newErrorFromMessage: "\(error)", in: JSContext.current())
125
135
 
126
136
  return nil
127
137
  }
@@ -139,7 +149,8 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
139
149
  try? context.dispatchEvent(event: "currentLocation", details: details)
140
150
  }
141
151
 
142
- pendingCurrentLocationCalls.forEach { (callId: Int, callback: (Result<CLLocation?, Error>) -> Void) in
152
+ pendingCurrentLocationCalls.forEach {
153
+ (callId: Int, callback: (Result<CLLocation?, Error>) -> Void) in
143
154
  pendingCurrentLocationCalls.removeValue(forKey: callId)
144
155
  callback(.success(locations.last))
145
156
  }
@@ -162,7 +173,8 @@ class CapacitorGeolocation: NSObject, CapacitorGeolocationExports, CLLocationMan
162
173
  try? context.dispatchEvent(event: "currentLocation", details: details)
163
174
  }
164
175
 
165
- pendingCurrentLocationCalls.forEach { (callId: Int, callback: (Result<CLLocation?, Error>) -> Void) in
176
+ pendingCurrentLocationCalls.forEach {
177
+ (callId: Int, callback: (Result<CLLocation?, Error>) -> Void) in
166
178
  pendingCurrentLocationCalls.removeValue(forKey: callId)
167
179
  callback(.failure(error))
168
180
  }
@@ -1,4 +1,5 @@
1
1
  import Foundation
2
+ import UIKit
2
3
  import JavaScriptCore
3
4
  import UserNotifications
4
5
 
@@ -136,7 +137,7 @@ class CapacitorNotifications: NSObject, CapacitorNotificationsExports {
136
137
  let content = UNMutableNotificationContent()
137
138
  content.title = NSString.localizedUserNotificationString(forKey: notificationOption.title, arguments: nil)
138
139
  content.body = NSString.localizedUserNotificationString(forKey: notificationOption.body, arguments: nil)
139
- content.userInfo = [:]
140
+ content.userInfo = ["source": "capacitor-background-runner"]
140
141
 
141
142
  if let extra = notificationOption.extra {
142
143
  content.userInfo["cap_extra"] = extra
@@ -4,8 +4,18 @@ import WatchConnectivity
4
4
  import UserNotifications
5
5
 
6
6
  @objc(BackgroundRunnerPlugin)
7
- public class BackgroundRunnerPlugin: CAPPlugin {
7
+ public class BackgroundRunnerPlugin: CAPPlugin, CAPBridgedPlugin {
8
+ public let identifier = "CapacitorBackgroundRunnerPlugin"
9
+ public let jsName = "CapacitorBackgroundRunner"
10
+ public let pluginMethods: [CAPPluginMethod] = [
11
+ CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "dispatchEvent", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "registerBackgroundTask", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "removeNotificationListeners", returnType: CAPPluginReturnPromise)
16
+ ]
8
17
  private let impl = BackgroundRunner()
18
+ private weak var originalDelegate: UNUserNotificationCenterDelegate?
9
19
 
10
20
  override public func load() {
11
21
  NotificationCenter.default.addObserver(
@@ -188,6 +198,11 @@ public class BackgroundRunnerPlugin: CAPPlugin {
188
198
  @objc func registerNotificationCategories() {
189
199
  let notificationCenter = UNUserNotificationCenter.current()
190
200
 
201
+ // Capture the original delegate if it's not self
202
+ if notificationCenter.delegate !== self {
203
+ originalDelegate = notificationCenter.delegate
204
+ }
205
+
191
206
  // Set the plugin as the notification delegate
192
207
  notificationCenter.delegate = self
193
208
  }
@@ -199,30 +214,68 @@ extension BackgroundRunnerPlugin: UNUserNotificationCenterDelegate {
199
214
  public func userNotificationCenter(_ center: UNUserNotificationCenter,
200
215
  didReceive response: UNNotificationResponse,
201
216
  withCompletionHandler completionHandler: @escaping () -> Void) {
217
+ let userInfo = response.notification.request.content.userInfo
218
+
219
+ if isBackgroundRunnerNotification(userInfo) {
220
+ handleBackgroundRunnerNotification(response, completionHandler: completionHandler)
221
+ } else {
222
+ forwardToOriginalDelegate(center, didReceive: response, withCompletionHandler: completionHandler)
223
+ }
224
+ }
225
+
226
+ // This is needed to present notifications when the app is in the foreground
227
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
228
+ willPresent notification: UNNotification,
229
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
230
+ let userInfo = notification.request.content.userInfo
231
+
232
+ if isBackgroundRunnerNotification(userInfo) {
233
+ handleBackgroundRunnerPresentation(completionHandler: completionHandler)
234
+ } else {
235
+ forwardToOriginalDelegate(center, willPresent: notification, withCompletionHandler: completionHandler)
236
+ }
237
+ }
238
+
239
+ // MARK: - Helper Methods
240
+
241
+ private func isBackgroundRunnerNotification(_ userInfo: [AnyHashable: Any]) -> Bool {
242
+ return (userInfo["source"] as? String) == "capacitor-background-runner"
243
+ }
244
+
245
+ private func handleBackgroundRunnerNotification(_ response: UNNotificationResponse, completionHandler: @escaping () -> Void) {
202
246
  let actionTypeId = response.notification.request.content.categoryIdentifier
203
247
  let notificationId = Int(response.notification.request.identifier) ?? -1
204
248
 
205
- // Create event data
206
249
  let eventData: [String: Any] = [
207
250
  "actionTypeId": actionTypeId,
208
251
  "notificationId": notificationId
209
252
  ]
210
253
 
211
- // Notify listeners with the action data - the 'true' parameter is for retaining the event
212
254
  notifyListeners("backgroundRunnerNotificationReceived", data: eventData, retainUntilConsumed: true)
213
-
214
255
  completionHandler()
215
256
  }
216
257
 
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
258
+ private func forwardToOriginalDelegate(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
259
+ if let originalDelegate = originalDelegate, originalDelegate.responds(to: #selector(userNotificationCenter(_:didReceive:withCompletionHandler:))) {
260
+ originalDelegate.userNotificationCenter?(center, didReceive: response, withCompletionHandler: completionHandler)
261
+ } else {
262
+ completionHandler()
263
+ }
264
+ }
265
+
266
+ private func handleBackgroundRunnerPresentation(completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
222
267
  if #available(iOS 14.0, *) {
223
268
  completionHandler([.banner, .sound, .badge])
224
269
  } else {
225
270
  completionHandler([.alert, .sound, .badge])
226
271
  }
227
272
  }
273
+
274
+ private func forwardToOriginalDelegate(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
275
+ if let originalDelegate = originalDelegate, originalDelegate.responds(to: #selector(userNotificationCenter(_:willPresent:withCompletionHandler:))) {
276
+ originalDelegate.userNotificationCenter?(center, willPresent: notification, withCompletionHandler: completionHandler)
277
+ } else {
278
+ handleBackgroundRunnerPresentation(completionHandler: completionHandler)
279
+ }
280
+ }
228
281
  }
@@ -1,11 +1,17 @@
1
1
  import Foundation
2
2
 
3
+ #if canImport(RunnerEngine)
4
+ import RunnerEngine
5
+ #endif
6
+
3
7
  extension Context {
4
8
  public func setupCapacitorAPI() {
5
9
  jsContext.setObject(CapacitorKVStore.self, forKeyedSubscript: "CapacitorKV" as NSString)
6
- jsContext.setObject(CapacitorGeolocation(context: self), forKeyedSubscript: "CapacitorGeolocation" as NSString)
10
+ jsContext.setObject(
11
+ CapacitorGeolocation(context: self), forKeyedSubscript: "CapacitorGeolocation" as NSString)
7
12
  jsContext.setObject(CapacitorWatch(), forKeyedSubscript: "CapacitorWatch" as NSString)
8
- jsContext.setObject(CapacitorNotifications.self, forKeyedSubscript: "CapacitorNotifications" as NSString)
13
+ jsContext.setObject(
14
+ CapacitorNotifications.self, forKeyedSubscript: "CapacitorNotifications" as NSString)
9
15
  jsContext.setObject(CapacitorDevice(), forKeyedSubscript: "CapacitorDevice" as NSString)
10
16
  jsContext.setObject(CapacitorApp.self, forKeyedSubscript: "CapacitorApp" as NSString)
11
17
  }
@@ -3,7 +3,7 @@ import JavaScriptCore
3
3
 
4
4
  public class Context {
5
5
  let name: String
6
- let jsContext: JSContext
6
+ public let jsContext: JSContext
7
7
 
8
8
  private var eventListeners = [String: JSValue]()
9
9
  private var timers = [Int: Timer]()
@@ -13,17 +13,17 @@ class JSCrypto: NSObject, JSCryptoExports {
13
13
  var rnd = [UInt8](repeating: 0, count: size)
14
14
  _ = SecRandomCopyBytes(kSecRandomDefault, size, &rnd)
15
15
 
16
- if arr.toArray() as? [UInt8] != nil {
16
+ if arr.toArray() is [UInt8] {
17
17
  for i in 0...(size - 1) {
18
18
  arr.setObject(rnd[i], atIndexedSubscript: i)
19
19
  }
20
20
  }
21
- if arr.toArray() as? [UInt16] != nil {
21
+ if arr.toArray() is [UInt16] {
22
22
  for i in 0...(size - 1) {
23
23
  arr.setObject(UInt16(rnd[i]), atIndexedSubscript: i)
24
24
  }
25
25
  }
26
- if arr.toArray() as? [UInt32] != nil {
26
+ if arr.toArray() is [UInt32] {
27
27
  for i in 0...(size - 1) {
28
28
  arr.setObject(UInt32(rnd[i]), forKeyedSubscript: i)
29
29
  }
@@ -27,7 +27,7 @@ import JavaScriptCore
27
27
  self.cause = nil
28
28
  }
29
29
 
30
- func toString() -> String {
30
+ public func toString() -> String {
31
31
  return message
32
32
  }
33
33
  }
@@ -12,7 +12,7 @@ public class Runner {
12
12
  runLoop = RunLoop.current
13
13
  }
14
14
 
15
- func createContext(name: String) throws -> Context {
15
+ public func createContext(name: String) throws -> Context {
16
16
  return try Context(vm: machine, contextName: name, runLoop: runLoop)
17
17
  }
18
18
  }
@@ -0,0 +1,21 @@
1
+ import Testing
2
+ @testable import CapacitorBackgroundRunner
3
+ @testable import RunnerEngine
4
+
5
+ @Test func testKeyValueAPI() async throws {
6
+ let runner = Runner()
7
+ let context = try runner.createContext(name: "io.backgroundrunner.testkv")
8
+ context.setupCapacitorAPI()
9
+
10
+ _ = try context.execute(code: "CapacitorKV.set('test', 'hello world');")
11
+
12
+ let value = try context.execute(code: "CapacitorKV.get('test');")
13
+
14
+ #expect(value?.toDictionary()?["value"] as? String == "hello world")
15
+
16
+ _ = try context.execute(code: "CapacitorKV.remove('test');")
17
+
18
+ let nullValue = try context.execute(code: "CapacitorKV.get('test');")
19
+
20
+ #expect(nullValue?.isNull ?? false)
21
+ }