import 'dart:async'; import 'dart:developer'; import 'dart:io'; import 'package:eatvio_app/core/app_config.dart'; import 'package:eatvio_app/core/app_initializer.dart'; import 'package:eatvio_app/core/utils/toasts.dart'; import 'package:flutter/services.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/token_storage.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/services.dart' show MethodChannel, PlatformException; import 'package:sentry_flutter/sentry_flutter.dart'; class FirebaseApi { final _firebaseMessaging = FirebaseMessaging.instance; Future getToken() async { String? token; if (await _isHuaweiDevice()) { token = await _getHuaweiPushTokenNative().timeout( const Duration(seconds: 5), onTimeout: () => null, ); } else { if ((sl().buildType == AppBuildType.prod)) { try { await _firebaseMessaging.requestPermission().timeout( const Duration(seconds: 5), ); } catch (e) { // Разрешение не критично, продолжаем log('Failed to request Firebase messaging permission: $e'); } } token = await _firebaseMessaging.getToken().timeout( const Duration(seconds: 5), onTimeout: () => null, ); } return token; } Future registerAnonymousPushToken() async { try { final deviceInfo = DeviceInfoPlugin(); await sl().post( '/api/anonymous_token', data: { 'platform': Platform.isIOS ? 'ios' : (await _isHuaweiDevice()) ? 'huawei' : 'android', 'hw_id': Platform.isIOS ? (await deviceInfo.iosInfo).identifierForVendor : (await deviceInfo.androidInfo).id, 'token': await getToken(), }, ).timeout( const Duration(seconds: 10), onTimeout: () { throw TimeoutException('registerAnonymousPushToken timeout'); }, ); } catch (e, st) { log(e.toString(), stackTrace: st); await Sentry.captureException(e, stackTrace: st); // Не пробрасываем ошибку дальше, так как это не критичная операция } } Future registerPushToken() async { if (await TokenStorage.haveTokenInStorage()) { try { final deviceInfo = DeviceInfoPlugin(); final isHuawei = Platform.isAndroid ? await _isHuaweiDevice() : false; await sl().post( '/api/profile/notification/token/register', data: { 'platform': Platform.isIOS ? 'ios' : (isHuawei ? 'huawei' : 'android'), 'hw_id': Platform.isIOS ? (await deviceInfo.iosInfo).identifierForVendor : (await deviceInfo.androidInfo).id, 'token': await getToken(), }, ).timeout( const Duration(seconds: 10), onTimeout: () { throw TimeoutException('registerPushToken timeout'); }, ); } catch (e, st) { log(e.toString(), stackTrace: st); await Sentry.captureException(e, stackTrace: st); // Не пробрасываем ошибку дальше, так как это не критичная операция } } } Future _isHuaweiDevice() async { if (!Platform.isAndroid) return false; try { final info = await DeviceInfoPlugin().androidInfo; final brand = info.brand.toLowerCase(); final manufacturer = info.manufacturer.toLowerCase(); return brand.contains('huawei') || brand.contains('honor') || manufacturer.contains('huawei') || manufacturer.contains('honor'); } catch (_) { return false; } } Future _getHuaweiPushTokenNative() async { try { const channel = MethodChannel('com.eatvioapp/hms_push'); final String? token = await channel.invokeMethod('getHuaweiToken'); return token; } on PlatformException catch (e, st) { showErrorToast('$e $st'); log(e.toString(), stackTrace: st); await Sentry.captureException(e, stackTrace: st); return null; } catch (e, st) { showErrorToast('$e $st'); log(e.toString(), stackTrace: st); await Sentry.captureException(e, stackTrace: st); return null; } } }