flutter 高德地图SDK 接入

本篇为flutter 项目集成高德地图flutter插件,话不多说,直接上代码

iOS 端

创建账号

创建高德账号流程我忘记截图,也就不放了,十分简单,我的 demo 测试是个人账号,手机号注册,然后绑定下支付宝即可,企业账号依据流程注册



iOS 获取 key 值流程十分简单(安卓注册 key 幺蛾子就多起来了,后面再说)

导入包

iOS 使用 map 和定位不需要在原生端导入,直接在 flutter中 pubspec.yaml中引入即可

# 高德地图
  amap_flutter_map: ^3.0.0
  # 定位
  amap_flutter_location: ^3.0.0

但是我要注意提醒你们的是,这样安装的高德SDK 是包含 IDFA 的,不过说实话避免使用 idfa真的是太累人了,有太多SDK其实都用 idfa 了,OpenInstall,友盟,bugly,等等,我的建议是,还不如直接就声明自己的 APP 使用了 idfa,这玩意儿现在习惯了我感觉用户其实没啥反感的,因为几乎每个 APP 都会弹这个请求弹窗.


配置权限

Xcode 打开iOS 下Runner.xcworkspace,右键info.plist选择



把下面的内容按自己的需求粘进去即可,文案什么的,越详细越好,说清楚自己拿这个权限想干啥,被拒过的人都懂

    <key>NSCameraUsageDescription</key>
    <string>请点击“好”以允许访问。若不允许,你将无法使用相机来拍照和视频</string>
    <key>NSLocalNetworkUsageDescription</key>
    <string>此 APP 不会连接到您所用网络上的设备,只会检测与您本地网关的连通性</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>请点击“允许”以允许访问。 若不允许,你所在的城市将无法出现在你的动态、个人主页。</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>请点击“允许”以允许访问。 若不允许,你所在的城市将无法出现在你的动态、个人主页。</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>请点击“允许”以允许访问。 若不允许,你所在的城市将无法出现在你的动态、个人主页。</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>请点击“好”以允许访问。若不允许,你将无法使用麦克风录制发送语音</string>
    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>请点击“好”以允许访问。若不允许,你将无法使用无法使用相册照片发送消息、上传头像和发布动态。</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>请点击“好”以允许访问。若不允许,你将无法使用无法使用相册照片发送消息、上传头像和发布动态。</string>
    <key>UILaunchStoryboardName</key>
    <key>NSUserTrackingUsageDescription</key>
    <string>请放心, 爱泡炸无法获取你在应用内的隐私,该权限仅用于标识设备以保障服务安全与提升浏览体验</string>

业务代码

业务代码我没有进行封装,直接在作为测试 demo 展示,也没做什么动画的渐变啥的

import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';

import 'package:flutter/material.dart';
import 'package:flutter_psd/common/utils/psdllog.dart';
import 'package:permission_handler/permission_handler.dart';

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

  @override
  _GaodeMapPageState createState() => _GaodeMapPageState();
}

class _GaodeMapPageState extends State<GaodeMapPage> {
  static const AMapApiKey amapApiKeys = AMapApiKey(
      iosKey: '9af9e11da0573c280a514f2f6372df5f',
      androidKey: 'eb909b4ee863e2bd0aa18098b7acc9ba');

  AMapController? mapController;
  AMapFlutterLocation? location;

  PermissionStatus? permissionStatus;
  CameraPosition? currentLocation;

  @override
  void initState() {
    super.initState();
    AMapFlutterLocation.setApiKey(
        "eb909b4ee863e2bd0aa18098b7acc9ba", "9af9e11da0573c280a514f2f6372df5f");
    AMapFlutterLocation.updatePrivacyAgree(true);
    AMapFlutterLocation.updatePrivacyShow(true, true);

    requestPermission();
  }

  Future<void> requestPermission() async {
    final status = await Permission.location.request();
    permissionStatus = status;
    switch (status) {
      case PermissionStatus.denied:
        psdllog("拒绝");
        break;
      case PermissionStatus.granted:
        requestLocation();
        break;
      case PermissionStatus.limited:
        psdllog("限制");
        break;
      default:
        psdllog("其他状态");
        requestLocation();
        break;
    }
  }

  void requestLocation() {
    location = AMapFlutterLocation()
      ..setLocationOption(AMapLocationOption())
      ..onLocationChanged().listen((event) {
        psdllog(event);
        double? latitude = double.parse(event['latitude'] as String);
        double? longitude = double.parse(event['longitude'] as String);
        if (latitude != null && longitude != null) {
          setState(() {
            currentLocation = CameraPosition(
              target: LatLng(latitude, longitude),
              zoom: 10,
            );
          });
        }
      })
      ..startLocation();
  }

