app.dart 7.6 KB

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