app.dart 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:assets_audio_player/assets_audio_player.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:flutter_flavor/flutter_flavor.dart';
  6. import 'package:get_storage/get_storage.dart';
  7. import 'package:isar/isar.dart';
  8. import 'package:trackoffical_app/service/service.dart';
  9. import 'package:trackoffical_app/service/user_profile.dart';
  10. import 'package:nfc_manager/nfc_manager.dart';
  11. import 'package:package_info_plus/package_info_plus.dart';
  12. import 'package:permission_handler/permission_handler.dart';
  13. import 'package:sensor/sensor.dart' as sensor;
  14. import 'package:system_clock/system_clock.dart';
  15. import 'package:vibration/vibration.dart';
  16. import '../global.dart';
  17. import '../model/platform.dart';
  18. import '../logger.dart';
  19. import '../model/m_position.dart';
  20. // import '../model/provider.dart';
  21. import 'package:trackoffical_app/pb.dart' as pb;
  22. import 'package:device_info_plus/device_info_plus.dart';
  23. import 'package:trackoffical_app/utils.dart' as utils;
  24. import 'package:flutter/material.dart';
  25. class App extends IService{
  26. var screenSize = Size.zero;
  27. static App get to => Get.find();
  28. static const _platform = MethodChannel('com.beswell.toapp/api');
  29. final _serverTime = _ServerTime();
  30. DateTime get now=>_serverTime.now();
  31. final userProfile = UserProfile();
  32. late String appVersion;
  33. PlatformInfo platformInfo = PlatformInfoAndroid();
  34. final isLocationServiceEnable = false.obs;
  35. final isNfcEnable = false.obs;
  36. var xDpi = 0.0;
  37. var yDpi = 0.0;
  38. var devicePixelRatio = 1.0;
  39. var isShowHomeWarn = true;
  40. AssetsAudioPlayer? _audioPlayer;
  41. var selectedMapId = 0.obs;
  42. double heightOneMM(){
  43. final dpi = xDpi;
  44. double pixelRatio = devicePixelRatio;
  45. double pixelCountInMm = dpi / pixelRatio / 25.4;
  46. return pixelCountInMm;
  47. }
  48. bool isFirstLocating = true;
  49. Future<bool> get isNfcAvailable async {
  50. final platform = platformInfo;
  51. if(platform is PlatformInfoIOS){
  52. if (platform.deviceVersion <8 ){
  53. return false;
  54. }
  55. }
  56. return await NfcManager.instance.isAvailable();
  57. }
  58. final List<pb.Region> regionList = [];
  59. correctByServerNow(DateTime serverNow)=>_serverTime.correctByServerNow(serverNow);
  60. Future<void> initBeforeApp()async{
  61. final flavor = await getFlavor();
  62. if(flavor == 'dev'){
  63. // GlobalVar.apiHost = 'totapi-lc.beswell.com';
  64. // GlobalVar.apiHost = 't-otapi.beswell.com';
  65. GlobalVar.apiHost = '192.168.0.3';
  66. // GlobalVar.apiPort = 10000;
  67. GlobalVar.flavor = Flavor.dev;
  68. info('版本:dev');
  69. FlavorConfig(
  70. name: "开发版",
  71. color: Colors.red,
  72. location: BannerLocation.topStart,
  73. );
  74. }
  75. }
  76. @override
  77. Future<App> init() async {
  78. await GetStorage.init();
  79. final deviceInfoPlugin = DeviceInfoPlugin();
  80. final packageInfo = await PackageInfo.fromPlatform();
  81. appVersion = packageInfo.version;
  82. String buildNumber = packageInfo.buildNumber;
  83. info("version: $appVersion\nbuildNumber: $buildNumber");
  84. xDpi = await sensor.Sensor.api.getXDPI();
  85. yDpi = await sensor.Sensor.api.getYDPI();
  86. try{
  87. if (Platform.isAndroid){
  88. platformInfo = PlatformInfoAndroid();
  89. }
  90. if (Platform.isIOS){
  91. final iosInfo = await deviceInfoPlugin.iosInfo;
  92. platformInfo = iosInfo.toModel();
  93. info('ios信息: $iosInfo');
  94. }
  95. }catch(e){
  96. warn('读取设备信息失败:', e);
  97. }
  98. workCheckLocationService();
  99. workCheckNFCEnable();
  100. return this;
  101. }
  102. final Rx<MPosition?> position = Rx(null);
  103. // final Rx<Provider?> selectedProvider = Rx(null);
  104. void workCheckLocationService()async{
  105. while(!isClosed){
  106. isLocationServiceEnable.value = await utils.isLocationServiceEnabled();
  107. await Future.delayed(100.milliseconds);
  108. }
  109. }
  110. void workCheckNFCEnable()async{
  111. while(!isClosed){
  112. isNfcEnable.value = await isNfcAvailable;
  113. await Future.delayed(100.milliseconds);
  114. }
  115. }
  116. Future<MPosition> getPosition({bool forceFlush=false, Duration? timeout}) async{
  117. if(!Platform.isIOS){
  118. var status = await Permission.location.status;
  119. if (!status.isGranted) {
  120. if (!await Permission.location.request().isGranted) {
  121. throw Exception('定位权限未获取');
  122. }
  123. }
  124. }
  125. await utils.checkLocationService();
  126. info('开始定位');
  127. var future = sensor.Sensor.getCurrentPosition();
  128. if(timeout!= null){
  129. future = future.timeout(timeout);
  130. }
  131. final p = await future;
  132. final p2 = MPosition(latitude: p.latitude, longitude: p.longitude);
  133. position.value = p2;
  134. return p2;
  135. }
  136. /// 设备是否支持 NFC
  137. Future<bool> hasNfc()async{
  138. return await _platform.invokeMethod('hasNfc');
  139. }
  140. /// 请求开启 NFC 并返回结果
  141. Future<bool> askEnableNfc()async{
  142. return await _platform.invokeMethod('askEnableNfc');
  143. }
  144. Future<String> getPosition2({bool forceFlush=false}) async{
  145. return await _platform.invokeMethod('getLocation');
  146. }
  147. /// android升级App
  148. // Future<void> updateApp(pb.GetUpdateVersionReply info)async{
  149. // return await _platform.invokeMethod('updateApp', {
  150. // 'url': info.vUrl,
  151. // 'version': info.vCode
  152. // });
  153. // }
  154. /// android升级App进度
  155. Future<float> getUpdateAppProcess()async{
  156. return await _platform.invokeMethod('getUpdateAppProcess');
  157. }
  158. /// android Flavor
  159. Future<String> getFlavor()async{
  160. if(Platform.isAndroid || Platform.isIOS){
  161. return await _platform.invokeMethod('getFlavor');
  162. }
  163. return '';
  164. }
  165. Future<void> soundPlayAsset(String src)async{
  166. soundStop();
  167. if(userProfile.gameSettingsSoundPrompt.value){
  168. _audioPlayer=AssetsAudioPlayer.newPlayer();
  169. await _audioPlayer!.open(
  170. Audio(src),
  171. showNotification: false,
  172. );
  173. }
  174. }
  175. void soundStop(){
  176. _audioPlayer?.stop();
  177. _audioPlayer=null;
  178. }
  179. Future<void> vibrate({
  180. int duration = 500,
  181. List<int> pattern = const [],
  182. int repeat = -1,
  183. List<int> intensities = const [],
  184. int amplitude = -1,
  185. })async{
  186. if(userProfile.gameSettingsVibrationPrompt.value){
  187. if (await Vibration.hasCustomVibrationsSupport()==true) {
  188. await Vibration.vibrate(duration: duration, pattern: pattern, repeat: repeat, intensities: intensities, amplitude: amplitude);
  189. } else {
  190. await Vibration.vibrate();
  191. }
  192. }
  193. }
  194. void locationStart(Duration minTime, double minDistanceM){
  195. sensor.Sensor.locationStart(minTime, minDistanceM);
  196. }
  197. void locationStop(){
  198. sensor.Sensor.api.locationStop();
  199. }
  200. Stream<MPosition> get locationStream{
  201. return sensor.Sensor.locationStream.map((event) => event.toModel());
  202. }
  203. }
  204. extension IosInfoExt on IosDeviceInfo{
  205. PlatformInfoIOS toModel(){
  206. final machine = utsname.machine;
  207. final info = PlatformInfoIOS();
  208. warn('iphone info: $info');
  209. if(machine != null){
  210. final regExp = RegExp('\\d+');
  211. final matches = regExp.allMatches(machine).toList();
  212. if (matches.isNotEmpty){
  213. var match = matches[0];
  214. try{
  215. info.deviceVersion = double.parse(match.group(0)!);
  216. }catch(e){
  217. warn('ios 读取手机型号失败($machine): ', e);
  218. }
  219. if (matches.length > 1){
  220. match = matches[1];
  221. try{
  222. info.deviceVersion += double.parse('0.${match.group(0)!}');
  223. }catch(e){
  224. warn('ios 读取手机型号失败($machine): ', e);
  225. }
  226. }
  227. }
  228. }
  229. return info;
  230. }
  231. }
  232. class _ServerTime{
  233. Duration? _systemOpenTimeWhenRcvServerTime;
  234. DateTime? _serverTime;
  235. correctByServerNow(DateTime serverNow){
  236. _systemOpenTimeWhenRcvServerTime = SystemClock.elapsedRealtime();
  237. _serverTime = serverNow;
  238. }
  239. DateTime now(){
  240. if(_systemOpenTimeWhenRcvServerTime==null){
  241. return DateTime.now();
  242. }
  243. return _serverTime!.add(SystemClock.elapsedRealtime() - _systemOpenTimeWhenRcvServerTime!);
  244. }
  245. }