@momo-kits/native-kits 0.156.1-test.9-debug → 0.156.1-tracking.2-debug
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/PUBLISH_GUIDE.md +410 -184
- package/compose/build.gradle.kts +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +1 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +2 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +46 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +57 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +218 -0
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme +32 -0
- package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/WorkspaceSettings.xcsettings +16 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +6 -0
- package/example/ios/Example.xcworkspace/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +5 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Pods-Example.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImage.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SDWebImageSwiftUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/SkeletonUI.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios-LottiePrivacyInfo.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/lottie-ios.xcscheme +58 -0
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/xcschememanagement.plist +60 -0
- package/gradle.properties +1 -1
- package/local.properties +2 -2
- package/package.json +1 -1
- package/{publish_release.sh → publish.sh} +195 -128
- package/publish_beta.sh +0 -275
package/compose/build.gradle.kts
CHANGED
|
@@ -72,6 +72,7 @@ val LocalNavigation = staticCompositionLocalOf<Navigation> {
|
|
|
72
72
|
|
|
73
73
|
@Stable
|
|
74
74
|
data class NavigationOptions(
|
|
75
|
+
val screenName: String? = null,
|
|
75
76
|
val onBackHandler: (() -> Unit)? = null,
|
|
76
77
|
val hiddenBack: Boolean = false,
|
|
77
78
|
val headerBackProps: HeaderBackProps = HeaderBackProps(),
|
|
@@ -87,6 +87,7 @@ fun NavigationContainer(
|
|
|
87
87
|
AppConfig provides config,
|
|
88
88
|
AppLanguage provides language,
|
|
89
89
|
) {
|
|
90
|
+
println(mergedContext)
|
|
90
91
|
LaunchedEffect(Unit) {
|
|
91
92
|
setNavigator?.invoke(navigator)
|
|
92
93
|
}
|
|
@@ -157,7 +158,5 @@ fun NavigationContainer(
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> {
|
|
161
|
-
error("No MaxApi provided")
|
|
162
|
-
}
|
|
161
|
+
val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> { null }
|
|
163
162
|
|
|
@@ -120,10 +120,23 @@ class Navigator(
|
|
|
120
120
|
fun showModal(
|
|
121
121
|
content: @Composable () -> Unit,
|
|
122
122
|
barrierDismissible: Boolean = true,
|
|
123
|
-
onDismiss: (() -> Unit)? = null
|
|
123
|
+
onDismiss: (() -> Unit)? = null,
|
|
124
|
+
popupName: String? = null,
|
|
125
|
+
title: String? = null,
|
|
126
|
+
desc: String? = null
|
|
124
127
|
){
|
|
125
128
|
val id = DynamicScreenRegistry.getLatestScreen()?.id ?: -1
|
|
126
|
-
OverplayComponentRegistry.registerOverplay(
|
|
129
|
+
OverplayComponentRegistry.registerOverplay(
|
|
130
|
+
id = id,
|
|
131
|
+
content = content,
|
|
132
|
+
type = OverplayComponentType.MODAL,
|
|
133
|
+
isSurface = false,
|
|
134
|
+
barrierDismissible = barrierDismissible,
|
|
135
|
+
onDismiss = onDismiss,
|
|
136
|
+
popupName = popupName,
|
|
137
|
+
popupTitle = title,
|
|
138
|
+
popupDesc = desc
|
|
139
|
+
)
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
fun showBottomSheet(
|
|
@@ -131,10 +144,24 @@ class Navigator(
|
|
|
131
144
|
isSurface: Boolean = false,
|
|
132
145
|
barrierDismissible: Boolean = true,
|
|
133
146
|
onDismiss: (() -> Unit)? = null,
|
|
134
|
-
bottomSheetHeader: BottomHeader? = null
|
|
147
|
+
bottomSheetHeader: BottomHeader? = null,
|
|
148
|
+
sheetName: String? = null,
|
|
149
|
+
title: String? = null,
|
|
150
|
+
desc: String? = null
|
|
135
151
|
){
|
|
136
152
|
val id = DynamicScreenRegistry.getLatestScreen()?.id ?: -1
|
|
137
|
-
OverplayComponentRegistry.registerOverplay(
|
|
153
|
+
OverplayComponentRegistry.registerOverplay(
|
|
154
|
+
id = id,
|
|
155
|
+
content = content,
|
|
156
|
+
type = OverplayComponentType.BOTTOM_SHEET,
|
|
157
|
+
isSurface = isSurface,
|
|
158
|
+
barrierDismissible = barrierDismissible,
|
|
159
|
+
onDismiss = onDismiss,
|
|
160
|
+
bottomSheetHeader = bottomSheetHeader,
|
|
161
|
+
sheetName = sheetName,
|
|
162
|
+
sheetTitle = title,
|
|
163
|
+
sheetDesc = desc
|
|
164
|
+
)
|
|
138
165
|
}
|
|
139
166
|
|
|
140
167
|
fun showSnackBar(snackBar: SnackBar, onDismiss: (() -> Unit)? = null) {
|
|
@@ -220,7 +247,10 @@ object DynamicScreenRegistry {
|
|
|
220
247
|
sealed class OverplayComponentParams {
|
|
221
248
|
class Modal(
|
|
222
249
|
val onDismiss: (() -> Unit)? = null,
|
|
223
|
-
val barrierDismissible: Boolean = true
|
|
250
|
+
val barrierDismissible: Boolean = true,
|
|
251
|
+
val popupName: String? = null,
|
|
252
|
+
val title: String? = null,
|
|
253
|
+
val desc: String? = null
|
|
224
254
|
) : OverplayComponentParams()
|
|
225
255
|
|
|
226
256
|
class BottomSheet(
|
|
@@ -228,6 +258,9 @@ sealed class OverplayComponentParams {
|
|
|
228
258
|
val onDismiss: (() -> Unit)? = null,
|
|
229
259
|
val barrierDismissible: Boolean = true,
|
|
230
260
|
val bottomSheetHeader: BottomHeader? = null,
|
|
261
|
+
val sheetName: String? = null,
|
|
262
|
+
val title: String? = null,
|
|
263
|
+
val desc: String? = null
|
|
231
264
|
) : OverplayComponentParams()
|
|
232
265
|
|
|
233
266
|
class SnackBar() : OverplayComponentParams()
|
|
@@ -259,10 +292,16 @@ object OverplayComponentRegistry {
|
|
|
259
292
|
barrierDismissible: Boolean = true,
|
|
260
293
|
onDismiss: (() -> Unit)?,
|
|
261
294
|
bottomSheetHeader: BottomHeader? = null,
|
|
295
|
+
popupName: String? = null,
|
|
296
|
+
sheetName: String? = null,
|
|
297
|
+
popupTitle: String? = null,
|
|
298
|
+
popupDesc: String? = null,
|
|
299
|
+
sheetTitle: String? = null,
|
|
300
|
+
sheetDesc: String? = null
|
|
262
301
|
){
|
|
263
302
|
val params = when(type){
|
|
264
|
-
OverplayComponentType.MODAL -> OverplayComponentParams.Modal(onDismiss, barrierDismissible)
|
|
265
|
-
OverplayComponentType.BOTTOM_SHEET -> OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader)
|
|
303
|
+
OverplayComponentType.MODAL -> OverplayComponentParams.Modal(onDismiss, barrierDismissible, popupName, popupTitle, popupDesc)
|
|
304
|
+
OverplayComponentType.BOTTOM_SHEET -> OverplayComponentParams.BottomSheet(isSurface, onDismiss, barrierDismissible, bottomSheetHeader, sheetName, sheetTitle, sheetDesc)
|
|
266
305
|
OverplayComponentType.SNACK_BAR -> OverplayComponentParams.SnackBar()
|
|
267
306
|
}
|
|
268
307
|
|
|
@@ -63,11 +63,16 @@ import vn.momo.kits.navigation.component.HeaderType
|
|
|
63
63
|
import vn.momo.kits.navigation.component.InputSearchType
|
|
64
64
|
import vn.momo.kits.platform.BackHandler
|
|
65
65
|
import vn.momo.kits.platform.getAndroidBuildVersion
|
|
66
|
+
import vn.momo.kits.navigation.tracking.ScreenTracker
|
|
67
|
+
import vn.momo.kits.navigation.tracking.ScreenTrackingState
|
|
68
|
+
import kotlinx.coroutines.delay
|
|
69
|
+
import kotlin.time.Clock
|
|
70
|
+
import kotlin.time.ExperimentalTime
|
|
66
71
|
|
|
67
72
|
internal val LocalFooterHeightPx = staticCompositionLocalOf { mutableIntStateOf(0) }
|
|
68
73
|
internal val LocalHeaderRightWidthPx = staticCompositionLocalOf { mutableIntStateOf(0) }
|
|
69
74
|
|
|
70
|
-
@OptIn(ExperimentalMaterialApi::class)
|
|
75
|
+
@OptIn(ExperimentalMaterialApi::class, ExperimentalTime::class)
|
|
71
76
|
@Composable
|
|
72
77
|
internal fun StackScreen(
|
|
73
78
|
content: @Composable () -> Unit,
|
|
@@ -77,12 +82,63 @@ internal fun StackScreen(
|
|
|
77
82
|
onBackHandler: (() -> Unit)? = null,
|
|
78
83
|
) {
|
|
79
84
|
val navigator = LocalNavigator.current
|
|
85
|
+
val maxApi = LocalMaxApi.current
|
|
86
|
+
val context = ApplicationContext.current
|
|
80
87
|
val statusBar = AppStatusBar.current
|
|
81
88
|
val density = LocalDensity.current
|
|
82
89
|
val navigation = remember { Navigation(id = id, bottomTabIndex = bottomTabIndex, initOptions = navigationOptions) }
|
|
83
90
|
|
|
84
91
|
val options by navigation.currentOptions
|
|
85
92
|
|
|
93
|
+
// Auto tracking state
|
|
94
|
+
val trackingState = remember {
|
|
95
|
+
ScreenTrackingState().apply {
|
|
96
|
+
startTime = Clock.System.now().toEpochMilliseconds()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
val screenName = remember(options.screenName) {
|
|
100
|
+
options.screenName ?: "Screen_$id"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Determine action: push or back
|
|
104
|
+
val action = remember {
|
|
105
|
+
if (ScreenTracker.getLastScreenName() != null) "push" else "push"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Auto tracking effects
|
|
109
|
+
LaunchedEffect(screenName) {
|
|
110
|
+
// Track screen navigated immediately
|
|
111
|
+
ScreenTracker.trackScreenNavigated(
|
|
112
|
+
maxApi = maxApi,
|
|
113
|
+
context = context,
|
|
114
|
+
screenName = screenName,
|
|
115
|
+
action = action,
|
|
116
|
+
state = trackingState
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
// Track screen displayed after 2 seconds (debounce)
|
|
120
|
+
delay(2000)
|
|
121
|
+
val loadTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
|
|
122
|
+
ScreenTracker.trackScreenDisplayed(
|
|
123
|
+
maxApi = maxApi,
|
|
124
|
+
context = context,
|
|
125
|
+
screenName = screenName,
|
|
126
|
+
duration = loadTime,
|
|
127
|
+
state = trackingState
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
// Track screen interacted after displayed
|
|
131
|
+
val interactionTime = Clock.System.now().toEpochMilliseconds() - trackingState.startTime
|
|
132
|
+
ScreenTracker.trackScreenInteracted(
|
|
133
|
+
maxApi = maxApi,
|
|
134
|
+
context = context,
|
|
135
|
+
screenName = screenName,
|
|
136
|
+
duration = interactionTime - loadTime,
|
|
137
|
+
totalDuration = interactionTime,
|
|
138
|
+
state = trackingState
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
86
142
|
val limit = with(density) {
|
|
87
143
|
(statusBar).toPx() + HEADER_HEIGHT
|
|
88
144
|
}.toInt()
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
package vn.momo.kits.navigation.tracking
|
|
2
|
+
|
|
3
|
+
import vn.momo.kits.application.MiniAppContext
|
|
4
|
+
import vn.momo.maxapi.IMaxApi
|
|
5
|
+
import kotlin.time.Clock
|
|
6
|
+
import kotlin.time.ExperimentalTime
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Screen tracking state holder
|
|
10
|
+
*/
|
|
11
|
+
class ScreenTrackingState {
|
|
12
|
+
@OptIn(ExperimentalTime::class)
|
|
13
|
+
var startTime: Long = Clock.System.now().toEpochMilliseconds()
|
|
14
|
+
var endTime: Long = startTime
|
|
15
|
+
var releaseNavigated: Boolean = false
|
|
16
|
+
var releaseLoad: Boolean = false
|
|
17
|
+
var releaseInteraction: Boolean = false
|
|
18
|
+
var previousScreenName: String? = null
|
|
19
|
+
var action: String = "push"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Screen tracker for auto tracking events
|
|
24
|
+
*
|
|
25
|
+
* Tracks 3 main events:
|
|
26
|
+
* - auto_screen_navigated: When screen is focused
|
|
27
|
+
* - auto_screen_displayed: When screen finished loading
|
|
28
|
+
* - auto_screen_interacted: When screen is ready for interaction
|
|
29
|
+
*/
|
|
30
|
+
object ScreenTracker {
|
|
31
|
+
|
|
32
|
+
private var lastScreenName: String? = null
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Track screen navigation event
|
|
36
|
+
* Called when screen is focused
|
|
37
|
+
*/
|
|
38
|
+
fun trackScreenNavigated(
|
|
39
|
+
maxApi: IMaxApi?,
|
|
40
|
+
context: MiniAppContext?,
|
|
41
|
+
screenName: String,
|
|
42
|
+
action: String,
|
|
43
|
+
state: ScreenTrackingState
|
|
44
|
+
) {
|
|
45
|
+
if (state.releaseNavigated) return
|
|
46
|
+
|
|
47
|
+
val previousScreen = lastScreenName
|
|
48
|
+
lastScreenName = screenName
|
|
49
|
+
|
|
50
|
+
maxApi?.track(
|
|
51
|
+
eventName = "auto_screen_navigated",
|
|
52
|
+
params = buildBaseParams(context, screenName).apply {
|
|
53
|
+
put("pre_screen_name", previousScreen)
|
|
54
|
+
put("state", "navigated")
|
|
55
|
+
put("action", action)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
state.releaseNavigated = true
|
|
60
|
+
state.previousScreenName = previousScreen
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Track screen displayed event
|
|
65
|
+
* Called when screen finished loading all elements
|
|
66
|
+
*/
|
|
67
|
+
fun trackScreenDisplayed(
|
|
68
|
+
maxApi: IMaxApi?,
|
|
69
|
+
context: MiniAppContext?,
|
|
70
|
+
screenName: String,
|
|
71
|
+
duration: Long,
|
|
72
|
+
state: ScreenTrackingState
|
|
73
|
+
) {
|
|
74
|
+
if (state.releaseLoad) return
|
|
75
|
+
|
|
76
|
+
maxApi?.track(
|
|
77
|
+
eventName = "auto_screen_displayed",
|
|
78
|
+
params = buildBaseParams(context, screenName).apply {
|
|
79
|
+
put("state", "load")
|
|
80
|
+
put("duration", duration)
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
state.releaseLoad = true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Track screen interacted event
|
|
89
|
+
* Called when screen is ready for user interaction
|
|
90
|
+
*/
|
|
91
|
+
fun trackScreenInteracted(
|
|
92
|
+
maxApi: IMaxApi?,
|
|
93
|
+
context: MiniAppContext?,
|
|
94
|
+
screenName: String,
|
|
95
|
+
duration: Long,
|
|
96
|
+
totalDuration: Long,
|
|
97
|
+
state: ScreenTrackingState
|
|
98
|
+
) {
|
|
99
|
+
if (state.releaseInteraction) return
|
|
100
|
+
|
|
101
|
+
maxApi?.track(
|
|
102
|
+
eventName = "auto_screen_interacted",
|
|
103
|
+
params = buildBaseParams(context, screenName).apply {
|
|
104
|
+
put("state", "interaction")
|
|
105
|
+
put("duration", duration)
|
|
106
|
+
put("total_duration", totalDuration)
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
state.releaseInteraction = true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Build base tracking params from MiniAppContext
|
|
115
|
+
*/
|
|
116
|
+
private fun buildBaseParams(
|
|
117
|
+
context: MiniAppContext?,
|
|
118
|
+
screenName: String,
|
|
119
|
+
componentName: String = "Screen"
|
|
120
|
+
): MutableMap<String, Any?> {
|
|
121
|
+
return mutableMapOf(
|
|
122
|
+
"app_id" to context?.appId,
|
|
123
|
+
"feature_code" to context?.appCode,
|
|
124
|
+
// "miniapp_version" to context?.,
|
|
125
|
+
"screen_name" to screenName,
|
|
126
|
+
"component_name" to componentName,
|
|
127
|
+
"tracking_source" to 1
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Track popup/modal displayed event
|
|
133
|
+
* Called when popup is opened or closed
|
|
134
|
+
*
|
|
135
|
+
* @param action "open" or "close"
|
|
136
|
+
* @param popupName name of the popup/modal
|
|
137
|
+
* @param parentScreenName the screen that shows the popup
|
|
138
|
+
* @param title popup title for tracking
|
|
139
|
+
* @param desc popup description for tracking
|
|
140
|
+
*/
|
|
141
|
+
fun trackPopupDisplayed(
|
|
142
|
+
maxApi: IMaxApi?,
|
|
143
|
+
context: MiniAppContext?,
|
|
144
|
+
action: String,
|
|
145
|
+
popupName: String?,
|
|
146
|
+
parentScreenName: String?,
|
|
147
|
+
title: String? = null,
|
|
148
|
+
desc: String? = null
|
|
149
|
+
) {
|
|
150
|
+
// When opening: screen_name = parent screen, component_name = popup name
|
|
151
|
+
// When closing: screen_name = popup name, component_name = parent screen
|
|
152
|
+
val screenName = if (action == "open") parentScreenName else popupName
|
|
153
|
+
val componentName = if (action == "open") popupName else parentScreenName
|
|
154
|
+
|
|
155
|
+
maxApi?.track(
|
|
156
|
+
eventName = "auto_popup_displayed",
|
|
157
|
+
params = mutableMapOf(
|
|
158
|
+
"app_id" to context?.appId,
|
|
159
|
+
"feature_code" to context?.appCode,
|
|
160
|
+
"screen_name" to screenName,
|
|
161
|
+
"component_name" to componentName,
|
|
162
|
+
"action" to action,
|
|
163
|
+
"title" to title,
|
|
164
|
+
"desc" to desc,
|
|
165
|
+
"tracking_source" to 1
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Track bottom sheet displayed event
|
|
172
|
+
* Called when bottom sheet is opened or closed
|
|
173
|
+
*
|
|
174
|
+
* @param action "open" or "close"
|
|
175
|
+
* @param sheetName name of the bottom sheet
|
|
176
|
+
* @param parentScreenName the screen that shows the bottom sheet
|
|
177
|
+
* @param title sheet title for tracking
|
|
178
|
+
* @param desc sheet description for tracking
|
|
179
|
+
*/
|
|
180
|
+
fun trackBottomSheetDisplayed(
|
|
181
|
+
maxApi: IMaxApi?,
|
|
182
|
+
context: MiniAppContext?,
|
|
183
|
+
action: String,
|
|
184
|
+
sheetName: String?,
|
|
185
|
+
parentScreenName: String?,
|
|
186
|
+
title: String? = null,
|
|
187
|
+
desc: String? = null
|
|
188
|
+
) {
|
|
189
|
+
val screenName = if (action == "open") parentScreenName else sheetName
|
|
190
|
+
val componentName = if (action == "open") sheetName else parentScreenName
|
|
191
|
+
|
|
192
|
+
maxApi?.track(
|
|
193
|
+
eventName = "auto_bottomsheet_displayed",
|
|
194
|
+
params = mutableMapOf(
|
|
195
|
+
"app_id" to context?.appId,
|
|
196
|
+
"feature_code" to context?.appCode,
|
|
197
|
+
"screen_name" to screenName,
|
|
198
|
+
"component_name" to componentName,
|
|
199
|
+
"action" to action,
|
|
200
|
+
"title" to title,
|
|
201
|
+
"desc" to desc,
|
|
202
|
+
"tracking_source" to 1
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get previous screen name for back navigation detection
|
|
209
|
+
*/
|
|
210
|
+
fun getLastScreenName(): String? = lastScreenName
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Reset tracker (for testing or cleanup)
|
|
214
|
+
*/
|
|
215
|
+
fun reset() {
|
|
216
|
+
lastScreenName = null
|
|
217
|
+
}
|
|
218
|
+
}
|
package/example/ios/Example.xcodeproj/xcuserdata/sonnguyen.xcuserdatad/xcschemes/Example.xcscheme
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Scheme
|
|
3
|
+
version = "1.3">
|
|
4
|
+
<BuildAction>
|
|
5
|
+
<BuildActionEntries>
|
|
6
|
+
<BuildActionEntry
|
|
7
|
+
buildForRunning = "YES">
|
|
8
|
+
<BuildableReference
|
|
9
|
+
BuildableIdentifier = "primary"
|
|
10
|
+
BlueprintIdentifier = "A6A920D22B2ADD1E00C1A11F"
|
|
11
|
+
BuildableName = "Example"
|
|
12
|
+
BlueprintName = "Example"
|
|
13
|
+
ReferencedContainer = "container:Example.xcodeproj">
|
|
14
|
+
</BuildableReference>
|
|
15
|
+
</BuildActionEntry>
|
|
16
|
+
</BuildActionEntries>
|
|
17
|
+
</BuildAction>
|
|
18
|
+
<LaunchAction
|
|
19
|
+
useCustomWorkingDirectory = "NO"
|
|
20
|
+
buildConfiguration = "Debug"
|
|
21
|
+
allowLocationSimulation = "YES">
|
|
22
|
+
<BuildableProductRunnable>
|
|
23
|
+
<BuildableReference
|
|
24
|
+
BuildableIdentifier = "primary"
|
|
25
|
+
BlueprintIdentifier = "A6A920D22B2ADD1E00C1A11F"
|
|
26
|
+
BuildableName = "Example"
|
|
27
|
+
BlueprintName = "Example"
|
|
28
|
+
ReferencedContainer = "container:Example.xcodeproj">
|
|
29
|
+
</BuildableReference>
|
|
30
|
+
</BuildableProductRunnable>
|
|
31
|
+
</LaunchAction>
|
|
32
|
+
</Scheme>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>SchemeUserState</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>Example.xcscheme</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>orderHint</key>
|
|
10
|
+
<integer>7</integer>
|
|
11
|
+
</dict>
|
|
12
|
+
</dict>
|
|
13
|
+
</dict>
|
|
14
|
+
</plist>
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>BuildLocationStyle</key>
|
|
6
|
+
<string>UseAppPreferences</string>
|
|
7
|
+
<key>CustomBuildLocationType</key>
|
|
8
|
+
<string>RelativeToDerivedData</string>
|
|
9
|
+
<key>DerivedDataCustomLocation</key>
|
|
10
|
+
<string>DerivedData</string>
|
|
11
|
+
<key>DerivedDataLocationStyle</key>
|
|
12
|
+
<string>WorkspaceRelativePath</string>
|
|
13
|
+
<key>ShowSharedSchemesAutomaticallyEnabled</key>
|
|
14
|
+
<true/>
|
|
15
|
+
</dict>
|
|
16
|
+
</plist>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Scheme
|
|
3
|
+
LastUpgradeVersion = "1600"
|
|
4
|
+
version = "1.3">
|
|
5
|
+
<BuildAction
|
|
6
|
+
parallelizeBuildables = "YES"
|
|
7
|
+
buildImplicitDependencies = "YES">
|
|
8
|
+
<BuildActionEntries>
|
|
9
|
+
<BuildActionEntry
|
|
10
|
+
buildForTesting = "YES"
|
|
11
|
+
buildForRunning = "YES"
|
|
12
|
+
buildForProfiling = "YES"
|
|
13
|
+
buildForArchiving = "YES"
|
|
14
|
+
buildForAnalyzing = "YES">
|
|
15
|
+
<BuildableReference
|
|
16
|
+
BuildableIdentifier = "primary"
|
|
17
|
+
BlueprintIdentifier = "3B6FB503A75BF5BC1FA6F30BC06B9D28"
|
|
18
|
+
BuildableName = "MoMoUIKits.framework"
|
|
19
|
+
BlueprintName = "MoMoUIKits"
|
|
20
|
+
ReferencedContainer = "container:Pods.xcodeproj">
|
|
21
|
+
</BuildableReference>
|
|
22
|
+
</BuildActionEntry>
|
|
23
|
+
</BuildActionEntries>
|
|
24
|
+
</BuildAction>
|
|
25
|
+
<TestAction
|
|
26
|
+
buildConfiguration = "Debug"
|
|
27
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
28
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
29
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
30
|
+
<Testables>
|
|
31
|
+
</Testables>
|
|
32
|
+
</TestAction>
|
|
33
|
+
<LaunchAction
|
|
34
|
+
buildConfiguration = "Debug"
|
|
35
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
36
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
37
|
+
launchStyle = "0"
|
|
38
|
+
useCustomWorkingDirectory = "NO"
|
|
39
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
40
|
+
debugDocumentVersioning = "YES"
|
|
41
|
+
debugServiceExtension = "internal"
|
|
42
|
+
allowLocationSimulation = "YES">
|
|
43
|
+
</LaunchAction>
|
|
44
|
+
<ProfileAction
|
|
45
|
+
buildConfiguration = "Release"
|
|
46
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
47
|
+
savedToolIdentifier = ""
|
|
48
|
+
useCustomWorkingDirectory = "NO"
|
|
49
|
+
debugDocumentVersioning = "YES">
|
|
50
|
+
</ProfileAction>
|
|
51
|
+
<AnalyzeAction
|
|
52
|
+
buildConfiguration = "Debug">
|
|
53
|
+
</AnalyzeAction>
|
|
54
|
+
<ArchiveAction
|
|
55
|
+
buildConfiguration = "Release"
|
|
56
|
+
revealArchiveInOrganizer = "YES">
|
|
57
|
+
</ArchiveAction>
|
|
58
|
+
</Scheme>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Scheme
|
|
3
|
+
LastUpgradeVersion = "1600"
|
|
4
|
+
version = "1.3">
|
|
5
|
+
<BuildAction
|
|
6
|
+
parallelizeBuildables = "YES"
|
|
7
|
+
buildImplicitDependencies = "YES">
|
|
8
|
+
<BuildActionEntries>
|
|
9
|
+
<BuildActionEntry
|
|
10
|
+
buildForTesting = "YES"
|
|
11
|
+
buildForRunning = "YES"
|
|
12
|
+
buildForProfiling = "YES"
|
|
13
|
+
buildForArchiving = "YES"
|
|
14
|
+
buildForAnalyzing = "YES">
|
|
15
|
+
<BuildableReference
|
|
16
|
+
BuildableIdentifier = "primary"
|
|
17
|
+
BlueprintIdentifier = "0AEE99A309977BD12A049FF48AF9BA4B"
|
|
18
|
+
BuildableName = "Pods_Example.framework"
|
|
19
|
+
BlueprintName = "Pods-Example"
|
|
20
|
+
ReferencedContainer = "container:Pods.xcodeproj">
|
|
21
|
+
</BuildableReference>
|
|
22
|
+
</BuildActionEntry>
|
|
23
|
+
</BuildActionEntries>
|
|
24
|
+
</BuildAction>
|
|
25
|
+
<TestAction
|
|
26
|
+
buildConfiguration = "Debug"
|
|
27
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
28
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
29
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
30
|
+
<Testables>
|
|
31
|
+
</Testables>
|
|
32
|
+
</TestAction>
|
|
33
|
+
<LaunchAction
|
|
34
|
+
buildConfiguration = "Debug"
|
|
35
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
36
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
37
|
+
launchStyle = "0"
|
|
38
|
+
useCustomWorkingDirectory = "NO"
|
|
39
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
40
|
+
debugDocumentVersioning = "YES"
|
|
41
|
+
debugServiceExtension = "internal"
|
|
42
|
+
allowLocationSimulation = "YES">
|
|
43
|
+
</LaunchAction>
|
|
44
|
+
<ProfileAction
|
|
45
|
+
buildConfiguration = "Release"
|
|
46
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
47
|
+
savedToolIdentifier = ""
|
|
48
|
+
useCustomWorkingDirectory = "NO"
|
|
49
|
+
debugDocumentVersioning = "YES">
|
|
50
|
+
</ProfileAction>
|
|
51
|
+
<AnalyzeAction
|
|
52
|
+
buildConfiguration = "Debug">
|
|
53
|
+
</AnalyzeAction>
|
|
54
|
+
<ArchiveAction
|
|
55
|
+
buildConfiguration = "Release"
|
|
56
|
+
revealArchiveInOrganizer = "YES">
|
|
57
|
+
</ArchiveAction>
|
|
58
|
+
</Scheme>
|