Flutter集成百度地图-Android集成

版本:flutter 2.10.4

百度地图3.2.0

IDE:Android Studio

最近公司项目需要集成地图,看着百度地图有flutter插件就开始忙活了,踩了一脑门子的坑,现在分享给大家。

2022-08-01 更新关于在调用poi搜索等功能时,提示鉴权失败的问题

引入的base包在as不提示时,建议手动添加引用

鉴权初始化后才可以使用搜索

import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart'
import 'dart:io' show Platform;

    
// 百度地图sdk初始化鉴权
    if (Platform.isIOS) {
      _locationPlugin.authAK('请在此输入您在开放平台上申请的API_KEY');
      BMFMapSDK.setApiKeyAndCoordType(
          '请在此输入您在开放平台上申请的API_KEY', BMF_COORD_TYPE.BD09LL);
    } else if (Platform.isAndroid) {
      // Android 目前不支持接口设置Apikey,
      // 请在主工程的Manifest文件里设置,详细配置方法请参考官网(https://lbsyun.baidu.com/)demo
      BMFMapSDK.setCoordType(BMF_COORD_TYPE.BD09LL);
    }

目录

1.申请AK、SHA1值

2.集成地图插件

3.Android端配置BmfMapApplication

4.flutter中使用地图widget 

 5.使用定位获取坐标,居中显示


1.申请AK、SHA1值

在百度开发者后台申请Android所需的AK值,这个网上很多教程不细说

2.集成地图插件

在flutter项目的pubspec.yami中,dependencies下添加如下插件

dependencies:  
  #https://lbsyun.baidu.com/index.php?title=flutter/loc/create-project/note
  #注意第三个插件在百度教程中是fflutter开头,实际为flutter开头
  flutter_baidu_mapapi_map: ^3.2.0
  flutter_baidu_mapapi_search: ^3.2.0
  flutter_baidu_mapapi_utils: ^3.2.0
  flutter_bmflocation: ^3.1.0

注意

第一个坑来了,

百度的地图教程多打了一个f,实际为 flutter_baidu_mapapi_utils: ^3.2.0

导致我第一次集成死活找不到插件。

之后使用pub get获取插件包即可

#如果获取不到插件,可能是百度地图的插件又更新了,建议使用any版本号重新在pubspec.lock中重新获取一下

例如flutter_baidu_mapapi_map: ^3.2.0修改为flutter_baidu_mapapi_map: any,然后pub get,打开项目下pubspec.lock翻到这个插件名,看看对应version版本修改一下

3.Android端配置BmfMapApplication

右击找到flutter菜单,用as打开android文件夹。

如果没有,直接用open打开android文件夹也行 

菜单置灰解决方案:新建一个xxx_android.imi文件与local.properties同级,xxx为项目名

内容为

<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="FacetManager">
    <facet type="android" name="Android">
      <configuration>
        <option name="ALLOW_USER_CONFIGURATION" value="false" />
        <option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/gen" />
        <option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/gen" />
        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/app/src/main/AndroidManifest.xml" />
        <option name="RES_FOLDER_RELATIVE_PATH" value="/app/src/main/res" />
        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/app/src/main/assets" />
        <option name="LIBS_FOLDER_RELATIVE_PATH" value="/app/src/main/libs" />
        <option name="PROGUARD_LOGS_FOLDER_RELATIVE_PATH" value="/app/src/main/proguard_logs" />
      </configuration>
    </facet>
  </component>
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/app/src/main/java" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
    </content>
    <orderEntry type="jdk" jdkName="Android API 30 Platform" jdkType="Android SDK" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="Flutter for Android" level="project" />
  </component>
</module>

 如果新建后还是不能在菜单中打开,可以试试

 还是不能打开,建议新建一个项目,找到imi文件,复制粘贴修改

文件类型为intelliJ.. 这个文件类型我没在Androidstudio找到

理论上可以用这个修改 

打开后在MainActivity同级下新建BaseApplication

import com.baidu.mapapi.base.BmfMapApplication;

public class BaseApplication extends BmfMapApplication {
    @Override
    public void onCreate() {
        super.onCreate();
    }
}

 可能会涉及到个别model中使用了min16版本,手动在build.gradle修改为19即可

