百度地图的Flutter官方文档非常老,参考价值不大,网上的教程也都是好几年前的,和目前的版本都有点出入。最终爬坑无数对接成功,也是不容易。
百度地图Flutter的官方文档地址:lbsyun.baidu.com/faq/api?tit...
先说下我的Flutter环境:flutter_windows_3.22.2,Android language:Kotlin Android Studio:2025.1.1 Patch 1
我这只是用来展示一些美术馆的位置,所以只用到2个插件,可以根据情况加载需要的插件
csharp
flutter pub add flutter_baidu_mapapi_map
flutter pub add flutter_baidu_mapapi_base
Android环境下的配置: 1,\android\build.gradle.kts文件,添加maven源
ini
maven {
url = uri("https://mapapi.bdimg.com/repository/maven-releases/")
// 如果是HTTP协议(非HTTPS),需要添加:
isAllowInsecureProtocol = true
}

2,新建自定义Application
新建文件:\androidl\app\src\main\kotlin\com\自己的包名\MyApplication.kt

内容如下:
kotlin
package com.*****.*****//自己的包名
import android.app.Application
import com.baidu.mapapi.CoordType
import com.baidu.mapapi.SDKInitializer
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 必须先设置隐私合规
SDKInitializer.setAgreePrivacy(applicationContext, true)
// 初始化SDK
SDKInitializer.initialize(applicationContext)
SDKInitializer.setCoordType(CoordType.BD09LL)
}
}

3,配置签名证书
生成证书CMD命令:
arduino
keytool -genkey -v -keystore release.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my_key
命令最后的my_key是别名,生成证书一定要记好密码
生成好的证书是一个.jks文件,可以重命名为release.jks,放到\android目录下
另外再新建个空白文档,输入以下内容:
ini
storePassword=你的证书密码
keyPassword=你的证书密码
keyAlias=my_key
storeFile=../release.jks
也保存至\android,命名:key.properties
验证证书的CMD命令,百度申请SDK KEY,需要查询SHA1的时候用的到:
arduino
keytool -list -v -keystore release.jks -alias my_key
4,加载自定义Application
修改\android\app\src\main\AndroidManifest.xml
修改顶部manifest
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.*****.*****"> <!-- 确保package与您的应用包名一致 -->
添加权限:
xml
<!--访问网络-->
<uses-permission android:name="android.permission.INTERNET" />
<!--粗略定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精确定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--申请调用 A-GPS 模块-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--用于访问 wifi 网络信息,wifi 信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--用于获取 wifi 的获取权限,wifi 信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--用于写入缓存数据到扩展存储卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
修改application:
xml
<application
android:label="@string/appName"
android:name=".MyApplication"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"> <!-- 添加以兼容Android 10+存储权限 -->
添加meta-data百度地图的SDK Key:
ini
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="你的百度SDK KEY 自行到百度地图开放平台申请" />

5,修改build.gradle.kts
文件目录:\android\app\build.gradle.kts
添加签名配置,key.properties就是刚刚你放在\android目录下key.properties:
javascript
// 加载签名配置(确保项目根目录有 key.properties 文件)
val keystoreProperties = Properties().apply {
load(File(rootProject.rootDir, "key.properties").inputStream())
}
signingConfigs {
create("release") { // 配置名为 "release" 的签名
storeFile = file(keystoreProperties["storeFile"] as String) // keystore 文件路径
storePassword = keystoreProperties["storePassword"] as String // keystore 密码
keyAlias = keystoreProperties["keyAlias"] as String // key 别名
keyPassword = keystoreProperties["keyPassword"] as String // key 密码
}
getByName("debug") {
storeFile = file(keystoreProperties["storeFile"] as String) // keystore 文件路径
storePassword = keystoreProperties["storePassword"] as String // keystore 密码
keyAlias = keystoreProperties["keyAlias"] as String // key 别名
keyPassword = keystoreProperties["keyPassword"] as String // key 密码
}
}
ini
buildTypes {
release {
signingConfig = signingConfigs.getByName("release") // 应用签名配置
isMinifyEnabled = true // 启用代码混淆
isShrinkResources = true // 移除无用资源
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
signingConfig = signingConfigs.getByName("debug") // debug模式也使用证书
}
}
依赖的百度地图包配置:
scss
dependencies {
implementation("com.baidu.lbsyun:BaiduMapSDK_Map:7.6.4")
implementation("com.baidu.lbsyun:BaiduMapSDK_Search:7.6.4")
implementation("com.baidu.lbsyun:BaiduMapSDK_Util:7.6.4")
}
另外百度地图要求最低minSdk,不小于22
ini
minSdk = 22


