iOS GPS 設定によるポップアップ、バックグラウンド処理修正。Android は未確認

This commit is contained in:
2024-05-02 11:51:52 +09:00
parent 9d8f1ef31a
commit 7a97127a19
13 changed files with 515 additions and 52 deletions

View File

@ -1,8 +1,12 @@
import 'dart:async';
import 'dart:io';
//import 'dart:convert';
//import 'dart:developer';
import 'package:rogapp/model/gps_data.dart';
import 'package:rogapp/utils/database_gps.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
//import 'package:vm_service/vm_service.dart';
//import 'package:dart_vm_info/dart_vm_info.dart';
@ -23,6 +27,10 @@ import 'package:rogapp/services/error_service.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
//import 'dart:async';
//import 'package:get/get.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
Map<String, dynamic> deviceInfo = {};
@ -114,6 +122,8 @@ void main() async {
//Get.put(LocationController());
requestLocationPermission();
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
Get.put(SettingsController()); // これを追加
@ -126,6 +136,21 @@ void main() async {
//runApp(const MyApp());
}
Future<void> requestLocationPermission() async {
try {
final status = await Permission.locationAlways.request();
if (status == PermissionStatus.granted) {
print('Location permission granted');
} else {
print('Location permission denied');
//await showLocationPermissionDeniedDialog(); // 追加
}
} catch (e) {
print('Error requesting location permission: $e');
}
}
// メモリ使用量の解説https://qiita.com/hukusuke1007/items/e4e987836412e9bc73b9
/*
@ -192,6 +217,99 @@ void showMemoryWarningDialog() {
}
}
StreamSubscription<Position>? positionStream;
bool background=false;
DateTime lastGPSCollectedTime=DateTime.now();
String team_name="";
String event_code="";
Future<void> startBackgroundTracking() async {
if (Platform.isIOS && background==false) {
final IndexController indexController = Get.find<IndexController>();
if(indexController.currentUser.length>0) {
team_name = indexController.currentUser[0]["user"]['team_name'];
event_code = indexController.currentUser[0]["user"]["event_code"];
}
background = true;
debugPrint("バックグラウンド処理を開始しました。");
final LocationSettings locationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 100,
);
try {
positionStream = Geolocator.getPositionStream(locationSettings: locationSettings)
.listen((Position? position) async {
if (position != null) {
final lat = position.latitude;
final lng = position.longitude;
//final timestamp = DateTime.now();
final accuracy = position.accuracy;
// GPS信号強度がlowの場合はスキップ
if (accuracy > 100) {
debugPrint("GPS signal strength is low. Skipping data saving.");
return;
}
Duration difference = lastGPSCollectedTime.difference(DateTime.now())
.abs();
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過普通に歩くスピード
//debugPrint("時間差:${difference}");
if (difference.inSeconds >= 10 ) {
debugPrint("バックグラウンドでのGPS取得時の処理(10secおき) count=${difference.inSeconds}, time=${DateTime.now()}");
// DBにGPSデータを保存 pages/destination/destination_controller.dart
await addGPStoDB(lat, lng);
lastGPSCollectedTime = DateTime.now();
}
}
}, onError: (error) {
if (error is LocationServiceDisabledException) {
print('Location services are disabled');
} else if (error is PermissionDeniedException) {
print('Location permissions are denied');
} else {
print('Location Error: $error');
}
});
} catch (e) {
print('Error starting background tracking: $e');
}
}
}
Future<void> addGPStoDB(double la, double ln) async {
//debugPrint("in addGPStoDB ${indexController.currentUser}");
GpsDatabaseHelper db = GpsDatabaseHelper.instance;
try {
GpsData gps_data = GpsData(
id: 0,
team_name: team_name,
event_code: event_code,
lat: la,
lon: ln,
is_checkin: 0,
created_at: DateTime.now().millisecondsSinceEpoch);
var res = await db.insertGps(gps_data);
//debugPrint("バックグラウンドでのGPS保存");
} catch (err) {
print("errr ready gps ${err}");
return;
}
}
Future<void> stopBackgroundTracking() async {
if (Platform.isIOS && background==true) {
background=false;
debugPrint("バックグラウンド処理:停止しました。");
await positionStream?.cancel();
positionStream = null;
}
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@ -209,8 +327,11 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
restoreGame();
}
WidgetsBinding.instance.addObserver(this);
debugPrint("Start MyAppState...");
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
@ -227,37 +348,69 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
LocationController locationController = Get.find<LocationController>();
DestinationController destinationController = Get.find<DestinationController>();
//DestinationController destinationController =
// Get.find<DestinationController>();
switch (state) {
case AppLifecycleState.resumed:
// Foreground に戻った時の処理
debugPrint(" ==(Status Changed)==> RESUMED. フォアグラウンドに戻りました");
locationController.resumePositionStream();
//print("RESUMED");
restoreGame();
// バックグラウンド処理を停止
if (Platform.isIOS && destinationController.isRunningBackgroundGPS) {
stopBackgroundTracking();
destinationController.isRunningBackgroundGPS=false;
destinationController.restartGPS();
} else if (Platform.isAndroid) {
const platform = MethodChannel('location');
platform.invokeMethod('stopLocationService');
}
break;
case AppLifecycleState.inactive:
locationController.resumePositionStream();
//print("INACTIVE");
// アプリが非アクティブになったときに発生します。
// これは、別のアプリやシステムのオーバーレイ(着信通話やアラームなど)によって一時的に中断された状態です。
debugPrint(" ==(Status Changed)==> PAUSED. 非アクティブ処理。");
//locationController.resumePositionStream();
// 追加: フロントエンドのGPS信号のlistenを停止
locationController.stopPositionStream();
if (Platform.isIOS ) { // iOSはバックグラウンドでもフロントの処理が生きている。
destinationController.isRunningBackgroundGPS=true;
startBackgroundTracking();
}else if(Platform.isAndroid){
const platform = MethodChannel('location');
platform.invokeMethod('startLocationService');
}
saveGameState();
break;
case AppLifecycleState.paused:
locationController.resumePositionStream();
//print("PAUSED");
// バックグラウンドに移行したときの処理
//locationController.resumePositionStream();
debugPrint(" ==(Status Changed)==> PAUSED. バックグラウンド処理。");
saveGameState();
break;
case AppLifecycleState.detached:
locationController.resumePositionStream();
//print("DETACHED");
// アプリが終了する直前に発生します。この状態では、アプリはメモリから解放される予定です。
//locationController.resumePositionStream();
debugPrint(" ==(Status Changed)==> DETACHED アプリは終了します。");
saveGameState();
break;
case AppLifecycleState.hidden:
locationController.resumePositionStream();
//print("DETACHED");
// Web用の特殊な状態で、モバイルアプリでは発生しません。
//locationController.resumePositionStream();
debugPrint(" ==(Status Changed)==> Hidden アプリが隠れた");
saveGameState();
break;
}
}
@override
Widget build(BuildContext context) {
return GetMaterialApp(