iOS GPS 設定によるポップアップ、バックグラウンド処理修正。Android は未確認
This commit is contained in:
@ -7,6 +7,8 @@
|
|||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<application
|
<application
|
||||||
android:label="岐阜ナビ"
|
android:label="岐阜ナビ"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
@ -39,5 +41,10 @@
|
|||||||
android:value="2" />
|
android:value="2" />
|
||||||
<meta-data android:name="com.google.android.geo.API_KEY"
|
<meta-data android:name="com.google.android.geo.API_KEY"
|
||||||
android:value="AIzaSyAUBI1ablMKuJwGj2-kSuEhvYxvB1A-mOE"/>
|
android:value="AIzaSyAUBI1ablMKuJwGj2-kSuEhvYxvB1A-mOE"/>
|
||||||
|
<service
|
||||||
|
android:name="com.example.rogapp.LocationService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="location" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.IBinder
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
|
||||||
|
class LocationService : Service() {
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
// フォアグラウンドサービスの設定
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val channel = NotificationChannel(
|
||||||
|
"location",
|
||||||
|
"Location",
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
)
|
||||||
|
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
notificationManager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
val notification = NotificationCompat.Builder(this, "location")
|
||||||
|
.setContentTitle("Tracking location...")
|
||||||
|
.setContentText("Location: null")
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
|
.setOngoing(true)
|
||||||
|
.build()
|
||||||
|
startForeground(1, notification)
|
||||||
|
}
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
// バックグラウンドでの位置情報取得処理を実装
|
||||||
|
val locationSettings = LocationSettings.Builder()
|
||||||
|
.setAccuracy(LocationAccuracy.HIGH)
|
||||||
|
.setDistanceFilter(100.0f)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Geolocator.getPositionStream(locationSettings)
|
||||||
|
.catch { e ->
|
||||||
|
// エラーハンドリング
|
||||||
|
println("Location Error: $e")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
.filterNotNull()
|
||||||
|
.filter { position ->
|
||||||
|
// GPS信号がlow以上の場合のみ記録
|
||||||
|
position.accuracy <= 100
|
||||||
|
}
|
||||||
|
.onEach { position ->
|
||||||
|
val lat = position.latitude
|
||||||
|
val lng = position.longitude
|
||||||
|
val timestamp = System.currentTimeMillis()
|
||||||
|
|
||||||
|
// データベースに位置情報を保存
|
||||||
|
addGPStoDB(lat, lng, timestamp)
|
||||||
|
}
|
||||||
|
.launchIn(CoroutineScope(Dispatchers.IO))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Error starting background tracking: $e")
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addGPStoDB(lat: Double, lng: Double, isCheckin: Int = 0) {
|
||||||
|
try {
|
||||||
|
val context = applicationContext
|
||||||
|
val preferences = context.getSharedPreferences("RogPreferences", Context.MODE_PRIVATE)
|
||||||
|
val teamName = preferences.getString("team_name", "") ?: ""
|
||||||
|
val eventCode = preferences.getString("event_code", "") ?: ""
|
||||||
|
|
||||||
|
if (teamName.isNotEmpty() && eventCode.isNotEmpty()) {
|
||||||
|
val gpsData = GpsData(
|
||||||
|
id = 0,
|
||||||
|
team_name = teamName,
|
||||||
|
event_code = eventCode,
|
||||||
|
lat = lat,
|
||||||
|
lon = lng,
|
||||||
|
is_checkin = isCheckin,
|
||||||
|
created_at = System.currentTimeMillis()
|
||||||
|
)
|
||||||
|
|
||||||
|
GlobalScope.launch {
|
||||||
|
val db = GpsDatabaseHelper.getInstance(context)
|
||||||
|
db.insertGps(gpsData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("Error adding GPS data to DB: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,5 +2,32 @@ package com.example.rogapp
|
|||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
class MainActivity: FlutterActivity() {
|
class MainActivity: FlutterActivity() {
|
||||||
|
private val CHANNEL = "location"
|
||||||
|
|
||||||
|
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||||
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
|
||||||
|
call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"startLocationService" -> {
|
||||||
|
val intent = Intent(this, LocationService::class.java)
|
||||||
|
startService(intent)
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
"stopLocationService" -> {
|
||||||
|
val intent = Intent(this, LocationService::class.java)
|
||||||
|
stopService(intent)
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,9 +11,9 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- flutter_keyboard_visibility (0.0.1):
|
- flutter_keyboard_visibility (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FMDB (2.7.5):
|
- FMDB (2.7.10):
|
||||||
- FMDB/standard (= 2.7.5)
|
- FMDB/standard (= 2.7.10)
|
||||||
- FMDB/standard (2.7.5)
|
- FMDB/standard (2.7.10)
|
||||||
- geolocator_apple (1.2.0):
|
- geolocator_apple (1.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- image_gallery_saver (2.0.2):
|
- image_gallery_saver (2.0.2):
|
||||||
@ -35,7 +35,7 @@ PODS:
|
|||||||
- qr_code_scanner (0.2.0):
|
- qr_code_scanner (0.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- MTBBarcodeScanner
|
- MTBBarcodeScanner
|
||||||
- ReachabilitySwift (5.0.0)
|
- ReachabilitySwift (5.2.1)
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@ -121,7 +121,7 @@ SPEC CHECKSUMS:
|
|||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_compass: cbbd285cea1584c7ac9c4e0c3e1f17cbea55e855
|
flutter_compass: cbbd285cea1584c7ac9c4e0c3e1f17cbea55e855
|
||||||
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: eae540775bf7d0c87a5af926ae37af69effe5a19
|
||||||
geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
|
geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461
|
||||||
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
|
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
|
||||||
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
|
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
|
||||||
@ -132,7 +132,7 @@ SPEC CHECKSUMS:
|
|||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
pointer_interceptor_ios: 9280618c0b2eeb80081a343924aa8ad756c21375
|
pointer_interceptor_ios: 9280618c0b2eeb80081a343924aa8ad756c21375
|
||||||
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
ReachabilitySwift: 5ae15e16814b5f9ef568963fb2c87aeb49158c66
|
||||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||||
sqflite: 50a33e1d72bd59ee092a519a35d107502757ebed
|
sqflite: 50a33e1d72bd59ee092a519a35d107502757ebed
|
||||||
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
||||||
|
|||||||
@ -138,8 +138,8 @@
|
|||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
CD1CB185AC38B6B245F9A672 /* [CP] Embed Pods Frameworks */,
|
E16D8B21E5C6C68755A033DB /* [CP] Embed Pods Frameworks */,
|
||||||
4D62FB08D65E9D3D4D84B418 /* [CP] Copy Pods Resources */,
|
03349FDCCEEF7287E57A0F48 /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -198,23 +198,7 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
03349FDCCEEF7287E57A0F48 /* [CP] Copy Pods Resources */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
alwaysOutOfDate = 1;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
|
||||||
);
|
|
||||||
name = "Thin Binary";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
|
||||||
};
|
|
||||||
4D62FB08D65E9D3D4D84B418 /* [CP] Copy Pods Resources */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@ -231,6 +215,22 @@
|
|||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@ -244,7 +244,7 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
|
||||||
};
|
};
|
||||||
9ACF47601C5E8A391157E87A /* [CP] Check Pods Manifest.lock */ = {
|
9ACF47601C5E8A391157E87A /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@ -268,7 +268,7 @@
|
|||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
CD1CB185AC38B6B245F9A672 /* [CP] Embed Pods Frameworks */ = {
|
E16D8B21E5C6C68755A033DB /* [CP] Embed Pods Frameworks */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
|||||||
@ -67,5 +67,13 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>FLTEnableImpeller</key>
|
<key>FLTEnableImpeller</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>location</string>
|
||||||
|
</array>
|
||||||
|
<key>NSLocationWhenInUseUsageDescription</key>
|
||||||
|
<string>This app needs access to location when open.</string>
|
||||||
|
<key>NSLocationAlwaysUsageDescription</key>
|
||||||
|
<string>This app needs access to location when in the background.</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
169
lib/main.dart
169
lib/main.dart
@ -1,8 +1,12 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
//import 'dart:convert';
|
//import 'dart:convert';
|
||||||
//import 'dart:developer';
|
//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/material.dart';
|
||||||
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
//import 'package:vm_service/vm_service.dart';
|
//import 'package:vm_service/vm_service.dart';
|
||||||
//import 'package:dart_vm_info/dart_vm_info.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 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
//import 'dart:async';
|
//import 'dart:async';
|
||||||
//import 'package:get/get.dart';
|
//import 'package:get/get.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
|
||||||
Map<String, dynamic> deviceInfo = {};
|
Map<String, dynamic> deviceInfo = {};
|
||||||
|
|
||||||
@ -114,6 +122,8 @@ void main() async {
|
|||||||
|
|
||||||
//Get.put(LocationController());
|
//Get.put(LocationController());
|
||||||
|
|
||||||
|
requestLocationPermission();
|
||||||
|
|
||||||
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
|
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
|
||||||
Get.put(SettingsController()); // これを追加
|
Get.put(SettingsController()); // これを追加
|
||||||
|
|
||||||
@ -126,6 +136,21 @@ void main() async {
|
|||||||
//runApp(const MyApp());
|
//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
|
// メモリ使用量の解説: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 {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({Key? key}) : super(key: key);
|
const MyApp({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -209,8 +327,11 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
|||||||
restoreGame();
|
restoreGame();
|
||||||
}
|
}
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
|
debugPrint("Start MyAppState...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
@ -227,37 +348,69 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
|||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
LocationController locationController = Get.find<LocationController>();
|
LocationController locationController = Get.find<LocationController>();
|
||||||
|
DestinationController destinationController = Get.find<DestinationController>();
|
||||||
|
|
||||||
//DestinationController destinationController =
|
//DestinationController destinationController =
|
||||||
// Get.find<DestinationController>();
|
// Get.find<DestinationController>();
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
|
// Foreground に戻った時の処理
|
||||||
|
debugPrint(" ==(Status Changed)==> RESUMED. フォアグラウンドに戻りました");
|
||||||
locationController.resumePositionStream();
|
locationController.resumePositionStream();
|
||||||
//print("RESUMED");
|
//print("RESUMED");
|
||||||
restoreGame();
|
restoreGame();
|
||||||
|
|
||||||
|
// バックグラウンド処理を停止
|
||||||
|
if (Platform.isIOS && destinationController.isRunningBackgroundGPS) {
|
||||||
|
stopBackgroundTracking();
|
||||||
|
destinationController.isRunningBackgroundGPS=false;
|
||||||
|
destinationController.restartGPS();
|
||||||
|
|
||||||
|
} else if (Platform.isAndroid) {
|
||||||
|
const platform = MethodChannel('location');
|
||||||
|
platform.invokeMethod('stopLocationService');
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.inactive:
|
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;
|
break;
|
||||||
case AppLifecycleState.paused:
|
case AppLifecycleState.paused:
|
||||||
locationController.resumePositionStream();
|
// バックグラウンドに移行したときの処理
|
||||||
//print("PAUSED");
|
//locationController.resumePositionStream();
|
||||||
|
debugPrint(" ==(Status Changed)==> PAUSED. バックグラウンド処理。");
|
||||||
saveGameState();
|
saveGameState();
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
locationController.resumePositionStream();
|
// アプリが終了する直前に発生します。この状態では、アプリはメモリから解放される予定です。
|
||||||
//print("DETACHED");
|
//locationController.resumePositionStream();
|
||||||
|
debugPrint(" ==(Status Changed)==> DETACHED アプリは終了します。");
|
||||||
saveGameState();
|
saveGameState();
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.hidden:
|
case AppLifecycleState.hidden:
|
||||||
locationController.resumePositionStream();
|
// Web用の特殊な状態で、モバイルアプリでは発生しません。
|
||||||
//print("DETACHED");
|
//locationController.resumePositionStream();
|
||||||
|
debugPrint(" ==(Status Changed)==> Hidden アプリが隠れた");
|
||||||
saveGameState();
|
saveGameState();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
|
|||||||
@ -946,6 +946,7 @@ class DestinationController extends GetxController {
|
|||||||
is_checkin: isCheckin,
|
is_checkin: isCheckin,
|
||||||
created_at: DateTime.now().millisecondsSinceEpoch);
|
created_at: DateTime.now().millisecondsSinceEpoch);
|
||||||
var res = await db.insertGps(gps_data);
|
var res = await db.insertGps(gps_data);
|
||||||
|
//debugPrint("Saved GPS data into DB...");
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print("errr ready gps ${err}");
|
print("errr ready gps ${err}");
|
||||||
@ -1202,7 +1203,10 @@ class DestinationController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// コントローラーの初期化時に呼び出されるライフサイクルメソッドです。
|
// コントローラーの初期化時に呼び出されるライフサイクルメソッドです。
|
||||||
//
|
//
|
||||||
|
bool inError=false;
|
||||||
|
bool isRunningBackgroundGPS=false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() async {
|
void onInit() async {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@ -1225,7 +1229,53 @@ class DestinationController extends GetxController {
|
|||||||
handleLocationUpdate(locationMarkerPosition);
|
handleLocationUpdate(locationMarkerPosition);
|
||||||
//}
|
//}
|
||||||
}, onError: (err) {
|
}, onError: (err) {
|
||||||
print("Location Error: $err");
|
if(inError==false){
|
||||||
|
inError = true;
|
||||||
|
debugPrint("Location Error: $err");
|
||||||
|
// エラーが発生した場合、locationMarkerPositionStreamControllerにエラーを追加します。
|
||||||
|
locationController.locationMarkerPositionStreamController.addError(err);
|
||||||
|
|
||||||
|
// ここにエラー発生時の処理を追加します。
|
||||||
|
if (err is LocationServiceDisabledException) {
|
||||||
|
// 位置情報サービスが無効になっている場合の処理
|
||||||
|
print('Location services are disabled');
|
||||||
|
Get.snackbar(
|
||||||
|
'エラー',
|
||||||
|
'位置情報サービスが無効になっています。設定画面から位置情報サービスを有効にして下さい。不明な場合にはエンジニアスタッフにお問い合わせください。',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
inError = false;
|
||||||
|
} else if (err is PermissionDeniedException) {
|
||||||
|
// 位置情報の権限がない場合の処理
|
||||||
|
print('Location permissions are denied');
|
||||||
|
Get.snackbar(
|
||||||
|
'エラー',
|
||||||
|
'位置情報サービスが許可されていません。設定画面から岐阜ナビの位置情報サービスを許可して下さい。不明な場合にはエンジニアスタッフにお問い合わせください。',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
inError = false;
|
||||||
|
} else {
|
||||||
|
// その他のエラーの場合の処理
|
||||||
|
print('Location Error: $err');
|
||||||
|
Get.snackbar(
|
||||||
|
'エラー',
|
||||||
|
'位置情報サービスに問題が発生しました。位置情報サービスを再起動していますので少しお待ちください。',
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
colorText: Colors.white,
|
||||||
|
duration: Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
|
||||||
|
// GPSデータのListenを再開する処理を追加
|
||||||
|
if( isRunningBackgroundGPS==false && inError ) {
|
||||||
|
restartGPS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//print("Location Error: $err");
|
||||||
});
|
});
|
||||||
|
|
||||||
startGame();
|
startGame();
|
||||||
@ -1233,6 +1283,14 @@ class DestinationController extends GetxController {
|
|||||||
checkGPSDataReceived();
|
checkGPSDataReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restartGPS(){
|
||||||
|
// GPSデータのListenを再開する処理を追加
|
||||||
|
Future.delayed(Duration(seconds: 5), () {
|
||||||
|
locationController.startPositionStream();
|
||||||
|
inError=false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// コントローラーのクローズ時に呼び出されるライフサイクルメソッドです。
|
// コントローラーのクローズ時に呼び出されるライフサイクルメソッドです。
|
||||||
//
|
//
|
||||||
@override
|
@override
|
||||||
@ -1248,18 +1306,23 @@ class DestinationController extends GetxController {
|
|||||||
//
|
//
|
||||||
// 要検討:GPSデータの追加に失敗した場合のエラーハンドリングを追加することをお勧めします。
|
// 要検討:GPSデータの追加に失敗した場合のエラーハンドリングを追加することをお勧めします。
|
||||||
//
|
//
|
||||||
|
double prevLat = 0.0; // 直前の位置
|
||||||
|
double prevLon = 0.0;
|
||||||
|
|
||||||
void handleLocationUpdate(LocationMarkerPosition? position) async {
|
void handleLocationUpdate(LocationMarkerPosition? position) async {
|
||||||
try {
|
try {
|
||||||
//final DestinationController destinationController = Get.find<DestinationController>();
|
//final DestinationController destinationController = Get.find<DestinationController>();
|
||||||
//final signalStrength = locationController.getGpsSignalStrength();
|
//final signalStrength = locationController.getGpsSignalStrength();
|
||||||
|
|
||||||
okToUseGPS = false;
|
okToUseGPS = false;
|
||||||
double prevLat = currentLat; // 直前の位置
|
|
||||||
double prevLon = currentLon;
|
|
||||||
|
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
currentLat = position.latitude;
|
currentLat = position.latitude;
|
||||||
currentLon = position.longitude;
|
currentLon = position.longitude;
|
||||||
|
if( prevLat==0.0 ){
|
||||||
|
prevLat = currentLat;
|
||||||
|
prevLon = currentLon;
|
||||||
|
}
|
||||||
lastValidGPSLocation = LatLng(currentLat, currentLon);
|
lastValidGPSLocation = LatLng(currentLat, currentLon);
|
||||||
okToUseGPS = true;
|
okToUseGPS = true;
|
||||||
lastGPSDataReceivedTime = DateTime.now();
|
lastGPSDataReceivedTime = DateTime.now();
|
||||||
@ -1316,7 +1379,8 @@ class DestinationController extends GetxController {
|
|||||||
Duration difference = lastGPSCollectedTime.difference(DateTime.now())
|
Duration difference = lastGPSCollectedTime.difference(DateTime.now())
|
||||||
.abs();
|
.abs();
|
||||||
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過(普通に歩くスピード)
|
// 最後にGPS信号を取得した時刻から10秒以上経過、かつ10m以上経過(普通に歩くスピード)
|
||||||
if (difference.inSeconds >= 10 && distanceToDest >= 10) {
|
//debugPrint("時間差:${difference.inSeconds}, 距離差:${distanceToDest}");
|
||||||
|
if (difference.inSeconds >= 10 || distanceToDest >= 30) {
|
||||||
// print(
|
// print(
|
||||||
// "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}");
|
// "^^^^^^^^ GPS data collected ${DateFormat('kk:mm:ss \n EEE d MMM').format(DateTime.now())}, ^^^ ${position.latitude}, ${position.longitude}");
|
||||||
|
|
||||||
@ -1333,11 +1397,14 @@ class DestinationController extends GetxController {
|
|||||||
if (isInRog.value) {
|
if (isInRog.value) {
|
||||||
await addGPStoDB(position.latitude, position.longitude);
|
await addGPStoDB(position.latitude, position.longitude);
|
||||||
lastGPSCollectedTime = DateTime.now();
|
lastGPSCollectedTime = DateTime.now();
|
||||||
|
prevLat = position.latitude;
|
||||||
|
prevLon = position.longitude;
|
||||||
|
debugPrint("フロントエンドでのGPS保存(時間差:${difference.inSeconds}, 距離差:${distanceToDest}) : Time=${lastGPSCollectedTime}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
debugPrint("Error: ${e}");
|
debugPrint("handleLocationUpdate Error: ${e}");
|
||||||
} finally {
|
} finally {
|
||||||
/* Akira , 2024-4-5
|
/* Akira , 2024-4-5
|
||||||
if (position != null &&
|
if (position != null &&
|
||||||
|
|||||||
@ -72,6 +72,7 @@ class _GpsPageState extends State<GpsPage> {
|
|||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
Container(
|
Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: i.is_checkin == 1
|
child: i.is_checkin == 1
|
||||||
@ -93,6 +94,8 @@ class _GpsPageState extends State<GpsPage> {
|
|||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
))
|
))
|
||||||
: Container()),
|
: Container()),
|
||||||
|
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||||
import 'package:geojson_vi/geojson_vi.dart';
|
import 'package:geojson_vi/geojson_vi.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:rogapp/model/destination.dart';
|
import 'package:rogapp/model/destination.dart';
|
||||||
@ -120,11 +121,76 @@ class IndexController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _checkLocationPermission() async {
|
||||||
|
if (Get.context == null) {
|
||||||
|
debugPrint('Get.context is null in _checkLocationPermission');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocationPermission permission = await Geolocator.checkPermission();
|
||||||
|
//permission = await Geolocator.requestPermission();
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
debugPrint('GPS : Denied');
|
||||||
|
await showLocationPermissionDeniedDialog();
|
||||||
|
} else if (permission == LocationPermission.deniedForever) {
|
||||||
|
debugPrint('GPS : Denied forever');
|
||||||
|
await showLocationPermissionDeniedDialog();
|
||||||
|
}else if (permission == LocationPermission.whileInUse){
|
||||||
|
debugPrint('GPS : While-In-Use');
|
||||||
|
await showLocationPermissionDeniedDialog();
|
||||||
|
|
||||||
|
}else{
|
||||||
|
debugPrint("Permission is no problem....");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 追加
|
||||||
|
Future<void> showLocationPermissionDeniedDialog() async {
|
||||||
|
if (Get.context != null) {
|
||||||
|
print('Showing location permission denied dialog');
|
||||||
|
await showDialog(
|
||||||
|
context: Get.context!,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () async => false,
|
||||||
|
child: AlertDialog(
|
||||||
|
title: Text('位置情報の許可が必要です'),
|
||||||
|
content: Text('設定>プライバシーとセキュリティ>位置情報サービス を開いて、岐阜ナビを探し、「位置情報の許可」を「常に」にして下さい。'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print('Get.context is null in showLocationPermissionDeniedDialog');
|
||||||
|
// Get.contextがnullの場合の処理
|
||||||
|
print('Location permission denied, but context is null');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
_connectivitySubscription =
|
_connectivitySubscription =
|
||||||
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
_connectivity.onConnectivityChanged.listen(_updateConnectionStatus);
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
|
||||||
|
print('IndexController onInit called'); // デバッグ用の出力を追加
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkPermission()
|
||||||
|
{
|
||||||
|
debugPrint("MapControllerの初期化が完了したら、位置情報の許可をチェックする");
|
||||||
|
_checkLocationPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -425,9 +491,11 @@ class IndexController extends GetxController {
|
|||||||
// 2024-04-03 Akira .. Update the code . See ticket 2800.
|
// 2024-04-03 Akira .. Update the code . See ticket 2800.
|
||||||
//
|
//
|
||||||
// 2024-4-8 Akira : See 2809
|
// 2024-4-8 Akira : See 2809
|
||||||
// IndexControllerクラスでは、Future.delayedの呼び出しをunawaitedで囲んで、非同期処理の結果を待たずに先に進むようにしました。これにより、メモリリークを防ぐことができます
|
// IndexControllerクラスでは、Future.delayedの呼び出しをunawaitedで囲んで、
|
||||||
|
// 非同期処理の結果を待たずに先に進むようにしました。これにより、メモリリークを防ぐことができます
|
||||||
//
|
//
|
||||||
// 要検討:Future.delayedを使用して非同期処理を待たずに先に進むようにしていますが、これによってメモリリークが発生する可能性があります。非同期処理の結果を適切に処理することを検討してください。
|
// 要検討:Future.delayedを使用して非同期処理を待たずに先に進むようにしていますが、
|
||||||
|
// これによってメモリリークが発生する可能性があります。非同期処理の結果を適切に処理することを検討してください。
|
||||||
//
|
//
|
||||||
void loadLocationsBound() async {
|
void loadLocationsBound() async {
|
||||||
if (isCustomAreaSelected.value == true) {
|
if (isCustomAreaSelected.value == true) {
|
||||||
@ -437,11 +505,6 @@ class IndexController extends GetxController {
|
|||||||
// MapControllerの初期化が完了するまで待機
|
// MapControllerの初期化が完了するまで待機
|
||||||
await waitForMapControllerReady();
|
await waitForMapControllerReady();
|
||||||
|
|
||||||
// Akira 追加:2024-4-6 #2800
|
|
||||||
//await waitForMapControllerReady(); // MapControllerの初期化が完了するまで待機
|
|
||||||
// Akira 追加:2024-4-6 #2800
|
|
||||||
// ==> remove 2024-4-8
|
|
||||||
|
|
||||||
locations.clear();
|
locations.clear();
|
||||||
String cat = currentCat.isNotEmpty ? currentCat[0] : "";
|
String cat = currentCat.isNotEmpty ? currentCat[0] : "";
|
||||||
if (currentCat.isNotEmpty && currentCat[0] == "-all-") {
|
if (currentCat.isNotEmpty && currentCat[0] == "-all-") {
|
||||||
@ -458,14 +521,16 @@ class IndexController extends GetxController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
LatLngBounds bounds = mapController.bounds!;
|
LatLngBounds bounds = mapController.bounds!;
|
||||||
|
if (bounds == null) {
|
||||||
|
// MapControllerの初期化が完了していない場合は処理を行わない
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
currentBound.clear();
|
currentBound.clear();
|
||||||
currentBound.add(bounds);
|
currentBound.add(bounds);
|
||||||
|
|
||||||
isLoading.value = true; // ローディング状態をtrueに設定
|
isLoading.value = true; // ローディング状態をtrueに設定
|
||||||
|
|
||||||
// unawaited( Future.delayed(const Duration(seconds: 1), () async {
|
|
||||||
// remove
|
|
||||||
|
|
||||||
//print("bounds --- (${bounds.southWest.latitude},${bounds.southWest.longitude}),(${bounds.northWest.latitude},${bounds.northWest.longitude}),(${bounds.northEast.latitude},${bounds.northEast.longitude}),(${bounds.southEast.latitude},${bounds.southEast.longitude})");
|
//print("bounds --- (${bounds.southWest.latitude},${bounds.southWest.longitude}),(${bounds.northWest.latitude},${bounds.northWest.longitude}),(${bounds.northEast.latitude},${bounds.northEast.longitude}),(${bounds.southEast.latitude},${bounds.southEast.longitude})");
|
||||||
|
|
||||||
// 要検討:APIからのレスポンスがnullの場合のエラーハンドリングが不十分です。適切なエラーメッセージを表示するなどの処理を追加してください。
|
// 要検討:APIからのレスポンスがnullの場合のエラーハンドリングが不十分です。適切なエラーメッセージを表示するなどの処理を追加してください。
|
||||||
@ -481,6 +546,7 @@ class IndexController extends GetxController {
|
|||||||
bounds.southEast.longitude,
|
bounds.southEast.longitude,
|
||||||
cat
|
cat
|
||||||
);
|
);
|
||||||
|
/*
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
// APIからのレスポンスがnullの場合
|
// APIからのレスポンスがnullの場合
|
||||||
print("LocationService.loadLocationsBound からの回答がnullのため、マップをリロード");
|
print("LocationService.loadLocationsBound からの回答がnullのため、マップをリロード");
|
||||||
@ -491,8 +557,33 @@ class IndexController extends GetxController {
|
|||||||
} // 追加
|
} // 追加
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
isLoading.value = false; // ローディング状態をfalseに設定
|
isLoading.value = false; // ローディング状態をfalseに設定
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
// APIからのレスポンスがnullの場合
|
||||||
|
print("LocationService.loadLocationsBound からの回答がnullです");
|
||||||
|
} else {
|
||||||
|
if (value.features.isEmpty) {
|
||||||
|
if (showPopup == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Get.snackbar(
|
||||||
|
"Too many Points",
|
||||||
|
"please zoom in",
|
||||||
|
backgroundColor: Colors.yellow,
|
||||||
|
colorText: Colors.white,
|
||||||
|
icon: const Icon(Icons.assistant_photo_outlined, size: 40.0, color: Colors.blue),
|
||||||
|
snackPosition: SnackPosition.TOP,
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
showPopup = false;
|
||||||
|
}
|
||||||
|
if (value.features.isNotEmpty) {
|
||||||
|
locations.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (value != null && value.features.isEmpty) {
|
if (value != null && value.features.isEmpty) {
|
||||||
if (showPopup == false) {
|
if (showPopup == false) {
|
||||||
return;
|
return;
|
||||||
@ -513,6 +604,7 @@ class IndexController extends GetxController {
|
|||||||
if (value != null && value.features.isNotEmpty) {
|
if (value != null && value.features.isNotEmpty) {
|
||||||
locations.add(value);
|
locations.add(value);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
} catch ( e) {
|
} catch ( e) {
|
||||||
print("Error in loadLocationsBound: $e");
|
print("Error in loadLocationsBound: $e");
|
||||||
// エラーが発生した場合のリトライ処理や適切なエラーメッセージの表示を行う
|
// エラーが発生した場合のリトライ処理や適切なエラーメッセージの表示を行う
|
||||||
|
|||||||
@ -104,6 +104,7 @@ class IndexPage extends GetView<IndexController> {
|
|||||||
// タップすることでGPS信号の強弱をシミュレーションできるようにする
|
// タップすることでGPS信号の強弱をシミュレーションできるようにする
|
||||||
// Akira 2024-4-5
|
// Akira 2024-4-5
|
||||||
//
|
//
|
||||||
|
/*
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (locationController.isSimulationMode) {
|
if (locationController.isSimulationMode) {
|
||||||
return DropdownButton<String>(
|
return DropdownButton<String>(
|
||||||
@ -129,6 +130,8 @@ class IndexPage extends GetView<IndexController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
Obx(() => locationController.isSimulationMode
|
Obx(() => locationController.isSimulationMode
|
||||||
? DropdownButton<String>(
|
? DropdownButton<String>(
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class LocationController extends GetxController {
|
|||||||
|
|
||||||
//===== Akira Added 2024-4-9 start
|
//===== Akira Added 2024-4-9 start
|
||||||
// GPSシミュレーション用の変数を追加 ===> 本番では false にする。
|
// GPSシミュレーション用の変数を追加 ===> 本番では false にする。
|
||||||
bool isSimulationMode = true;
|
bool isSimulationMode = false;
|
||||||
|
|
||||||
// GPS信号強度をシミュレートするための変数
|
// GPS信号強度をシミュレートするための変数
|
||||||
final Rx<String> _simulatedSignalStrength = Rx<String>('low');
|
final Rx<String> _simulatedSignalStrength = Rx<String>('low');
|
||||||
@ -93,6 +93,7 @@ class LocationController extends GetxController {
|
|||||||
return 'low';
|
return 'low';
|
||||||
}
|
}
|
||||||
final accuracy = position.accuracy;
|
final accuracy = position.accuracy;
|
||||||
|
//debugPrint("getGpsSignalStrength : ${accuracy}");
|
||||||
if(isSimulationMode){
|
if(isSimulationMode){
|
||||||
return _simulatedSignalStrength.value; // GPS信号強度シミュレーション
|
return _simulatedSignalStrength.value; // GPS信号強度シミュレーション
|
||||||
}else {
|
}else {
|
||||||
@ -346,6 +347,7 @@ class LocationController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleLocationUpdate(LocationMarkerPosition? position) async {
|
void handleLocationUpdate(LocationMarkerPosition? position) async {
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
//debugPrint("position = ${position}");
|
//debugPrint("position = ${position}");
|
||||||
|
|||||||
@ -70,9 +70,12 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// MapControllerの初期化が完了するまで待機
|
// MapControllerの初期化が完了するまで待機
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
debugPrint("MapControllerの初期化が完了");
|
||||||
setState(() {
|
setState(() {
|
||||||
indexController.isMapControllerReady.value = true;
|
indexController.isMapControllerReady.value = true;
|
||||||
});
|
});
|
||||||
|
// MapControllerの初期化が完了したら、IndexControllerのonInitを呼び出す
|
||||||
|
indexController.checkPermission();
|
||||||
});
|
});
|
||||||
|
|
||||||
late MapResetController mapResetController = MapResetController();
|
late MapResetController mapResetController = MapResetController();
|
||||||
|
|||||||
Reference in New Issue
Block a user