feat(digital-id): Цифровой ID — WebView-мост к оригиналу + нативный режим

Реализован функционал Цифрового ID (паспорт, СНИЛС, ИНН, ОМС, водительское,
СТС и др.) двумя путями с переключателем в меню разработчика.

WebView-мост (по умолчанию):
- Открывает оригинальную страницу digital-id.max.ru и реализует нативный
  хост-мост window.WebViewHandler (postEvent/receiveEvent), который настоящее
  приложение MAX предоставляет нативно: lifecycle-события, биометрия,
  SecureStorage/DeviceStorage, OpenLink (переход на Госуслуги) и заворот
  OAuth-callback (externalCallback) обратно в мини-апп.
- botId Цифрового ID резолвится из settings-entry-banners конфига логина
  (как Сферум).

Нативный режим:
- DigitalIdModule — REST-клиент к ext-api.max.ru (все эндпоинты по образцу
  библиотеки gaijin: biometry, docs, esia, qr, verify, acms, profile),
  авторизация через #WebAppData= из webAppInitData.
- Модели документов и экран онбординга/просмотра.

Прочее:
- Тумблер AppDigitalIdNative (WebView/нативно) и кнопка «Сбросить Цифровой ID»
  (очистка кук и данных WebView) — в настройках разработчика.
This commit is contained in:
klockky
2026-06-08 18:23:23 +03:00
parent 7ad258f6c0
commit 06b5720638
10 changed files with 1624 additions and 8 deletions
+16
View File
@@ -5,6 +5,12 @@ import '../../core/storage/token_storage.dart';
abstract class EntryBannerApps {
static const String sferumKey = 'entry_banner_app_sferum';
static const String digitalIdKey = 'entry_banner_app_digital_id';
static const Map<String, String> iconMatchers = {
sferumKey: 'sferum',
digitalIdKey: 'digital',
};
}
class WebAppLaunch {
@@ -46,6 +52,16 @@ class WebAppModule {
return fetchLaunch(botId);
}
Future<WebAppLaunch> fetchDigitalId() async {
final botId = await _resolveEntryApp(EntryBannerApps.digitalIdKey);
if (botId == null) {
throw const WebAppUnavailable(
'Цифровой ID сейчас недоступен. Переподключитесь и попробуйте снова.',
);
}
return fetchLaunch(botId);
}
Future<int?> _resolveEntryApp(String key) async {
final accountId = await TokenStorage.getActiveAccountId();
if (accountId == null) return null;