  @override
  void dispose() {
    location?.destroy();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          "高德地图",
          style: TextStyle(),
        ),
      ),
      body: currentLocation == null
          ? Container()
          : Center(
              child: SizedBox(
              child: AMapWidget(
                apiKey: amapApiKeys,
                // 初始化地图中心店
                initialCameraPosition: currentLocation!,
                //定位小蓝点
                myLocationStyleOptions: MyLocationStyleOptions(
                  true,
                ),
                // 普通地图normal,卫星地图satellite,夜间视图night,导航视图 navi,公交视图bus,
                mapType: MapType.normal,
                // 缩放级别范围
                minMaxZoomPreference: MinMaxZoomPreference(3, 20),
                // 隐私政策包含高德 必须填写
                privacyStatement: AMapPrivacyStatement(
                    hasAgree: true, hasContains: true, hasShow: true),
                // 地图创建成功时返回AMapController
                onMapCreated: (AMapController controller) {
                  mapController = controller;
                },
              ),
            )),
    );
  }
}

代码在上面,然后我讲一些 iOS权限错误还有和Android 通用的高德错误.

  • 1.iOS双定位权限
[MAMapKit] 要在iOS 11及以上版本使用定位服务, 需要在Info.plist中添加NSLocationAlwaysAndWhenInUseUsageDescription和NSLocationWhenInUseUsageDescription字段。

这是两个权限说明必须要全部配置,顺便提一嘴,iOS 隐私权限不管你在哪用,进入APP 第一时间就要弹出,定位权限没有这个要求.

    1. permission_handler报错
* What went wrong:
Execution failed for task ':permission_handler:compileDebugJavaWithJavac'.


一开始以为是 flutter 版本问题(今天测试 demo的时候,看到有人说2.10.0版本的 flutter 有个系统 bug),又看到有篇 stackoverflow 说升级版本就能解决这个 bug,所以升级到了2.10.1,然而还是没有解决.于是就去翻permission_handler的 issue,终于找到了,很幸运的是
permission_handler的作者刚刚好在昨天解释了这个 bug地址戳这

我当时使用的版本是7.* 升级后我就解决了这个问题

代码说明

高德 flutter 文档地址: 戳这儿
iOSbug少,基本按照文档来即可,而且由于是中文文档,看起来一点也不费劲,这边建议先获取到定位后在展示地图,这样,直接能够显示到中心的小蓝点.

// 隐私政策包含高德 必须填写
 privacyStatement: AMapPrivacyStatement(hasAgree: true, hasContains: true, hasShow: true),

定位的隐私政策也会一样,不然直接拋异常,高德希望你在隐私网址中提到高德地图的使用,正确合规的做法是在同意隐私政策的时候设置权限为 true
AMapFlutterLocation..updatePrivacyAgree(true)..updatePrivacyShow(true, true);

原生里的 key优先级小于 Widget 代码中.

定位中获取的参数map 经纬度为 string.

{locTime: 2022-02-11 21:51:03, province: 浙江省, callbackTime: 2022-02-11 21:51:03, district: 西湖区, country: 中国, street: ****, speed: -1.0, latitude: 30.287363, city: 杭州市, streetNumber: 177-1号, bearing: -1.0, accuracy: 35.0, adCode: 330106, altitude: 11.046348571777344, locationType: 1, longitude: 120.128650, cityCode: 0571, address: 浙江省杭州市西湖区*****, description: 浙江省杭州市西湖区*****}

高德的 flutterAPI 接口提供的确实很少,甚至感觉有点简陋,其实这东西如果以后有精力的话,可以尝试自己封装一下,当然安卓端我搞起来确实难度有点大,主要是要做好公共接口,做好channel 通信,剩下的就是各端的小伙伴去努力实现了,顺便可以练练插件.高德源码我也看了下,通道目前做的还不是太多,希望后面能丰富起来.


AMapController

效果展示

安卓端

安卓端配置真的是一言难尽,iOS 的过度顺利导致我以为安卓端的兼容也十分简单,我感觉周五一下午的时间全用来 碰 bug 上了,下面叙述下我的血泪史
首先尝试安卓模拟器运行项目

  • 运行,报错



    跟着改成31

  • 再运行,再报错,kotlin gradle 插件版本有问题



    修改根build.gradle

