Flutterなんですが、デバイスの位置情報が必要で、geolocatorパッケージを試しに使ってみました。
//main.dart import 'package:geolocator/geolocator.dart'; import 'package:flutter/material.dart'; void main(){ runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { //print("tp---===---===>>>${tp['items'].keys}"); return MaterialApp( title: 'Flutter Storage Example', home: SixthRoute(title:"六番目の画面"), ); } } //https://pub.dev/packages/firebase_auth/example class SixthRoute extends StatefulWidget { SixthRoute({Key key,this.title}) : super(key: key); final String title; @override _SixthRouteState createState() => _SixthRouteState(); } class _SixthRouteState extends State<SixthRoute> { Position cp=Position(latitude:10.0,accuracy:20.0); @override Widget build(BuildContext context) { Future<Position> position = Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high); position.then( (p){ setState((){ cp=p; }); } ); return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text("現在地は$cpです。"), Container( child: RaisedButton( child: const Text('Test registration'), onPressed: (){}//() => _pushPage(context, RegisterPage()), ), padding: const EdgeInsets.all(16), alignment: Alignment.center, ), Container( child: RaisedButton( child: const Text('Test SignIn/SignOut'), onPressed: (){}//() => _pushPage(context, SignInPage()), ), padding: const EdgeInsets.all(16), alignment: Alignment.center, ), ], ), ); } void _pushPage(BuildContext context, Widget page) { Navigator.of(context).push( MaterialPageRoute<void>(builder: (_) => page), ); } }
とりあえずfirebase_authのサンプルに埋め込んで試してみただけでfirebase_authの部分はどうでもいいのですが、
上記のコードで緯度経度が取得できました。できたのですが、出来過ぎというか、予想した挙動と少し違いました。
上記のコードで、スマホを持って移動するとその都度緯度経度の(画面上の)表示が変化します。
上記の書き方で、変数cpがSixthRouteウィジェットのstateになると思います。
なので、setState関数によりstateであるcpに、getCurrentPositionメソッドで取得した位置情報がセットされると、
Text("現在地は$cpです。")
のテキストウィジェットがリビルドされると思うのですが、getCurrentPositionの返り値はFuture型なので、コンプリートするのは一度だけ。それは位置情報が取得できた時、と予想するのが自然だと思います。
つまり_SixthRouteStateクラスのbuild()メソッドが実行され、その中でgetCurrentPositionメソッド実行
→Futureがコンプリート(位置情報取得完了)
→cpに位置情報セット
→Text("現在地は$cpです。")の部分を書き換え。
上記が一度行われてそれだけ、という挙動を予想していたのですが、実際は動くたびに(動くたびというより一定時間ごとに)
Text("現在地は$cpです。")
の部分が変化しています。(動くたびにというよりもよく見ると動いても動かなくても一定時間ごとに更新されている挙動)
これってStreamを使って位置が変わるたびにそれをリッスンしてstateにセットし直す、ということをする必要が有ると思うのですが、なぜStreamを使っていないのに、表示が継続的に更新されるのでしょうか?
Flutterに関して考えていくとこういう推測になると思うのですが、getCurrentPositionの中身を見てみると
Future<Position> getCurrentPosition({ LocationAccuracy desiredAccuracy = LocationAccuracy.best, GeolocationPermission locationPermissionLevel = GeolocationPermission.location, }) async { final PermissionStatus permission = await _getLocationPermission( toPermissionLevel(locationPermissionLevel)); if (permission == PermissionStatus.granted) { final LocationOptions locationOptions = LocationOptions( accuracy: desiredAccuracy, distanceFilter: 0, forceAndroidLocationManager: await _shouldForceAndroidLocationManager()); final Map<dynamic, dynamic> positionMap = await _methodChannel.invokeMethod('getCurrentPosition', Codec.encodeLocationOptions(locationOptions)); try { return Position.fromMap(positionMap); } on ArgumentError { return null; } } else { _handleInvalidPermissions(permission); } return null; }
_methodChannelが使われているので、Swiftの処理を呼び出しているみたいです。結局Swift側でそういう風に実装されているから、みたいな話なんでしょうか?
それでもgetCurrentPositionメソッドの返り値の型がFuture型なのは変わりようがないので、どうにも辻褄が合わないような気がします。
あともう一つ、このコード(位置情報を利用するコード)の場合iOSシミュレータだとうまく動かない(いつまで経っても位置情報が表示されない)ので、iphoneの実機(6s)に繋いで実行すると
Launching lib/main.dart on Owner の iPhone in debug mode... Automatically signing iOS for device deployment using specified development team in Xcode project: 54N944Z87S Running Xcode build... Xcode build done. 21.1s Installing and launching... Installing and launching... 9.1s ═══════════════════════════════════════════════════════════════════════════════════ Your device is locked. Unlock your device first before running. ═══════════════════════════════════════════════════════════════════════════════════ 2020-08-07 01:46:43.301 ios-deploy[91069:691397] [ !! ] Unable to mount developer disk image. (e80000e2) Could not run build/ios/iphoneos/Runner.app on e735eacdced5c5f325b378c703dbd6b60d65eb8c. Try launching Xcode and selecting "Product > Run" to fix the problem: open ios/Runner.xcworkspace Error launching application on Owner の iPhone.
上記のエラーが出て、指示通りリンク(Xcode)を開いてproducu>runを実行すると実機のアプリが起動します。
これって何が原因なんでしょうか?
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/09/11 00:16
2020/09/11 01:14
2020/09/14 06:14
2020/09/14 08:04