@capacitor/background-runner 1.0.6-dev-20240409T144959.0 → 1.0.6-dev-20240416T212318.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.
package/README.md CHANGED
@@ -157,7 +157,7 @@ Calling `resolve()` \ `reject()` is **required** within every event handler call
157
157
  <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
158
158
 
159
159
  On load, Background Runner will automatically register a
160
- background task that will be scheduled and ran once your app is
160
+ background task that will be scheduled and run once your app is
161
161
  backgrounded.
162
162
 
163
163
  | Prop | Type | Description | Since |
@@ -764,7 +764,7 @@
764
764
  "type": "boolean | undefined"
765
765
  }
766
766
  ],
767
- "docs": "On load, Background Runner will automatically register a\nbackground task that will be scheduled and ran once your app is\nbackgrounded."
767
+ "docs": "On load, Background Runner will automatically register a\nbackground task that will be scheduled and run once your app is\nbackgrounded."
768
768
  }
769
769
  ]
770
770
  }
package/dist/docs.json CHANGED
@@ -307,7 +307,7 @@
307
307
  "type": "boolean | undefined"
308
308
  }
309
309
  ],
310
- "docs": "On load, Background Runner will automatically register a\nbackground task that will be scheduled and ran once your app is\nbackgrounded."
310
+ "docs": "On load, Background Runner will automatically register a\nbackground task that will be scheduled and run once your app is\nbackgrounded."
311
311
  }
312
312
  ]
313
313
  }
