Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,6 @@ allprojects {
}
}

apply plugin: 'org.jetbrains.kotlinx.kover'

dependencies {
kover(project(':sdk'))
kover(project(':mindbox-firebase'))
kover(project(':mindbox-huawei'))
kover(project(':mindbox-rustore'))
kover(project(':mindbox-firebase-starter'))
kover(project(':mindbox-huawei-starter'))
kover(project(':mindbox-rustore-starter'))
kover(project(':mindbox-sdk-starter-core'))
}

tasks.register('clean', Delete) {
delete rootProject.getLayout().getBuildDirectory()
}
7 changes: 3 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ volley = "1.2.1"
gson = "2.8.9"
work_manager = "2.8.1"
androidx_lifecycle = "2.8.7"
androidx_startup = "1.2.0"
androidx_core_ktx = "1.13.0"
androidx_annotations = "1.3.0"
constraint_layout = "2.1.4"
Expand All @@ -39,7 +40,6 @@ agcp = "1.9.1.300"
ktlint-plugin = "12.1.1"
ksp = "1.9.22-1.0.17"
maven_publish = "0.32.0"
kover = "0.8.3"

pushclient = "7.2.0"

Expand All @@ -52,7 +52,6 @@ buildscript-plugins = [
"ktlint_gradle_plugin",
"ksp_gradle_plugin",
"maven_publish_plugin",
"kover_gradle_plugin",
]

test = [
Expand Down Expand Up @@ -88,6 +87,7 @@ room_ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
room_compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
work_manager = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work_manager" }
androidx_lifecycle = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidx_lifecycle" }
androidx_startup = { group = "androidx.startup", name = "startup-runtime", version.ref = "androidx_startup" }
hms_push = { group = "com.huawei.hms", name = "push", version.ref = "hms_push" }
hms_ads_identifier = { group = "com.huawei.hms", name = "ads-identifier", version.ref = "hms_ads_identifier" }
constraint_layout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraint_layout" }
Expand Down Expand Up @@ -118,5 +118,4 @@ google_services = { module = "com.google.gms:google-services", version.ref = "go
agcp = { module = "com.huawei.agconnect:agcp", version.ref = "agcp" }
ktlint_gradle_plugin = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlint-plugin" }
ksp_gradle_plugin = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version.ref = "ksp" }
maven_publish_plugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "maven_publish" }
kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" }
maven_publish_plugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "maven_publish" }
1 change: 0 additions & 1 deletion modulesCommon.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ apply plugin: 'kotlin-android'
apply plugin: 'signing'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
apply plugin: 'com.vanniktech.maven.publish'
apply plugin: 'org.jetbrains.kotlinx.kover'

group = 'com.github.mindbox-cloud'