如果BmfMapApplication不存在,重新在flutter中pubget几次,flutter clean几次

如果还是不存在,大概提供一下BmfMapApplication路径提供参考,是否是model没有编译进来,或者包没引入到

之后按教程修改application的name值为BaseApplication,添加权限

添加AK值

<application>  
    <meta-data  
        android:name="com.baidu.lbsapi.API_KEY"  
        android:value="请输入百度开放平台申请的Android端API KEY" />  
</application>

 按教程还需要添加混淆

打开android 目录app下的build.gradle文件,在release代码块中添加如下内容。(默认情况下 flutter不会开启 Android 的混 淆)

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.

            signingConfig signingConfigs.debug
            minifyEnabled true
            useProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }

 新建混淆文件

-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-keep class com.baidu.vi.** {*;}
-dontwarn com.baidu.**

4.flutter中使用地图widget 

百度地图的widget为BMFMapWidget
BMFMapWidget(
          onBMFMapCreated: (controller) {
            //自定义onBMFMapCreated方法,用于获取controller
            onBMFMapCreated(controller);
          },
          mapOptions: BMFMapOptions(
              center: BMFCoordinate(39.917215, 116.380341),
              zoomLevel: 12,
              mapPadding:
                  BMFEdgeInsets(left: 30, top: 0, right: 30, bottom: 0)),
        )
  late BMFMapController _controller;

 
 void onBMFMapCreated(BMFMapController controller) {
    _controller = controller;
    _controller.showUserLocation(true);
  }

如果在widget中报错,找不到BMFMapOptions、BMFEdgeInsets等类,路径为

使用引入强行添加。可能原因是在android的BmfMapApplication没有正常引入,也可能是pubget获取的百度地图版本问题,更新最新的版本可能解决。

import 'package:flutter_baidu_mapapi_map/src/models/bmf_map_options.dart';

 5.使用定位获取坐标,居中显示

声明所需的几个变量

  late LocationFlutterPlugin _locationPlugin;

  BaiduLocationIOSOption iosOption =
      BaiduLocationIOSOption(coordType: BMFLocationCoordType.gcj02);

  BaiduLocationAndroidOption androidOption =
      BaiduLocationAndroidOption(coordType: BMFLocationCoordType.gcj02);

  late BMFMapController _controller;

  late BaiduLocation _location;

 在initState中初始化。

注意

_locationPlugin.setAgreePrivacy(true);

这句话在百度教程没有,是否同意隐私协议的东西,不加上不会加载地图,神奇的玩意坑了我一下午

  @override
  void initState() {
    _locationPlugin = LocationFlutterPlugin();
    _locationPlugin.setAgreePrivacy(true);
    _location = BaiduLocation();
    _locationPlugin.seriesLocationCallback(callback: (BaiduLocation result) {
      _location = result;
      _stopLocation();
      updatePosition();
    });

    _startLocation();
  }

Android权限建议在androidmanifest配置单多添加一份。存储涉及的storage权限可能有坑,建议加上

//  申请权限
  Future<bool> requestPermission() async {
    // 申请权限
    final status = await Permission.location.request();
    //获取存储权限,可能涉及到地图的shareprefences读写问题,建议加上并进行判断
    //await Permission.storage.status;

    if (status.isGranted) {
      print("定位权限申请通过");
      return true;
    } else {
      print("定位权限申请不通过");
      return false;
    }
  }

  /// 停止定位
  void _stopLocation() {
    if (null != _locationPlugin) {
      _locationPlugin.stopLocation();
    }
  }

//  开始定位
  void _startLocation() {
    if (null != _locationPlugin) {
      //申请定位权限
      requestPermission().then((value) => {
            if (value)
              {_setLocOption(), _locationPlugin.startLocation()}
            else
              {
                EasyLoading.showToast("需要定位权限",
                    toastPosition:EasyLoadingToastPosition.bottom)
              }
          });
    }
  }

