Плагин активити#
Activity Plugin — это автономный модуль, который встраивается прямо в GsBaseActivity, добавляя ей новую функцию (NFC-сканер, BLE-монитор, WebRTC-звонки и т.п.) без изменений в бизнес-логике экранов и без пересборки ядра GMF.
К плагинам активити можно получать доступ из главного потока.
Базовые плагины (камера, NFC, QR-сканер) включены «из коробки» и будут пополняться; разработчик может добавить собственный, реализовав тот же интерфейс.
Мотивация#
Изолировать платформенные API: весь код работы с NFC, камерой или сенсорами живёт в плагине, а приложение общается только через колбэк-интерфейсы.
Повторно использовать логику: один плагин можно подключить сразу во многие приложения.
Синхронизировать жизненный цикл: плагин получает те же события (
onCreate/Resume/Pause…), что иActivity, и не нарушает транзакции State Manager’а.
Контракт#
interface ActivityPlugin : IPkg {
/* ───────────── 1. Инициализация ───────────── */
/** Один раз до показа UI. Можно выполнять работу в IO-диспетчере. */
suspend fun initializeAsync(activity: GsBaseActivity<*>) {}
/** Вызывается сразу после инициализации UI. */
fun onInitializeUi(activity: GsBaseActivity<*>, navigator: Navigator) {}
/* ───────────── 2. Жизненный цикл ───────────── */
fun onCreate (activity: GsBaseActivity<*>) {}
fun onStart (activity: GsBaseActivity<*>) {}
fun onResume (activity: GsBaseActivity<*>) {}
fun onPause (activity: GsBaseActivity<*>) {}
fun onStop (activity: GsBaseActivity<*>) {}
fun onDestroy(activity: GsBaseActivity<*>) {}
/** Activity получила новый Intent (например, NFC-метку). */
fun onNewIntent(activity: GsBaseActivity<*>, intent: Intent) {}
}
Подключение плагина в Activity#
class MainActivity : GsBaseActivity<AppNavigator>() {
override fun provideModules(): List<KClass<out ActivityPlugin>> =
listOf(MyAnalyticsPlugin::class)
}
Тип-список — передаёте
KClass; экземпляр будет лениво создан черезsession.getSimplePkg().
Так удобнее, если плагин в разных модулях и нужен DI-контейнер.
Порядок инициализации#
GsBaseActivityсобираетStateManagerиNavigator.Вызывает
plugin.initializeAsync()параллельно с инициализациейStateManager’а; здесь выполняются тяжёлые операции (запуск CameraX, чтение лицензий и т.п.).UI создан —
onInitializeUi()даёт плагину объектNavigator.Далее события
onCreate/Start/Resume…приходят в том же порядке, что и вActivity.
Обмен данными с экраном#
Плагин хранит публичные
MutableStateFlow/Callback-свойства —ViewModelили VCI подписывается и получает данные.Если нужно уведомить только текущий экран, проще всего передать лямбду-делегат при вызове (в
afterEnter), как показано в NFC-примере, либо получить плагин через сессию.
Пример NFC-плагина#
class NfcActivityPlugin : ActivityPlugin {
private val isWriteNow = AtomicBoolean(false)
private var adapter: NfcAdapter? = null
var onRead: (String) -> Unit = {}
override suspend fun initializeAsync(activity: GsBaseActivity<*>) {
adapter = activity.getSystemService(NfcManager::class.java).defaultAdapter
setupForegroundDispatch(activity)
}
override fun onResume(activity: GsBaseActivity<*>) {
adapter?.enableForegroundDispatch(activity, pendingIntent, filters, null)
}
override fun onPause(activity: GsBaseActivity<*>) {
adapter?.disableForegroundDispatch(activity)
}
override fun onNewIntent(activity: GsBaseActivity<*>, intent: Intent) {
if (!isWriteNow.get()) {
val payload = readNdef(intent)
onRead(payload)
}
}
/* остальной код — чтение, запись, шифрование */
}
Плагин полностью управляет
NfcAdapter, не нагружаяActivity.В
onReadпередаёт данные обратно в экран (VCI) илиState.
Activity-плагины позволяют подключать новые аппаратные возможности так же легко, как dependency в Gradle. Всё управление происходит в одном месте, жизненный цикл синхронизирован, а бизнес-код экранов остаётся чистым.