@amplitude/analytics-react-native 1.3.3 → 1.3.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.
- package/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativeModule.kt +101 -0
- package/android/src/main/java/com/amplitude/reactnative/LegacyDatabaseStorage.kt +313 -0
- package/ios/AmplitudeReactNative.m +3 -0
- package/ios/AmplitudeReactNative.swift +74 -0
- package/ios/AmplitudeReactNative.xcodeproj/project.pbxproj +9 -17
- package/ios/LegacyDatabaseStorage.swift +224 -0
- package/lib/commonjs/config.js +19 -7
- package/lib/commonjs/config.js.map +1 -1
- package/lib/commonjs/migration/remnant-data-migration.js +170 -0
- package/lib/commonjs/migration/remnant-data-migration.js.map +1 -0
- package/lib/commonjs/react-native-client.js +2 -2
- package/lib/commonjs/react-native-client.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/config.js +18 -7
- package/lib/module/config.js.map +1 -1
- package/lib/module/migration/remnant-data-migration.js +163 -0
- package/lib/module/migration/remnant-data-migration.js.map +1 -0
- package/lib/module/react-native-client.js +2 -2
- package/lib/module/react-native-client.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/config.d.ts.map +1 -1
- package/lib/typescript/migration/remnant-data-migration.d.ts +20 -0
- package/lib/typescript/migration/remnant-data-migration.d.ts.map +1 -0
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +5 -5
- package/src/config.ts +26 -7
- package/src/migration/remnant-data-migration.ts +168 -0
- package/src/react-native-client.ts +2 -2
- package/src/version.ts +1 -1
|
@@ -6,12 +6,20 @@ import com.facebook.react.bridge.ReactApplicationContext
|
|
|
6
6
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
7
7
|
import com.facebook.react.bridge.ReactMethod
|
|
8
8
|
import com.facebook.react.bridge.ReadableMap
|
|
9
|
+
import com.facebook.react.bridge.WritableNativeArray
|
|
9
10
|
import com.facebook.react.bridge.WritableNativeMap
|
|
10
11
|
|
|
11
12
|
const val MODULE_NAME = "AmplitudeReactNative"
|
|
12
13
|
|
|
13
14
|
@ReactModule(name = MODULE_NAME)
|
|
14
15
|
class AmplitudeReactNativeModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
16
|
+
companion object {
|
|
17
|
+
const val DEVICE_ID_KEY = "device_id"
|
|
18
|
+
const val USER_ID_KEY = "user_id"
|
|
19
|
+
const val LAST_EVENT_TIME_KEY = "last_event_time"
|
|
20
|
+
const val LAST_EVENT_ID_KEY = "last_event_id"
|
|
21
|
+
const val PREVIOUS_SESSION_ID_KEY = "previous_session_id"
|
|
22
|
+
}
|
|
15
23
|
|
|
16
24
|
private var androidContextProvider: AndroidContextProvider? = null
|
|
17
25
|
|
|
@@ -42,4 +50,97 @@ class AmplitudeReactNativeModule(private val reactContext: ReactApplicationConte
|
|
|
42
50
|
putString("appSetId", androidContextProvider!!.appSetId)
|
|
43
51
|
})
|
|
44
52
|
}
|
|
53
|
+
|
|
54
|
+
@ReactMethod
|
|
55
|
+
private fun getLegacySessionData(instanceName: String?, promise: Promise) {
|
|
56
|
+
try {
|
|
57
|
+
val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)
|
|
58
|
+
val deviceId = getLegacyValue(storage, DEVICE_ID_KEY)
|
|
59
|
+
val userId = getLegacyValue(storage, USER_ID_KEY)
|
|
60
|
+
val previousSessionId = getLegacyLongValue(storage, PREVIOUS_SESSION_ID_KEY)
|
|
61
|
+
val lastEventTime = getLegacyLongValue(storage, LAST_EVENT_TIME_KEY)
|
|
62
|
+
val lastEventId = getLegacyLongValue(storage, LAST_EVENT_ID_KEY)
|
|
63
|
+
promise.resolve(WritableNativeMap().apply {
|
|
64
|
+
if (deviceId != null) {
|
|
65
|
+
putString("deviceId", deviceId)
|
|
66
|
+
}
|
|
67
|
+
if (userId != null) {
|
|
68
|
+
putString("userId", userId)
|
|
69
|
+
}
|
|
70
|
+
if (previousSessionId != null) {
|
|
71
|
+
putDouble("sessionId", previousSessionId.toDouble())
|
|
72
|
+
}
|
|
73
|
+
if (lastEventTime != null) {
|
|
74
|
+
putDouble("lastEventTime", lastEventTime.toDouble())
|
|
75
|
+
}
|
|
76
|
+
if (lastEventId != null) {
|
|
77
|
+
putDouble("lastEventId", lastEventId.toDouble())
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
} catch (e: Exception) {
|
|
81
|
+
LogcatLogger.logger.error(
|
|
82
|
+
"can't get legacy session data: $e"
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private fun getLegacyValue(storage: LegacyDatabaseStorage, key: String): String? {
|
|
88
|
+
try {
|
|
89
|
+
return storage.getValue(key)
|
|
90
|
+
} catch (e: Exception) {
|
|
91
|
+
LogcatLogger.logger.error(
|
|
92
|
+
"can't get legacy $key: $e"
|
|
93
|
+
)
|
|
94
|
+
return null
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private fun getLegacyLongValue(storage: LegacyDatabaseStorage, key: String): Long? {
|
|
99
|
+
try {
|
|
100
|
+
return storage.getLongValue(key)
|
|
101
|
+
} catch (e: Exception) {
|
|
102
|
+
LogcatLogger.logger.error(
|
|
103
|
+
"can't get legacy $key: $e"
|
|
104
|
+
)
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@ReactMethod
|
|
110
|
+
private fun getLegacyEvents(instanceName: String?, eventKind: String, promise: Promise) {
|
|
111
|
+
try {
|
|
112
|
+
val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)
|
|
113
|
+
val jsonEvents = when (eventKind) {
|
|
114
|
+
"event" -> storage.readEvents()
|
|
115
|
+
"identify" -> storage.readIdentifies()
|
|
116
|
+
"interceptedIdentify" -> storage.readInterceptedIdentifies()
|
|
117
|
+
else -> listOf()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
val events = WritableNativeArray()
|
|
121
|
+
jsonEvents.forEach { event -> events.pushString(event.toString()) }
|
|
122
|
+
promise.resolve(events)
|
|
123
|
+
} catch (e: Exception) {
|
|
124
|
+
LogcatLogger.logger.error(
|
|
125
|
+
"can't get legacy ${eventKind}s: $e"
|
|
126
|
+
)
|
|
127
|
+
promise.resolve(WritableNativeArray())
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@ReactMethod
|
|
132
|
+
private fun removeLegacyEvent(instanceName: String?, eventKind: String, eventId: Int) {
|
|
133
|
+
try {
|
|
134
|
+
val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)
|
|
135
|
+
when (eventKind) {
|
|
136
|
+
"event" -> storage.removeEvent(eventId)
|
|
137
|
+
"identify" -> storage.removeIdentify(eventId)
|
|
138
|
+
"interceptedIdentify" -> storage.removeInterceptedIdentify(eventId)
|
|
139
|
+
}
|
|
140
|
+
} catch (e: Exception) {
|
|
141
|
+
LogcatLogger.logger.error(
|
|
142
|
+
"can't remove legacy $eventKind with id=$eventId: $e"
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
45
146
|
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
package com.amplitude.reactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.database.Cursor
|
|
5
|
+
import android.database.sqlite.SQLiteDatabase
|
|
6
|
+
import android.database.sqlite.SQLiteException
|
|
7
|
+
import android.database.sqlite.SQLiteOpenHelper
|
|
8
|
+
import org.json.JSONObject
|
|
9
|
+
import java.io.File
|
|
10
|
+
import java.util.LinkedList
|
|
11
|
+
import java.util.Locale
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Store the database related constants.
|
|
15
|
+
* Align with com/amplitude/api/DatabaseHelper.java in previous SDK.
|
|
16
|
+
*/
|
|
17
|
+
object DatabaseConstants {
|
|
18
|
+
const val DEFAULT_INSTANCE = "\$default_instance"
|
|
19
|
+
const val DATABASE_NAME = "com.amplitude.api"
|
|
20
|
+
const val DATABASE_VERSION = 4
|
|
21
|
+
|
|
22
|
+
const val EVENT_TABLE_NAME = "events"
|
|
23
|
+
const val IDENTIFY_TABLE_NAME = "identifys"
|
|
24
|
+
const val IDENTIFY_INTERCEPTOR_TABLE_NAME = "identify_interceptor"
|
|
25
|
+
const val ID_FIELD = "id"
|
|
26
|
+
const val EVENT_FIELD = "event"
|
|
27
|
+
|
|
28
|
+
const val LONG_STORE_TABLE_NAME = "long_store"
|
|
29
|
+
const val STORE_TABLE_NAME = "store"
|
|
30
|
+
const val KEY_FIELD = "key"
|
|
31
|
+
const val VALUE_FIELD = "value"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The SDK doesn't need to write/read from local sqlite database.
|
|
36
|
+
* This storage class is used for migrating events only.
|
|
37
|
+
*/
|
|
38
|
+
class LegacyDatabaseStorage(context: Context, databaseName: String) : SQLiteOpenHelper(
|
|
39
|
+
context,
|
|
40
|
+
databaseName,
|
|
41
|
+
null,
|
|
42
|
+
DatabaseConstants.DATABASE_VERSION
|
|
43
|
+
) {
|
|
44
|
+
private var file: File = context.getDatabasePath(databaseName)
|
|
45
|
+
var currentDbVersion: Int = DatabaseConstants.DATABASE_VERSION
|
|
46
|
+
private set
|
|
47
|
+
|
|
48
|
+
override fun onCreate(db: SQLiteDatabase) {
|
|
49
|
+
throw NotImplementedError()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
|
|
53
|
+
currentDbVersion = oldVersion
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private fun queryDb(
|
|
57
|
+
db: SQLiteDatabase,
|
|
58
|
+
table: String?,
|
|
59
|
+
columns: Array<String?>?,
|
|
60
|
+
selection: String?,
|
|
61
|
+
selectionArgs: Array<String?>?,
|
|
62
|
+
orderBy: String?,
|
|
63
|
+
): Cursor? {
|
|
64
|
+
return db.query(table, columns, selection, selectionArgs, null, null, orderBy, null)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private fun handleIfCursorRowTooLargeException(e: java.lang.IllegalStateException) {
|
|
68
|
+
val message = e.message
|
|
69
|
+
if (!message.isNullOrEmpty() && message.contains("Couldn't read") && message.contains("CursorWindow")) {
|
|
70
|
+
closeDb()
|
|
71
|
+
} else {
|
|
72
|
+
throw e
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private fun convertIfCursorWindowException(e: java.lang.RuntimeException) {
|
|
77
|
+
val message = e.message
|
|
78
|
+
if (!message.isNullOrEmpty() && (message.startsWith("Cursor window allocation of") || message.startsWith("Could not allocate CursorWindow"))) {
|
|
79
|
+
throw CursorWindowAllocationException(message)
|
|
80
|
+
} else {
|
|
81
|
+
throw e
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private fun closeDb() {
|
|
86
|
+
try {
|
|
87
|
+
close()
|
|
88
|
+
} catch (e: Exception) {
|
|
89
|
+
LogcatLogger.logger.error("close failed: ${e.message}")
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Synchronized
|
|
94
|
+
fun readEvents(): List<JSONObject> {
|
|
95
|
+
return readEventsFromTable(DatabaseConstants.EVENT_TABLE_NAME)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@Synchronized
|
|
99
|
+
fun readIdentifies(): List<JSONObject> {
|
|
100
|
+
return readEventsFromTable(DatabaseConstants.IDENTIFY_TABLE_NAME)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@Synchronized
|
|
104
|
+
fun readInterceptedIdentifies(): List<JSONObject> {
|
|
105
|
+
if (currentDbVersion < 4) {
|
|
106
|
+
return listOf()
|
|
107
|
+
}
|
|
108
|
+
return readEventsFromTable(DatabaseConstants.IDENTIFY_INTERCEPTOR_TABLE_NAME)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private fun readEventsFromTable(table: String): List<JSONObject> {
|
|
112
|
+
if (!file.exists()) {
|
|
113
|
+
return arrayListOf()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
val events: MutableList<JSONObject> = LinkedList()
|
|
117
|
+
var cursor: Cursor? = null
|
|
118
|
+
try {
|
|
119
|
+
val db = readableDatabase
|
|
120
|
+
cursor = queryDb(
|
|
121
|
+
db,
|
|
122
|
+
table,
|
|
123
|
+
arrayOf(DatabaseConstants.ID_FIELD, DatabaseConstants.EVENT_FIELD),
|
|
124
|
+
null,
|
|
125
|
+
null,
|
|
126
|
+
DatabaseConstants.ID_FIELD + " ASC",
|
|
127
|
+
)
|
|
128
|
+
while (cursor!!.moveToNext()) {
|
|
129
|
+
val eventId = cursor.getLong(0)
|
|
130
|
+
val event = cursor.getString(1)
|
|
131
|
+
if (event.isNullOrEmpty()) {
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
val obj = JSONObject(event)
|
|
135
|
+
obj.put("event_id", eventId)
|
|
136
|
+
events.add(obj)
|
|
137
|
+
}
|
|
138
|
+
} catch (e: SQLiteException) {
|
|
139
|
+
LogcatLogger.logger.error(
|
|
140
|
+
"read events from $table failed: ${e.message}"
|
|
141
|
+
)
|
|
142
|
+
closeDb()
|
|
143
|
+
} catch (e: StackOverflowError) {
|
|
144
|
+
LogcatLogger.logger.error(
|
|
145
|
+
"read events from $table failed: ${e.message}"
|
|
146
|
+
)
|
|
147
|
+
closeDb()
|
|
148
|
+
} catch (e: IllegalStateException) { // put before Runtime since IllegalState extends
|
|
149
|
+
handleIfCursorRowTooLargeException(e)
|
|
150
|
+
} catch (e: RuntimeException) {
|
|
151
|
+
convertIfCursorWindowException(e)
|
|
152
|
+
} finally {
|
|
153
|
+
cursor?.close()
|
|
154
|
+
close()
|
|
155
|
+
}
|
|
156
|
+
return events
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@Synchronized
|
|
160
|
+
fun removeEvent(eventId: Int) {
|
|
161
|
+
removeEventFromTable(DatabaseConstants.EVENT_TABLE_NAME, eventId)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@Synchronized
|
|
165
|
+
fun removeIdentify(eventId: Int) {
|
|
166
|
+
removeEventFromTable(DatabaseConstants.IDENTIFY_TABLE_NAME, eventId)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Synchronized
|
|
170
|
+
fun removeInterceptedIdentify(eventId: Int) {
|
|
171
|
+
if (currentDbVersion < 4) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
removeEventFromTable(DatabaseConstants.IDENTIFY_INTERCEPTOR_TABLE_NAME, eventId)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private fun removeEventFromTable(table: String, eventId: Int) {
|
|
178
|
+
try {
|
|
179
|
+
val db = writableDatabase
|
|
180
|
+
db.delete(
|
|
181
|
+
table,
|
|
182
|
+
"${DatabaseConstants.ID_FIELD} = ?",
|
|
183
|
+
arrayOf(eventId.toString())
|
|
184
|
+
)
|
|
185
|
+
} catch (e: SQLiteException) {
|
|
186
|
+
LogcatLogger.logger.error(
|
|
187
|
+
"remove events from $table failed: ${e.message}"
|
|
188
|
+
)
|
|
189
|
+
closeDb()
|
|
190
|
+
} catch (e: StackOverflowError) {
|
|
191
|
+
LogcatLogger.logger.error(
|
|
192
|
+
"remove events from $table failed: ${e.message}"
|
|
193
|
+
)
|
|
194
|
+
closeDb()
|
|
195
|
+
} finally {
|
|
196
|
+
close()
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@Synchronized
|
|
201
|
+
fun getValue(key: String): String? {
|
|
202
|
+
return getValueFromTable(DatabaseConstants.STORE_TABLE_NAME, key) as String?
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@Synchronized
|
|
206
|
+
fun getLongValue(key: String): Long? {
|
|
207
|
+
return getValueFromTable(DatabaseConstants.LONG_STORE_TABLE_NAME, key) as Long?
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private fun getValueFromTable(table: String, key: String): Any? {
|
|
211
|
+
if (!file.exists()) {
|
|
212
|
+
return null
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
var value: Any? = null
|
|
216
|
+
var cursor: Cursor? = null
|
|
217
|
+
try {
|
|
218
|
+
val db = readableDatabase
|
|
219
|
+
cursor = queryDb(
|
|
220
|
+
db,
|
|
221
|
+
table,
|
|
222
|
+
arrayOf<String?>(
|
|
223
|
+
DatabaseConstants.KEY_FIELD,
|
|
224
|
+
DatabaseConstants.VALUE_FIELD
|
|
225
|
+
),
|
|
226
|
+
DatabaseConstants.KEY_FIELD + " = ?",
|
|
227
|
+
arrayOf(key),
|
|
228
|
+
null,
|
|
229
|
+
)
|
|
230
|
+
if (cursor!!.moveToFirst()) {
|
|
231
|
+
value = if (table == DatabaseConstants.STORE_TABLE_NAME) cursor.getString(1) else cursor.getLong(1)
|
|
232
|
+
}
|
|
233
|
+
} catch (e: SQLiteException) {
|
|
234
|
+
LogcatLogger.logger.error(
|
|
235
|
+
"getValue from $table failed: ${e.message}"
|
|
236
|
+
)
|
|
237
|
+
// Hard to recover from SQLiteExceptions, just start fresh
|
|
238
|
+
closeDb()
|
|
239
|
+
} catch (e: StackOverflowError) {
|
|
240
|
+
LogcatLogger.logger.error(
|
|
241
|
+
"getValue from $table failed: ${e.message}"
|
|
242
|
+
)
|
|
243
|
+
// potential stack overflow error when getting database on custom Android versions
|
|
244
|
+
closeDb()
|
|
245
|
+
} catch (e: IllegalStateException) { // put before Runtime since IllegalState extends
|
|
246
|
+
// cursor window row too big exception
|
|
247
|
+
handleIfCursorRowTooLargeException(e)
|
|
248
|
+
} catch (e: RuntimeException) {
|
|
249
|
+
// cursor window allocation exception
|
|
250
|
+
convertIfCursorWindowException(e)
|
|
251
|
+
} finally {
|
|
252
|
+
cursor?.close()
|
|
253
|
+
close()
|
|
254
|
+
}
|
|
255
|
+
return value
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@Synchronized
|
|
259
|
+
fun removeValue(key: String) {
|
|
260
|
+
removeValueFromTable(DatabaseConstants.STORE_TABLE_NAME, key)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@Synchronized
|
|
264
|
+
fun removeLongValue(key: String) {
|
|
265
|
+
removeValueFromTable(DatabaseConstants.LONG_STORE_TABLE_NAME, key)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private fun removeValueFromTable(table: String, key: String) {
|
|
269
|
+
try {
|
|
270
|
+
val db = writableDatabase
|
|
271
|
+
db.delete(
|
|
272
|
+
table,
|
|
273
|
+
"${DatabaseConstants.KEY_FIELD} = ?",
|
|
274
|
+
arrayOf(key)
|
|
275
|
+
)
|
|
276
|
+
} catch (e: SQLiteException) {
|
|
277
|
+
LogcatLogger.logger.error(
|
|
278
|
+
"remove value from $table failed: ${e.message}"
|
|
279
|
+
)
|
|
280
|
+
closeDb()
|
|
281
|
+
} catch (e: StackOverflowError) {
|
|
282
|
+
LogcatLogger.logger.error(
|
|
283
|
+
"remove value from $table failed: ${e.message}"
|
|
284
|
+
)
|
|
285
|
+
closeDb()
|
|
286
|
+
} finally {
|
|
287
|
+
close()
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
class CursorWindowAllocationException(description: String?) :
|
|
293
|
+
java.lang.RuntimeException(description)
|
|
294
|
+
|
|
295
|
+
object LegacyDatabaseStorageProvider {
|
|
296
|
+
private val instances: MutableMap<String, LegacyDatabaseStorage> = mutableMapOf()
|
|
297
|
+
|
|
298
|
+
fun getStorage(context: Context, instanceName: String?): LegacyDatabaseStorage {
|
|
299
|
+
val databaseName = getDatabaseName(instanceName)
|
|
300
|
+
var storage = instances[databaseName]
|
|
301
|
+
if (storage == null) {
|
|
302
|
+
storage = LegacyDatabaseStorage(context, databaseName)
|
|
303
|
+
instances[databaseName] = storage
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return storage
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private fun getDatabaseName(instanceName: String?): String {
|
|
310
|
+
val normalizedInstanceName = instanceName?.lowercase(Locale.getDefault())
|
|
311
|
+
return if (normalizedInstanceName.isNullOrEmpty() || normalizedInstanceName == DatabaseConstants.DEFAULT_INSTANCE) DatabaseConstants.DATABASE_NAME else "${DatabaseConstants.DATABASE_NAME}_$normalizedInstanceName"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -3,5 +3,8 @@
|
|
|
3
3
|
@interface RCT_EXTERN_MODULE(AmplitudeReactNative, NSObject)
|
|
4
4
|
|
|
5
5
|
RCT_EXTERN_METHOD(getApplicationContext: (NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
6
|
+
RCT_EXTERN_METHOD(getLegacySessionData: (NSString*)instanceName resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
7
|
+
RCT_EXTERN_METHOD(getLegacyEvents: (NSString*)instanceName eventKind:(NSString*)eventKind resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
8
|
+
RCT_EXTERN_METHOD(removeLegacyEvent: (NSString*)instanceName eventKind:(NSString*)eventKind eventId:(double)eventId)
|
|
6
9
|
|
|
7
10
|
@end
|
|
@@ -33,4 +33,78 @@ class ReactNative: NSObject {
|
|
|
33
33
|
}
|
|
34
34
|
resolve(applicationContext)
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
@objc
|
|
38
|
+
func getLegacySessionData(
|
|
39
|
+
_ instanceName: String?,
|
|
40
|
+
resolver resolve: RCTPromiseResolveBlock,
|
|
41
|
+
rejecter reject: RCTPromiseRejectBlock
|
|
42
|
+
) -> Void {
|
|
43
|
+
let storage = LegacyDatabaseStorage.getStorage(instanceName)
|
|
44
|
+
var sessionData: [String: Any?] = [:]
|
|
45
|
+
|
|
46
|
+
if let deviceId = storage.getValue("device_id") {
|
|
47
|
+
sessionData["deviceId"] = deviceId
|
|
48
|
+
}
|
|
49
|
+
if let userId = storage.getValue("user_id") {
|
|
50
|
+
sessionData["userId"] = userId
|
|
51
|
+
}
|
|
52
|
+
if let previousSessionId = storage.getLongValue("previous_session_id") {
|
|
53
|
+
sessionData["sessionId"] = previousSessionId
|
|
54
|
+
}
|
|
55
|
+
if let lastEventTime = storage.getLongValue("previous_session_time") {
|
|
56
|
+
sessionData["lastEventTime"] = lastEventTime
|
|
57
|
+
}
|
|
58
|
+
if let lastEventId = storage.getLastEventId() {
|
|
59
|
+
sessionData["lastEventId"] = lastEventId
|
|
60
|
+
}
|
|
61
|
+
resolve(sessionData)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@objc
|
|
65
|
+
func getLegacyEvents(
|
|
66
|
+
_ instanceName: String?,
|
|
67
|
+
eventKind: String,
|
|
68
|
+
resolver resolve: RCTPromiseResolveBlock,
|
|
69
|
+
rejecter reject: RCTPromiseRejectBlock
|
|
70
|
+
) -> Void {
|
|
71
|
+
let storage = LegacyDatabaseStorage.getStorage(instanceName)
|
|
72
|
+
var events: [[String: Any]] = []
|
|
73
|
+
switch eventKind {
|
|
74
|
+
case "event":
|
|
75
|
+
events = storage.readEvents()
|
|
76
|
+
case "identify":
|
|
77
|
+
events = storage.readIdentifies()
|
|
78
|
+
case "interceptedIdentify":
|
|
79
|
+
events = storage.readInterceptedIdentifies()
|
|
80
|
+
default:
|
|
81
|
+
break
|
|
82
|
+
}
|
|
83
|
+
var jsonEvents: [String] = []
|
|
84
|
+
events.forEach { event in
|
|
85
|
+
if let jsonEvent = try? JSONSerialization.data(withJSONObject: event) {
|
|
86
|
+
jsonEvents.append(String(decoding: jsonEvent, as: UTF8.self))
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
resolve(jsonEvents)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@objc
|
|
93
|
+
func removeLegacyEvent(
|
|
94
|
+
_ instanceName: String?,
|
|
95
|
+
eventKind: String,
|
|
96
|
+
eventId: Double
|
|
97
|
+
) -> Void {
|
|
98
|
+
let storage = LegacyDatabaseStorage.getStorage(instanceName)
|
|
99
|
+
switch eventKind {
|
|
100
|
+
case "event":
|
|
101
|
+
storage.removeEvent(Int64(eventId))
|
|
102
|
+
case "identify":
|
|
103
|
+
storage.removeIdentify(Int64(eventId))
|
|
104
|
+
case "interceptedIdentify":
|
|
105
|
+
storage.removeInterceptedIdentify(Int64(eventId))
|
|
106
|
+
default:
|
|
107
|
+
break
|
|
108
|
+
}
|
|
109
|
+
}
|
|
36
110
|
}
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
objects = {
|
|
8
8
|
|
|
9
9
|
/* Begin PBXBuildFile section */
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
F4FF95D7245B92E800C19C63 /*
|
|
13
|
-
|
|
10
|
+
5E555C0D2413F4C50049A1A2 /* PBXBuildFile */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */; };
|
|
11
|
+
8EDEC1ED2DCD14B370FA86F1 /* LegacyDatabaseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */; };
|
|
12
|
+
F4FF95D7245B92E800C19C63 /* AmplitudeReactNative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */; };
|
|
14
13
|
/* End PBXBuildFile section */
|
|
15
14
|
|
|
16
15
|
/* Begin PBXCopyFilesBuildPhase section */
|
|
@@ -27,11 +26,10 @@
|
|
|
27
26
|
|
|
28
27
|
/* Begin PBXFileReference section */
|
|
29
28
|
134814201AA4EA6300B7C361 /* libAmplitudeReactNative.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAmplitudeReactNative.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
30
|
-
|
|
29
|
+
8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyDatabaseStorage.swift; sourceTree = "<group>"; };
|
|
31
30
|
B3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AmplitudeReactNative.m; sourceTree = "<group>"; };
|
|
32
31
|
F4FF95D5245B92E700C19C63 /* AmplitudeReactNative-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AmplitudeReactNative-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
33
32
|
F4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmplitudeReactNative.swift; sourceTree = "<group>"; };
|
|
34
|
-
|
|
35
33
|
/* End PBXFileReference section */
|
|
36
34
|
|
|
37
35
|
/* Begin PBXFrameworksBuildPhase section */
|
|
@@ -56,12 +54,11 @@
|
|
|
56
54
|
58B511D21A9E6C8500147676 = {
|
|
57
55
|
isa = PBXGroup;
|
|
58
56
|
children = (
|
|
59
|
-
|
|
60
57
|
F4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */,
|
|
61
58
|
B3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */,
|
|
62
59
|
F4FF95D5245B92E700C19C63 /* AmplitudeReactNative-Bridging-Header.h */,
|
|
63
|
-
|
|
64
60
|
134814211AA4EA7D00B7C361 /* Products */,
|
|
61
|
+
8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */,
|
|
65
62
|
);
|
|
66
63
|
sourceTree = "<group>";
|
|
67
64
|
};
|
|
@@ -99,7 +96,7 @@
|
|
|
99
96
|
};
|
|
100
97
|
};
|
|
101
98
|
};
|
|
102
|
-
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "
|
|
99
|
+
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "AmplitudeReactNative" */;
|
|
103
100
|
compatibilityVersion = "Xcode 3.2";
|
|
104
101
|
developmentRegion = English;
|
|
105
102
|
hasScannedForEncodings = 0;
|
|
@@ -122,10 +119,9 @@
|
|
|
122
119
|
isa = PBXSourcesBuildPhase;
|
|
123
120
|
buildActionMask = 2147483647;
|
|
124
121
|
files = (
|
|
125
|
-
|
|
126
122
|
F4FF95D7245B92E800C19C63 /* AmplitudeReactNative.swift in Sources */,
|
|
127
|
-
B3E7B58A1CC2AC0600A0062D
|
|
128
|
-
|
|
123
|
+
B3E7B58A1CC2AC0600A0062D,
|
|
124
|
+
8EDEC1ED2DCD14B370FA86F1 /* LegacyDatabaseStorage.swift in Sources */,
|
|
129
125
|
);
|
|
130
126
|
runOnlyForDeploymentPostprocessing = 0;
|
|
131
127
|
};
|
|
@@ -238,11 +234,9 @@
|
|
|
238
234
|
OTHER_LDFLAGS = "-ObjC";
|
|
239
235
|
PRODUCT_NAME = ReactNative;
|
|
240
236
|
SKIP_INSTALL = YES;
|
|
241
|
-
|
|
242
237
|
SWIFT_OBJC_BRIDGING_HEADER = "AmplitudeReactNative-Bridging-Header.h";
|
|
243
238
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
244
239
|
SWIFT_VERSION = 5.0;
|
|
245
|
-
|
|
246
240
|
};
|
|
247
241
|
name = Debug;
|
|
248
242
|
};
|
|
@@ -259,17 +253,15 @@
|
|
|
259
253
|
OTHER_LDFLAGS = "-ObjC";
|
|
260
254
|
PRODUCT_NAME = ReactNative;
|
|
261
255
|
SKIP_INSTALL = YES;
|
|
262
|
-
|
|
263
256
|
SWIFT_OBJC_BRIDGING_HEADER = "AmplitudeReactNative-Bridging-Header.h";
|
|
264
257
|
SWIFT_VERSION = 5.0;
|
|
265
|
-
|
|
266
258
|
};
|
|
267
259
|
name = Release;
|
|
268
260
|
};
|
|
269
261
|
/* End XCBuildConfiguration section */
|
|
270
262
|
|
|
271
263
|
/* Begin XCConfigurationList section */
|
|
272
|
-
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "
|
|
264
|
+
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "AmplitudeReactNative" */ = {
|
|
273
265
|
isa = XCConfigurationList;
|
|
274
266
|
buildConfigurations = (
|
|
275
267
|
58B511ED1A9E6C8500147676 /* Debug */,
|