473 lines
16 KiB
Dart
473 lines
16 KiB
Dart
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<bool>? _permissionCompleter;
|
||
|
||
static Future<bool> checkAndRequestPermissions() async {
|
||
if (_isRequestingPermission) {
|
||
return _permissionCompleter!.future;
|
||
}
|
||
|
||
_isRequestingPermission = true;
|
||
_permissionCompleter = Completer<bool>();
|
||
|
||
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<bool> _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<bool> _requestAllLocationPermissions() async {
|
||
await Permission.location.request();
|
||
await Permission.locationWhenInUse.request();
|
||
final alwaysStatus = await Permission.locationAlways.request();
|
||
|
||
return alwaysStatus == PermissionStatus.granted;
|
||
}
|
||
|
||
static Future<bool> _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<bool> _isAndroid13OrAbove() async {
|
||
if (Platform.isAndroid) {
|
||
final androidVersion = int.tryParse(Platform.operatingSystemVersion.split('.').first) ?? 0;
|
||
return androidVersion >= 13;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
static Future<bool> 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<bool> checkAndRequestPermissions_old() async {
|
||
if (_isRequestingPermission) {
|
||
return _permissionCompleter!.future;
|
||
}
|
||
|
||
_isRequestingPermission = true;
|
||
_permissionCompleter = Completer<bool>();
|
||
|
||
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<void> 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<bool> showLocationDisclosure() async {
|
||
if (Platform.isIOS) {
|
||
return await _showLocationDisclosureIOS();
|
||
} else if (Platform.isAndroid) {
|
||
return await _showLocationDisclosureAndroid();
|
||
} else {
|
||
// その他のプラットフォームの場合はデフォルトの処理を行う
|
||
return await _showLocationDisclosureIOS();
|
||
}
|
||
}
|
||
|
||
static Future<bool> _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<bool>(
|
||
AlertDialog(
|
||
title: const Text('位置情報の使用について'),
|
||
content: const SingleChildScrollView(
|
||
child: ListBody(
|
||
children: <Widget>[
|
||
Text('このアプリでは、以下の目的で位置情報を使用します:'),
|
||
Text(
|
||
'• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'),
|
||
Text('• 移動履歴の記録(バックグラウンドでも継続)'),
|
||
Text('• 現在地周辺の情報表示'),
|
||
Text('\nバックグラウンドでも位置情報を継続的に取得します。'),
|
||
Text('これにより、バッテリーの消費が増加する可能性があります。'),
|
||
Text('同意しない場合には、アプリは終了します。'),
|
||
],
|
||
),
|
||
),
|
||
actions: <Widget>[
|
||
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<bool> _showLocationDisclosureAndroid() async {
|
||
return await showDialog<bool>(
|
||
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: <Widget>[
|
||
Text('このアプリでは、以下の目的で位置情報を使用します:'),
|
||
Text('• チェックポイントの自動チェックイン(アプリが閉じているときも含む)'),
|
||
Text('• 移動履歴の記録(バックグラウンドでも継続)'),
|
||
Text('• 現在地周辺の情報表示'),
|
||
Text('\nバックグラウンドでも位置情報を継続的に取得します。'),
|
||
Text('これにより、バッテリーの消費が増加する可能性があります。'),
|
||
Text('同意しない場合には、アプリは終了します。'),
|
||
],
|
||
),
|
||
),
|
||
actions: <Widget>[
|
||
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<bool> 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>();
|
||
|
||
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<bool> checkStoragePermission() async {
|
||
//debugPrint("(gifunavi)== checkStoragePermission ==");
|
||
final storagePermission = await Permission.storage.status;
|
||
return storagePermission == PermissionStatus.granted;
|
||
}
|
||
|
||
static Future<void> 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<bool> checkLocationBasicPermission() async {
|
||
//debugPrint("(gifunavi)== checkLocationBasicPermission ==");
|
||
final locationPermission = await Permission.location.status;
|
||
return locationPermission == PermissionStatus.granted;
|
||
}
|
||
|
||
static Future<bool> checkLocationWhenInUsePermission() async {
|
||
//debugPrint("(gifunavi)== checkLocationWhenInUsePermission ==");
|
||
final whenInUsePermission = await Permission.locationWhenInUse.status;
|
||
return whenInUsePermission == PermissionStatus.granted;
|
||
}
|
||
|
||
static Future<bool> checkLocationAlwaysPermission() async {
|
||
//debugPrint("(gifunavi)== checkLocationAlwaysPermission ==");
|
||
final alwaysPermission = await Permission.locationAlways.status;
|
||
return alwaysPermission == PermissionStatus.granted;
|
||
}
|
||
|
||
static bool isBasicPermission=false;
|
||
static Future<void> 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<void> 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<void> 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<void> 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();
|
||
}
|
||
}
|
||
|
||
|
||
*/
|
||
|
||
|
||
} |