//  设置定位参数
  void _setLocOption() {
    androidOption.setCoorType("bd09ll"); // 设置返回的位置坐标系类型
    androidOption.setIsNeedAltitude(true); // 设置是否需要返回海拔高度信息
    androidOption.setIsNeedAddress(true); // 设置是否需要返回地址信息
    androidOption.setIsNeedLocationPoiList(true); // 设置是否需要返回周边poi信息
    androidOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
    androidOption.setIsNeedLocationDescribe(true); // 设置是否需要返回位置描述
    androidOption.setOpenGps(true); // 设置是否需要使用gps
    androidOption.setLocationMode(BMFLocationMode.hightAccuracy); // 设置定位模式
    androidOption.setScanspan(1000); // 设置发起定位请求时间间隔
    Map androidMap = androidOption.getMap();
    Map iosdMap = iosOption.getMap();
    _locationPlugin.prepareLoc(androidMap, iosdMap); //ios和安卓定位设置
  }

//更新地点
void updatePosition() {
    BMFCoordinate coordinate = BMFCoordinate(
        _location.latitude ?? 39.917215, _location.longitude ?? 116.380341);

    BMFMapOptions options = BMFMapOptions(
        center: coordinate,
        zoomLevel: 17,
        mapPadding: BMFEdgeInsets(left: 30, top: 0, right: 30, bottom: 0));

    BMFLocation location = BMFLocation(
        coordinate: coordinate,
        altitude: 0,
        horizontalAccuracy: 5,
        verticalAccuracy: -1.0,
        speed: -1.0,
        course: -1.0);

    BMFUserLocation userLocation = BMFUserLocation(
      location: location,
    );

    _controller.updateLocationData(userLocation);
    _controller.updateMapOptions(options);
  }

申请权限、Toast等插件使用了如下插件。

dependencies:
#Tost
  flutter_easyloading: ^3.0.3
#动态权限申请
  permission_handler : ^6.0.2

分割线。大概踩坑结束,能够显示地图并且定位在附近地点,居中显示 

最后贴一下全部代码作为参考

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_baidu_mapapi_base/src/map/bmf_models.dart';
import 'package:flutter_baidu_mapapi_search/flutter_baidu_mapapi_search.dart';
import 'package:flutter_bmflocation/flutter_bmflocation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:permission_handler/permission_handler.dart';


class MapRoute extends StatefulWidget {
  const MapRoute({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MapRouteState();
  }
}

class MapRouteState extends State<MapRoute> {
  late TextEditingController positionController;
  late LocationFlutterPlugin _locationPlugin;
  BaiduLocationIOSOption iosOption =
      BaiduLocationIOSOption(coordType: BMFLocationCoordType.gcj02);
  BaiduLocationAndroidOption androidOption =
      BaiduLocationAndroidOption(coordType: BMFLocationCoordType.gcj02);
  late BMFMapController _controller;
  late BaiduLocation _location;

  @override
  void initState() {
    positionController = TextEditingController();
    _locationPlugin = LocationFlutterPlugin();
    _locationPlugin.setAgreePrivacy(true);
    _location = BaiduLocation();
    _locationPlugin.seriesLocationCallback(callback: (BaiduLocation result) {
      _location = result;
      _stopLocation();
      updatePosition();
    });

    _startLocation();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: const Text(
          "选取地点",
          style: TextStyle(color: Colors.black),
        ),
        centerTitle: true,
        backgroundColor: Colors.white,
        actions: <Widget>[
          MaterialButton(
            child: const Text("确定", style: TextStyle(fontSize: 15)),
            onPressed: () {},
          )
        ],
        leading: IconButton(
            onPressed: () {
              Navigator.pop(context);
            },
            icon: const Icon(Icons.arrow_back_ios, color: Colors.black)),
      ),
      body: _map(),
    );
  }

  Widget _map() {
    return Container(
        child: Column(
      children: [
        Container(
          child: TextField(
              controller: positionController,
              style: const TextStyle(color: Colors.black),
              decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: "请输入地点",
                  hintStyle: const TextStyle(color: Colors.grey, fontSize: 14),
                  suffix: Container(
                    child: MaterialButton(
                      child: const Text("确认"),
                      onPressed: () {
                        serchPosition(positionController.text);
                      },
                    ),
                  ))),
        ),
        Expanded(
            child: BMFMapWidget(
          onBMFMapCreated: (controller) {
            //自定义onBMFMapCreated方法,用于获取controller
            onBMFMapCreated(controller);
          },
          mapOptions: BMFMapOptions(
              center: BMFCoordinate(39.917215, 116.380341),
              zoomLevel: 12,
              mapPadding:
                  BMFEdgeInsets(left: 30, top: 0, right: 30, bottom: 0)),
        ))
      ],
    ));
  }

  void onBMFMapCreated(BMFMapController controller) {
    _controller = controller;
    _controller.showUserLocation(true);
  }

  //  申请权限
  Future<bool> requestPermission() async {
    // 申请权限
    final status = await Permission.location.request();
    if (status.isGranted) {
      print("定位权限申请通过");
      return true;
    } else {
      print("定位权限申请不通过");
      return false;
    }
  }

  /// 停止定位
  void _stopLocation() {
    if (null != _locationPlugin) {
      _locationPlugin.stopLocation();
    }
  }

