@simplysm/capacitor-plugin-intent 12.16.52 → 14.0.4

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 (36) hide show
  1. package/README.md +69 -139
  2. package/android/build.gradle +1 -0
  3. package/android/src/main/kotlin/kr/co/simplysm/capacitor/intent/IntentPlugin.kt +365 -0
  4. package/dist/Intent.d.ts +29 -18
  5. package/dist/Intent.d.ts.map +1 -0
  6. package/dist/Intent.js +41 -22
  7. package/dist/Intent.js.map +1 -0
  8. package/dist/IntentPlugin.d.ts +72 -0
  9. package/dist/IntentPlugin.d.ts.map +1 -0
  10. package/dist/IntentPlugin.js +2 -0
  11. package/dist/IntentPlugin.js.map +1 -0
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +4 -2
  15. package/dist/index.js.map +1 -0
  16. package/dist/web/IntentWeb.d.ts +7 -5
  17. package/dist/web/IntentWeb.d.ts.map +1 -0
  18. package/dist/web/IntentWeb.js +17 -13
  19. package/dist/web/IntentWeb.js.map +1 -0
  20. package/package.json +15 -10
  21. package/src/Intent.ts +56 -25
  22. package/src/IntentPlugin.ts +81 -0
  23. package/src/index.ts +2 -1
  24. package/src/web/IntentWeb.ts +27 -16
  25. package/android/src/main/java/kr/co/simplysm/capacitor/intent/IntentPlugin.java +0 -376
  26. package/dist/IIntentPlugin.d.ts +0 -63
  27. package/dist/IIntentPlugin.js +0 -1
  28. package/src/IIntentPlugin.ts +0 -65
  29. package/tests/slice1-directory-and-config.spec.ts +0 -50
  30. package/tests/slice2-java-renaming.spec.ts +0 -34
  31. package/tests/slice3-typescript-renaming.spec.ts +0 -76
  32. package/tests/slice4-docs-and-deprecation.spec.ts +0 -31
  33. package/tests/slice5-start-activity-for-result-android.spec.md +0 -98
  34. package/tests/slice5-start-activity-for-result-types.spec.ts +0 -40
  35. package/tests/slice6-start-activity-for-result-web.spec.ts +0 -34
  36. package/tsconfig.json +0 -8
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @simplysm/capacitor-plugin-intent
2
2
 
