@dashx/react-native 1.1.5 → 1.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.
- package/.DS_Store +0 -0
- package/.claude/settings.local.json +18 -1
- package/.gitignore +1 -1
- package/CHANGELOG.md +34 -0
- package/DashXReactNative.podspec +12 -26
- package/README.md +3 -1
- package/__tests__/fallback.test.js +72 -0
- package/__tests__/index.test.js +46 -5
- package/android/build.gradle +27 -1
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModuleImpl.kt +384 -0
- package/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +85 -0
- package/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +33 -0
- package/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +106 -0
- package/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +33 -0
- package/index.d.ts +24 -2
- package/index.js +22 -11
- package/ios/DashXNotificationHandler.swift +257 -0
- package/ios/DashXReactNative-Bridging-Header.h +0 -2
- package/ios/DashXReactNative.mm +32 -9
- package/ios/DashXReactNative.swift +27 -19
- package/package.json +11 -2
- package/src/NativeDashXReactNative.ts +42 -0
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -231
- package/android/src/main/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -18
- package/ios/DashXRCTAppDelegate.h +0 -3
- package/ios/DashXRCTAppDelegate.swift +0 -266
- package/ios/DashXReactNative.h +0 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
package com.dashx.rn.sdk
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.app.Activity
|
|
5
|
+
import android.app.NotificationChannel
|
|
6
|
+
import android.app.NotificationManager
|
|
7
|
+
import android.content.Context
|
|
8
|
+
import android.content.pm.PackageManager
|
|
9
|
+
import android.os.Build
|
|
10
|
+
import androidx.core.app.ActivityCompat
|
|
11
|
+
import androidx.core.content.ContextCompat
|
|
12
|
+
import com.dashx.rn.sdk.util.*
|
|
13
|
+
import com.dashx.android.DashX
|
|
14
|
+
import com.dashx.android.DashXLog
|
|
15
|
+
import com.dashx.android.DashXLog.LogLevel
|
|
16
|
+
import com.dashx.android.data.Asset
|
|
17
|
+
import com.facebook.react.bridge.*
|
|
18
|
+
import com.facebook.react.modules.core.PermissionAwareActivity
|
|
19
|
+
import com.facebook.react.modules.core.PermissionListener
|
|
20
|
+
import kotlinx.serialization.decodeFromString
|
|
21
|
+
import kotlinx.serialization.encodeToString
|
|
22
|
+
import kotlinx.serialization.json.Json
|
|
23
|
+
import kotlinx.serialization.json.JsonObject
|
|
24
|
+
|
|
25
|
+
class DashXReactNativeModuleImpl(private val reactContext: ReactApplicationContext) {
|
|
26
|
+
private val tag = DashXReactNativeModuleImpl::class.java.simpleName
|
|
27
|
+
|
|
28
|
+
fun initialize() {
|
|
29
|
+
MessageReceivedEventHolder.reactContext = reactContext
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fun invalidate() {
|
|
33
|
+
MessageReceivedEventHolder.reactContext = null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fun setLogLevel(level: Double) {
|
|
37
|
+
// JS contract: 0 = off, 1 = errors, 2 = debug
|
|
38
|
+
// Native SDK: OFF = -1, ERROR = 0, INFO = 1, DEBUG = 2
|
|
39
|
+
val logLevel = when (level.toInt()) {
|
|
40
|
+
0 -> LogLevel.OFF
|
|
41
|
+
1 -> LogLevel.ERROR
|
|
42
|
+
2 -> LogLevel.DEBUG
|
|
43
|
+
else -> LogLevel.OFF
|
|
44
|
+
}
|
|
45
|
+
DashXLog.setLogLevel(logLevel)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun configure(options: ReadableMap) {
|
|
49
|
+
createDefaultNotificationChannel()
|
|
50
|
+
DashX.configure(
|
|
51
|
+
reactContext,
|
|
52
|
+
options.getString("publicKey")!!,
|
|
53
|
+
options.getStringIfPresent("baseURI"),
|
|
54
|
+
options.getStringIfPresent("targetEnvironment")
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private fun createDefaultNotificationChannel() {
|
|
59
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
|
60
|
+
val notificationManager = reactContext.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return
|
|
61
|
+
|
|
62
|
+
val existing = notificationManager.getNotificationChannel(DEFAULT_CHANNEL_ID)
|
|
63
|
+
if (existing != null) return
|
|
64
|
+
|
|
65
|
+
val channel = NotificationChannel(
|
|
66
|
+
DEFAULT_CHANNEL_ID,
|
|
67
|
+
DEFAULT_CHANNEL_NAME,
|
|
68
|
+
NotificationManager.IMPORTANCE_HIGH
|
|
69
|
+
).apply {
|
|
70
|
+
enableVibration(true)
|
|
71
|
+
setShowBadge(true)
|
|
72
|
+
lockscreenVisibility = android.app.Notification.VISIBILITY_PUBLIC
|
|
73
|
+
}
|
|
74
|
+
notificationManager.createNotificationChannel(channel)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fun identify(options: ReadableMap?) {
|
|
78
|
+
val optionsHashMap = options?.toHashMap()
|
|
79
|
+
?.filterValues { it != null }
|
|
80
|
+
?.mapValues { it.value.toString() }
|
|
81
|
+
DashX.identify(optionsHashMap?.let { HashMap(it) })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fun setIdentity(uid: String?, token: String?) {
|
|
85
|
+
DashX.setIdentity(uid, token)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fun reset() {
|
|
89
|
+
DashX.reset()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fun track(event: String, data: ReadableMap?) {
|
|
93
|
+
val jsonData = try {
|
|
94
|
+
data?.toHashMap()
|
|
95
|
+
?.filterValues { it != null }
|
|
96
|
+
?.mapValues { it.value.toString() }
|
|
97
|
+
?.let { HashMap(it) }
|
|
98
|
+
} catch (e: Exception) {
|
|
99
|
+
DashXLog.d(tag, "Failed to convert track data, sending event without data: ${e.message}")
|
|
100
|
+
null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
DashX.track(event, jsonData)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fun screen(screenName: String, data: ReadableMap?) {
|
|
107
|
+
val screenData = data?.toHashMap()
|
|
108
|
+
?.filterValues { it != null }
|
|
109
|
+
?.mapValues { it.value.toString() }
|
|
110
|
+
?.let { HashMap(it) }
|
|
111
|
+
?: HashMap()
|
|
112
|
+
DashX.screen(screenName, screenData)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fun fetchRecord(urn: String, options: ReadableMap?, promise: Promise) {
|
|
116
|
+
val preview = options?.getBooleanIfPresent("preview")
|
|
117
|
+
val language = options?.getStringIfPresent("language")
|
|
118
|
+
val fields = try {
|
|
119
|
+
convertReadableArrayToKJsonList(options?.getArray("fields"))
|
|
120
|
+
} catch (e: Exception) {
|
|
121
|
+
DashXLog.d(tag, e.message)
|
|
122
|
+
promise.reject(E_UNSPECIFIED, "Error parsing fields: ${e.message}")
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
val include = try {
|
|
126
|
+
convertReadableArrayToKJsonList(options?.getArray("include"))
|
|
127
|
+
} catch (e: Exception) {
|
|
128
|
+
DashXLog.d(tag, e.message)
|
|
129
|
+
promise.reject(E_UNSPECIFIED, "Error parsing include: ${e.message}")
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
val exclude = try {
|
|
133
|
+
convertReadableArrayToKJsonList(options?.getArray("exclude"))
|
|
134
|
+
} catch (e: Exception) {
|
|
135
|
+
DashXLog.d(tag, e.message)
|
|
136
|
+
promise.reject(E_UNSPECIFIED, "Error parsing exclude: ${e.message}")
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
DashX.fetchRecord(
|
|
141
|
+
urn = urn,
|
|
142
|
+
preview = preview,
|
|
143
|
+
language = language,
|
|
144
|
+
fields = fields,
|
|
145
|
+
include = include,
|
|
146
|
+
exclude = exclude,
|
|
147
|
+
onError = {
|
|
148
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
149
|
+
},
|
|
150
|
+
onSuccess = {
|
|
151
|
+
promise.resolve(convertJsonToMap(convertKJsonToJson(it)))
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
fun searchRecords(resource: String, options: ReadableMap?, promise: Promise) {
|
|
157
|
+
val jsonFilter = try {
|
|
158
|
+
convertMapToJson(options?.getMap("filter"))?.let { convertJsonToKJson(it) }
|
|
159
|
+
} catch (e: Exception) {
|
|
160
|
+
DashXLog.d(tag, e.message)
|
|
161
|
+
promise.reject(E_UNSPECIFIED, "Error parsing filter: ${e.message}")
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
val order = try {
|
|
165
|
+
convertReadableArrayToKJsonList(options?.getArray("order"))
|
|
166
|
+
} catch (e: Exception) {
|
|
167
|
+
DashXLog.d(tag, e.message)
|
|
168
|
+
promise.reject(E_UNSPECIFIED, "Error parsing order: ${e.message}")
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
val limit = options?.getIntIfPresent("limit")
|
|
172
|
+
val preview = options?.getBooleanIfPresent("preview")
|
|
173
|
+
val language = options?.getStringIfPresent("language")
|
|
174
|
+
val fields = try {
|
|
175
|
+
convertReadableArrayToKJsonList(options?.getArray("fields"))
|
|
176
|
+
} catch (e: Exception) {
|
|
177
|
+
DashXLog.d(tag, e.message)
|
|
178
|
+
promise.reject(E_UNSPECIFIED, "Error parsing fields: ${e.message}")
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
val include = try {
|
|
182
|
+
convertReadableArrayToKJsonList(options?.getArray("include"))
|
|
183
|
+
} catch (e: Exception) {
|
|
184
|
+
DashXLog.d(tag, e.message)
|
|
185
|
+
promise.reject(E_UNSPECIFIED, "Error parsing include: ${e.message}")
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
val exclude = try {
|
|
189
|
+
convertReadableArrayToKJsonList(options?.getArray("exclude"))
|
|
190
|
+
} catch (e: Exception) {
|
|
191
|
+
DashXLog.d(tag, e.message)
|
|
192
|
+
promise.reject(E_UNSPECIFIED, "Error parsing exclude: ${e.message}")
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
DashX.searchRecords(
|
|
197
|
+
resource = resource,
|
|
198
|
+
filter = jsonFilter,
|
|
199
|
+
order = order,
|
|
200
|
+
limit = limit,
|
|
201
|
+
preview = preview,
|
|
202
|
+
language = language,
|
|
203
|
+
fields = fields,
|
|
204
|
+
include = include,
|
|
205
|
+
exclude = exclude,
|
|
206
|
+
onError = {
|
|
207
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
208
|
+
},
|
|
209
|
+
onSuccess = { records ->
|
|
210
|
+
val readableArray = Arguments.createArray()
|
|
211
|
+
records.forEach {
|
|
212
|
+
readableArray.pushMap(convertJsonToMap(convertKJsonToJson(it)))
|
|
213
|
+
}
|
|
214
|
+
promise.resolve(readableArray)
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fun fetchStoredPreferences(promise: Promise) {
|
|
220
|
+
DashX.fetchStoredPreferences(
|
|
221
|
+
onError = {
|
|
222
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
223
|
+
},
|
|
224
|
+
onSuccess = { content ->
|
|
225
|
+
promise.resolve(convertJsonToMap(convertKJsonToJson(Json.decodeFromString<JsonObject>(Json.encodeToString(content)))))
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
fun saveStoredPreferences(preferenceData: ReadableMap?, promise: Promise) {
|
|
231
|
+
val preferencesString = MapUtil.toJSONElement(preferenceData).toString()
|
|
232
|
+
|
|
233
|
+
DashX.saveStoredPreferences(
|
|
234
|
+
Json.decodeFromString<JsonObject>(preferencesString),
|
|
235
|
+
onError = {
|
|
236
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
237
|
+
},
|
|
238
|
+
onSuccess = { content ->
|
|
239
|
+
promise.resolve(convertJsonToMap(convertKJsonToJson(Json.decodeFromString<JsonObject>(Json.encodeToString(content)))))
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
fun subscribe() {
|
|
245
|
+
DashX.subscribe()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
fun unsubscribe() {
|
|
249
|
+
DashX.unsubscribe()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// --- iOS-only methods: no-op stubs on Android (JS guards prevent these from being called) ---
|
|
253
|
+
|
|
254
|
+
fun enableLifecycleTracking() {
|
|
255
|
+
// iOS-only; no-op on Android
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
fun enableAdTracking() {
|
|
259
|
+
// iOS-only; no-op on Android
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
fun processURL(url: String, source: String?, forwardToLinkHandler: Boolean) {
|
|
263
|
+
// iOS-only; no-op on Android
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
fun trackNotificationNavigation(action: ReadableMap?, notificationId: String?) {
|
|
267
|
+
// iOS-only; no-op on Android
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
fun uploadAsset(filePath: String, resource: String, attribute: String, promise: Promise) {
|
|
271
|
+
val file = java.io.File(filePath)
|
|
272
|
+
DashX.uploadAsset(
|
|
273
|
+
file = file,
|
|
274
|
+
resource = resource,
|
|
275
|
+
attribute = attribute,
|
|
276
|
+
onSuccess = { asset ->
|
|
277
|
+
try {
|
|
278
|
+
val jsonString = Json.encodeToString(asset)
|
|
279
|
+
val jsonObject = org.json.JSONObject(jsonString)
|
|
280
|
+
promise.resolve(convertJsonToMap(jsonObject))
|
|
281
|
+
} catch (e: Exception) {
|
|
282
|
+
promise.resolve(null)
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
onError = {
|
|
286
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
287
|
+
}
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
fun fetchAsset(assetId: String, promise: Promise) {
|
|
292
|
+
DashX.fetchAsset(
|
|
293
|
+
assetId = assetId,
|
|
294
|
+
onSuccess = { asset ->
|
|
295
|
+
try {
|
|
296
|
+
val jsonString = Json.encodeToString(asset)
|
|
297
|
+
val jsonObject = org.json.JSONObject(jsonString)
|
|
298
|
+
promise.resolve(convertJsonToMap(jsonObject))
|
|
299
|
+
} catch (e: Exception) {
|
|
300
|
+
promise.resolve(null)
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
onError = {
|
|
304
|
+
promise.reject(E_UNSPECIFIED, it.message)
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
fun requestNotificationPermission(promise: Promise) {
|
|
310
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
311
|
+
promise.resolve(PERMISSION_AUTHORIZED)
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
val alreadyGranted = ContextCompat.checkSelfPermission(
|
|
316
|
+
reactContext,
|
|
317
|
+
Manifest.permission.POST_NOTIFICATIONS
|
|
318
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
319
|
+
if (alreadyGranted) {
|
|
320
|
+
promise.resolve(PERMISSION_AUTHORIZED)
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
val activity = reactContext.currentActivity as? PermissionAwareActivity
|
|
325
|
+
if (activity == null) {
|
|
326
|
+
promise.reject(E_UNSPECIFIED, "No current activity to request permission from")
|
|
327
|
+
return
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
reactContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
331
|
+
.edit()
|
|
332
|
+
.putBoolean(KEY_PERMISSION_REQUESTED, true)
|
|
333
|
+
.apply()
|
|
334
|
+
|
|
335
|
+
val listener = PermissionListener { requestCode, _, grantResults ->
|
|
336
|
+
if (requestCode != NOTIFICATION_PERMISSION_REQUEST_CODE) return@PermissionListener false
|
|
337
|
+
val granted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
|
|
338
|
+
promise.resolve(if (granted) PERMISSION_AUTHORIZED else PERMISSION_DENIED)
|
|
339
|
+
true
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
activity.requestPermissions(
|
|
343
|
+
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
|
344
|
+
NOTIFICATION_PERMISSION_REQUEST_CODE,
|
|
345
|
+
listener
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
fun getNotificationPermissionStatus(promise: Promise) {
|
|
350
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
351
|
+
promise.resolve(PERMISSION_AUTHORIZED)
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
val granted = ContextCompat.checkSelfPermission(
|
|
355
|
+
reactContext,
|
|
356
|
+
Manifest.permission.POST_NOTIFICATIONS
|
|
357
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
358
|
+
if (granted) {
|
|
359
|
+
promise.resolve(PERMISSION_AUTHORIZED)
|
|
360
|
+
} else {
|
|
361
|
+
val wasRequested = reactContext
|
|
362
|
+
.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
363
|
+
.getBoolean(KEY_PERMISSION_REQUESTED, false)
|
|
364
|
+
promise.resolve(if (wasRequested) PERMISSION_DENIED else PERMISSION_NOT_DETERMINED)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
companion object {
|
|
369
|
+
const val NAME = "DashXReactNative"
|
|
370
|
+
private const val E_UNSPECIFIED = "EUNSPECIFIED"
|
|
371
|
+
private const val DEFAULT_CHANNEL_ID = "default_dashx_notification_channel"
|
|
372
|
+
private const val DEFAULT_CHANNEL_NAME = "Notifications"
|
|
373
|
+
|
|
374
|
+
private const val NOTIFICATION_PERMISSION_REQUEST_CODE = 3571
|
|
375
|
+
|
|
376
|
+
private const val PREFS_NAME = "dashx_rn_prefs"
|
|
377
|
+
private const val KEY_PERMISSION_REQUESTED = "notification_permission_requested"
|
|
378
|
+
|
|
379
|
+
// Mirrors iOS UNAuthorizationStatus values used by the JS layer.
|
|
380
|
+
private const val PERMISSION_NOT_DETERMINED = 0
|
|
381
|
+
private const val PERMISSION_DENIED = 1
|
|
382
|
+
private const val PERMISSION_AUTHORIZED = 2
|
|
383
|
+
}
|
|
384
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package com.dashx.rn.sdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
|
|
7
|
+
class DashXReactNativeModule(reactContext: ReactApplicationContext) :
|
|
8
|
+
NativeDashXReactNativeSpec(reactContext) {
|
|
9
|
+
|
|
10
|
+
private val impl = DashXReactNativeModuleImpl(reactContext)
|
|
11
|
+
|
|
12
|
+
override fun getName(): String = DashXReactNativeModuleImpl.NAME
|
|
13
|
+
|
|
14
|
+
override fun initialize() {
|
|
15
|
+
super.initialize()
|
|
16
|
+
impl.initialize()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun invalidate() {
|
|
20
|
+
impl.invalidate()
|
|
21
|
+
super.invalidate()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun configure(options: ReadableMap) = impl.configure(options)
|
|
25
|
+
|
|
26
|
+
override fun identify(options: ReadableMap?) = impl.identify(options)
|
|
27
|
+
|
|
28
|
+
override fun setIdentity(uid: String?, token: String?) = impl.setIdentity(uid, token)
|
|
29
|
+
|
|
30
|
+
override fun reset() = impl.reset()
|
|
31
|
+
|
|
32
|
+
override fun track(event: String, data: ReadableMap?) = impl.track(event, data)
|
|
33
|
+
|
|
34
|
+
override fun screen(screenName: String, data: ReadableMap?) = impl.screen(screenName, data)
|
|
35
|
+
|
|
36
|
+
override fun fetchRecord(urn: String, options: ReadableMap?, promise: Promise) =
|
|
37
|
+
impl.fetchRecord(urn, options, promise)
|
|
38
|
+
|
|
39
|
+
override fun searchRecords(resource: String, options: ReadableMap?, promise: Promise) =
|
|
40
|
+
impl.searchRecords(resource, options, promise)
|
|
41
|
+
|
|
42
|
+
override fun fetchStoredPreferences(promise: Promise) = impl.fetchStoredPreferences(promise)
|
|
43
|
+
|
|
44
|
+
override fun saveStoredPreferences(preferenceData: ReadableMap?, promise: Promise) =
|
|
45
|
+
impl.saveStoredPreferences(preferenceData, promise)
|
|
46
|
+
|
|
47
|
+
override fun subscribe() = impl.subscribe()
|
|
48
|
+
|
|
49
|
+
override fun unsubscribe() = impl.unsubscribe()
|
|
50
|
+
|
|
51
|
+
override fun setLogLevel(level: Double) = impl.setLogLevel(level)
|
|
52
|
+
|
|
53
|
+
override fun enableLifecycleTracking() = impl.enableLifecycleTracking()
|
|
54
|
+
|
|
55
|
+
override fun enableAdTracking() = impl.enableAdTracking()
|
|
56
|
+
|
|
57
|
+
override fun processURL(url: String, source: String?, forwardToLinkHandler: Boolean) =
|
|
58
|
+
impl.processURL(url, source, forwardToLinkHandler)
|
|
59
|
+
|
|
60
|
+
override fun trackNotificationNavigation(action: ReadableMap?, notificationId: String?) =
|
|
61
|
+
impl.trackNotificationNavigation(action, notificationId)
|
|
62
|
+
|
|
63
|
+
override fun uploadAsset(
|
|
64
|
+
filePath: String,
|
|
65
|
+
resource: String,
|
|
66
|
+
attribute: String,
|
|
67
|
+
promise: Promise
|
|
68
|
+
) = impl.uploadAsset(filePath, resource, attribute, promise)
|
|
69
|
+
|
|
70
|
+
override fun fetchAsset(assetId: String, promise: Promise) = impl.fetchAsset(assetId, promise)
|
|
71
|
+
|
|
72
|
+
override fun requestNotificationPermission(promise: Promise) =
|
|
73
|
+
impl.requestNotificationPermission(promise)
|
|
74
|
+
|
|
75
|
+
override fun getNotificationPermissionStatus(promise: Promise) =
|
|
76
|
+
impl.getNotificationPermissionStatus(promise)
|
|
77
|
+
|
|
78
|
+
override fun addListener(eventName: String) {
|
|
79
|
+
// Required for RN built-in Event Emitter Calls
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
override fun removeListeners(count: Double) {
|
|
83
|
+
// Required for RN built-in Event Emitter Calls
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.dashx.rn.sdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
|
|
9
|
+
class DashXReactNativePackage : BaseReactPackage() {
|
|
10
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
11
|
+
return if (name == DashXReactNativeModuleImpl.NAME) {
|
|
12
|
+
DashXReactNativeModule(reactContext)
|
|
13
|
+
} else {
|
|
14
|
+
null
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
19
|
+
return ReactModuleInfoProvider {
|
|
20
|
+
mapOf(
|
|
21
|
+
DashXReactNativeModuleImpl.NAME to ReactModuleInfo(
|
|
22
|
+
DashXReactNativeModuleImpl.NAME,
|
|
23
|
+
DashXReactNativeModuleImpl.NAME,
|
|
24
|
+
false, // canOverrideExistingModule
|
|
25
|
+
false, // needsEagerInit
|
|
26
|
+
false, // hasConstants
|
|
27
|
+
false, // isCxxModule
|
|
28
|
+
true // isTurboModule
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
package com.dashx.rn.sdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
import com.facebook.react.bridge.ReadableMap
|
|
8
|
+
|
|
9
|
+
class DashXReactNativeModule(reactContext: ReactApplicationContext) :
|
|
10
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
11
|
+
|
|
12
|
+
private val impl = DashXReactNativeModuleImpl(reactContext)
|
|
13
|
+
|
|
14
|
+
override fun getName(): String = DashXReactNativeModuleImpl.NAME
|
|
15
|
+
|
|
16
|
+
override fun initialize() {
|
|
17
|
+
super.initialize()
|
|
18
|
+
impl.initialize()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override fun invalidate() {
|
|
22
|
+
impl.invalidate()
|
|
23
|
+
super.invalidate()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@ReactMethod
|
|
27
|
+
fun configure(options: ReadableMap) = impl.configure(options)
|
|
28
|
+
|
|
29
|
+
@ReactMethod
|
|
30
|
+
fun identify(options: ReadableMap?) = impl.identify(options)
|
|
31
|
+
|
|
32
|
+
@ReactMethod
|
|
33
|
+
fun setIdentity(uid: String?, token: String?) = impl.setIdentity(uid, token)
|
|
34
|
+
|
|
35
|
+
@ReactMethod
|
|
36
|
+
fun reset() = impl.reset()
|
|
37
|
+
|
|
38
|
+
@ReactMethod
|
|
39
|
+
fun track(event: String, data: ReadableMap?) = impl.track(event, data)
|
|
40
|
+
|
|
41
|
+
@ReactMethod
|
|
42
|
+
fun screen(screenName: String, data: ReadableMap?) = impl.screen(screenName, data)
|
|
43
|
+
|
|
44
|
+
@ReactMethod
|
|
45
|
+
fun fetchRecord(urn: String, options: ReadableMap?, promise: Promise) =
|
|
46
|
+
impl.fetchRecord(urn, options, promise)
|
|
47
|
+
|
|
48
|
+
@ReactMethod
|
|
49
|
+
fun searchRecords(resource: String, options: ReadableMap?, promise: Promise) =
|
|
50
|
+
impl.searchRecords(resource, options, promise)
|
|
51
|
+
|
|
52
|
+
@ReactMethod
|
|
53
|
+
fun fetchStoredPreferences(promise: Promise) = impl.fetchStoredPreferences(promise)
|
|
54
|
+
|
|
55
|
+
@ReactMethod
|
|
56
|
+
fun saveStoredPreferences(preferenceData: ReadableMap?, promise: Promise) =
|
|
57
|
+
impl.saveStoredPreferences(preferenceData, promise)
|
|
58
|
+
|
|
59
|
+
@ReactMethod
|
|
60
|
+
fun subscribe() = impl.subscribe()
|
|
61
|
+
|
|
62
|
+
@ReactMethod
|
|
63
|
+
fun unsubscribe() = impl.unsubscribe()
|
|
64
|
+
|
|
65
|
+
@ReactMethod
|
|
66
|
+
fun setLogLevel(level: Double) = impl.setLogLevel(level)
|
|
67
|
+
|
|
68
|
+
@ReactMethod
|
|
69
|
+
fun enableLifecycleTracking() = impl.enableLifecycleTracking()
|
|
70
|
+
|
|
71
|
+
@ReactMethod
|
|
72
|
+
fun enableAdTracking() = impl.enableAdTracking()
|
|
73
|
+
|
|
74
|
+
@ReactMethod
|
|
75
|
+
fun processURL(url: String, source: String?, forwardToLinkHandler: Boolean) =
|
|
76
|
+
impl.processURL(url, source, forwardToLinkHandler)
|
|
77
|
+
|
|
78
|
+
@ReactMethod
|
|
79
|
+
fun trackNotificationNavigation(action: ReadableMap?, notificationId: String?) =
|
|
80
|
+
impl.trackNotificationNavigation(action, notificationId)
|
|
81
|
+
|
|
82
|
+
@ReactMethod
|
|
83
|
+
fun uploadAsset(filePath: String, resource: String, attribute: String, promise: Promise) =
|
|
84
|
+
impl.uploadAsset(filePath, resource, attribute, promise)
|
|
85
|
+
|
|
86
|
+
@ReactMethod
|
|
87
|
+
fun fetchAsset(assetId: String, promise: Promise) = impl.fetchAsset(assetId, promise)
|
|
88
|
+
|
|
89
|
+
@ReactMethod
|
|
90
|
+
fun requestNotificationPermission(promise: Promise) =
|
|
91
|
+
impl.requestNotificationPermission(promise)
|
|
92
|
+
|
|
93
|
+
@ReactMethod
|
|
94
|
+
fun getNotificationPermissionStatus(promise: Promise) =
|
|
95
|
+
impl.getNotificationPermissionStatus(promise)
|
|
96
|
+
|
|
97
|
+
@ReactMethod
|
|
98
|
+
fun addListener(eventName: String) {
|
|
99
|
+
// Required for RN built-in Event Emitter Calls
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@ReactMethod
|
|
103
|
+
fun removeListeners(count: Double) {
|
|
104
|
+
// Required for RN built-in Event Emitter Calls
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.dashx.rn.sdk
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
|
|
9
|
+
class DashXReactNativePackage : BaseReactPackage() {
|
|
10
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
11
|
+
return if (name == DashXReactNativeModuleImpl.NAME) {
|
|
12
|
+
DashXReactNativeModule(reactContext)
|
|
13
|
+
} else {
|
|
14
|
+
null
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
19
|
+
return ReactModuleInfoProvider {
|
|
20
|
+
mapOf(
|
|
21
|
+
DashXReactNativeModuleImpl.NAME to ReactModuleInfo(
|
|
22
|
+
DashXReactNativeModuleImpl.NAME,
|
|
23
|
+
DashXReactNativeModuleImpl.NAME,
|
|
24
|
+
false, // canOverrideExistingModule
|
|
25
|
+
false, // needsEagerInit
|
|
26
|
+
false, // hasConstants
|
|
27
|
+
false, // isCxxModule
|
|
28
|
+
false // isTurboModule
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { EmitterSubscription } from 'react-native';
|
|
|
7
7
|
export enum DashXErrorCode {
|
|
8
8
|
/** An unspecified error occurred. */
|
|
9
9
|
EUNSPECIFIED = 'EUNSPECIFIED',
|
|
10
|
+
/** The operation is not supported on this platform. */
|
|
11
|
+
EUNSUPPORTED = 'EUNSUPPORTED',
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export interface ConfigureOptions {
|
|
@@ -72,6 +74,12 @@ export type NavigationAction =
|
|
|
72
74
|
| { type: 'richLanding'; url: string }
|
|
73
75
|
| { type: 'clickAction'; action: string };
|
|
74
76
|
|
|
77
|
+
export interface NotificationClickedEvent {
|
|
78
|
+
notification: NotificationMessage;
|
|
79
|
+
action: NavigationAction | null;
|
|
80
|
+
actionIdentifier: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
75
83
|
export interface ProcessURLOptions {
|
|
76
84
|
source?: string;
|
|
77
85
|
forwardToLinkHandler?: boolean;
|
|
@@ -90,9 +98,11 @@ export interface DashXInstance {
|
|
|
90
98
|
identify(options: IdentifyOptions): void;
|
|
91
99
|
|
|
92
100
|
/**
|
|
93
|
-
* Set user identity using a UID and authentication token.
|
|
101
|
+
* Set user identity using a UID and authentication token. Both are
|
|
102
|
+
* nullable — passing `null` clears that field on the native SDK. Empty
|
|
103
|
+
* strings are forwarded as-is (no coercion to `null`).
|
|
94
104
|
*/
|
|
95
|
-
setIdentity(uid: string, token
|
|
105
|
+
setIdentity(uid: string | null, token?: string | null): void;
|
|
96
106
|
|
|
97
107
|
/**
|
|
98
108
|
* Clear the current user identity and reset SDK state.
|
|
@@ -222,6 +232,18 @@ export interface DashXInstance {
|
|
|
222
232
|
* Returns a subscription that can be removed via `.remove()`.
|
|
223
233
|
*/
|
|
224
234
|
onLinkReceived(callback: (url: string) => void): EmitterSubscription;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Register a listener for notification tap events. Fired when the user taps
|
|
238
|
+
* a DashX notification or one of its action buttons. The callback receives
|
|
239
|
+
* the full notification payload, the resolved `NavigationAction` (parsed
|
|
240
|
+
* from the payload; `null` if no navigation intent could be resolved), and
|
|
241
|
+
* the raw `actionIdentifier` from `UNNotificationResponse`.
|
|
242
|
+
* Returns a subscription that can be removed via `.remove()`.
|
|
243
|
+
*/
|
|
244
|
+
onNotificationClicked(
|
|
245
|
+
callback: (event: NotificationClickedEvent) => void
|
|
246
|
+
): EmitterSubscription;
|
|
225
247
|
}
|
|
226
248
|
|
|
227
249
|
declare const DashX: DashXInstance;
|