Fixed Location Permission issue on Android - 1
This commit is contained in:
@ -9,6 +9,7 @@
|
||||
<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" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
||||
<application
|
||||
android:label="岐阜ナビ"
|
||||
android:name="${applicationName}"
|
||||
|
||||
@ -20,6 +20,7 @@ import com.google.android.gms.location.LocationCallback
|
||||
import com.google.android.gms.location.LocationRequest
|
||||
import com.google.android.gms.location.LocationResult
|
||||
import com.google.android.gms.location.LocationServices
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
@ -27,6 +28,7 @@ import java.util.Date
|
||||
import java.util.Locale
|
||||
import android.app.Notification
|
||||
|
||||
|
||||
data class GpsData(
|
||||
val id: Int,
|
||||
val team_name: String,
|
||||
@ -54,6 +56,7 @@ class GpsDatabaseHelper(private val context: Context) {
|
||||
|
||||
class LocationService : Service() {
|
||||
private lateinit var fusedLocationClient: FusedLocationProviderClient
|
||||
private lateinit var gpsDatabaseHelper: GpsDatabaseHelper
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
@ -61,12 +64,13 @@ class LocationService : Service() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Log.d("LocationService", "Android: onCreate.")
|
||||
|
||||
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
||||
gpsDatabaseHelper = GpsDatabaseHelper.getInstance(applicationContext)
|
||||
|
||||
// 位置情報の権限チェックとGPS有効化の確認を行う
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.FOREGROUND_SERVICE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
val locationRequest = LocationRequest.create().apply {
|
||||
@ -75,45 +79,37 @@ class LocationService : Service() {
|
||||
fastestInterval = 5000
|
||||
}
|
||||
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
|
||||
|
||||
// フォアグラウンドサービスの設定
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val channel = NotificationChannel(CHANNEL_ID, "Location", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||
notificationManager?.createNotificationChannel(channel)
|
||||
}
|
||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("Tracking location...")
|
||||
.setContentText("Location: null")
|
||||
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
|
||||
.setOngoing(true)
|
||||
.build()
|
||||
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
} else {
|
||||
Log.d("LocationService", "GPS is disabled.")
|
||||
// GPSが無効の場合の処理を追加する(例: ユーザーにGPSを有効にするように促すなど)
|
||||
stopSelf() // サービスを停止する
|
||||
}
|
||||
} else {
|
||||
Log.d("LocationService", "Location permission is not granted.")
|
||||
// 位置情報の権限が許可されていない場合の処理を追加する
|
||||
Log.d("LocationService", "Location permission or Foreground service location permission is not granted.")
|
||||
// 位置情報の権限またはフォアグラウンドサービスの位置情報の権限が許可されていない場合の処理を追加する
|
||||
stopSelf() // サービスを停止する
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// GPSデバイスが有効になっているか確認する
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
Log.d("LocationService", "GPS is disabled.")
|
||||
// GPSが無効の場合の処理を追加する(例: ユーザーにGPSを有効にするように促すなど)
|
||||
}else{
|
||||
Log.d("LocationService", "GPS is enabled.")
|
||||
}
|
||||
*/
|
||||
|
||||
// フォアグラウンドサービスの設定
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val CHANNEL_ID = "location"
|
||||
val channel = NotificationChannel(CHANNEL_ID, "Location", NotificationManager.IMPORTANCE_DEFAULT)
|
||||
val notificationManager = getSystemService(NotificationManager::class.java) // この行を追加
|
||||
|
||||
Log.d("LocationService", "Android: Foreground service.")
|
||||
|
||||
notificationManager?.createNotificationChannel(channel)
|
||||
}
|
||||
val notification = NotificationCompat.Builder(this, "location")
|
||||
.setContentTitle("Tracking location...")
|
||||
.setContentText("Location: null")
|
||||
.setSmallIcon(android.R.drawable.ic_menu_mylocation) // リソースが存在しないため0を設定
|
||||
.setOngoing(true)
|
||||
.build()
|
||||
Log.d("LocationService", "Android: Foreground service 2.")
|
||||
|
||||
startForeground(1, notification)
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
@ -170,8 +166,6 @@ class LocationService : Service() {
|
||||
private val locationCallback = object : LocationCallback() {
|
||||
override fun onLocationResult(locationResult: LocationResult) {
|
||||
val currentLocation = locationResult.lastLocation
|
||||
//Log.d("LocationService", "Android: onLocationResult.")
|
||||
|
||||
if (currentLocation != null) {
|
||||
val accuracy = currentLocation.accuracy
|
||||
if (accuracy <= 30) {
|
||||
@ -181,13 +175,12 @@ class LocationService : Service() {
|
||||
val lon = currentLocation.longitude
|
||||
val currentTime = System.currentTimeMillis()
|
||||
|
||||
// GPS データをデバッグ用に表示
|
||||
// GPSデータをデバッグ用に表示
|
||||
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
|
||||
val formattedTime = sdf.format(Date(currentTime))
|
||||
//Log.d("LocationService", "Latitude: $lat, Longitude: $lon, Time: $formattedTime, Accuracy: $accuracy")
|
||||
|
||||
// GPS データをデータベースに保存
|
||||
GlobalScope.launch {
|
||||
// GPSデータをデータベースに保存
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
addGPStoDB(lat, lon, currentTime)
|
||||
}
|
||||
|
||||
@ -203,36 +196,16 @@ class LocationService : Service() {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.d("LocationService", "Android: onStartCommand.")
|
||||
|
||||
/* onCreate でやってるので除外。
|
||||
// 位置情報の権限チェックとGPS有効化の確認を行う
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
val locationRequest = LocationRequest.create().apply {
|
||||
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
|
||||
interval = 10000
|
||||
fastestInterval = 5000
|
||||
}
|
||||
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)
|
||||
} else {
|
||||
Log.d("LocationService", "GPS is disabled.")
|
||||
// GPSが無効の場合の処理を追加する(例: ユーザーにGPSを有効にするように促すなど)
|
||||
}
|
||||
} else {
|
||||
Log.d("LocationService", "Location permission is not granted.")
|
||||
// 位置情報の権限が許可されていない場合の処理を追加する
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// Foregroundサービスを開始
|
||||
startForeground(NOTIFICATION_ID, createNotification())
|
||||
|
||||
return START_STICKY
|
||||
}
|
||||
*/
|
||||
|
||||
private suspend fun addGPStoDB(lat: Double, lng: Double, timestamp: Long, isCheckin: Int = 0) {
|
||||
try {
|
||||
@ -241,7 +214,6 @@ class LocationService : Service() {
|
||||
val teamName = preferences.getString("team_name", "") ?: ""
|
||||
val eventCode = preferences.getString("event_code", "") ?: ""
|
||||
|
||||
|
||||
if (teamName.isNotEmpty() && eventCode.isNotEmpty()) {
|
||||
val gpsData = GpsData(
|
||||
id = 0,
|
||||
@ -253,13 +225,12 @@ class LocationService : Service() {
|
||||
created_at = timestamp
|
||||
)
|
||||
|
||||
val db = GpsDatabaseHelper.getInstance(context)
|
||||
db.insertGps(gpsData)
|
||||
gpsDatabaseHelper.insertGps(gpsData)
|
||||
Log.d("LocationService", "Android: addGPStoDB.")
|
||||
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("LocationService", "Error adding GPS data to DB", e)
|
||||
// エラーメッセージをユーザーに表示するなどの処理を追加
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,6 +36,11 @@ class MainActivity: FlutterActivity() {
|
||||
stopLocationService()
|
||||
result.success(null)
|
||||
}
|
||||
"isLocationServiceRunning" -> {
|
||||
Log.d("MainActivity", "Android: called isLocationServiceRunnung.")
|
||||
val isRunning = isServiceRunning(LocationService::class.java)
|
||||
result.success(isRunning)
|
||||
}
|
||||
else -> {
|
||||
result.notImplemented()
|
||||
}
|
||||
@ -75,9 +80,8 @@ class MainActivity: FlutterActivity() {
|
||||
}
|
||||
|
||||
private fun startLocationService() {
|
||||
Log.d("MainActivity", "Android: startLocationService.")
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.FOREGROUND_SERVICE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (!isServiceRunning(LocationService::class.java)) {
|
||||
val intent = Intent(this, LocationService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
@ -91,16 +95,19 @@ class MainActivity: FlutterActivity() {
|
||||
Log.d("MainActivity", "Location service is already running.")
|
||||
}
|
||||
} else {
|
||||
Log.d("MainActivity", "Location permission is not granted.")
|
||||
// 位置情報の権限が許可されていない場合の処理を追加する
|
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_REQUEST_CODE)
|
||||
Log.d("MainActivity", "Location permission or Foreground service location permission is not granted.")
|
||||
// 位置情報の権限またはフォアグラウンドサービスの位置情報の権限が許可されていない場合の処理を追加する
|
||||
// 例: ユーザーに権限の必要性を説明し、許可を求めるダイアログを表示するなど
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopLocationService() {
|
||||
Log.d("MainActivity", "Android: stopLocationService.")
|
||||
val intent = Intent(this, LocationService::class.java)
|
||||
stopService(intent)
|
||||
if (isServiceRunning(LocationService::class.java)) {
|
||||
val intent = Intent(this, LocationService::class.java)
|
||||
stopService(intent)
|
||||
} else {
|
||||
Log.d("MainActivity", "Location service is not running.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isServiceRunning(serviceClass: Class<*>): Boolean {
|
||||
|
||||
@ -8,6 +8,32 @@ import Flutter
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
|
||||
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
|
||||
let locationServiceChannel = FlutterMethodChannel(name: "location",
|
||||
binaryMessenger: controller.binaryMessenger)
|
||||
locationServiceChannel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
|
||||
if call.method == "isLocationServiceRunning" {
|
||||
result(self.isLocationServiceRunning())
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
locationManager = CLLocationManager()
|
||||
locationManager?.delegate = self
|
||||
locationManager?.requestAlwaysAuthorization()
|
||||
locationManager?.startUpdatingLocation()
|
||||
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
private func isLocationServiceRunning() -> Bool {
|
||||
guard let locationManager = locationManager else {
|
||||
return false
|
||||
}
|
||||
|
||||
let isRunning = locationManager.monitoredRegions.count > 0 || locationManager.location != nil
|
||||
return isRunning
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import 'dart:io';
|
||||
//import 'dart:convert';
|
||||
//import 'dart:developer';
|
||||
import 'package:rogapp/model/gps_data.dart';
|
||||
import 'package:rogapp/pages/home/home_page.dart';
|
||||
import 'package:rogapp/utils/database_gps.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart';
|
||||
@ -31,6 +32,8 @@ import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'pages/permission/permission.dart';
|
||||
|
||||
|
||||
Map<String, dynamic> deviceInfo = {};
|
||||
|
||||
@ -129,7 +132,10 @@ void main() async {
|
||||
|
||||
//Get.put(LocationController());
|
||||
|
||||
requestLocationPermission();
|
||||
//await PermissionController.checkAndRequestPermissions();
|
||||
//requestLocationPermission();
|
||||
|
||||
|
||||
|
||||
// startMemoryMonitoring(); // 2024-4-8 Akira: メモリ使用量のチェックを開始 See #2810
|
||||
Get.put(SettingsController()); // これを追加
|
||||
@ -143,10 +149,11 @@ void main() async {
|
||||
*/
|
||||
|
||||
runApp(const ProviderScope(child: MyApp()));
|
||||
|
||||
//runApp(HomePage()); // MyApp()からHomePage()に変更
|
||||
//runApp(const MyApp());
|
||||
}
|
||||
|
||||
/*
|
||||
Future<void> requestLocationPermission() async {
|
||||
try {
|
||||
final status = await Permission.locationAlways.request();
|
||||
@ -160,6 +167,7 @@ Future<void> requestLocationPermission() async {
|
||||
print('Error requesting location permission: $e');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// メモリ使用量の解説:https://qiita.com/hukusuke1007/items/e4e987836412e9bc73b9
|
||||
@ -289,6 +297,16 @@ Future<void> startBackgroundTracking() async {
|
||||
} catch (e) {
|
||||
print('Error starting background tracking: $e');
|
||||
}
|
||||
}else if (Platform.isAndroid && background == false) {
|
||||
background = true;
|
||||
debugPrint("バックグラウンド処理を開始しました。");
|
||||
|
||||
try {
|
||||
// 位置情報の権限が許可されているかを確認
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
}catch(e){
|
||||
print('Error starting background tracking: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,8 +339,12 @@ Future<void> stopBackgroundTracking() async {
|
||||
}else if(Platform.isAndroid && background==true){
|
||||
background=false;
|
||||
debugPrint("バックグラウンド処理:停止しました。");
|
||||
await positionStream?.cancel();
|
||||
positionStream = null;
|
||||
const platform = MethodChannel('location');
|
||||
try {
|
||||
await platform.invokeMethod('stopLocationService');
|
||||
} on PlatformException catch (e) {
|
||||
print("Failed to stop location service: '${e.message}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,6 +366,12 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||
}
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
/*
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
*/
|
||||
|
||||
debugPrint("Start MyAppState...");
|
||||
}
|
||||
|
||||
@ -458,6 +486,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return GetMaterialApp(
|
||||
translations: StringValues(),
|
||||
locale: const Locale('ja', 'JP'),
|
||||
@ -480,4 +509,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||
enableLog: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -36,6 +36,8 @@ import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||
import 'package:rogapp/utils/const.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'package:rogapp/pages/permission/permission.dart';
|
||||
|
||||
// 目的地に関連する状態管理とロジックを担当するクラスです。
|
||||
//
|
||||
class DestinationController extends GetxController {
|
||||
@ -1265,6 +1267,12 @@ class DestinationController extends GetxController {
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
|
||||
/*
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
*/
|
||||
|
||||
startGPSCheckTimer();
|
||||
|
||||
// MapControllerの初期化完了を待機するフラグを設定
|
||||
@ -1715,6 +1723,7 @@ class DestinationController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 位置情報の許可を確認する関数です。
|
||||
//
|
||||
void checkPermission() async {
|
||||
@ -1726,6 +1735,7 @@ class DestinationController extends GetxController {
|
||||
permission = await Geolocator.requestPermission();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// IDに基づいて目的地を取得する関数です。
|
||||
//
|
||||
|
||||
@ -15,6 +15,11 @@ class _HomePageState extends State<HomePage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
/*
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_checkLocationService(); // 非同期的に呼び出す
|
||||
});
|
||||
*/
|
||||
_checkLocationService();
|
||||
}
|
||||
|
||||
|
||||
@ -190,11 +190,15 @@ class IndexController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void checkPermission()
|
||||
{
|
||||
debugPrint("MapControllerの初期化が完了したら、位置情報の許可をチェックする");
|
||||
_checkLocationPermission();
|
||||
}
|
||||
*/
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
|
||||
@ -1,78 +1,156 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:rogapp/routes/app_pages.dart';
|
||||
import 'package:rogapp/services/location_service.dart';
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
class PermissionHandlerScreen extends StatefulWidget {
|
||||
const PermissionHandlerScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PermissionHandlerScreenState createState() =>
|
||||
_PermissionHandlerScreenState();
|
||||
}
|
||||
class PermissionController {
|
||||
|
||||
class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_checkPermissionStatus();
|
||||
});
|
||||
static Future<bool> checkLocationPermissions() async {
|
||||
debugPrint("(gifunavi)== checkLocationPermissions ==");
|
||||
final alwaysPermission = await Permission.locationAlways.status;
|
||||
final whenInUsePermission = await Permission.locationWhenInUse.status;
|
||||
final locationPermission = await Permission.location.status;
|
||||
|
||||
return (alwaysPermission == PermissionStatus.granted || whenInUsePermission == PermissionStatus.granted) &&
|
||||
(locationPermission == PermissionStatus.granted);
|
||||
}
|
||||
|
||||
Future<void> _checkPermissionStatus() async {
|
||||
PermissionStatus status = await Permission.location.status;
|
||||
static Future<bool> checkLocationBasicPermission() async {
|
||||
debugPrint("(gifunavi)== checkLocationBasicPermission ==");
|
||||
final locationPermission = await Permission.location.status;
|
||||
return locationPermission == PermissionStatus.granted;
|
||||
}
|
||||
|
||||
if (status.isGranted) {
|
||||
if (context.mounted) {
|
||||
Get.offNamed(AppPages.LOGIN);
|
||||
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();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (context.mounted) {
|
||||
_showPermissionRequestDialog();
|
||||
}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();
|
||||
}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();
|
||||
}
|
||||
}
|
||||
}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();
|
||||
}
|
||||
}
|
||||
|
||||
void _showPermissionRequestDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('location_permission_required_title'.tr),
|
||||
content: Text('location_permission_required_message'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('cancel'.tr),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
Get.offNamed(AppPages.HOME);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text('ok'.tr),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_requestLocationPermission();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
static void showPermissionDeniedDialog() {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: Text('location_permission_needed_title'.tr),
|
||||
// 位置情報への許可が必要です
|
||||
content: Text('location_permission_needed_main'.tr),
|
||||
// 岐阜ロゲでは、位置情報を使用してスタート・チェックイン・ゴール等の通過照明及び移動手段の記録のために、位置情報のトラッキングを行なっています。このためバックグラウンドでもトラッキングができるように位置情報の権限が必要です。
|
||||
// 設定画面で、「岐阜ナビ」に対して、常に位置情報を許可するように設定してください。
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('キャンセル'),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('設定'),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
openAppSettings();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _requestLocationPermission() async {
|
||||
final status = await Permission.location.request();
|
||||
if (status.isGranted) {
|
||||
Get.offNamed(AppPages.LOGIN);
|
||||
} else {
|
||||
Get.offNamed(AppPages.HOME);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(body: Container());
|
||||
}
|
||||
}
|
||||
@ -1,188 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:rogapp/routes/app_pages.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class PermissionHandlerScreen extends StatefulWidget {
|
||||
const PermissionHandlerScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PermissionHandlerScreen> createState() =>
|
||||
_PermissionHandlerScreenState();
|
||||
}
|
||||
|
||||
class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_checkPermissionStatus();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _checkPermissionStatus() async {
|
||||
PermissionStatus status = await Permission.location.status;
|
||||
|
||||
if (status.isGranted) {
|
||||
if (context.mounted) {
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
}
|
||||
} else {
|
||||
if (context.mounted) {
|
||||
Get.toNamed(AppPages.HOME);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
_checkPermissionStatus() async {
|
||||
PermissionStatus status = await Permission.location.status;
|
||||
|
||||
if (status.isGranted == false) {
|
||||
if (context.mounted) {
|
||||
showAlert(context);
|
||||
}
|
||||
} else if (status.isPermanentlyDenied) {
|
||||
await requestPermission();
|
||||
} else {
|
||||
if (mounted) {
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void showAlert(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: Text('location_permission_title'.tr),
|
||||
content: SingleChildScrollView(
|
||||
child: Text('location_permission_content'.tr),
|
||||
|
||||
),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
requestPermission();
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
// 要検討:位置情報の許可が拒否された場合、適切なエラーメッセージを表示することを検討してください。
|
||||
//
|
||||
/*
|
||||
Future<void> requestPermission() async {
|
||||
PermissionStatus permission = await Permission.location.status;
|
||||
if (permission == PermissionStatus.permanentlyDenied) {
|
||||
showPermanentAlert();
|
||||
} else {
|
||||
PermissionStatus newPermission = await Permission.location.request();
|
||||
if (newPermission != PermissionStatus.granted) {
|
||||
exit(0);
|
||||
} else {
|
||||
if (context.mounted) {
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Future<void> requestPermission() async {
|
||||
PermissionStatus permission = await Permission.location.request();
|
||||
if (permission == PermissionStatus.granted) {
|
||||
if (context.mounted) {
|
||||
Get.toNamed(AppPages.LOGIN);
|
||||
}
|
||||
} else if (permission == PermissionStatus.denied) {
|
||||
await showLocationPermissionDeniedDialog();
|
||||
} else if (permission == PermissionStatus.permanentlyDenied) {
|
||||
await showPermanentlyDeniedDialog();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showLocationPermissionDeniedDialog() async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('location_permission_denied_title'.tr),
|
||||
content: Text('location_permission_denied_message'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('ok'.tr),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> showPermanentlyDeniedDialog() async {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('location_permission_permanently_denied_title'.tr),
|
||||
content: Text('location_permission_permanently_denied_message'.tr),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('open_settings'.tr),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
openAppSettings();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Text(""),
|
||||
);
|
||||
}
|
||||
|
||||
// 要検討:ユーザーが位置情報の許可を拒否し続けた場合の対処方法を明確にすることをお勧めします。
|
||||
//
|
||||
void showPermanentAlert() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
title: Text('location_disabled_title'.tr),
|
||||
content: SingleChildScrollView(
|
||||
child: Text('location_disabled_content'.tr),
|
||||
|
||||
),
|
||||
actions: <Widget>[
|
||||
ElevatedButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () async {
|
||||
await openAppSettings().then(
|
||||
(value) async {
|
||||
if (value) {
|
||||
if (await Permission
|
||||
.location.status.isPermanentlyDenied ==
|
||||
true &&
|
||||
await Permission.location.status.isGranted ==
|
||||
false) {
|
||||
requestPermission(); /* opens app settings until permission is granted */
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,7 @@ import 'package:rogapp/pages/debug/debug_binding.dart';
|
||||
import 'package:rogapp/pages/subperf/subperf_page.dart';
|
||||
import 'package:rogapp/spa/spa_binding.dart';
|
||||
import 'package:rogapp/spa/spa_page.dart';
|
||||
import 'package:rogapp/widgets/permission_handler_screen.dart';
|
||||
|
||||
part 'app_routes.dart';
|
||||
|
||||
@ -42,6 +43,7 @@ class AppPages {
|
||||
static const DESTINATION_MAP = Routes.DESTINATION_MAP;
|
||||
static const HOME = Routes.HOME;
|
||||
static const PERMISSION = Routes.PERMISSION;
|
||||
//static const PERMISSION = Routes.HOME;
|
||||
static const SEARCH = Routes.SEARCH;
|
||||
static const MAINPERF = Routes.MAINPERF;
|
||||
static const SUBPERF = Routes.SUBPERF;
|
||||
@ -88,7 +90,7 @@ class AppPages {
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.PERMISSION,
|
||||
page: () => const PermissionHandlerScreen(),
|
||||
page: () => PermissionHandlerScreen(),
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.SEARCH,
|
||||
@ -127,4 +129,5 @@ class AppPages {
|
||||
),
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:geojson_vi/geojson_vi.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
@ -9,6 +10,7 @@ import 'package:rogapp/utils/const.dart';
|
||||
class LocationService {
|
||||
|
||||
|
||||
|
||||
static Future<GeoJSONFeatureCollection?> loadLocationsFor(
|
||||
String perfecture, String cat) async {
|
||||
final IndexController indexController = Get.find<IndexController>();
|
||||
@ -187,4 +189,16 @@ class LocationService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static const platform = MethodChannel('location');
|
||||
|
||||
static Future<bool> isLocationServiceRunning() async {
|
||||
try {
|
||||
final bool isRunning = await platform.invokeMethod('isLocationServiceRunning');
|
||||
return isRunning;
|
||||
} catch (e) {
|
||||
print("Failed to check if location service is running: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:latlong2/latlong.dart';
|
||||
//import 'package:rogapp/widgets/debug_widget.dart';
|
||||
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
|
||||
import 'package:rogapp/pages/destination/destination_controller.dart';
|
||||
import 'package:rogapp/pages/permission/permission.dart';
|
||||
|
||||
// LocationControllerクラスは、GetxControllerを継承したクラスであり、位置情報の管理を担当しています。
|
||||
// LocationControllerは以下の機能を提供しています。
|
||||
@ -188,6 +189,18 @@ class LocationController extends GetxController {
|
||||
// Check for location service and permissions before starting the stream
|
||||
// 位置情報サービスの有効性をチェックし、無効な場合はエラーハンドリングを行います。
|
||||
//
|
||||
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
|
||||
/*
|
||||
bool isPermissionGranted = await PermissionController.checkLocationPermissions();
|
||||
if (!isPermissionGranted) {
|
||||
PermissionController.showPermissionDeniedDialog();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
// Use GetX's context to show a dialog
|
||||
@ -262,6 +275,7 @@ class LocationController extends GetxController {
|
||||
);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// 位置情報の設定を行います。z11
|
||||
// Set up the location options
|
||||
|
||||
@ -391,7 +391,7 @@ class StringValues extends Translations{
|
||||
'location_permission_permanently_denied_message': '位置情報の許可が永久に拒否されました。位置情報の許可を付与するには、アプリ設定を開いてください。',
|
||||
'open_settings': '設定を開く',
|
||||
'location_permission_needed_title': '位置情報への許可が必要です',
|
||||
'location_permission_needed_main': '位置情報への許可が拒否されています。設定を開いて、位置情報の許可を「岐阜ナビ」に与えてください。',
|
||||
'location_permission_needed_main': '岐阜ロゲでは、位置情報を使用してスタート・チェックイン・ゴール等の通過照明及び移動手段の記録のために、位置情報のトラッキングを行なっています。このためバックグラウンドでもトラッキングができるように位置情報の権限が必要です。設定画面で、「岐阜ナビ」に対して、常に位置情報を許可するように設定してください。',
|
||||
'open_settings': '設定を開く',
|
||||
'location_permission_denied_title': '位置情報へのアクセスが拒否されています。',
|
||||
'location_permission_denied_main': 'この岐阜ナビアプリは正常に動かすには位置情報への許可が必要です。「設定」画面で位置情報の許可を指定してください。',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:rogapp/pages/destination/destination_controller.dart';
|
||||
import 'package:rogapp/routes/app_pages.dart'; // これを追加
|
||||
|
||||
@ -14,8 +15,34 @@ class _CurrentPositionState extends State<CurrentPosition> {
|
||||
final DestinationController destinationController =
|
||||
Get.find<DestinationController>();
|
||||
|
||||
void _onLongPress() {
|
||||
Get.toNamed(AppPages.SETTINGS); // これを追加
|
||||
void _onLongPress() async {
|
||||
PermissionStatus status = await Permission.location.status;
|
||||
if (!status.isGranted) {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text('位置情報の許可が必要です'),
|
||||
content: Text('現在位置を表示するには、位置情報の許可が必要です。「設定」からアプリの権限を許可してください。'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('キャンセル'),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('設定'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
openAppSettings();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Get.toNamed(AppPages.SETTINGS);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||
import 'package:geojson_vi/geojson_vi.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:rogapp/pages/permission/permission.dart';
|
||||
import 'package:rogapp/pages/settings/settings_binding.dart';
|
||||
import 'package:rogapp/model/destination.dart';
|
||||
import 'package:rogapp/pages/destination/destination_controller.dart';
|
||||
@ -75,7 +76,8 @@ class _MapWidgetState extends State<MapWidget> with WidgetsBindingObserver {
|
||||
indexController.isMapControllerReady.value = true;
|
||||
});
|
||||
// MapControllerの初期化が完了したら、IndexControllerのonInitを呼び出す
|
||||
indexController.checkPermission();
|
||||
//indexController.checkPermission();
|
||||
PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
|
||||
late MapResetController mapResetController = MapResetController();
|
||||
|
||||
31
lib/widgets/permission_handler_screen.dart
Normal file
31
lib/widgets/permission_handler_screen.dart
Normal file
@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:rogapp/pages/permission/permission.dart';
|
||||
|
||||
class PermissionHandlerScreen extends StatefulWidget {
|
||||
@override
|
||||
_PermissionHandlerScreenState createState() => _PermissionHandlerScreenState();
|
||||
}
|
||||
|
||||
class _PermissionHandlerScreenState extends State<PermissionHandlerScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await PermissionController.checkAndRequestPermissions();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('権限の確認'),
|
||||
),
|
||||
body: Center(
|
||||
child: Text('権限の確認中...'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -760,6 +760,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2+1"
|
||||
logging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: logging
|
||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -38,6 +38,7 @@ dependencies:
|
||||
flutter_map: ^6.0.1
|
||||
geolocator: ^10.1.0
|
||||
permission_handler: ^11.3.1
|
||||
logging: ^1.0.2
|
||||
# flutter_dev_tools: ^0.0.2
|
||||
# permission_handler: ^11.1.0 <== older
|
||||
# permission_handler 11.2.0 (11.3.1 available)
|
||||
|
||||
Reference in New Issue
Block a user