buildscript {
    ext.kotlin_version = '1.6.10'
    *****
}

运行正常,进入地图界面的时候拋异常

  • java.lang.NoClassDefFoundError: Failed resolution of: Lcom/amap/api/location/AMapLocationClient;

很明显,连类都找不到,一番查询后,得知Android 需要手动导入 sdk
在官方文档中,我采用手动拖入sdk+so


  • 再运行,再报错errorCode: 10 *******请检查AndroidManifest.xml文件是否配置了APSService定位服务
    AndroidManifest.xml增加
       <service android:name="com.amap.api.location.APSService"></service>
  • APSService标红
    网上查询到app/build.gradle 下增加
dependencies {
//    implementation files('src/libs/AMap3DMap_AMapLocation/AMap3DMap_9.0.0_AMapLocation_5.6.2_20220113.jar')
    implementation('com.amap.api:location:5.2.0')
}

这里我一开始查到是手动右键将 jar 包增加到library


但是报了一个什么错我忘记记录了
然后我查了下,查到下面的写法implementation('com.amap.api:location:5.2.0')目前不知道这两者的区别
再运行,在报错

  • errorCode: 12, errorInfo: 缺少定位权限 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:定位权限被禁用,请授予应用定位权限#1201#定位权限被禁用,请授予应用定位权限#1201

  • errorInfo: WIFI信息不足 请到http://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode/查看错误码说明,错误详细信息:当前基站为伪基站,并且搜到的WIFI数量不足,请移动到WIFI比较丰富的区域#0202#当前基站为伪基站,并且搜到的WIFI数量不足,请移动到WIFI比较丰富的区域#0202}
    这两个我后面换安卓真机运行就消失了,应该是项目重启,或者 APP 卸载,或者 flutter clean , gradle clean 等等,上面的其他几个 bug 我有些有尝试过清缓存解决,也许没提到,但是大家心里要有个印象
    再运行,再报错

  • Flutter multidex handling is disabled. If you wish to let the tool configure multidex, use the --mutidex flag.
    这个我请了清缓存,重启下就好了

  • 再运行,再报错



    其实到这儿,我心理已经大概有点底了,项目可以正常运行,只是定位无法提供,这里设计到 Android key 的创建,这里的出错应该是我没配好,其实最开始应该要写下如何创建 Android 的高德 key 的,后面补上,文章先写到这,明儿再找时间调调,然后把文章更新下,应该只需要亿点点时间.(主要是 bug 太多,再不写我就忘记我遇到过哪些 bug 了)


2022-02-12 09:57:09 更新 Android真机高德地图定位成功

昨天有个 bug 是鉴权失败导致定位失败
我按照昨天最后高德给出的鉴权失败流程一点点尝试,并没有解决,我怀疑我获取的 key 并不是我注册的 key,今天尝试用另外一种方法解决

在创建 debug.storekey 成功后, 创建 key 的方法戳这,我采用高德提供的获取 key 方式获取cd ~/.android


然后将该 SHA1更新到高德 key 中
最后鉴权成功.

再运行,成功获取到坐标


然而地图黑屏了,仅显示左下角一个 logo, 控制台打印报错



查了很多资料,最后怀疑是 so 文件导入出错,高德给了两种导入方法



在下载 sdk 的时候,高德附带了各个平台的 so 文件

我直接使用第一种方法,可能我导入的确实有点问题,并没有成功,于是我改成第二种方法




顺便提一下,对于 jar 包的引入,我还是改成了本地 jar 包

这是因为在尝试网上给出的implementation('com.amap.api:location:5.2.0')后,我发现报了一个找不到 MapView 啥的实现方法,推断出'com.amap.api:location:5.2.0'只能实现高德location库的方法,我想着还是用本地的 jar 包才对,要不然放那就是白导入了.

运行报错如果发现



可以尝试增加


效果展示

最后的最后,安卓真机地图的导入才算是结束了,最后展示下效果吧


PS

这次的安卓高德地图的配置,感觉基本把能踩的全踩了个遍,也是因为自己对安卓系统不太熟,平时也常用 iOS 真机或者模拟器测,也基本没啥问题,昨天也痛定思痛,以后再也不搞 iOS 模拟器了,下了个 momo,以后全部用安卓测代码,
顺便贴个momo模拟器 配置

system_profiler SPUSBDataType
复制ID/Vender ID到/.android/adb_usb.ini
adb kill-server
adb start-server
adb devices
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容