还需要新建一个\android\app、proguard-rules.pro文件,用于安卓release版本打包时,保留百度地图的所有类,不然会APP闪退 文件内容如下:
php
# 保留百度地图的所有类(防止被混淆或移除)
-keep class com.baidu.** { *; }
-keep class vi.** { *; }
-keep class com.baidu.platform.** { *; }
-keep class com.baidu.mapsdkplatform.** { *; }
# 保留所有 native 方法
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留 Parcelable 序列化类
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留 Flutter 相关类(可选,如果用到其他插件)
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }

目前为止,安卓端的配置就好了,然后就是Flutter代码部分
项目入口文件main.dart的百度地图全局初始化:
顶部导入组件
arduino
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
在main()中添加初始化代码:
scss
/// 设置用户是否同意SDK隐私协议
BMFMapSDK.setAgreePrivacy(true);
// 百度地图sdk初始化鉴权
if (Platform.isIOS) {
BMFMapSDK.setApiKeyAndCoordType('****你的百度SDK KEY****', BMF_COORD_TYPE.BD09LL);
} else if (Platform.isAndroid) {
// Android 目前不支持接口设置Apikey,
// 请在主工程的Manifest文件里设置,详细配置方法请参考官网(https://lbsyun.baidu.com/)demo
BMFMapSDK.setCoordType(BMF_COORD_TYPE.BD09LL);
}
然后再项目页面中,就可以根据实际项目要求,使用百度地图,给个我在的DEMO仅供参考:
dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
import 'package:url_launcher/url_launcher.dart';
import '../components/pagebox_article.dart';
// 坐标系转换函数,腾讯坐标系转百度坐标系 GCJ-02 to BD-09 conversion
Map<String, double> gcj02ToBd09(double lng, double lat) {
const xPi = 3.14159265358979324 * 3000.0 / 180.0;
final x = lng, y = lat;
final z = sqrt(x * x + y * y) + 0.00002 * sin(y * xPi);
final theta = atan2(y, x) + 0.000003 * cos(x * xPi);
final bdLng = z * cos(theta) + 0.0065;
final bdLat = z * sin(theta) + 0.006;
return {'lng': bdLng, 'lat': bdLat};
}
class ArtExhibitionsMapController extends GetxController {
String? latitude;
String? longitude;
String? title;
String? address;
BMFMapController? mapController;
bool isMapReady = false; // 添加地图准备状态
@override
void onInit() {
super.onInit();
latitude = Get.parameters['latitude'];
longitude = Get.parameters['longitude'];
title = Get.parameters['title'];
address = Get.parameters['address'];
// 延迟初始化地图版本检查
WidgetsBinding.instance.addPostFrameCallback((_) {
_initMap();
});
}
Future<void> _initMap() async {
try {
Map? map = await BMFMapBaseVersion.nativeBaseVersion;
print('+++////////////////////////////////////////获取原生地图版本号:$map');
isMapReady = true;
update(); // 通知UI更新
} catch (e) {
print('地图初始化失败: $e');
}
}
@override
void onClose() {
print('释放地图控制器');
mapController = null;
isMapReady = false;
super.onClose();
}
}
class ArtExhibitionsMapPage extends StatelessWidget {
const ArtExhibitionsMapPage({super.key});
@override
Widget build(BuildContext context) {
final ArtExhibitionsMapController c = Get.put(ArtExhibitionsMapController());
return ArticlePageBox(
appbarTitle: tr("map"),
body: GetBuilder<ArtExhibitionsMapController>(
builder: (c) {
if (c.latitude == null || c.longitude == null || !c.isMapReady) {
return const Center(child: CircularProgressIndicator());
}
final lat = double.tryParse(c.latitude ?? '') ?? 39.915;
final lng = double.tryParse(c.longitude ?? '') ?? 116.404;
// 腾讯地图 GCJ-02 坐标转百度地图 BD-09 坐标
final bd09Coord = gcj02ToBd09(lng, lat);
return SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(
children: [
// 百度地图:全屏填充
BMFMapWidget(
onBMFMapCreated: (controller) {
c.mapController = controller;
/// 地图加载回调
c.mapController?.setMapDidLoadCallback(callback:() {
print('地图加载完成');
});
/// 地图标记点点击回调
c.mapController?.setMapClickedMarkerCallback(callback: (BMFMarker marker) {
print('marker点击----${marker.toMap()}');
});
// 地图addMarker,如果不放在回调里面,就放在这个延时函数里面
Future.delayed(const Duration(milliseconds: 300), () {
controller.updateMapOptions(BMFMapOptions(
center: BMFCoordinate(bd09Coord['lat']!, bd09Coord['lng']!),
zoomLevel: 17,
));
final marker = BMFMarker.icon(
position: BMFCoordinate(bd09Coord['lat']!, bd09Coord['lng']!),
title: c.title ?? "",
subtitle: c.address ?? "",
identifier: 'galleryMarker',
icon: 'images/marker.png',
titleOptions: BMFTitleOptions( //Android独有
text: c.title ?? "",
bgColor: Colors.white,
fontColor: Colors.black,
fontSize: 48
),
canShowCallout: true, // 允许显示信息窗口iOS独有
selected: true, // 默认选中(自动显示信息窗口)iOS独有
);
controller.addMarker(marker);
});
},
mapOptions: BMFMapOptions(
center: BMFCoordinate(
bd09Coord['lat'] ?? 39.915,
bd09Coord['lng'] ?? 116.404,
),
zoomLevel: 17,
),
),
// 悬浮在底部的导航按钮
MapsPositioned(
lat: bd09Coord['lat'] ?? 39.915,
lng: bd09Coord['lng'] ?? 116.404,
title: c.title ?? "",
)
],
),
);
},
),
);
}
}
// Positioned按钮组件
class MapsPositioned extends StatelessWidget {
final double lat;
final double lng;
final String title;
const MapsPositioned({super.key, required this.lat, required this.lng, required this.title});
@override
Widget build(BuildContext context) {
return Positioned(
bottom: 30,
left: MediaQuery.of(context).size.width * 0.1, // (100% - 80%) / 2 = 居中
width: MediaQuery.of(context).size.width * 0.8,
child: ElevatedButton(
onPressed: () async {
final baiduUri = Uri.parse('baidumap://map/marker?location=$lat,$lng&title=$title&coord_type=bd09ll');
final webUri = Uri.parse('https://api.map.baidu.com/marker?location=$lat,$lng&title=$title&output=html');
try {
if (await canLaunchUrl(baiduUri)) {
await launchUrl(baiduUri, mode: LaunchMode.externalApplication);
} else {
await launchUrl(webUri);
}
} catch (e) {
await launchUrl(webUri);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
textStyle: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
child: Text("navigation").tr(),
),
);
}
}
APP中打开百度地图的页面,只能在真机上测试,模拟器会闪退。不管安卓机还是iOS模拟器,都闪退。
如果内容对Flutter开发者有些许帮助的话,之后再写一下iOS版本的配置