flutter 高德地图SDK 接入

2022-02-12  本文已影响0人  简单coder

本篇为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 通用的高德错误.

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

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

* 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 上了,下面叙述下我的血泪史
首先尝试安卓模拟器运行项目

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

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

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


       <service android:name="com.amap.api.location.APSService"></service>
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')目前不知道这两者的区别
再运行,在报错

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
上一篇 下一篇

猜你喜欢

热点阅读