import 'dart:async'; import 'dart:io'; import 'package:assets_audio_player/assets_audio_player.dart'; import 'package:flutter/services.dart'; import 'package:flutter_flavor/flutter_flavor.dart'; import 'package:get_storage/get_storage.dart'; import 'package:isar/isar.dart'; import 'package:trackoffical_app/service/service.dart'; import 'package:trackoffical_app/service/user_profile.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:sensor/sensor.dart' as sensor; import 'package:system_clock/system_clock.dart'; import 'package:vibration/vibration.dart'; import '../global.dart'; import '../model/platform.dart'; import '../logger.dart'; import '../model/m_position.dart'; import '../model/provider.dart'; import 'package:trackoffical_app/pb.dart' as pb; import 'package:device_info_plus/device_info_plus.dart'; import 'package:trackoffical_app/utils.dart' as utils; import 'package:flutter/material.dart'; class App extends IService{ var screenSize = Size.zero; static App get to => Get.find(); static const _platform = MethodChannel('com.beswell.app/api'); final _serverTime = _ServerTime(); DateTime get now=>_serverTime.now(); final userProfile = UserProfile(); late String appVersion; PlatformInfo platformInfo = PlatformInfoAndroid(); final isLocationServiceEnable = false.obs; final isNfcEnable = false.obs; var xDpi = 0.0; var yDpi = 0.0; var devicePixelRatio = 1.0; var isShowHomeWarn = true; AssetsAudioPlayer? _audioPlayer; double heightOneMM(){ final dpi = xDpi; double pixelRatio = devicePixelRatio; double pixelCountInMm = dpi / pixelRatio / 25.4; return pixelCountInMm; } bool isFirstLocating = true; Future get isNfcAvailable async { final platform = platformInfo; if(platform is PlatformInfoIOS){ if (platform.deviceVersion <8 ){ return false; } } return await NfcManager.instance.isAvailable(); } final List regionList = []; correctByServerNow(DateTime serverNow)=>_serverTime.correctByServerNow(serverNow); Future initBeforeApp()async{ final flavor = await getFlavor(); if(flavor == 'dev'){ GlobalVar.apiHost='totapi-lc.beswell.com'; GlobalVar.flavor=Flavor.dev; info('版本:dev'); FlavorConfig( name: "开发版", color: Colors.red, location: BannerLocation.topStart, ); } } @override Future init() async { await GetStorage.init(); final deviceInfoPlugin = DeviceInfoPlugin(); final packageInfo = await PackageInfo.fromPlatform(); appVersion = packageInfo.version; String buildNumber = packageInfo.buildNumber; info("version: $appVersion\nbuildNumber: $buildNumber"); xDpi = await sensor.Sensor.api.getXDPI(); yDpi = await sensor.Sensor.api.getYDPI(); try{ if (Platform.isAndroid){ platformInfo = PlatformInfoAndroid(); } if (Platform.isIOS){ final iosInfo = await deviceInfoPlugin.iosInfo; platformInfo = iosInfo.toModel(); info('ios信息: $iosInfo'); } }catch(e){ warn('读取设备信息失败:', e); } workCheckLocationService(); workCheckNFCEnable(); return this; } final Rx position = Rx(null); final Rx selectedProvider = Rx(null); void workCheckLocationService()async{ while(!isClosed){ isLocationServiceEnable.value = await utils.isLocationServiceEnabled(); await Future.delayed(100.milliseconds); } } void workCheckNFCEnable()async{ while(!isClosed){ isNfcEnable.value = await isNfcAvailable; await Future.delayed(100.milliseconds); } } Future getPosition({bool forceFlush=false, Duration? timeout}) async{ if(!Platform.isIOS){ var status = await Permission.location.status; if (!status.isGranted) { if (!await Permission.location.request().isGranted) { throw Exception('定位权限未获取'); } } } await utils.checkLocationService(); info('开始定位'); var future = sensor.Sensor.getCurrentPosition(); if(timeout!= null){ future = future.timeout(timeout); } final p = await future; final p2 = MPosition(latitude: p.latitude, longitude: p.longitude); position.value = p2; return p2; } /// 设备是否支持 NFC Future hasNfc()async{ return await _platform.invokeMethod('hasNfc'); } /// 请求开启 NFC 并返回结果 Future askEnableNfc()async{ return await _platform.invokeMethod('askEnableNfc'); } Future getPosition2({bool forceFlush=false}) async{ return await _platform.invokeMethod('getLocation'); } /// android升级App Future updateApp(pb.GetUpdateVersionReply info)async{ return await _platform.invokeMethod('updateApp', { 'url': info.vUrl, 'version': info.vCode }); } /// android升级App进度 Future getUpdateAppProcess()async{ return await _platform.invokeMethod('getUpdateAppProcess'); } /// android Flavor Future getFlavor()async{ if(Platform.isAndroid || Platform.isIOS){ return await _platform.invokeMethod('getFlavor'); } return ''; } Future soundPlayAsset(String src)async{ soundStop(); if(userProfile.gameSettingsSoundPrompt.value){ _audioPlayer=AssetsAudioPlayer.newPlayer(); await _audioPlayer!.open( Audio(src), showNotification: false, ); } } void soundStop(){ _audioPlayer?.stop(); _audioPlayer=null; } Future vibrate({ int duration = 500, List pattern = const [], int repeat = -1, List intensities = const [], int amplitude = -1, })async{ if(userProfile.gameSettingsVibrationPrompt.value){ if (await Vibration.hasCustomVibrationsSupport()==true) { await Vibration.vibrate(duration: duration, pattern: pattern, repeat: repeat, intensities: intensities, amplitude: amplitude); } else { await Vibration.vibrate(); } } } void locationStart(Duration minTime, double minDistanceM){ sensor.Sensor.locationStart(minTime, minDistanceM); } void locationStop(){ sensor.Sensor.api.locationStop(); } Stream get locationStream{ return sensor.Sensor.locationStream.map((event) => event.toModel()); } } extension IosInfoExt on IosDeviceInfo{ PlatformInfoIOS toModel(){ final machine = utsname.machine; final info = PlatformInfoIOS(); warn('iphone info: $info'); if(machine != null){ final regExp = RegExp('\\d+'); final matches = regExp.allMatches(machine).toList(); if (matches.isNotEmpty){ var match = matches[0]; try{ info.deviceVersion = double.parse(match.group(0)!); }catch(e){ warn('ios 读取手机型号失败($machine): ', e); } if (matches.length > 1){ match = matches[1]; try{ info.deviceVersion += double.parse('0.${match.group(0)!}'); }catch(e){ warn('ios 读取手机型号失败($machine): ', e); } } } } return info; } } class _ServerTime{ Duration? _systemOpenTimeWhenRcvServerTime; DateTime? _serverTime; correctByServerNow(DateTime serverNow){ _systemOpenTimeWhenRcvServerTime = SystemClock.elapsedRealtime(); _serverTime = serverNow; } DateTime now(){ if(_systemOpenTimeWhenRcvServerTime==null){ return DateTime.now(); } return _serverTime!.add(SystemClock.elapsedRealtime() - _systemOpenTimeWhenRcvServerTime!); } }