Flutterのアップデートが日々行われているからか、ググってみたものをパクってコードに落としてみても、意図した動作をしないことがあった。
例えば、geolocatorを使うこのサイトを参考にしても、位置情報サービスを許可するダイアログが表示されない。
それどころか、なぜかLAN内を探索できるようにするかのダイアログが表示されたりして、意味がわからない。これは出たり出なかったりするので、恐らくAndroid Studioからデバッガが接続しているために表示されるものだろう。。。と勝手な解釈をして無かったことにする。
結果的にgeolocatorは使わず、locatorだけでよかった。多分GPSの位置情報はlocatorで、Mapに表示させたりするのにgeolocatorを使うのかもしれない。
一番参考になった(というよりパクれた)サイトはこのサイトだった。
基本的には、メイン画面から、GPS位置情報取得用ページに飛ぶと、イニシャライザでgetlocationを実行する。この時に位置情報取得の許可ダイアログが出てくる。
許可しない場合、例外を捕捉してOS上のどの問題が発生しているのかを判断するルーチンを用意したが、一番最初に拒否した時には、補足できず、「no data」のままになってしまう。
画面を戻って、再度GPS位置情報取得用ページに飛ぶと、例外を捕捉でき、設定アプリから許可してねって促すメッセージを表示できる。残念ながらこの問題はどうにもならなかった。
あと、常にGPS値に変化があった場合に取得するルーチンを用意したが、iOSシミュレータでは動作しなかった。実機(iPhone SE2)では動作したが、アプリが開いている間のみ。ホーム画面に戻ると、数秒間は取得を続けるが、そのうち取得しなくなる。スリープ状態になるのだと思う。
とりあえずアプリ表示中のみでも、GPS位置情報を取得し続けられるので、今後はこれをAppleマップやGoogleマップに位置情報を渡して表示させるものを作る予定。
誰も興味ないとは思うが、一応GitHubにてPublic設定にしてあるので興味がある方はご覧ください。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:location/location.dart';
import 'package:permission_handler/permission_handler.dart' as per_handler;
class GpsPosition extends StatefulWidget {
const GpsPosition({Key? key}) : super(key: key);
@override
_GpsPositionState createState() => _GpsPositionState();
}
class _GpsPositionState extends State<GpsPosition> {
String currentLocationText = 'no data';
final Location _locationService = Location();
late bool _serviceEnabled;
late PermissionStatus _permissionGranted;
late LocationData _locationData;
@override
void initState() {
super.initState();
// GPS値を監視する ※実機だと動作するがエミュレーターだと動作しない
//initWatchLocationService();
// FloatActionButtonを押してGPS値を取得する
getLocationAndPlatformState();
}
/// GPS値を監視する
void initWatchLocationService() async {
_serviceEnabled = await _locationService.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await _locationService.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await _locationService.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await _locationService.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return;
}
}
_locationData = await _locationService.getLocation();
_locationService.onLocationChanged.listen((LocationData currentLocation) {
// Use current location
setState(() {
currentLocationText = '$currentLocation';
});
});
_locationService.enableBackgroundMode(enable: true);
}
void getLocationAndPlatformState() async {
try {
/// ↓ここで位置情報取得の許諾ダイアログが表示される
/// iOS:設定アプリ>プライバシー>位置情報サービス>当該アプリ
LocationData myLocation = await _locationService.getLocation();
setState(() {
currentLocationText = '$myLocation';
});
} on PlatformException catch (e) {
String error = '位置情報が取得できません';
if (e.code.contains('PERMISSION_DENIED')) {
error = '位置情報取得の許可が得られませんでした';
error += '設定アプリにて許可するようにお願いします';
}
setState(() {
currentLocationText = error;
});
bool isShown = await per_handler.Permission.contacts.shouldShowRequestRationale;
if (isShown == false) {
per_handler.openAppSettings();
// sleep(const Duration(seconds: 2));
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('GPS Position'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
currentLocationText,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
getLocationAndPlatformState();
},
child: const Icon(Icons.location_on),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:gpsposition/gps_position.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => GpsPosition()),
);
},
child: const Text('位置情報取得ページへ'),
),
],
),
),
);
}
}