From 83e071673cb757730f04f26e3a3726321afd7355 Mon Sep 17 00:00:00 2001 From: b-dev-mobile Date: Thu, 9 Jul 2026 12:58:55 +0000 Subject: [PATCH] =?UTF-8?q?talk-native:=20=D1=83=D0=B1=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=20runBlocking=20=D1=81=D0=BE=20=D1=81=D1=82=D0=B0=D1=80=D1=82?= =?UTF-8?q?=D0=B0=20=D0=B8=20=D0=BF=D1=83=D1=82=D0=B8=20=D0=B7=D0=B2=D0=BE?= =?UTF-8?q?=D0=BD=D0=BA=D0=B0=20(=D0=B0=D1=83=D0=B4=D0=B8=D1=82=20C4/?= =?UTF-8?q?=D0=BF.7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TalkVendorUserSync.ensureUser → suspend(IO). Прогрев на старте приложения — в фоновом scope (раньше блокировал main в Application.onCreate, вкл. чтение AuthStore/Keystore). Путь звонка: подготовка vendor-юзера в корутине (IO), запуск CallActivity на main — убран ANR-риск на входящем звонке. Поведение то же: при неготовности — тот же тост, фолбэк WebView сохранён. --- .../talknative/TalkNativeCallLauncher.kt | 41 ++++++++++++------- .../feature/talknative/TalkVendorBootstrap.kt | 17 ++++++-- .../feature/talknative/TalkVendorUserSync.kt | 9 ++-- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkNativeCallLauncher.kt b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkNativeCallLauncher.kt index d73d0eb..b01e839 100644 --- a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkNativeCallLauncher.kt +++ b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkNativeCallLauncher.kt @@ -5,6 +5,10 @@ import android.content.Context import android.content.Intent import android.util.Log import android.widget.Toast +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import ru.f7cloud.talk.activities.CallActivity import ru.f7cloud.talk.services.CallForegroundService import ru.f7cloud.talk.utils.bundle.BundleKeys @@ -22,6 +26,9 @@ object TalkNativeCallLauncher { private const val TAG = "TalkNativeCallLauncher" private const val WEBVIEW_CALL_ACTIVITY = "ru.forbion.f7cloud.feature.talk.TalkCallActivity" + // Main-scope для запуска звонка после suspend-подготовки vendor-юзера (IO) + private val launchScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) + fun launchIncomingCall( context: Context, session: AuthSession, @@ -83,26 +90,30 @@ object TalkNativeCallLauncher { } return } - if (!TalkVendorBootstrap.ensureSessionReady(context, session)) { - showError(context, "Не удалось подготовить Talk для звонка") - return - } val token = callContext.roomToken.trim() if (token.isBlank()) { showError(context, "Некорректная комната звонка") return } - runCatching { - startCallActivity( - context, - buildCallIntent(context, session, callContext, incomingFromNotification, suppressIncomingRingtone), - ) - }.onFailure { error -> - Log.e(TAG, "Native CallActivity launch failed", error) - if (TalkNativeConfig.allowWebViewCallFallback) { - launchWebViewFallback(context, session, token, incomingFromNotification) - } else { - showError(context, "Не удалось начать звонок") + // Подготовка vendor-юзера — suspend (IO): раньше runBlocking держал main + // на пути звонка (ANR-риск на входящем звонке, аудит C4). Запуск activity — на main. + launchScope.launch { + if (!TalkVendorBootstrap.ensureSessionReady(context, session)) { + showError(context, "Не удалось подготовить Talk для звонка") + return@launch + } + runCatching { + startCallActivity( + context, + buildCallIntent(context, session, callContext, incomingFromNotification, suppressIncomingRingtone), + ) + }.onFailure { error -> + Log.e(TAG, "Native CallActivity launch failed", error) + if (TalkNativeConfig.allowWebViewCallFallback) { + launchWebViewFallback(context, session, token, incomingFromNotification) + } else { + showError(context, "Не удалось начать звонок") + } } } } diff --git a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorBootstrap.kt b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorBootstrap.kt index 66dd921..30c6bcb 100644 --- a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorBootstrap.kt +++ b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorBootstrap.kt @@ -2,6 +2,10 @@ package ru.forbion.f7cloud.feature.talknative import android.content.Context import android.util.Log +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import ru.forbion.f7cloud.core.auth.AuthSession import ru.forbion.f7cloud.core.auth.AuthStore @@ -10,15 +14,20 @@ import ru.forbion.f7cloud.core.auth.AuthStore */ object TalkVendorBootstrap { private const val TAG = "TalkVendorBootstrap" + private val warmupScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + /** Прогрев vendor-юзера на старте — в фоне (раньше блокировал main в Application.onCreate). */ fun onApplicationCreate(context: Context) { if (!TalkNativeConfig.bootstrapVendorRuntime) return - val session = AuthStore(context).load() ?: return - runCatching { TalkVendorUserSync.ensureUser(context, session) } - .onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") } + val appContext = context.applicationContext + warmupScope.launch { + val session = AuthStore(appContext).load() ?: return@launch + runCatching { TalkVendorUserSync.ensureUser(appContext, session) } + .onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") } + } } - fun ensureSessionReady(context: Context, session: AuthSession): Boolean { + suspend fun ensureSessionReady(context: Context, session: AuthSession): Boolean { if (!TalkNativeConfig.bootstrapVendorRuntime) return true return runCatching { TalkVendorUserSync.ensureUser(context, session) } .onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") } diff --git a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorUserSync.kt b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorUserSync.kt index a80ae61..d7ee4c7 100644 --- a/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorUserSync.kt +++ b/feature/talk-native/src/main/java/ru/forbion/f7cloud/feature/talknative/TalkVendorUserSync.kt @@ -5,22 +5,25 @@ import android.util.Log import ru.f7cloud.talk.application.F7cloudTalkApplication import ru.f7cloud.talk.f7cloud.F7TalkUserSync import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import ru.forbion.f7cloud.core.auth.AuthSession /** * Ensures talk-android [ru.f7cloud.talk.data.user.model.User] exists for F7cloud sessions. * Required before native [ru.f7cloud.talk.activities.CallActivity] can run. + * + * suspend (IO) — раньше был runBlocking на main (старт приложения и путь звонка), + * что давало ANR-риск из аудита (C4/п.7). */ object TalkVendorUserSync { private const val TAG = "TalkVendorUserSync" - fun ensureUser(context: Context, session: AuthSession): Boolean { + suspend fun ensureUser(context: Context, session: AuthSession): Boolean { if (context.applicationContext !is F7cloudTalkApplication) { Log.w(TAG, "Application is not F7cloudTalkApplication, skip sync") return false } - return runBlocking(Dispatchers.IO) { + return withContext(Dispatchers.IO) { runCatching { F7TalkUserSync.get().ensureUser( serverUrl = session.serverUrl,