Expand Down
1 change: 1 addition & 0 deletions sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ dependencies {

// Handle app lifecycle
implementation libs.androidx.lifecycle
implementation libs.androidx.startup
implementation libs.threetenabp

// Glide
Expand Down
10 changes: 10 additions & 0 deletions sdk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

<uses-sdk tools:overrideLibrary="io.mockk, io.mockk.proxy.android" />
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="cloud.mindbox.mobile_sdk.managers.MindboxLifecycleInitializer"
android:value="androidx.startup" />
</provider>

<activity
android:name="cloud.mindbox.mobile_sdk.inapp.presentation.actions.PushActivationActivity"
android:excludeFromRecents="true"
Expand Down
251 changes: 118 additions & 133 deletions sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import androidx.annotation.DrawableRes
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import androidx.lifecycle.Lifecycle.State.RESUMED
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.WorkerFactory
import cloud.mindbox.common.MindboxCommon
import cloud.mindbox.mobile_sdk.di.MindboxDI
Expand Down Expand Up @@ -88,7 +86,7 @@ public object Mindbox : MindboxLog {
private val tokenCallbacks = ConcurrentHashMap<String, (String?) -> Unit>()
private val deviceUuidCallbacks = ConcurrentHashMap<String, (String) -> Unit>()

private lateinit var lifecycleManager: LifecycleManager
private val lifecycleManager: LifecycleManager? get() = LifecycleManager.instance

private val userVisitManager: UserVisitManager by mindboxInject { userVisitManager }
private val timeProvider by mindboxInject { timeProvider }
Expand Down Expand Up @@ -554,152 +552,139 @@ public object Mindbox : MindboxLog {
context: Context,
configuration: MindboxConfiguration,
pushServices: List<MindboxPushService>,
) {
LoggingExceptionHandler.runCatching {
verifyThreadExecution(methodName = "init")
val currentProcessName = context.getCurrentProcessName()
if (!context.isMainProcess(currentProcessName)) {
logW("Skip Mindbox init not in main process! Current process $currentProcessName")
return@runCatching
}
Stopwatch.start(Stopwatch.INIT_SDK)
): Unit = loggingRunCatching {
verifyThreadExecution(methodName = "init")
val currentProcessName = context.getCurrentProcessName()
if (!context.isMainProcess(currentProcessName)) {
logW("Skip Mindbox init not in main process! Current process $currentProcessName")
return@loggingRunCatching
}
Stopwatch.start(Stopwatch.INIT_SDK)

initComponents(context.applicationContext)
pushConverters = selectPushServiceHandler(pushServices)
logI("init in $currentProcessName. firstInitCall: ${firstInitCall.get()}, " +
initComponents(context.applicationContext)
pushConverters = selectPushServiceHandler(pushServices)
logI(
"init in $currentProcessName. firstInitCall: ${firstInitCall.get()}, " +
"configuration: $configuration, pushServices: " +
pushServices.joinToString(", ") { it.javaClass.simpleName } +
", SdkVersion:${getSdkVersion()}, CommonSdkVersion:${MindboxCommon.VERSION_NAME}")
", SdkVersion:${getSdkVersion()}, CommonSdkVersion:${MindboxCommon.VERSION_NAME}",
)

if (!firstInitCall.get()) {
InitializeLock.reset(InitializeLock.State.SAVE_MINDBOX_CONFIG)
} else {
userVisitManager.saveUserVisit()
}
if (!firstInitCall.get()) {
InitializeLock.reset(InitializeLock.State.SAVE_MINDBOX_CONFIG)
} else {
userVisitManager.saveUserVisit()
}

initScope.launch {
InitializeLock.await(InitializeLock.State.MIGRATION)
val checkResult = checkConfig(configuration)
val validatedConfiguration = validateConfiguration(configuration)
DbManager.saveConfigurations(Configuration(configuration))
logI("init. checkResult: $checkResult")
if (checkResult != ConfigUpdate.NOT_UPDATED && !MindboxPreferences.isFirstInitialize) {
logI("init. softReinitialization")
softReinitialization(context.applicationContext)
}
launchInitJob(context, configuration, pushServices)
setupLifecycleManager(context)
attachLifecycleCallbacks()
}

if (checkResult == ConfigUpdate.UPDATED) {
setPushServiceHandler(context, pushServices)
firstInitialization(context.applicationContext, validatedConfiguration)
private fun launchInitJob(
context: Context,
configuration: MindboxConfiguration,
pushServices: List<MindboxPushService>,
) {
initScope.launch {
InitializeLock.await(InitializeLock.State.MIGRATION)
val checkResult = checkConfig(configuration)
val validatedConfiguration = validateConfiguration(configuration)
DbManager.saveConfigurations(Configuration(configuration))
logI("init. checkResult: $checkResult")
if (checkResult != ConfigUpdate.NOT_UPDATED && !MindboxPreferences.isFirstInitialize) {
logI("init. softReinitialization")
softReinitialization(context.applicationContext)
}

val isTrackVisitNotSent = Mindbox::lifecycleManager.isInitialized &&
!lifecycleManager.isTrackVisitSent()
if (isTrackVisitNotSent) {
MindboxLoggerImpl.d(this, "Track visit event with source $DIRECT")
sendTrackVisitEvent(context.applicationContext, DIRECT)
}
} else {
mindboxScope.launch {
setPushServiceHandler(context, pushServices)
}
MindboxEventManager.sendEventsIfExist(context.applicationContext)
if (checkResult == ConfigUpdate.UPDATED) {
setPushServiceHandler(context, pushServices)
firstInitialization(context.applicationContext, validatedConfiguration)
} else {
mindboxScope.launch {
setPushServiceHandler(context, pushServices)
}
MindboxPreferences.uuidDebugEnabled = configuration.uuidDebugEnabled
}.initState(InitializeLock.State.SAVE_MINDBOX_CONFIG)
.invokeOnCompletion { throwable ->
if (throwable == null) {
if (firstInitCall.get()) {
val activity = context as? Activity
if (activity != null && lifecycleManager.isCurrentActivityResumed) {
inAppMessageManager.registerCurrentActivity(activity)
mindboxScope.launch {
inAppMutex.withLock {
logI("Start inapp manager after init. firstInitCall: ${firstInitCall.get()}")
if (!firstInitCall.getAndSet(false)) return@launch
inAppMessageManager.listenEventAndInApp()
inAppMessageManager.initLogs()
MindboxEventManager.eventFlow.emit(MindboxEventManager.appStarted())
inAppMessageManager.requestConfig().join()
}
}
MindboxEventManager.sendEventsIfExist(context.applicationContext)
}
Comment on lines +600 to +608
MindboxPreferences.uuidDebugEnabled = configuration.uuidDebugEnabled
}.initState(InitializeLock.State.SAVE_MINDBOX_CONFIG)
.invokeOnCompletion { throwable ->
if (throwable == null && firstInitCall.get()) {
val activity = context as? Activity
if (activity != null && lifecycleManager?.isCurrentActivityResumed == true) {
inAppMessageManager.registerCurrentActivity(activity)
mindboxScope.launch {
inAppMutex.withLock {
logI("Start inapp manager after init. firstInitCall: ${firstInitCall.get()}")
if (!firstInitCall.getAndSet(false)) return@launch
inAppMessageManager.listenEventAndInApp()
inAppMessageManager.initLogs()
MindboxEventManager.eventFlow.emit(MindboxEventManager.appStarted())
inAppMessageManager.requestConfig().join()
}
}
}
}
// Handle back app in foreground
(context.applicationContext as? Application)?.apply {
val applicationLifecycle = ProcessLifecycleOwner.get().lifecycle
}
}

if (!Mindbox::lifecycleManager.isInitialized) {
val activity = context as? Activity
val isApplicationResumed = applicationLifecycle.currentState == RESUMED
if (isApplicationResumed && activity == null) {
logE("Incorrect context type for calling init in this place")
}
if (isApplicationResumed || context !is Application) {
logW(
"We recommend to call Mindbox.init() synchronously from " +
"Application.onCreate. If you can't do so, don't forget to " +
"call Mindbox.initPushServices from Application.onCreate",
)
private fun setupLifecycleManager(context: Context) {
if (LifecycleManager.isRegister) {
if (!firstInitCall.get()) {
lifecycleManager?.scheduleReinitTrackVisit()
}
return
}

logW("Register LifecycleManager (startup initializer not found)")
LifecycleManager.register(context)
}

private fun attachLifecycleCallbacks() {
lifecycleManager?.callbacks = object : LifecycleManager.Callbacks {
override fun onActivityStarted(activity: Activity) {
UuidCopyManager.onAppMovedToForeground(activity)
mindboxScope.launch {
if (!MindboxPreferences.isFirstInitialize) {
updateAppInfo(activity.applicationContext)
}
}
}

logI("init. init lifecycleManager")
lifecycleManager = LifecycleManager(
currentActivityName = activity?.javaClass?.name,
currentIntent = activity?.intent,
isAppInBackground = !isApplicationResumed,
onActivityStarted = { startedActivity ->
UuidCopyManager.onAppMovedToForeground(startedActivity)
mindboxScope.launch {
if (!MindboxPreferences.isFirstInitialize) {
updateAppInfo(startedActivity.applicationContext)
}
}
},
onActivityPaused = { pausedActivity ->
inAppMessageManager.onPauseCurrentActivity(pausedActivity)
},
onActivityResumed = { resumedActivity ->
inAppMessageManager.onResumeCurrentActivity(
resumedActivity
)
if (firstInitCall.get()) {
mindboxScope.launch {
InitializeLock.await(InitializeLock.State.SAVE_MINDBOX_CONFIG)
inAppMutex.withLock {
logI("Start inapp manager after resume activity. firstInitCall: ${firstInitCall.get()}")
if (!firstInitCall.getAndSet(false)) return@launch
inAppMessageManager.listenEventAndInApp()
inAppMessageManager.initLogs()
MindboxEventManager.eventFlow.emit(MindboxEventManager.appStarted())
inAppMessageManager.requestConfig().join()
}
}
}
},
onActivityStopped = { resumedActivity ->
inAppMessageManager.onStopCurrentActivity(resumedActivity)
},
onTrackVisitReady = { source, requestUrl ->
sessionStorageManager.hasSessionExpired()
eventScope.launch {
sendTrackVisitEvent(
MindboxDI.appModule.appContext,
source,
requestUrl
)
}
override fun onActivityPaused(activity: Activity) {
inAppMessageManager.onPauseCurrentActivity(activity)
}

override fun onActivityResumed(activity: Activity) {
inAppMessageManager.onResumeCurrentActivity(activity)
if (firstInitCall.get()) {
mindboxScope.launch {
InitializeLock.await(InitializeLock.State.SAVE_MINDBOX_CONFIG)
inAppMutex.withLock {
logI("Start in-app manager after resume activity. firstInitCall: ${firstInitCall.get()}")
if (!firstInitCall.getAndSet(false)) return@launch
inAppMessageManager.listenEventAndInApp()
inAppMessageManager.initLogs()
MindboxEventManager.eventFlow.emit(MindboxEventManager.appStarted())
inAppMessageManager.requestConfig().join()
}
)
} else {
unregisterActivityLifecycleCallbacks(lifecycleManager)
applicationLifecycle.removeObserver(lifecycleManager)
lifecycleManager.wasReinitialized()
}
}
}

registerActivityLifecycleCallbacks(lifecycleManager)
applicationLifecycle.addObserver(lifecycleManager)
override fun onActivityStopped(activity: Activity) {
inAppMessageManager.onStopCurrentActivity(activity)
}

override fun onTrackVisitReady(source: String?, requestUrl: String?) {
sessionStorageManager.hasSessionExpired()
eventScope.launch {
sendTrackVisitEvent(
MindboxDI.appModule.appContext,
source,
requestUrl,
)
}
}
}
}
Expand Down Expand Up @@ -889,8 +874,8 @@ public object Mindbox : MindboxLog {
*/
public fun onNewIntent(intent: Intent?): Unit = LoggingExceptionHandler.runCatching {
MindboxLoggerImpl.d(this, "onNewIntent. intent: $intent")
if (Mindbox::lifecycleManager.isInitialized) {
lifecycleManager.onNewIntent(intent)
if (lifecycleManager != null) {
lifecycleManager?.onNewIntent(intent)
} else {
MindboxLoggerImpl.d(this, "onNewIntent. LifecycleManager is not initialized. Skipping.")
}
Expand Down
Loading
Loading