talk-native: убран runBlocking со старта и пути звонка (аудит C4/п.7)
TalkVendorUserSync.ensureUser → suspend(IO). Прогрев на старте приложения — в фоновом scope (раньше блокировал main в Application.onCreate, вкл. чтение AuthStore/Keystore). Путь звонка: подготовка vendor-юзера в корутине (IO), запуск CallActivity на main — убран ANR-риск на входящем звонке. Поведение то же: при неготовности — тот же тост, фолбэк WebView сохранён.
This commit is contained in:
+26
-15
@@ -5,6 +5,10 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
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.activities.CallActivity
|
||||||
import ru.f7cloud.talk.services.CallForegroundService
|
import ru.f7cloud.talk.services.CallForegroundService
|
||||||
import ru.f7cloud.talk.utils.bundle.BundleKeys
|
import ru.f7cloud.talk.utils.bundle.BundleKeys
|
||||||
@@ -22,6 +26,9 @@ object TalkNativeCallLauncher {
|
|||||||
private const val TAG = "TalkNativeCallLauncher"
|
private const val TAG = "TalkNativeCallLauncher"
|
||||||
private const val WEBVIEW_CALL_ACTIVITY = "ru.forbion.f7cloud.feature.talk.TalkCallActivity"
|
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(
|
fun launchIncomingCall(
|
||||||
context: Context,
|
context: Context,
|
||||||
session: AuthSession,
|
session: AuthSession,
|
||||||
@@ -83,26 +90,30 @@ object TalkNativeCallLauncher {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!TalkVendorBootstrap.ensureSessionReady(context, session)) {
|
|
||||||
showError(context, "Не удалось подготовить Talk для звонка")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val token = callContext.roomToken.trim()
|
val token = callContext.roomToken.trim()
|
||||||
if (token.isBlank()) {
|
if (token.isBlank()) {
|
||||||
showError(context, "Некорректная комната звонка")
|
showError(context, "Некорректная комната звонка")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runCatching {
|
// Подготовка vendor-юзера — suspend (IO): раньше runBlocking держал main
|
||||||
startCallActivity(
|
// на пути звонка (ANR-риск на входящем звонке, аудит C4). Запуск activity — на main.
|
||||||
context,
|
launchScope.launch {
|
||||||
buildCallIntent(context, session, callContext, incomingFromNotification, suppressIncomingRingtone),
|
if (!TalkVendorBootstrap.ensureSessionReady(context, session)) {
|
||||||
)
|
showError(context, "Не удалось подготовить Talk для звонка")
|
||||||
}.onFailure { error ->
|
return@launch
|
||||||
Log.e(TAG, "Native CallActivity launch failed", error)
|
}
|
||||||
if (TalkNativeConfig.allowWebViewCallFallback) {
|
runCatching {
|
||||||
launchWebViewFallback(context, session, token, incomingFromNotification)
|
startCallActivity(
|
||||||
} else {
|
context,
|
||||||
showError(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, "Не удалось начать звонок")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-4
@@ -2,6 +2,10 @@ package ru.forbion.f7cloud.feature.talknative
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
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.AuthSession
|
||||||
import ru.forbion.f7cloud.core.auth.AuthStore
|
import ru.forbion.f7cloud.core.auth.AuthStore
|
||||||
|
|
||||||
@@ -10,15 +14,20 @@ import ru.forbion.f7cloud.core.auth.AuthStore
|
|||||||
*/
|
*/
|
||||||
object TalkVendorBootstrap {
|
object TalkVendorBootstrap {
|
||||||
private const val TAG = "TalkVendorBootstrap"
|
private const val TAG = "TalkVendorBootstrap"
|
||||||
|
private val warmupScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
|
/** Прогрев vendor-юзера на старте — в фоне (раньше блокировал main в Application.onCreate). */
|
||||||
fun onApplicationCreate(context: Context) {
|
fun onApplicationCreate(context: Context) {
|
||||||
if (!TalkNativeConfig.bootstrapVendorRuntime) return
|
if (!TalkNativeConfig.bootstrapVendorRuntime) return
|
||||||
val session = AuthStore(context).load() ?: return
|
val appContext = context.applicationContext
|
||||||
runCatching { TalkVendorUserSync.ensureUser(context, session) }
|
warmupScope.launch {
|
||||||
.onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") }
|
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
|
if (!TalkNativeConfig.bootstrapVendorRuntime) return true
|
||||||
return runCatching { TalkVendorUserSync.ensureUser(context, session) }
|
return runCatching { TalkVendorUserSync.ensureUser(context, session) }
|
||||||
.onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") }
|
.onFailure { Log.w(TAG, "Talk user sync failed: ${it.message}") }
|
||||||
|
|||||||
+6
-3
@@ -5,22 +5,25 @@ import android.util.Log
|
|||||||
import ru.f7cloud.talk.application.F7cloudTalkApplication
|
import ru.f7cloud.talk.application.F7cloudTalkApplication
|
||||||
import ru.f7cloud.talk.f7cloud.F7TalkUserSync
|
import ru.f7cloud.talk.f7cloud.F7TalkUserSync
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.withContext
|
||||||
import ru.forbion.f7cloud.core.auth.AuthSession
|
import ru.forbion.f7cloud.core.auth.AuthSession
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures talk-android [ru.f7cloud.talk.data.user.model.User] exists for F7cloud sessions.
|
* Ensures talk-android [ru.f7cloud.talk.data.user.model.User] exists for F7cloud sessions.
|
||||||
* Required before native [ru.f7cloud.talk.activities.CallActivity] can run.
|
* Required before native [ru.f7cloud.talk.activities.CallActivity] can run.
|
||||||
|
*
|
||||||
|
* suspend (IO) — раньше был runBlocking на main (старт приложения и путь звонка),
|
||||||
|
* что давало ANR-риск из аудита (C4/п.7).
|
||||||
*/
|
*/
|
||||||
object TalkVendorUserSync {
|
object TalkVendorUserSync {
|
||||||
private const val TAG = "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) {
|
if (context.applicationContext !is F7cloudTalkApplication) {
|
||||||
Log.w(TAG, "Application is not F7cloudTalkApplication, skip sync")
|
Log.w(TAG, "Application is not F7cloudTalkApplication, skip sync")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return runBlocking(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
F7TalkUserSync.get().ensureUser(
|
F7TalkUserSync.get().ensureUser(
|
||||||
serverUrl = session.serverUrl,
|
serverUrl = session.serverUrl,
|
||||||
|
|||||||
Reference in New Issue
Block a user