diff --git a/android/src/main/java/com/mindboxsdk/MindboxPushServicesDiscovery.kt b/android/src/main/java/com/mindboxsdk/MindboxPushServicesDiscovery.kt new file mode 100644 index 0000000..e1e2eb4 --- /dev/null +++ b/android/src/main/java/com/mindboxsdk/MindboxPushServicesDiscovery.kt @@ -0,0 +1,72 @@ +package com.mindboxsdk + +import android.os.Bundle +import android.util.Log +import cloud.mindbox.mobile_sdk.pushes.MindboxPushService + +internal class MindboxPushServicesDiscovery(private val meta: Bundle?) { + + companion object { + private const val TAG = "MindboxPushServicesDiscovery" + private const val PUSH_PROVIDER_PREFIX = "cloud.mindbox.push.provider." + } + + private val providerPriority: Map by lazy(LazyThreadSafetyMode.NONE) { + mapOf("FCM" to 0, "HCM" to 1, "RuStore" to 2) + } + + val services: List by lazy(LazyThreadSafetyMode.NONE) { + if (meta == null) { + return@lazy emptyList() + } + meta.keySet() + .asSequence() + .filter { it.startsWith(PUSH_PROVIDER_PREFIX) } + .mapNotNull { key -> meta.getString(key)?.takeIf { it.isNotBlank() } } + .mapNotNull { className -> loadPushService(className) } + .distinctBy { it::class.java.name } + .sortedWith( + compareBy { providerPriority[it.tag] ?: Int.MAX_VALUE } + .thenBy { it.tag } + ) + .toList() + .also { list -> + Log.i(TAG, "Found ${list.size} push services: ${list.joinToString { it.tag }}") + list + } + } + + private fun loadPushService(className: String): MindboxPushService? { + return runCatching { + val clazz = Class.forName(className) + + if (!MindboxPushService::class.java.isAssignableFrom(clazz)) { + Log.w(TAG, "Class $className does not implement MindboxPushService") + return@runCatching null + } + getPushServiceInstance(clazz)?.also { + Log.i(TAG, "Loaded push provider: $className") + } ?: run { + Log.e(TAG, "Failed to create instance for provider: $className") + null + } + }.getOrElse { exception -> + when (exception) { + is ClassNotFoundException -> Log.e(TAG, "Push provider class not found: $className", exception) + else -> Log.e(TAG, "Failed to load push provider: $className", exception) + } + null + } + } + + private fun getPushServiceInstance(clazz: Class<*>): MindboxPushService? { + return runCatching { + val instanceField = clazz.getDeclaredField("INSTANCE") + instanceField.isAccessible = true + instanceField.get(null) as? MindboxPushService + }.getOrElse { + Log.w(TAG, "Failed to get instance for ${clazz.name}") + null + } + } +} diff --git a/android/src/main/java/com/mindboxsdk/MindboxSdkInitProvider.kt b/android/src/main/java/com/mindboxsdk/MindboxSdkInitProvider.kt index 23f8633..950c8e7 100644 --- a/android/src/main/java/com/mindboxsdk/MindboxSdkInitProvider.kt +++ b/android/src/main/java/com/mindboxsdk/MindboxSdkInitProvider.kt @@ -6,7 +6,10 @@ import android.content.ContentValues import android.content.pm.PackageManager import android.database.Cursor import android.net.Uri +import android.os.Bundle import android.util.Log +import cloud.mindbox.mobile_sdk.pushes.MindboxPushService +import cloud.mindbox.mobile_sdk.Mindbox internal class MindboxSdkInitProvider : ContentProvider() { @@ -19,8 +22,10 @@ internal class MindboxSdkInitProvider : ContentProvider() { runCatching { Log.i(TAG, "onCreate initProvider.") (context?.applicationContext as? Application)?.let { application -> - if (isAutoInitEnabled(application)) { + val meta = application.readMetaData() + if (isAutoInitEnabled(application, meta)) { Log.i(TAG, "Automatic initialization is enabled.") + Mindbox.initPushServices(application, MindboxPushServicesDiscovery(meta).services) MindboxSdkLifecycleListener.register(application) } else { Log.i(TAG, "Automatic initialization is disabled.") @@ -32,17 +37,14 @@ internal class MindboxSdkInitProvider : ContentProvider() { return true } - private fun isAutoInitEnabled(application: Application): Boolean = - runCatching { - val appInfo = application.packageManager.getApplicationInfo( - application.packageName, - PackageManager.GET_META_DATA - ) - appInfo.metaData - ?.getBoolean(AUTO_INIT_ENABLED_KEY, false) - ?.also { Log.i(TAG, "Result of reading mindbox metadata is $it") } - ?: false - }.getOrElse { false } + private fun isAutoInitEnabled(application: Application, metaData: Bundle?): Boolean = + metaData + ?.getBoolean(AUTO_INIT_ENABLED_KEY, false) + ?: false + + private fun Application.readMetaData(): Bundle? = runCatching { + packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA).metaData + }.getOrNull() override fun query( uri: Uri,