//  开始定位
  void _startLocation() {
    if (null != _locationPlugin) {
      //申请定位权限
      requestPermission().then((value) => {
            if (value)
              {_setLocOption(), _locationPlugin.startLocation()}
            else
              {
                EasyLoading.showToast("需要定位权限",
                    toastPosition:EasyLoadingToastPosition.bottom)
              }
          });
    }
  }

//  设置定位参数
  void _setLocOption() {
    androidOption.setCoorType("bd09ll"); // 设置返回的位置坐标系类型
    androidOption.setIsNeedAltitude(true); // 设置是否需要返回海拔高度信息
    androidOption.setIsNeedAddress(true); // 设置是否需要返回地址信息
    androidOption.setIsNeedLocationPoiList(true); // 设置是否需要返回周边poi信息
    androidOption.setIsNeedNewVersionRgc(true); // 设置是否需要返回最新版本rgc信息
    androidOption.setIsNeedLocationDescribe(true); // 设置是否需要返回位置描述
    androidOption.setOpenGps(true); // 设置是否需要使用gps
    androidOption.setLocationMode(BMFLocationMode.hightAccuracy); // 设置定位模式
    androidOption.setScanspan(1000); // 设置发起定位请求时间间隔
    Map androidMap = androidOption.getMap();
    Map iosdMap = iosOption.getMap();
    _locationPlugin.prepareLoc(androidMap, iosdMap); //ios和安卓定位设置
  }

  Future<void> serchPosition(String text) async {
// 构造检索参数
    BMFSuggestionSearchOption suggestionSearchOption =
        BMFSuggestionSearchOption(
            keyword: text, cityname: _location.city ?? "北京");
// 检索实例
    BMFSuggestionSearch suggestionSearch = BMFSuggestionSearch();
// 检索回调
    suggestionSearch.onGetSuggestSearchResult(callback:
        (BMFSuggestionSearchResult result, BMFSearchErrorCode errorCode) {
      print('sug检索回调 result = ${result.toMap()} \n errorCode = ${errorCode}');
      // 解析reslut,具体参考demo
    });
// 发起检索
    bool flag = await suggestionSearch.suggestionSearch(suggestionSearchOption);
  }

  void updatePosition() {
    BMFCoordinate coordinate = BMFCoordinate(
        _location.latitude ?? 39.917215, _location.longitude ?? 116.380341);

    BMFMapOptions options = BMFMapOptions(
        center: coordinate,
        zoomLevel: 17,
        mapPadding: BMFEdgeInsets(left: 30, top: 0, right: 30, bottom: 0));

    BMFLocation location = BMFLocation(
        coordinate: coordinate,
        altitude: 0,
        horizontalAccuracy: 5,
        verticalAccuracy: -1.0,
        speed: -1.0,
        course: -1.0);

    BMFUserLocation userLocation = BMFUserLocation(
      location: location,
    );

    _controller.updateLocationData(userLocation);
    _controller.updateMapOptions(options);
  }
}

————————————2022.7.7——————————————————————————

  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值