使用Flutter定位包獲取地理位置
Flutter 中獲取地理位置
如今,發(fā)現(xiàn)用戶位置是移動(dòng)應(yīng)用程序非常常見且功能強(qiáng)大的用例。如果您曾經(jīng)嘗試過(guò)在 Android 中實(shí)現(xiàn)位置,您就會(huì)知道樣例代碼會(huì)變得多么復(fù)雜和混亂。
但這與 Flutter 不同——它有很多令人驚嘆的包,可以為您抽象出樣板代碼,并使實(shí)現(xiàn)地理定位成為夢(mèng)想。另一個(gè)好的方面是您可以在 Android 和 iOS 上獲得這些功能。
讓我們快速瀏覽一下我們今天正在構(gòu)建的用于收集位置數(shù)據(jù)的內(nèi)容:
本文將帶您了解兩個(gè)最流行且易于使用的 Flutter 地理定位包。
讓我們從location開始,這是Flutter 最喜歡的包。這很簡(jiǎn)單。只需三個(gè)簡(jiǎn)單的步驟,您就可以獲取當(dāng)前用戶位置以及處理位置權(quán)限。
先決條件
在繼續(xù)前進(jìn)之前,讓我們快速檢查一下我們需要的東西:
- 該FlutterSDK
- 編輯器:您可以使用 Visual Code 或 Android Studio
- 至少對(duì) Flutter 有初級(jí)的了解
差不多就是這樣!
使用 Flutter 定位包
設(shè)置
將依賴項(xiàng)添加到您的文件中:pubspec.yaml
location: ^4.3.0
由于 Android 和 iOS 處理權(quán)限的方式不同,因此我們必須在每個(gè)平臺(tái)上分別添加它們。
安卓版
將以下位置權(quán)限添加到:AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
如果您還想在后臺(tái)訪問用戶的位置,請(qǐng)?jiān)谠L問后臺(tái)位置之前使用該API,并在清單文件中添加后臺(tái)權(quán)限:enableBackgroundMode({bool enable})
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
對(duì)于 iOS
將以下位置權(quán)限添加到:Info.plist
<key>NSLocationWhenInUseUsageDescription</key> <string>此應(yīng)用需要訪問您的位置</string>
NSLocationWhenInUseUsageDescription
是您需要的唯一許可。這也允許您訪問后臺(tái)位置,唯一需要注意的是,當(dāng)應(yīng)用程序在后臺(tái)訪問位置時(shí),狀態(tài)欄中會(huì)顯示藍(lán)色徽章。與 Android 不同,我們?cè)谄渲刑砑恿藛为?dú)的權(quán)限以在后臺(tái)訪問用戶的位置。
位置權(quán)限
我們需要在請(qǐng)求用戶位置之前檢查位置服務(wù)狀態(tài)和權(quán)限狀態(tài),這可以使用以下幾行代碼輕松完成:
Location location = new Location(); bool _serviceEnabled; PermissionStatus _permissionGranted; _serviceEnabled = await location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await location.requestService(); if (!_serviceEnabled) { return null; } } _permissionGranted = await location.hasPermission(); if (_permissionGranted == PermissionStatus.denied) { _permissionGranted = await location.requestPermission(); if (_permissionGranted != PermissionStatus.granted) { return null; } }
首先,我們創(chuàng)建一個(gè)由Location()
包提供的對(duì)象,location反過(guò)來(lái)為我們提供了兩個(gè)有用的方法。檢查設(shè)備位置是否已啟用或用戶是否已手動(dòng)禁用它。``serviceEnabled()
對(duì)于后者,我們顯示了一個(gè)原生提示,允許用戶通過(guò)調(diào)用快速啟用位置,然后我們?cè)贆z查一次,如果他們從提示中啟用了它。requestService()
一旦我們確定啟用了位置服務(wù),下一步就是通過(guò)調(diào)用它來(lái)檢查我們的應(yīng)用程序是否具有使用它的必要權(quán)限,這將返回.hasPermission()``PermissionStatus
PermissionStatus
是可以具有以下三個(gè)值之一的枚舉:
PermissionStatus.granted
: 定位服務(wù)權(quán)限已被授予PermissionStatus.denied
: 定位服務(wù)權(quán)限被拒絕PermissionStatus.deniedForever
: 位置服務(wù)權(quán)限被用戶永久拒絕。這僅適用于 iOS。在這種情況下不會(huì)顯示對(duì)話框requestPermission()
如果狀態(tài)為 ,我們可以通過(guò)調(diào)用顯示請(qǐng)求位置權(quán)限的系統(tǒng)提示。對(duì)于 status
,我們可以立即訪問 location
,因此我們返回一個(gè).denied,``requestPermission()``granted``null
如果您還想在后臺(tái)訪問用戶位置,請(qǐng)使用。location.enableBackgroundMode(enable: **true**)
獲取當(dāng)前位置
如果位置服務(wù)可用并且用戶已授予位置權(quán)限,那么我們只需兩行代碼即可獲取用戶位置 - 不,我不是在開玩笑:
LocationData _locationData; _locationData = await location.getLocation();
LocationData
類提供以下位置信息:
class LocationData { final double latitude; // Latitude, in degrees final double longitude; // Longitude, in degrees final double accuracy; // Estimated horizontal accuracy of this location, radial, in meters final double altitude; // In meters above the WGS 84 reference ellipsoid final double speed; // In meters/second final double speedAccuracy; // In meters/second, always 0 on iOS final double heading; // Heading is the horizontal direction of travel of this device, in degrees final double time; // timestamp of the LocationData final bool isMock; // Is the location currently mocked }
您還可以通過(guò)添加onLocationChanged
偵聽器在用戶位置發(fā)生變化時(shí)監(jiān)聽位置更新來(lái)獲得連續(xù)回調(diào),這是出租車應(yīng)用程序、司機(jī)/騎手應(yīng)用程序等的一個(gè)很好的用例:
location.onLocationChanged.listen((LocationData currentLocation) { // current user location });
注意,一旦您想停止收聽更新,請(qǐng)不要忘記取消流訂閱。
瞧!現(xiàn)在我們有了用戶位置的當(dāng)前緯度和經(jīng)度值。
讓我們利用這些緯度和經(jīng)度值來(lái)獲取用戶的完整地址或反向地理編碼。
為此,我們將使用另一個(gè)驚人的 Flutter 包:geocode。
使用 Flutter 地理編碼包
設(shè)置
將依賴項(xiàng)添加到您的文件中:pubspec.yaml
dependencies: geocode: 1.0.1
獲取地址
獲取地址再簡(jiǎn)單不過(guò)了。就打電話吧。就是這樣!帶有空檢查的完整函數(shù)如下所示:reverseGeocoding(latitude: lat, longitude: lang)
Future<String> _getAddress(double? lat, double? lang) async { if (lat == null || lang == null) return ""; GeoCode geoCode = GeoCode(); Address address = await geoCode.reverseGeocoding(latitude: lat, longitude: lang); return "${address.streetAddress}, ${address.city}, ${address.countryName}, ${address.postal}"; }
沒那么簡(jiǎn)單!
完整的代碼如下所示:
class GetUserLocation extends StatefulWidget { GetUserLocation({Key? key, required this.title}) : super(key: key); final String title; @override _GetUserLocationState createState() => _GetUserLocationState(); } class _GetUserLocationState extends State<GetUserLocation> { LocationData? currentLocation; String address = ""; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Center( child: Padding( padding: EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ if (currentLocation != null) Text( "Location: ${currentLocation?.latitude}, ${currentLocation?.longitude}"), if (currentLocation != null) Text("Address: $address"), MaterialButton( onPressed: () { _getLocation().then((value) { LocationData? location = value; _getAddress(location?.latitude, location?.longitude) .then((value) { setState(() { currentLocation = location; address = value; }); }); }); }, color: Colors.purple, child: Text( "Get Location", style: TextStyle(color: Colors.white), ), ), ], ), ), ), ); } Future<LocationData?> _getLocation() async { Location location = new Location(); LocationData _locationData; bool _serviceEnabled; PermissionStatus _permissionGranted; _serviceEnabled = await location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await location.requestService(); if (!_serviceEnabled) { return null; } } _permissionGranted = await location.hasPermission(); if (_permissionGranted == PermissionStatus.denied) { _permissionGranted = await location.requestPermission(); if (_permissionGranted != PermissionStatus.granted) { return null; } } _locationData = await location.getLocation(); return _locationData; } Future<String> _getAddress(double? lat, double? lang) async { if (lat == null || lang == null) return ""; GeoCode geoCode = GeoCode(); Address address = await geoCode.reverseGeocoding(latitude: lat, longitude: lang); return "${address.streetAddress}, ${address.city}, ${address.countryName}, ${address.postal}"; } }
常見的陷阱
盡管這些軟件包讓我們的生活變得更輕松,而且我們不必處理在 Android 和 iOS 中本地訪問位置的復(fù)雜過(guò)程,但您可能會(huì)面臨很多問題。讓我們來(lái)看看它們以及可以幫助您修復(fù)這些問題的步驟:
- 應(yīng)用內(nèi)存泄漏:如果您一直在收聽位置更新,請(qǐng)確保取消流訂閱,一旦您想停止收聽更新
- 用戶必須接受位置權(quán)限才能始終允許使用后臺(tái)位置。位置權(quán)限對(duì)話框提示中未顯示始終允許的 Android 11 選項(xiàng)。用戶必須從應(yīng)用程序設(shè)置中手動(dòng)啟用它
- 用戶可能在 iOS 上永遠(yuǎn)拒絕定位,因此不會(huì)顯示要求定位權(quán)限的本機(jī)提示。確保處理這種邊緣情況
requestPermisssions()
- 用戶可能隨時(shí)從應(yīng)用程序設(shè)置中撤銷位置權(quán)限,因此在訪問位置數(shù)據(jù)之前,請(qǐng)確保在應(yīng)用程序恢復(fù)時(shí)檢查它們
結(jié)論
由于 Flutter 簡(jiǎn)化了訪問位置,因此我們作為開發(fā)人員可能會(huì)立即將其添加到我們的應(yīng)用程序中。但同時(shí),我們需要確保我們的應(yīng)用程序真正適合請(qǐng)求用戶位置并利用它為用戶增加一些價(jià)值的用例,而不是僅僅將位置數(shù)據(jù)發(fā)送到服務(wù)器。
隨著即將推出的 Android 和 iOS 操作系統(tǒng)版本中安全性和隱私性的提高,訪問位置數(shù)據(jù)而不向用戶提供價(jià)值可能會(huì)導(dǎo)致您的應(yīng)用程序被商店拒絕。有很多很好的用例,您可以使用用戶位置,例如,根據(jù)用戶位置為食品/外賣應(yīng)用程序個(gè)性化主屏幕,該應(yīng)用程序顯示按用戶當(dāng)前位置的接近程度訂購(gòu)的餐廳。取件/送貨應(yīng)用程序是最常見的用例。
您還可以在您實(shí)際想要使用的特定屏幕上詢問用戶位置,而不是立即在主屏幕上詢問。這使用戶更清楚,并且他們不太可能拒絕位置權(quán)限。
到此這篇關(guān)于使用Flutter定位包獲取地理位置的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 中Crash時(shí)如何獲取異常信息詳解及實(shí)例
這篇文章主要介紹了Android 中Crash時(shí)如何獲取異常信息詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02Android自定義scrollview實(shí)現(xiàn)回彈效果
這篇文章主要為大家詳細(xì)介紹了Android自定義scrollview實(shí)現(xiàn)回彈效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Android調(diào)用系統(tǒng)時(shí)間格式顯示時(shí)間信息
這篇文章主要介紹了Android調(diào)用系統(tǒng)時(shí)間格式顯示時(shí)間信息的使用方法,代碼很簡(jiǎn)單2014-01-01Android程序開發(fā)之自定義設(shè)置TabHost,TabWidget樣式
這篇文章主要介紹了Android程序開發(fā)之自定義設(shè)置TabHost,TabWidget樣式的相關(guān)資料,需要的朋友可以參考下2016-03-03Android編程實(shí)現(xiàn)自定義ImageView圓圖功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義ImageView圓圖功能的方法,結(jié)合實(shí)例形式分析了Android自定義ImageView及實(shí)現(xiàn)圓圖效果的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-08-08Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫效果
這篇文章主要介紹了Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫效果,最近比較火的抖音快手直播視頻都有這樣的效果,下面腳本之家小編給大家?guī)?lái)android 仿直播點(diǎn)贊效果的實(shí)現(xiàn)代碼,需要的朋友參考下吧2018-03-03