csp_amap_flutter_location
一个功能强大的Flutter高德地图定位插件,支持Android、iOS和鸿蒙平台。
English | 中文
Features
- ✅ Multi-platform Support: Android, iOS, and HarmonyOS
- ✅ High Precision: Powered by AMap Location SDK
- ✅ Rich Configuration: Multiple location modes and parameters
- ✅ Real-time Updates: Stream-based location listening
- ✅ Address Information: Reverse geocoding support
- ✅ Privacy Compliant: Built-in privacy policy management
- ✅ Easy Integration: Simple API design
Installation
Add this to your package's pubspec.yaml file:
dependencies:
csp_amap_flutter_location: ^1.0.5
Then run:
flutter pub get
Setup
1. Get API Keys
First, you need to obtain API keys from AMap Open Platform:
2. Platform Configuration
Android
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
iOS
Add location permissions to your ios/Runner/Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to provide location-based services.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs location access to provide location-based services.</string>
HarmonyOS
Refer to HarmonyOS Location SDK Guide for detailed setup.
Quick Start
import 'package:flutter/material.dart';
import 'package:csp_amap_flutter_location/amap_flutter_location.dart';
import 'package:csp_amap_flutter_location/amap_location_option.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late AMapFlutterLocation _locationPlugin;
Map<String, Object>? _locationResult;
@override
void initState() {
super.initState();
_locationPlugin = AMapFlutterLocation();
// Set privacy policy (required by Chinese law)
AMapFlutterLocation.updatePrivacyShow(true, true);
AMapFlutterLocation.updatePrivacyAgree(true);
// Set API keys
AMapFlutterLocation.setApiKey(
"YOUR_ANDROID_KEY",
"YOUR_IOS_KEY",
ohosKey: "YOUR_HARMONYOS_KEY" // Optional
);
// Listen to location updates
_locationPlugin.onLocationChanged().listen((Map<String, Object> result) {
setState(() {
_locationResult = result;
});
});
}
@override
void dispose() {
_locationPlugin.destroy();
super.dispose();
}
void _startLocation() {
// Configure location options
AMapLocationOption locationOption = AMapLocationOption();
locationOption.onceLocation = false;
locationOption.needAddress = true;
locationOption.geoLanguage = GeoLanguage.DEFAULT;
_locationPlugin.setLocationOption(locationOption);
_locationPlugin.startLocation();
}
void _stopLocation() {
_locationPlugin.stopLocation();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('AMap Location Demo'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ElevatedButton(
onPressed: _startLocation,
child: Text('Start Location'),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: _stopLocation,
child: Text('Stop Location'),
),
],
),
SizedBox(height: 20),
Text(
'Location Result:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
if (_locationResult != null)
Expanded(
child: SingleChildScrollView(
child: Text(
_formatLocationResult(_locationResult!),
style: TextStyle(fontSize: 14),
),
),
),
],
),
),
),
);
}
String _formatLocationResult(Map<String, Object> result) {
StringBuffer buffer = StringBuffer();
result.forEach((key, value) {
buffer.writeln('$key: $value');
});
return buffer.toString();
}
}
API Reference
AMapFlutterLocation
Static Methods
| Method | Description |
|---|---|
setApiKey(String androidKey, String iosKey, {String? ohosKey}) |
Set API keys for different platforms |
updatePrivacyShow(bool hasShow, bool hasContains) |
Update privacy policy display status |
updatePrivacyAgree(bool hasAgree) |
Update privacy policy agreement status |
Instance Methods
| Method | Description |
|---|---|
setLocationOption(AMapLocationOption option) |
Configure location parameters |
startLocation() |
Start location updates |
stopLocation() |
Stop location updates |
destroy() |
Destroy the location service |
onLocationChanged() |
Listen to location changes (returns Stream) |
AMapLocationOption
| Property | Type | Default | Description |
|---|---|---|---|
needAddress |
bool |
true |
Whether to return address information |
geoLanguage |
GeoLanguage |
DEFAULT |
Language for reverse geocoding |
onceLocation |
bool |
false |
Whether to locate only once |
locationMode |
AMapLocationMode |
Hight_Accuracy |
Location mode (Android only) |
locationInterval |
int |
2000 |
Location update interval in milliseconds (Android only) |
desiredAccuracy |
DesiredAccuracy |
Best |
Desired accuracy (iOS only) |
distanceFilter |
double |
-1 |
Minimum distance for updates in meters (iOS only) |
Location Result
The location result is returned as a Map<String, Object> with the following keys:
| Key | Type | Description |
|---|---|---|
latitude |
double |
Latitude |
longitude |
double |
Longitude |
accuracy |
double |
Location accuracy in meters |
altitude |
double |
Altitude in meters |
bearing |
double |
Bearing in degrees |
speed |
double |
Speed in m/s |
locationTime |
String |
Location timestamp |
address |
String |
Formatted address |
country |
String |
Country |
province |
String |
Province/State |
city |
String |
City |
district |
String |
District |
street |
String |
Street |
streetNumber |
String |
Street number |
cityCode |
String |
City code |
adCode |
String |
Administrative division code |
errorCode |
String |
Error code (when location fails) |
errorInfo |
String |
Error message (when location fails) |
Advanced Usage
Single Location
AMapLocationOption option = AMapLocationOption();
option.onceLocation = true;
_locationPlugin.setLocationOption(option);
_locationPlugin.startLocation();
High-Precision Location
AMapLocationOption option = AMapLocationOption();
option.locationMode = AMapLocationMode.Hight_Accuracy;
option.desiredAccuracy = DesiredAccuracy.Best;
_locationPlugin.setLocationOption(option);
Custom Update Interval
AMapLocationOption option = AMapLocationOption();
option.locationInterval = 5000; // 5 seconds
_locationPlugin.setLocationOption(option);
Troubleshooting
Android Dependency Issues
If you encounter NoClassDefFoundError or ClassNotFoundException on Android:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/amap/api/location/AMapLocationClient;
This is caused by incorrect dependency configuration. The plugin has been fixed to use api instead of compileOnly for the AMap SDK dependency:
dependencies {
api 'com.amap.api:location:6.4.9'
}
iOS Podfile Issues
If you encounter Podfile errors on iOS:
rm ios/Podfile
flutter build ios
Permission Issues
Make sure you have:
- Added required permissions to platform manifests
- Requested runtime permissions in your app
- Set up privacy policy compliance (for Chinese apps)
API Key Issues
- Verify your API keys are correct
- Check if your bundle ID/package name matches the one in AMap console
- Ensure your API keys have the required permissions enabled
Location Not Working Unless onLocationChanged() Is Called (errorCode: 10001)
Fixed in v1.0.3, hardened in v1.0.4 (#IK029E)
Previously, the native event channel was only activated after you explicitly
called onLocationChanged().listen(...), so if the listener was omitted the
SDK initialization was incomplete and location failed with 获取apikey失败: errorCode:10001 even though the key was correct.
Since v1.0.3 the plugin automatically activates the event channel when
setApiKey() is called, and since v1.0.4 it is also activated as soon as
an AMapFlutterLocation instance is created. You no longer need to add a
"dummy" onLocationChanged() listener in main.dart. Just follow the Quick
Start example above.
HarmonyOS Build Error: Module Name Mismatch
Fixed in v1.0.3 (#IDAX62)
If you see an error like:
local dependency "csp_amap_flutter_location" ... does not match the actual
name "st_amap_flutter_location" of its oh-package.json5
Make sure the local dependency name in example/ohos/entry/oh-package.json5
matches the module name in the plugin's ohos/oh-package.json5 and
ohos/src/main/module.json5 (all should be csp_amap_flutter_location).
If you cloned an older copy, re-fetch the latest version, then clean and
rebuild the HarmonyOS project (rm -rf ohos/.hvigor ohos/build).
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you have any questions or issues, please:
- Check the documentation
- Search existing issues
- Create a new issue if needed
Changelog
See CHANGELOG.md for details about changes in each version.