@amplitude/plugin-engagement-react-native 0.1.1-alpha.3 → 0.1.1-alpha.5
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
|
@@ -16,8 +16,27 @@ npm install @amplitude/plugin-engagement-react-native
|
|
|
16
16
|
npm install @react-native-async-storage/async-storage
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
Add the source for the `AmplitudeEngagementSwift` pod to your Podfile:
|
|
20
|
+
```rb
|
|
21
|
+
target '<your appname>' do
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
pod "AmplitudeEngagementSwift", :git => "https://github.com/amplitude/Amplitude-Engagement-Swift"
|
|
25
|
+
|
|
26
|
+
...
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Re-run `pod install` in the `ios` directory:
|
|
31
|
+
```sh
|
|
32
|
+
$ cd ios
|
|
33
|
+
$ bundle exec pod install
|
|
34
|
+
```
|
|
35
|
+
|
|
19
36
|
## Usage
|
|
20
37
|
|
|
38
|
+
### Setup code
|
|
39
|
+
|
|
21
40
|
Setup by adding the plugin and calling “init” as usual:
|
|
22
41
|
|
|
23
42
|
```
|
|
@@ -48,6 +67,14 @@ Linking.addEventListener('url', async ({ url }) => {
|
|
|
48
67
|
});
|
|
49
68
|
```
|
|
50
69
|
|
|
70
|
+
### Linking setup
|
|
71
|
+
If you don't already have it set up, please follow this guide to enable deep-linking support in your React Native app in addition to adding the above Linking code:
|
|
72
|
+
https://reactnative.dev/docs/linking#enabling-deep-links
|
|
73
|
+
|
|
74
|
+
Then, following the Alpha Onboarding guide to setup the "scheme" for the deep links in your Android and iOS projects.
|
|
75
|
+
|
|
76
|
+
### Boot
|
|
77
|
+
|
|
51
78
|
Finally, “boot” with the user’s ID:
|
|
52
79
|
|
|
53
80
|
```
|
package/android/build.gradle
CHANGED
|
@@ -74,6 +74,12 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
74
74
|
dependencies {
|
|
75
75
|
implementation "com.facebook.react:react-android"
|
|
76
76
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
|
+
|
|
78
|
+
// Amplitude Engagement SDK
|
|
79
|
+
implementation "com.amplitude:amplitude-engagement-android:1.0.8"
|
|
80
|
+
|
|
81
|
+
// Amplitude Analytics SDK (required dependency)
|
|
82
|
+
implementation "com.amplitude:analytics-android:1.+"
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
react {
|
|
@@ -1,16 +1,180 @@
|
|
|
1
1
|
package com.amplitude.pluginengagementreactnative
|
|
2
2
|
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.app.Application
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.os.Bundle
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import androidx.core.net.toUri
|
|
9
|
+
import com.amplitude.android.engagement.AmplitudeEngagement
|
|
10
|
+
import com.amplitude.android.engagement.AmplitudeInitOptions
|
|
11
|
+
import com.amplitude.android.engagement.ui.theme.ThemeMode
|
|
12
|
+
import com.amplitude.core.events.BaseEvent
|
|
13
|
+
import com.facebook.react.bridge.ActivityEventListener
|
|
14
|
+
import com.facebook.react.bridge.Arguments
|
|
15
|
+
import com.facebook.react.bridge.Callback
|
|
16
|
+
import com.facebook.react.bridge.LifecycleEventListener
|
|
3
17
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
18
|
+
import com.facebook.react.bridge.ReadableMap
|
|
19
|
+
import com.facebook.react.bridge.WritableArray
|
|
4
20
|
import com.facebook.react.module.annotations.ReactModule
|
|
21
|
+
import kotlinx.coroutines.Dispatchers
|
|
22
|
+
import kotlinx.coroutines.runBlocking
|
|
23
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
5
24
|
|
|
6
25
|
@ReactModule(name = PluginEngagementReactNativeModule.NAME)
|
|
7
|
-
class PluginEngagementReactNativeModule(reactContext: ReactApplicationContext) :
|
|
26
|
+
class PluginEngagementReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
8
27
|
NativePluginEngagementReactNativeSpec(reactContext) {
|
|
9
28
|
|
|
29
|
+
private data class InstanceInfo(val apiKey: String, val instance: AmplitudeEngagement)
|
|
30
|
+
|
|
31
|
+
private var instances = ConcurrentHashMap<Double, InstanceInfo>()
|
|
32
|
+
private var _id: Double = 0.0
|
|
33
|
+
|
|
10
34
|
override fun getName(): String {
|
|
11
35
|
return NAME
|
|
12
36
|
}
|
|
13
37
|
|
|
38
|
+
override fun newInstance(apiKey: String): Double {
|
|
39
|
+
val existingId = instances.entries.firstOrNull { it.value.apiKey == apiKey }?.key
|
|
40
|
+
if (existingId != null) {
|
|
41
|
+
return existingId
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return synchronized(this) {
|
|
45
|
+
runBlocking(Dispatchers.Main) {
|
|
46
|
+
val amplitudeEngagement = __ReactNative__AESDK(reactContext, apiKey, AmplitudeInitOptions())
|
|
47
|
+
|
|
48
|
+
// The React Native environment seems to have a different activity management lifecycle;
|
|
49
|
+
// so we need to register our own listener to get the current activity.
|
|
50
|
+
amplitudeEngagement.setCurrentActivity(reactContext.currentActivity)
|
|
51
|
+
val lifecycleEventListener: LifecycleEventListener = object : LifecycleEventListener {
|
|
52
|
+
override fun onHostResume() {
|
|
53
|
+
amplitudeEngagement.setCurrentActivity(reactContext.currentActivity)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun onHostPause() {
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override fun onHostDestroy() {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
reactContext.addLifecycleEventListener(lifecycleEventListener)
|
|
64
|
+
|
|
65
|
+
_id++
|
|
66
|
+
val id = _id
|
|
67
|
+
instances[id] = InstanceInfo(
|
|
68
|
+
apiKey,
|
|
69
|
+
amplitudeEngagement
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
id
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
override fun boot(id: Double, userId: String, deviceId: String) {
|
|
78
|
+
val instance = instances[id]?.instance ?: return
|
|
79
|
+
|
|
80
|
+
runBlocking(Dispatchers.Main) {
|
|
81
|
+
Log.d("PluginEngagementReactNativeModule", "boot: $userId, $deviceId")
|
|
82
|
+
instance.boot(userId, deviceId)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override fun setThemeMode(id: Double, themeMode: String?) {
|
|
87
|
+
val instance = instances[id]?.instance ?: return
|
|
88
|
+
|
|
89
|
+
runBlocking(Dispatchers.Main) {
|
|
90
|
+
if (themeMode != null) {
|
|
91
|
+
instance.setThemeMode(ThemeMode.valueOf(themeMode))
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun reset(id: Double, key: String, stepIndex: Double) {
|
|
97
|
+
val instance = instances[id]?.instance ?: return
|
|
98
|
+
runBlocking(Dispatchers.Main) {
|
|
99
|
+
instance.reset(key, stepIndex.toInt())
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override fun list(id: Double): WritableArray {
|
|
104
|
+
val writableArray = Arguments.createArray()
|
|
105
|
+
val instance = instances[id]?.instance ?: return writableArray
|
|
106
|
+
runBlocking(Dispatchers.Main) {
|
|
107
|
+
val guidesAndSurveysList = instance.list()
|
|
108
|
+
guidesAndSurveysList.forEach { guide ->
|
|
109
|
+
Log.d("PluginEngagementReactNativeModule", "list: $guide")
|
|
110
|
+
val map = Arguments.createMap();
|
|
111
|
+
map.putInt("id", guide.id);
|
|
112
|
+
map.putString("title", guide.title);
|
|
113
|
+
map.putString("status", guide.status);
|
|
114
|
+
map.putInt("step", guide.step);
|
|
115
|
+
writableArray.pushMap(map);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return writableArray
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
override fun show(id: Double, key: String, stepIndex: Double) {
|
|
122
|
+
val instance = instances[id]?.instance ?: return
|
|
123
|
+
runBlocking(Dispatchers.Main) {
|
|
124
|
+
instance.show(key, stepIndex.toInt())
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
override fun screen(id: Double, screenName: String) {
|
|
129
|
+
val instance = instances[id]?.instance ?: return
|
|
130
|
+
runBlocking(Dispatchers.Main) {
|
|
131
|
+
instance.screen(screenName)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
override fun closeAll(id: Double) {
|
|
136
|
+
val instance = instances[id]?.instance ?: return
|
|
137
|
+
runBlocking(Dispatchers.Main) {
|
|
138
|
+
instance.closeAll()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
override fun forwardEvent(id: Double, event: ReadableMap) {
|
|
143
|
+
val instance = instances[id]?.instance ?: return
|
|
144
|
+
val baseEvent = BaseEvent()
|
|
145
|
+
baseEvent.eventType = event.getString("event_type") ?: return
|
|
146
|
+
baseEvent.eventId = event.getDouble("event_id").toLong()
|
|
147
|
+
baseEvent.platform = event.getString("platform")
|
|
148
|
+
baseEvent.osName = event.getString("os_name")
|
|
149
|
+
baseEvent.osVersion = event.getString("os_version")
|
|
150
|
+
baseEvent.eventProperties = event.getMap("event_properties")?.toHashMap()
|
|
151
|
+
baseEvent.groupProperties = event.getMap("group_properties")?.toHashMap()
|
|
152
|
+
baseEvent.groups = event.getMap("groups")?.toHashMap()
|
|
153
|
+
baseEvent.userProperties = event.getMap("user_properties")?.toHashMap()
|
|
154
|
+
Log.d("PluginEngagementReactNativeModule", "forwardEvent: $baseEvent")
|
|
155
|
+
runBlocking(Dispatchers.Main) {
|
|
156
|
+
instance.forwardEvent(baseEvent)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
override fun addCallback(id: Double, key: String, func: Callback) {
|
|
161
|
+
val instance = instances[id]?.instance ?: return
|
|
162
|
+
runBlocking(Dispatchers.Main) {
|
|
163
|
+
instance.addCallback(key) { func.invoke() }
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
override fun handleURL(id: Double, url: String): Boolean {
|
|
168
|
+
val instance = instances[id]?.instance ?: return false
|
|
169
|
+
|
|
170
|
+
val uri = url.toUri()
|
|
171
|
+
val intent = Intent(Intent.ACTION_VIEW, uri)
|
|
172
|
+
|
|
173
|
+
return runBlocking(Dispatchers.Main) {
|
|
174
|
+
instance.handlePreviewLinkIntent(intent)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
14
178
|
|
|
15
179
|
companion object {
|
|
16
180
|
const val NAME = "PluginEngagementReactNative"
|
|
@@ -35,7 +35,7 @@ var _id = 0
|
|
|
35
35
|
return DispatchQueue.main.sync {
|
|
36
36
|
_id += 1;
|
|
37
37
|
let id = _id + 1;
|
|
38
|
-
instances[id] = (apiKey,
|
|
38
|
+
instances[id] = (apiKey, __ReactNative__AESDK(apiKey, AmplitudeInitOptions(logLevel: AmplitudeLogLevel.verbose)))
|
|
39
39
|
return id
|
|
40
40
|
}
|
|
41
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amplitude/plugin-engagement-react-native",
|
|
3
|
-
"version": "0.1.1-alpha.
|
|
3
|
+
"version": "0.1.1-alpha.5",
|
|
4
4
|
"description": "Amplitude Engagement plugin for React Native",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"@eslint/compat": "^1.2.7",
|
|
65
65
|
"@eslint/eslintrc": "^3.3.0",
|
|
66
66
|
"@eslint/js": "^9.22.0",
|
|
67
|
-
"@evilmartians/lefthook": "^1.5.0",
|
|
68
67
|
"@react-native-community/cli": "15.0.0-alpha.2",
|
|
69
68
|
"@react-native/babel-preset": "0.79.2",
|
|
70
69
|
"@react-native/eslint-config": "^0.78.0",
|