import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'dart:async'; class PermissionController { static bool _isRequestingPermission = false; static Completer? _permissionCompleter; static Future checkAndRequestPermissions() async { if (_isRequestingPermission) { return _permissionCompleter!.future; } _isRequestingPermission = true; _permissionCompleter = Completer(); try { bool hasPermissions = await _checkLocationPermissions(); if (!hasPermissions) { bool userAgreed = await showLocationDisclosure(); if (userAgreed) { if (Platform.isAndroid && !await _isAndroid13OrAbove()) { hasPermissions = await _requestAndroidPreS(); } else { hasPermissions = await _requestAllLocationPermissions(); } } else { print('User did not agree to location usage'); hasPermissions = false; SystemNavigator.pop(); } } _isRequestingPermission = false; _permissionCompleter!.complete(hasPermissions); } catch (e) { print('Error in permission request: $e'); _isRequestingPermission = false; _permissionCompleter!.complete(false); } return _permissionCompleter!.future; } static Future _checkLocationPermissions() async { final locationPermission = await Permission.location.status; final whenInUsePermission = await Permission.locationWhenInUse.status; final alwaysPermission = await Permission.locationAlways.status; return locationPermission == PermissionStatus.granted && (whenInUsePermission == PermissionStatus.granted || alwaysPermission == PermissionStatus.granted); } static Future _requestAllLocationPermissions() async { await Permission.location.request(); await Permission.locationWhenInUse.request(); final alwaysStatus = await Permission.locationAlways.request(); return alwaysStatus == PermissionStatus.granted; } static Future _requestAndroidPreS() async { await Permission.location.request(); await Permission.locationWhenInUse.request(); // Android 13以前では、ユーザーに設定画面で権限を許可するように促す await showDialog( context: Get.context!, builder: (context) => AlertDialog( title: Text('バックグラウンド位置情報の許可'), content: Text('アプリの設定画面で「常に許可」を選択してください。'), actions: [ TextButton( child: Text('設定を開く'), onPressed: () { openAppSettings(); Navigator.of(context).pop(); }, ), ], ), ); // 設定画面から戻ってきた後、再度権限をチェック return await Permission.locationAlways.isGranted; } static Future _isAndroid13OrAbove() async { if (Platform.isAndroid) { final androidVersion = int.tryParse(Platform.operatingSystemVersion.split('.').first) ?? 0; return androidVersion >= 13; } return false; } static Future checkLocationPermissions_old() async { final locationPermission = await Permission.location.status; if (locationPermission.isDenied) { await showLocationDisclosure(); final result = await Permission.location.request(); if (result.isDenied) { await openAppSettings(); } } final whenInUsePermission = await Permission.locationWhenInUse.status; final alwaysPermission = await Permission.locationAlways.status; return locationPermission == PermissionStatus.granted && (whenInUsePermission == PermissionStatus.granted || alwaysPermission == PermissionStatus.granted); } static Future checkAndRequestPermissions_old() async { if (_isRequestingPermission) { return _permissionCompleter!.future; } _isRequestingPermission = true; _permissionCompleter = Completer(); try { bool hasPermissions = await _checkLocationPermissions(); if (!hasPermissions) { bool userAgreed = await showLocationDisclosure(); if (userAgreed) { hasPermissions = await _requestAllLocationPermissions(); } else { print('User did not agree to location usage'); hasPermissions = false; // アプリを終了 SystemNavigator.pop(); } } _isRequestingPermission = false; _permissionCompleter!.complete(hasPermissions); } catch( e ) { print('Error in permission request: $e'); _isRequestingPermission = false; _permissionCompleter!.complete(false); } debugPrint("Finish checkAndRequestPermissions..."); return _permissionCompleter!.future; } static Future requestAllLocationPermissions() async { await Permission.location.request(); await Permission.locationWhenInUse.request(); await Permission.locationAlways.request(); if (await Permission.locationAlways.isGranted) { const platform = MethodChannel('location'); try { await platform.invokeMethod('startLocationService'); } on PlatformException catch (e) { debugPrint("Failed to start location service: '${e.message}'."); } } } static Future showLocationDisclosure() async { if (Platform.isIOS) { return await _showLocationDisclosureIOS(); } else if (Platform.isAndroid) { return await _showLocationDisclosureAndroid(); } else { // その他のプラットフォームの場合はデフォルトの処理を行う return await _showLocationDisclosureIOS(); } } static Future _showLocationDisclosureIOS() async { if (Get.context == null) { print('Context is null, cannot show dialog'); return false; } if (Get.isDialogOpen ?? false) { print('A dialog is already open'); return false; } try { final result = await Get.dialog( AlertDialog( title: const Text('位置情報の使用について'), content: const SingleChildScrollView( child: ListBody( children: [ Text('このアプリでは、以下の目的で位置情報を使用します:'), Text( '• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'), Text('• 移動履歴の記録(バックグラウンドでも継続)'), Text('• 現在地周辺の情報表示'), Text('\nバックグラウンドでも位置情報を継続的に取得します。'), Text('これにより、バッテリーの消費が増加する可能性があります。'), Text('同意しない場合には、アプリは終了します。'), ], ), ), actions: [ TextButton( child: const Text('同意しない'), onPressed: () => Get.back(result: false), ), TextButton( child: const Text('同意する'), onPressed: () => Get.back(result: true), ), ], ), barrierDismissible: false, ); return result ?? false; }catch(e){ print('Dialog error: $e'); return false; } } static Future _showLocationDisclosureAndroid() async { return await showDialog( context: Get.overlayContext ?? Get.context ?? (throw Exception('No valid context found')), barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: const Text('位置情報の使用について'), content: const SingleChildScrollView( child: ListBody( children: [ Text('このアプリでは、以下の目的で位置情報を使用します:'), Text('• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'), Text('• 移動履歴の記録(バックグラウンドでも継続)'), Text('• 現在地周辺の情報表示'), Text('\nバックグラウンドでも位置情報を継続的に取得します。'), Text('これにより、バッテリーの消費が増加する可能性があります。'), Text('同意しない場合には、アプリは終了します。'), ], ), ), actions: [ TextButton( child: const Text('同意しない'), onPressed: () => Navigator.of(context).pop(false), ), TextButton( child: const Text('同意する'), onPressed: () => Navigator.of(context).pop(true), ), ], ); }, ) ?? false; } static void showPermissionDeniedDialog(String title,String message) { Get.dialog( AlertDialog( //title: Text('location_permission_needed_title'.tr), title: Text(title.tr), // 位置情報への許可が必要です //content: Text('location_permission_needed_main'.tr), content: Text(message.tr), // 岐阜ロゲでは、位置情報を使用してスタート・チェックイン・ゴール等の通過照明及び移動手段の記録のために、位置情報のトラッキングを行なっています。このためバックグラウンドでもトラッキングができるように位置情報の権限が必要です。 // 設定画面で、「岐阜ナビ」に対して、常に位置情報を許可するように設定してください。 actions: [ TextButton( child: const Text('キャンセル'), onPressed: () => Get.back(), ), TextButton( child: const Text('設定'), onPressed: () { Get.back(); openAppSettings(); }, ), ], ), ); } /* static Future requestLocationPermissions(BuildContext context) async { if (_isRequestingPermission) { // If a request is already in progress, wait for it to complete return _permissionCompleter!.future; } _isRequestingPermission = true; _permissionCompleter = Completer(); bool userAgreed = await showLocationDisclosure(context); if (userAgreed) { try { final locationStatus = await Permission.location.request(); final whenInUseStatus = await Permission.locationWhenInUse.request(); final alwaysStatus = await Permission.locationAlways.request(); if (locationStatus == PermissionStatus.granted && (whenInUseStatus == PermissionStatus.granted || alwaysStatus == PermissionStatus.granted)) { _permissionCompleter!.complete(true); } else { showPermissionDeniedDialog('location_permission_needed_title', 'location_permission_needed_main'); _permissionCompleter!.complete(false); } } catch (e) { print('Error requesting location permission: $e'); _permissionCompleter!.complete(false); } } else { print('User did not agree to location usage'); _permissionCompleter!.complete(false); // Exit the app SystemNavigator.pop(); } _isRequestingPermission = false; return _permissionCompleter!.future; } */ static Future checkStoragePermission() async { //debugPrint("(gifunavi)== checkStoragePermission =="); final storagePermission = await Permission.storage.status; return storagePermission == PermissionStatus.granted; } static Future requestStoragePermission() async { //debugPrint("(gifunavi)== requestStoragePermission =="); final storagePermission = await Permission.storage.request(); if (storagePermission == PermissionStatus.granted) { return; } if (storagePermission == PermissionStatus.permanentlyDenied) { // リクエストが完了するまで待機 await Future.delayed(const Duration(milliseconds: 500)); showPermissionDeniedDialog('storage_permission_needed_title','storage_permission_needed_main'); } } /* static Future checkLocationBasicPermission() async { //debugPrint("(gifunavi)== checkLocationBasicPermission =="); final locationPermission = await Permission.location.status; return locationPermission == PermissionStatus.granted; } static Future checkLocationWhenInUsePermission() async { //debugPrint("(gifunavi)== checkLocationWhenInUsePermission =="); final whenInUsePermission = await Permission.locationWhenInUse.status; return whenInUsePermission == PermissionStatus.granted; } static Future checkLocationAlwaysPermission() async { //debugPrint("(gifunavi)== checkLocationAlwaysPermission =="); final alwaysPermission = await Permission.locationAlways.status; return alwaysPermission == PermissionStatus.granted; } static bool isBasicPermission=false; static Future requestLocationBasicPermissions() async { //debugPrint("(gifunavi)== requestLocationBasicPermissions =="); try{ if(!isBasicPermission){ isBasicPermission=true; final locationStatus = await Permission.location.request(); if (locationStatus != PermissionStatus.granted) { showPermissionDeniedDialog('location_permission_needed_title','location_permission_needed_main'); } } }catch (e, stackTrace){ print('Exception: $e'); print('Stack trace: $stackTrace'); debugPrintStack(label: 'Exception occurred', stackTrace: stackTrace); } } static bool isLocationServiceRunning = false; static bool isRequestedWhenInUsePermission = false; static Future requestLocationWhenInUsePermissions() async { //debugPrint("(gifunavi)== requestLocationWhenInUsePermissions =="); try{ if(!isRequestedWhenInUsePermission){ isRequestedWhenInUsePermission=true; final whenInUseStatus = await Permission.locationWhenInUse.request(); if (whenInUseStatus != PermissionStatus.granted) { showPermissionDeniedDialog('location_permission_needed_title','location_permission_needed_main'); }else{ if( !isLocationServiceRunning ){ isLocationServiceRunning=true; const platform = MethodChannel('location'); try { await platform.invokeMethod('startLocationService'); // Location Service を開始する。 } on PlatformException catch (e) { debugPrint("Failed to start location service: '${e.message}'."); } } } } }catch (e, stackTrace){ debugPrint('Exception: $e'); debugPrint('Stack trace: $stackTrace'); debugPrintStack(label: 'Exception occurred', stackTrace: stackTrace); } } static bool isRequestedAlwaysPermission = false; static Future requestLocationAlwaysPermissions() async { //debugPrint("(gifunavi)== requestLocationAlwaysPermissions =="); try { if( !isRequestedAlwaysPermission ){ isRequestedAlwaysPermission=true; final alwaysStatus = await Permission.locationAlways.request(); if (alwaysStatus != PermissionStatus.granted) { showPermissionDeniedDialog('location_permission_needed_title','location_permission_needed_main'); } } }catch (e, stackTrace){ print('Exception: $e'); print('Stack trace: $stackTrace'); debugPrintStack(label: 'Exception occurred', stackTrace: stackTrace); } } static Future checkAndRequestPermissions() async { final hasPermissions = await checkLocationBasicPermission(); if (!hasPermissions) { await requestLocationBasicPermissions(); } final hasWIUPermissions = await checkLocationWhenInUsePermission(); if (!hasWIUPermissions) { await requestLocationWhenInUsePermissions(); } final hasAlwaysPermissions = await checkLocationAlwaysPermission(); if (!hasAlwaysPermissions) { await requestLocationAlwaysPermissions(); } } */ }