@@ -43,7 +43,7 @@ declare module '@capacitor/cli' {
43
43
  interface PluginsConfig {
44
44
  /**
45
45
  * On load, Background Runner will automatically register a
46
- * background task that will be scheduled and ran once your app is
46
+ * background task that will be scheduled and run once your app is
47
47
  * backgrounded.
48
48
  */
49
49
  BackgroundRunner?: {
@@ -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 ran 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 } 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"]}
@@ -5,8 +5,8 @@ import JavaScriptCore
5
5
 
6
6
  public class BackgroundRunner {
7
7
  public static let shared = BackgroundRunner()
8
-
9
- private var config: RunnerConfig?
8
+ public var config: RunnerConfig?
9
+
10
10
  private var runner = Runner()
11
11
 
12
12
  public init() {
@@ -17,93 +17,51 @@ public class BackgroundRunner {
17
17
  print("could not initialize BackgroundRunner: \(error)")
18
18
  }
19
19
  }
20
-
21
- public func registerBackgroundTask() {
20
+
21
+ public func scheduleBackgroundTasks() throws {
22
22
  guard let config = config else {
23
- print("no runner to register")
24
- return
23
+ throw BackgroundRunnerPluginError.noRunnerConfig
25
24
  }
26
-
27
- if config.event == nil {
28
- print("cannot register background task without a event to call")
29
- return
30
- }
31
-
32
- BGTaskScheduler.shared.register(forTaskWithIdentifier: config.label, using: nil) { task in
33
- do {
34
- task.expirationHandler = {
35
- print("task timed out")
36
- }
37
-
38
- guard let event = config.event else {
39
- throw BackgroundRunnerPluginError.invalidRunnerConfig(reason: "runner event is missing or invalid")
40
- }
41
-
42
- _ = try BackgroundRunner.shared.execute(config: config, event: event)
43
-
44
- task.setTaskCompleted(success: true)
45
- } catch {
46
- print("background task error: \(error)")
47
- task.setTaskCompleted(success: false)
48
- }
49
- }
50
- }
51
-
52
- public func scheduleBackgroundTasks() {
53
- guard let config = config else {
25
+
26
+ if !config.autoSchedule {
54
27
  return
55
28
  }
56
29
 
57
30
  guard let interval = config.interval else {
58
- print("cannot register background task without a configured interval")
59
- return
31
+ throw BackgroundRunnerPluginError.invalidRunnerConfig(reason: "cannot register background task without a configured interval")
60
32
  }
61
33
 
62
34
  let request = BGAppRefreshTaskRequest(identifier: config.label)
63
35
  request.earliestBeginDate = Date(timeIntervalSinceNow: Double(interval) * 60)
64
36
 
65
- do {
66
- print("Scheduling \(config.label)")
37
+ print("Scheduling \(config.label)")
67
38
 
68
- try BGTaskScheduler.shared.submit(request)
69
- } catch {
70
- print("Could not schedule app refresh: \(error)")
71
- }
72
- }
73
-
74
- public func getConfig() -> RunnerConfig? {
75
- return config
39
+ try BGTaskScheduler.shared.submit(request)
76
40
  }
77
41
 
78
- public func dispatchEvent(event: String, inputArgs: [String: Any]?, callbackId: String? = nil) throws {
79
- if let config = config {
80
- let waitGroup = DispatchGroup()
81
- waitGroup.enter()
82
-
83
- var err: Error?
42
+ public func registerBackgroundTask() throws {
43
+ guard let config = config else {
44
+ throw BackgroundRunnerPluginError.noRunnerConfig
45
+ }
84
46
 
85
- // swiftlint:disable:next unowned_variable_capture
86
- DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
87
- do {
88
- _ = try self.execute(config: config, event: event, inputArgs: inputArgs, callbackId: callbackId)
89
- } catch {
90
- err = error
91
- print("[\(config.label)]: \(error)")
47
+ BGTaskScheduler.shared.register(forTaskWithIdentifier: config.label, using: nil) { task in
48
+ do {
49
+ task.expirationHandler = {
50
+ print("task timed out")
92
51
  }
93
52
 
94
- waitGroup.leave()
95
- }
53
+ _ = try BackgroundRunner.shared.execute(config: config)
96
54
 
97
- waitGroup.wait()
98
-
99
- if let err = err {
100
- throw err
55
+ task.setTaskCompleted(success: true)
56
+ } catch {
57
+ print("background task error: \(error)")
58
+ task.setTaskCompleted(success: false)
101
59
  }
102
60
  }
103
61
  }
104
-
62
+
105
63
  // swiftlint:disable:next cyclomatic_complexity function_body_length
106
- public func execute(config: RunnerConfig, event: String, inputArgs: [String: Any]? = nil, callbackId: String? = nil) throws -> [String: Any]? {
64
+ public func execute(config: RunnerConfig, inputArgs: [String: Any]? = nil, callbackId: String? = nil) throws -> [String: Any]? {
107
65
  do {
108
66
  let context = try initContext(config: config, callbackId: callbackId)
109
67
 
@@ -170,9 +128,10 @@ public class BackgroundRunner {
170
128
 
171
129
  waitGroup.enter()
172
130
 
173
- try context.dispatchEvent(event: event, details: args)
131
+ try context.dispatchEvent(event: config.event, details: args)
174
132
 
175
133
  waitGroup.wait()
134
+
176
135
 
177
136
  if let rejection = rejectionErr {
178
137
  throw EngineError.jsException(details: rejection.message)
@@ -185,6 +144,33 @@ public class BackgroundRunner {
185
144
  }
186
145
  }
187
146
 
147
+ public func dispatchEvent(event: String, inputArgs: [String: Any]?, callbackId: String? = nil) throws {
148
+ if let config = config {
149
+ let waitGroup = DispatchGroup()
150
+ waitGroup.enter()
151
+
152
+ var err: Error?
153
+
154
+ // swiftlint:disable:next unowned_variable_capture
155
+ DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
156
+ do {
157
+ _ = try self.execute(config: config, inputArgs: inputArgs, callbackId: callbackId)
158
+ } catch {
159
+ err = error
160
+ print("[\(config.label)]: \(error)")
161
+ }
162
+
163
+ waitGroup.leave()
164
+ }
165
+
166
+ waitGroup.wait()
167
+
168
+ if let err = err {
169
+ throw err
170
+ }
171
+ }
172
+ }
173
+
188
174
  private func loadRunnerConfig() throws -> RunnerConfig? {
189
175
  guard let capacitorConfigFileURL = Bundle.main.url(forResource: "capacitor.config.json", withExtension: nil) else {
190
176
  throw BackgroundRunnerPluginError.runnerError(reason: "capacitor.config.json file not found")
@@ -1,6 +1,7 @@
1
1
  import Foundation
2
2
 
3
3
  public enum BackgroundRunnerPluginError: Error, Equatable {
4
+ case noRunnerConfig
4
5
  case invalidRunnerConfig(reason: String)
5
6
  case invalidArgument(reason: String)
6
7
  case runnerError(reason: String)
@@ -13,6 +13,7 @@ public class BackgroundRunnerPlugin: CAPPlugin {
13
13
  name: UIApplication.didEnterBackgroundNotification,
14
14
  object: nil
15
15
  )
16
+
16
17
  initWatchConnectivity()
17
18
  }
18
19
 
@@ -54,22 +55,23 @@ public class BackgroundRunnerPlugin: CAPPlugin {
54
55
 
55
56
  @objc func dispatchEvent(_ call: CAPPluginCall) {
56
57
  do {
57
- guard let runnerEvent = call.getString("event") else {
58
+ guard let runnerEvent = call.getString("event"), !runnerEvent.isEmpty else {
58
59
  throw BackgroundRunnerPluginError.invalidArgument(reason: "event is missing or invalid")
59
60
  }
60
61
 
61
62
  let details = call.getObject("details", JSObject())
62
63
 
63
- guard let config = impl.getConfig() else {
64
- throw BackgroundRunnerPluginError.runnerError(reason: "no runner config loaded")
64
+ guard var config = impl.config else {
65
+ throw BackgroundRunnerPluginError.noRunnerConfig
65
66
  }
67
+
68
+ config.event = runnerEvent
66
69
 
67
70
  // swiftlint:disable:next unowned_variable_capture
68
71
  DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
69
72
  do {
70
73
  let result = try self.impl.execute(
71
74
  config: config,
72
- event: runnerEvent,
73
75
  inputArgs: details as [String: Any],
74
76
  callbackId: call.callbackId
75
77
  )
@@ -94,14 +96,27 @@ public class BackgroundRunnerPlugin: CAPPlugin {
94
96
  }
95
97
 
96
98
  @objc private func didEnterBackground() {
97
- impl.scheduleBackgroundTasks()
99
+ do {
100
+ try impl.scheduleBackgroundTasks()
101
+ } catch {
102
+ print("could not schedule background task: \(error)")
103
+ }
98
104
  }
99
105
 
100
106
  public static func registerBackgroundTask() {
101
- BackgroundRunner.shared.registerBackgroundTask()
107
+ do {
108
+ try BackgroundRunner.shared.registerBackgroundTask()
109
+ } catch {
110
+ print("could not register background task: \(error)")
111
+ }
102
112
  }
103
113
 
104
114
  public static func dispatchEvent(event: String, eventArgs: [AnyHashable: Any], completionHandler: ((Result<Bool, Error>) -> Void)) {
115
+ if event.isEmpty {
116
+ completionHandler(.failure(BackgroundRunnerPluginError.invalidArgument(reason: "event is missing or invalid")))
117
+ return
118
+ }
119
+
105
120
  var args: [String: Any] = [:]
106
121
 
107
122
  eventArgs.forEach { (key: AnyHashable, value: Any) in
@@ -147,7 +162,7 @@ public class BackgroundRunnerPlugin: CAPPlugin {
147
162
  return
148
163
  }
149
164
 
150
- guard let config = impl.getConfig() else {
165
+ guard let config = impl.config else {
151
166
  return
152
167
  }
153
168
 
@@ -13,9 +13,11 @@ class CapacitorKVStore: NSObject, CapacitorKVStoreExports {
13
13
  }
14
14
 
15
15
  static func get(_ key: String) -> JSValue {
16
+ guard let value = UserDefaults.standard.string(forKey: key) else {
17
+ return JSValue(nullIn: JSContext.current())
18
+ }
19
+
16
20
  var valueWrapper: [String: String] = [:]
17
-
18
- let value = UserDefaults.standard.string(forKey: key)
19
21
  valueWrapper["value"] = value
20
22
 
21
23
  return JSValue(object: valueWrapper, in: JSContext.current())
@@ -5,7 +5,7 @@ public struct RunnerConfig {
5
5
  let label: String
6
6
  let src: String
7
7
  var autoSchedule: Bool
8
- let event: String?
8
+ var event: String
9
9
  let repeats: Bool?
10
10
  let enableWatchConnectivity: Bool
11
11
 
@@ -20,7 +20,7 @@ public struct RunnerConfig {
20
20
  throw BackgroundRunnerPluginError.invalidRunnerConfig(reason: "runner source file path is missing or invalid")
21
21
  }
22
22
 
23
- let event = jsObject["event"] as? String
23
+ let event = jsObject["event"] as? String ?? ""
24
24
  let repeats = jsObject["repeat"] as? Bool
25
25
  let interval = jsObject["interval"] as? Int
26
26
  let autoStart = jsObject["autoStart"] as? Bool
@@ -3,31 +3,17 @@ import JavaScriptCore
3
3
 
4
4
  public class Runner {
5
5
  var machine: JSVirtualMachine
6
- var contexts: [String: Context]
7
6
 
8
7
  private let runLoop: RunLoop
9
8
  private var thread: Thread?
10
9
 
11
10
  public init() {
12
11
  machine = JSVirtualMachine()
13
- contexts = [:]
14
12
  runLoop = RunLoop.current
15
13
  }
16
14
 
17
15
  func createContext(name: String) throws -> Context {
18
- let context = try Context(vm: machine, contextName: name, runLoop: runLoop)
19
-
20
- if contexts.keys.contains(name) {
21
- throw EngineError.runnerError(details: "context with name \(name) already exists")
22
- }
23
-
24
- contexts[name] = context
25
-
26
- return context
27
- }
28
-
29
- func destroyContext(name: String) {
30
- contexts.removeValue(forKey: name)
16
+ return try Context(vm: machine, contextName: name, runLoop: runLoop)
31
17
  }
32
18
 
33
19
  func start() {
@@ -54,6 +40,7 @@ public class Runner {
54
40
  }
55
41
 
56
42
  thread.cancel()
43
+
57
44
  while !thread.isFinished {
58
45
  Thread.sleep(forTimeInterval: 0.05)
59
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/background-runner",
3
- "version": "1.0.6-dev-20240409T144959.0",
3
+ "version": "1.0.6-dev-20240416T212318.0",
4
4
  "description": "Capacitor Background Runner",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",
@@ -81,5 +81,5 @@
81
81
  "src": "android"
82
82
  }
83
83
  },
84
- "gitHead": "18f72b6c17bb83bb0e9dde3b0b4c1d3db5309b0d"
84
+ "gitHead": "bbb1e6ffec4fe612f069f39b3e4c1b4daed27210"
85
85
  }