3
- Capacitor Intent Plugin -- Android intent send/receive for industrial devices (barcode scanners, PDA, etc.). Provides subscription-based intent receiving, intent sending with extras, launch intent retrieval, and startActivityForResult support.
3
+ Capacitor Intent plugin for Android broadcast communication and activity results.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,196 +8,126 @@ Capacitor Intent Plugin -- Android intent send/receive for industrial devices (b
8
8
  npm install @simplysm/capacitor-plugin-intent
9
9
  ```
10
10
 
11
- **Peer dependencies:**
12
-
13
- - `@capacitor/core` ^7.4.4
14
-
15
11
  ## API Overview
16
12
 
13
+ ### Intent
14
+
17
15
  | API | Type | Description |
18
16
  |-----|------|-------------|
19
- | `Intent` | Abstract class | Static methods for subscribing to, sending, and managing Android intents |
20
- | `IIntentResult` | Interface | Intent result containing action and extras |
21
- | `IStartActivityForResultOptions` | Interface | Options for starting an activity for result |
22
- | `IActivityResult` | Interface | Activity result containing resultCode, data, and extras |
23
- | `IIntentPlugin` | Interface | Low-level Capacitor plugin interface for intent operations |
17
+ | `IntentResult` | Interface | Data received from a broadcast or launch intent |
18
+ | `StartActivityForResultOptions` | Interface | Options for starting an Android activity and awaiting its result |
19
+ | `StartActivityForResultResult` | Interface | Result returned from a started activity |
20
+ | `IntentPlugin` | Interface | Native plugin interface for intent operations |
21
+ | `Intent` | Class | Static API for broadcast send/receive, launch intents, and activity results |
24
22
 
25
- ## API Reference
23
+ ## Interfaces
26
24
 
27
- ### `IIntentResult`
25
+ ### IntentResult
28
26
 
29
- Result object received from an intent or launch intent.
30
-
31
- ```typescript
32
- export interface IIntentResult {
33
- /** Intent action */
34
- action?: string;
35
- /** Extra data */
36
- extras?: Record<string, unknown>;
37
- }
38
- ```
27
+ Data received from a broadcast or launch intent.
39
28
 
40
29
  | Field | Type | Description |
41
30
  |-------|------|-------------|
42
- | `action` | `string \| undefined` | The intent action string |
43
- | `extras` | `Record<string, unknown> \| undefined` | Extra data attached to the intent |
44
-
45
- ### `IStartActivityForResultOptions`
46
-
47
- Options for starting an activity and receiving its result.
48
-
49
- ```typescript
50
- export interface IStartActivityForResultOptions {
51
- /** Intent action */
52
- action: string;
53
- /** Data URI */
54
- uri?: string;
55
- /** Extra data */
56
- extras?: Record<string, unknown>;
57
- /** Target package name */
58
- package?: string;
59
- /** Target component class name */
60
- component?: string;
61
- /** MIME type */
62
- type?: string;
63
- }
64
- ```
31
+ | `action` | `string \| undefined` | The intent action string (e.g. `"com.example.SCAN_RESULT"`) |
32
+ | `extras` | `Record<string, unknown> \| undefined` | Key-value map of intent extras |
33
+
34
+ ### StartActivityForResultOptions
35
+
36
+ Options for launching an Android activity and awaiting its result.
65
37
 
66
38
  | Field | Type | Description |
67
39
  |-------|------|-------------|
68
- | `action` | `string` | Intent action (required) |
69
- | `uri` | `string \| undefined` | Data URI |
70
- | `extras` | `Record<string, unknown> \| undefined` | Extra data to include in the intent |
71
- | `package` | `string \| undefined` | Target package name |
72
- | `component` | `string \| undefined` | Target component class name (requires `package`) |
73
- | `type` | `string \| undefined` | MIME type |
74
-
75
- ### `IActivityResult`
76
-
77
- Result returned from a started activity.
78
-
79
- ```typescript
80
- export interface IActivityResult {
81
- /** Activity result code (RESULT_OK = -1, RESULT_CANCELED = 0) */
82
- resultCode: number;
83
- /** Result data URI */
84
- data?: string;
85
- /** Result extras */
86
- extras?: Record<string, unknown>;
87
- }
88
- ```
40
+ | `action` | `string \| undefined` | Intent action (e.g. `"android.intent.action.VIEW"`) |
41
+ | `uri` | `string \| undefined` | Data URI to pass to the intent |
42
+ | `extras` | `Record<string, unknown> \| undefined` | Extra key-value pairs to include |
43
+ | `type` | `string \| undefined` | MIME type (e.g. `"image/*"`) |
44
+ | `packageName` | `string \| undefined` | Target package name for an explicit intent |
45
+ | `className` | `string \| undefined` | Target class name for an explicit intent |
46
+ | `flags` | `number \| undefined` | Intent flags bitmask |
47
+
48
+ ### StartActivityForResultResult
49
+
50
+ Result returned when a launched activity finishes.
89
51
 
90
52
  | Field | Type | Description |
91
53
  |-------|------|-------------|
92
- | `resultCode` | `number` | Activity result code (`RESULT_OK = -1`, `RESULT_CANCELED = 0`) |
93
- | `data` | `string \| undefined` | Result data URI |
94
- | `extras` | `Record<string, unknown> \| undefined` | Result extras |
95
-
96
- ### `IIntentPlugin`
97
-
98
- Low-level Capacitor plugin interface. Use `Intent` instead for a simplified API.
99
-
100
- ```typescript
101
- export interface IIntentPlugin {
102
- subscribe(
103
- options: { filters: string[] },
104
- callback: (result: IIntentResult) => void,
105
- ): Promise<{ id: string }>;
106
- unsubscribe(options: { id: string }): Promise<void>;
107
- unsubscribeAll(): Promise<void>;
108
- send(options: { action: string; extras?: Record<string, unknown> }): Promise<void>;
109
- getLaunchIntent(): Promise<IIntentResult>;
110
- startActivityForResult(options: IStartActivityForResultOptions): Promise<IActivityResult>;
111
- }
112
- ```
54
+ | `resultCode` | `number` | Android result code (`RESULT_OK = -1`, `RESULT_CANCELED = 0`) |
55
+ | `data` | `{ action?: string; uri?: string; extras?: Record<string, unknown> } \| undefined` | Optional data returned by the activity, including its action, URI, and extras |
113
56
 
114
- | Method | Parameters | Returns | Description |
115
- |--------|------------|---------|-------------|
116
- | `subscribe` | `options: { filters: string[] }, callback` | `Promise<{ id: string }>` | Register an intent receiver with action filters |
117
- | `unsubscribe` | `options: { id: string }` | `Promise<void>` | Remove a specific intent receiver by ID |
118
- | `unsubscribeAll` | -- | `Promise<void>` | Remove all intent receivers |
119
- | `send` | `options: { action, extras? }` | `Promise<void>` | Send an intent with action and optional extras |
120
- | `getLaunchIntent` | -- | `Promise<IIntentResult>` | Get the intent that launched the app |
121
- | `startActivityForResult` | `options: IStartActivityForResultOptions` | `Promise<IActivityResult>` | Start an activity and receive its result |
57
+ ### IntentPlugin
122
58
 
123
- ### `Intent`
59
+ Native plugin interface for intent operations.
124
60
 
125
- Abstract class with static methods for Android intent send/receive. Designed for industrial device integration (barcode scanners, PDA, etc.).
61
+ | Method | Signature | Description |
62
+ |--------|-----------|-------------|
63
+ | `subscribe` | `(options: { filters: string[] }, callback: (result: IntentResult) => void) => Promise<{ id: string }>` | Register a broadcast receiver for the given action filters |
64
+ | `unsubscribe` | `(options: { id: string }) => Promise<void>` | Unregister a broadcast receiver by subscription ID |
65
+ | `unsubscribeAll` | `() => Promise<void>` | Unregister all broadcast receivers |
66
+ | `send` | `(options: { action: string; extras?: Record<string, unknown> }) => Promise<void>` | Send a broadcast intent |
67
+ | `getLaunchIntent` | `() => Promise<IntentResult>` | Get the intent that launched the current activity |
68
+ | `addListener` | `(eventName: "newIntent", listenerFunc: (data: IntentResult) => void) => Promise<PluginListenerHandle>` | Listen for new intents delivered to the activity |
69
+ | `removeAllListeners` | `() => Promise<void>` | Remove all event listeners |
70
+ | `startActivityForResult` | `(options: StartActivityForResultOptions) => Promise<StartActivityForResultResult>` | Start an activity and await its result |
126
71
 
127
- ```typescript
128
- export abstract class Intent {
129
- static async subscribe(
130
- filters: string[],
131
- callback: (result: IIntentResult) => void,
132
- ): Promise<() => Promise<void>>;
72
+ ## Classes
133
73
 
134
- static async unsubscribeAll(): Promise<void>;
74
+ ### Intent
135
75
 
136
- static async send(options: {
137
- action: string;
138
- extras?: Record<string, unknown>;
139
- }): Promise<void>;
76
+ Android Intent plugin for broadcast send/receive and launch intent handling. Designed for industrial devices such as barcode scanners and PDAs.
140
77
 
141
- static async getLaunchIntent(): Promise<IIntentResult>;
78
+ All methods are static.
142
79
 
143
- static async startActivityForResult(
144
- options: IStartActivityForResultOptions,
145
- ): Promise<IActivityResult>;
146
- }
147
- ```
148
-
149
- | Method | Parameters | Returns | Description |
150
- |--------|------------|---------|-------------|
151
- | `subscribe` | `filters: string[], callback: (result: IIntentResult) => void` | `Promise<() => Promise<void>>` | Register an intent receiver; returns an unsubscribe function |
152
- | `unsubscribeAll` | -- | `Promise<void>` | Remove all registered intent receivers |
153
- | `send` | `options: { action: string; extras?: Record<string, unknown> }` | `Promise<void>` | Send an intent with action and optional extras |
154
- | `getLaunchIntent` | -- | `Promise<IIntentResult>` | Retrieve the intent that launched the application |
155
- | `startActivityForResult` | `options: IStartActivityForResultOptions` | `Promise<IActivityResult>` | Start an activity and receive its result |
80
+ | Method | Signature | Description |
81
+ |--------|-----------|-------------|
82
+ | `subscribe` | `static async subscribe(filters: string[], callback: (result: IntentResult) => void): Promise<() => Promise<void>>` | Register a broadcast receiver for the given action filters. Returns an async unsubscribe function. |
83
+ | `unsubscribeAll` | `static async unsubscribeAll(): Promise<void>` | Unregister all active broadcast receivers |
84
+ | `send` | `static async send(options: { action: string; extras?: Record<string, unknown> }): Promise<void>` | Send a broadcast intent with the specified action and optional extras |
85
+ | `getLaunchIntent` | `static async getLaunchIntent(): Promise<IntentResult>` | Retrieve the intent that launched the current activity |
86
+ | `addListener` | `static async addListener(eventName: "newIntent", callback: (result: IntentResult) => void): Promise<PluginListenerHandle>` | Add a listener for new intents delivered to the activity via `onNewIntent` |
87
+ | `removeAllListeners` | `static async removeAllListeners(): Promise<void>` | Remove all registered event listeners |
88
+ | `startActivityForResult` | `static async startActivityForResult(options: StartActivityForResultOptions): Promise<StartActivityForResultResult>` | Start an Android activity and return its result when it finishes |
156
89
 
157
90
  ## Usage Examples
158
91
 
159
- ### Subscribe to intents from a barcode scanner
92
+ ### Subscribe to barcode scanner broadcasts
160
93
 
161
- ```typescript
94
+ ```ts
162
95
  import { Intent } from "@simplysm/capacitor-plugin-intent";
163
96
 
164
97
  const unsubscribe = await Intent.subscribe(
165
- ["com.symbol.datawedge.api.RESULT_ACTION"],
98
+ ["com.example.scanner.BARCODE_RESULT"],
166
99
  (result) => {
167
- console.log("Action:", result.action);
168
- console.log("Extras:", result.extras);
100
+ const barcode = result.extras?.["barcode"] as string;
101
+ handleBarcode(barcode);
169
102
  },
170
103
  );
171
104
 
172
- // Later, unsubscribe
105
+ // Later, stop listening
173
106
  await unsubscribe();
174
107
  ```
175
108
 
176
- ### Send an intent to trigger a scan
109
+ ### Send a broadcast
177
110
 
178
- ```typescript
111
+ ```ts
179
112
  import { Intent } from "@simplysm/capacitor-plugin-intent";
180
113
 
181
114
  await Intent.send({
182
- action: "com.symbol.datawedge.api.ACTION",
183
- extras: {
184
- "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER": "TOGGLE_SCANNING",
185
- },
115
+ action: "com.example.ACTION_TRIGGER_SCAN",
116
+ extras: { mode: "continuous" },
186
117
  });
187
118
  ```
188
119
 
189
120
  ### Start an activity for result
190
121
 
191
- ```typescript
122
+ ```ts
192
123
  import { Intent } from "@simplysm/capacitor-plugin-intent";
193
124
 
194
125
  const result = await Intent.startActivityForResult({
195
- action: "android.intent.action.GET_CONTENT",
126
+ action: "android.intent.action.PICK",
196
127
  type: "image/*",
197
128
  });
198
129
 
199
- if (result.resultCode === -1) {
200
- // RESULT_OK
201
- console.log("Selected:", result.data);
130
+ if (result.resultCode === -1 && result.data?.uri) {
131
+ loadImage(result.data.uri);
202
132
  }
203
133
  ```
@@ -1,4 +1,5 @@
1
1
  apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
2
3
 
3
4
  android {
4
5
  namespace "kr.co.simplysm.capacitor.intent"
@@ -0,0 +1,365 @@
1
+ package kr.co.simplysm.capacitor.intent
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.ComponentName
5
+ import android.content.Context
6
+ import android.content.Intent
7
+ import android.content.IntentFilter
8
+ import android.net.Uri
9
+ import android.os.Build
10
+ import android.os.Bundle
11
+ import android.os.Parcelable
12
+ import android.util.Log
13
+ import androidx.activity.result.ActivityResult
14
+ import com.getcapacitor.JSArray
15
+ import com.getcapacitor.JSObject
16
+ import com.getcapacitor.Plugin
17
+ import com.getcapacitor.PluginCall
18
+ import com.getcapacitor.PluginMethod
19
+ import com.getcapacitor.annotation.ActivityCallback
20
+ import com.getcapacitor.annotation.CapacitorPlugin
21
+ import org.json.JSONArray
22
+ import org.json.JSONException
23
+ import org.json.JSONObject
24
+ import java.util.UUID
25
+
26
+ @CapacitorPlugin(name = "Intent")
27
+ class IntentPlugin : Plugin() {
28
+
29
+ companion object {
30
+ private const val TAG = "IntentPlugin"
31
+ }
32
+
33
+ private val receivers = mutableMapOf<String, BroadcastReceiver>()
34
+
35
+ override fun handleOnNewIntent(intent: Intent) {
36
+ super.handleOnNewIntent(intent)
37
+ notifyListeners("newIntent", intentToJson(intent))
38
+ }
39
+
40
+ @PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
41
+ fun subscribe(call: PluginCall) {
42
+ try {
43
+ val filters = call.getArray("filters")
44
+
45
+ if (filters == null || filters.length() == 0) {
46
+ call.reject("filters is required")
47
+ return
48
+ }
49
+
50
+ call.setKeepAlive(true)
51
+
52
+ val receiverId = UUID.randomUUID().toString()
53
+
54
+ val intentFilter = IntentFilter()
55
+ for (i in 0 until filters.length()) {
56
+ intentFilter.addAction(filters.getString(i))
57
+ }
58
+
59
+ val receiver = object : BroadcastReceiver() {
60
+ override fun onReceive(context: Context, intent: Intent) {
61
+ val result = intentToJson(intent)
62
+ result.put("id", receiverId)
63
+ call.resolve(result)
64
+ }
65
+ }
66
+
67
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
68
+ context.registerReceiver(receiver, intentFilter, Context.RECEIVER_EXPORTED)
69
+ } else {
70
+ context.registerReceiver(receiver, intentFilter)
71
+ }
72
+
73
+ receivers[receiverId] = receiver
74
+
75
+ val ret = JSObject()
76
+ ret.put("id", receiverId)
77
+ call.resolve(ret)
78
+ } catch (e: Exception) {
79
+ Log.e(TAG, "subscribe failed", e)
80
+ call.reject("subscribe failed: " + e.message)
81
+ }
82
+ }
83
+
84
+ @PluginMethod
85
+ fun unsubscribe(call: PluginCall) {
86
+ try {
87
+ val id = call.getString("id")
88
+ if (id == null) {
89
+ call.reject("id is required")
90
+ return
91
+ }
92
+
93
+ val receiver = receivers.remove(id)
94
+ if (receiver != null) {
95
+ context.unregisterReceiver(receiver)
96
+ }
97
+
98
+ call.resolve()
99
+ } catch (e: Exception) {
100
+ Log.e(TAG, "unsubscribe failed", e)
101
+ call.reject("unsubscribe failed: " + e.message)
102
+ }
103
+ }
104
+
105
+ @PluginMethod
106
+ fun unsubscribeAll(call: PluginCall) {
107
+ try {
108
+ for (receiver in receivers.values) {
109
+ try {
110
+ context.unregisterReceiver(receiver)
111
+ } catch (ignored: Exception) {
112
+ }
113
+ }
114
+ receivers.clear()
115
+ call.resolve()
116
+ } catch (e: Exception) {
117
+ Log.e(TAG, "unsubscribeAll failed", e)
118
+ call.reject("unsubscribeAll failed: " + e.message)
119
+ }
120
+ }
121
+
122
+ @PluginMethod
123
+ fun send(call: PluginCall) {
124
+ try {
125
+ val action = call.getString("action")
126
+ if (action == null) {
127
+ call.reject("action is required")
128
+ return
129
+ }
130
+
131
+ val intent = Intent(action)
132
+
133
+ val extras = call.getObject("extras")
134
+ if (extras != null) {
135
+ populateExtras(intent, extras)
136
+ }
137
+
138
+ context.sendBroadcast(intent)
139
+ call.resolve()
140
+ } catch (e: Exception) {
141
+ Log.e(TAG, "send failed", e)
142
+ call.reject("send failed: " + e.message)
143
+ }
144
+ }
145
+
146
+ @PluginMethod
147
+ fun getLaunchIntent(call: PluginCall) {
148
+ try {
149
+ val intent = activity.intent
150
+ call.resolve(intentToJson(intent))
151
+ } catch (e: Exception) {
152
+ Log.e(TAG, "getLaunchIntent failed", e)
153
+ call.reject("getLaunchIntent failed: " + e.message)
154
+ }
155
+ }
156
+
157
+ @PluginMethod
158
+ fun startActivityForResult(call: PluginCall) {
159
+ try {
160
+ val intent = buildIntent(call)
161
+ startActivityForResult(call, intent, "handleActivityResult")
162
+ } catch (e: Exception) {
163
+ Log.e(TAG, "startActivityForResult failed", e)
164
+ call.reject("startActivityForResult failed: " + e.message)
165
+ }
166
+ }
167
+
168
+ @ActivityCallback
169
+ private fun handleActivityResult(call: PluginCall?, result: ActivityResult) {
170
+ if (call == null) {
171
+ return
172
+ }
173
+
174
+ val json = JSObject()
175
+ json.put("resultCode", result.resultCode)
176
+
177
+ val data = result.data
178
+ if (data != null) {
179
+ val dataJson = JSObject()
180
+ if (data.action != null) {
181
+ dataJson.put("action", data.action)
182
+ }
183
+ if (data.data != null) {
184
+ dataJson.put("uri", data.data.toString())
185
+ }
186
+ val extras = data.extras
187
+ if (extras != null) {
188
+ dataJson.put("extras", bundleToJson(extras))
189
+ }
190
+ json.put("data", dataJson)
191
+ }
192
+
193
+ call.resolve(json)
194
+ }
195
+
196
+ private fun buildIntent(call: PluginCall): Intent {
197
+ val intent = Intent()
198
+
199
+ val action = call.getString("action")
200
+ if (action != null) {
201
+ intent.action = action
202
+ }
203
+
204
+ val uri = call.getString("uri")
205
+ val type = call.getString("type")
206
+ when {
207
+ uri != null && type != null -> intent.setDataAndType(Uri.parse(uri), type)
208
+ uri != null -> intent.data = Uri.parse(uri)
209
+ type != null -> intent.type = type
210
+ }
211
+
212
+ val extras = call.getObject("extras")
213
+ if (extras != null) {
214
+ populateExtras(intent, extras)
215
+ }
216
+
217
+ val packageName = call.getString("packageName")
218
+ val className = call.getString("className")
219
+ when {
220
+ packageName != null && className != null ->
221
+ intent.component = ComponentName(packageName, className)
222
+ packageName != null -> intent.setPackage(packageName)
223
+ }
224
+
225
+ val flags = call.getInt("flags")
226
+ if (flags != null) {
227
+ intent.addFlags(flags)
228
+ }
229
+
230
+ return intent
231
+ }
232
+
233
+ @Throws(JSONException::class)
234
+ private fun populateExtras(intent: Intent, extras: JSObject) {
235
+ val keys = extras.keys()
236
+ while (keys.hasNext()) {
237
+ val key = keys.next()
238
+ val value = extras.get(key)
239
+
240
+ when (value) {
241
+ is String -> intent.putExtra(key, value)
242
+ is Int -> intent.putExtra(key, value)
243
+ is Long -> intent.putExtra(key, value)
244
+ is Double -> intent.putExtra(key, value)
245
+ is Boolean -> intent.putExtra(key, value)
246
+ is JSONArray -> {
247
+ val strArr = Array(value.length()) { i -> value.getString(i) }
248
+ intent.putExtra(key, strArr)
249
+ }
250
+ is JSONObject -> {
251
+ val bundle = jsonToBundle(value)
252
+ intent.putExtra(key, bundle)
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ @Throws(JSONException::class)
259
+ private fun jsonToBundle(json: JSONObject): Bundle {
260
+ val bundle = Bundle()
261
+ val keys = json.keys()
262
+ while (keys.hasNext()) {
263
+ val key = keys.next()
264
+ val value = json.get(key)
265
+
266
+ when (value) {
267
+ is String -> bundle.putString(key, value)
268
+ is Int -> bundle.putInt(key, value)
269
+ is Long -> bundle.putLong(key, value)
270
+ is Double -> bundle.putDouble(key, value)
271
+ is Boolean -> bundle.putBoolean(key, value)
272
+ }
273
+ }
274
+ return bundle
275
+ }
276
+
277
+ private fun intentToJson(intent: Intent?): JSObject {
278
+ val json = JSObject()
279
+
280
+ if (intent == null) {
281
+ return json
282
+ }
283
+
284
+ try {
285
+ json.put("action", intent.action)
286
+
287
+ val extras = intent.extras
288
+ if (extras != null) {
289
+ json.put("extras", bundleToJson(extras))
290
+ }
291
+ } catch (e: Exception) {
292
+ Log.e(TAG, "intentToJson failed", e)
293
+ }
294
+
295
+ return json
296
+ }
297
+
298
+ private fun bundleToJson(bundle: Bundle?): JSObject {
299
+ val json = JSObject()
300
+
301
+ if (bundle == null) {
302
+ return json
303
+ }
304
+
305
+ for (key in bundle.keySet()) {
306
+ try {
307
+ val value = bundle.get(key)
308
+
309
+ when (value) {
310
+ null -> json.put(key, JSONObject.NULL)
311
+ is String -> json.put(key, value)
312
+ is Int -> json.put(key, value)
313
+ is Long -> json.put(key, value)
314
+ is Double -> json.put(key, value)
315
+ is Float -> json.put(key, value.toDouble())
316
+ is Boolean -> json.put(key, value)
317
+ is Bundle -> json.put(key, bundleToJson(value))
318
+ is Array<*> -> {
319
+ if (value.isArrayOf<String>()) {
320
+ val arr = JSArray()
321
+ @Suppress("UNCHECKED_CAST")
322
+ for (s in value as Array<String>) {
323
+ arr.put(s)
324
+ }
325
+ json.put(key, arr)
326
+ } else if (value.isArrayOf<Parcelable>()) {
327
+ val arr = JSArray()
328
+ @Suppress("UNCHECKED_CAST")
329
+ for (p in value as Array<Parcelable>) {
330
+ arr.put(p.toString())
331
+ }
332
+ json.put(key, arr)
333
+ } else {
334
+ json.put(key, value.toString())
335
+ }
336
+ }
337
+ is IntArray -> {
338
+ val arr = JSArray()
339
+ for (i in value) {
340
+ arr.put(i)
341
+ }
342
+ json.put(key, arr)
343
+ }
344
+ is Parcelable -> json.put(key, value.toString())
345
+ else -> json.put(key, value.toString())
346
+ }
347
+ } catch (e: Exception) {
348
+ Log.w(TAG, "bundleToJson key failed: $key", e)
349
+ }
350
+ }
351
+
352
+ return json
353
+ }
354
+
355
+ override fun handleOnDestroy() {
356
+ for (receiver in receivers.values) {
357
+ try {
358
+ context.unregisterReceiver(receiver)
359
+ } catch (ignored: Exception) {
360
+ }
361
+ }
362
+ receivers.clear()
363
+ super.handleOnDestroy()
364
+ }
365
+ }