Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用

马肤

温馨提示:这篇文章已超过439天没有更新,请注意相关的内容是否还可用!

摘要:本文将介绍如何在Android和iOS平台上接入Flutter高德地图,包括定位和地图功能。通过简单的步骤,开发者可以实现在Flutter应用中集成高德地图服务,包括用户定位和地图展示。这将为用户提供便捷的位置服务和导航体验,加速移动应用的开发进程。

定位

Android

参考链接

官方文档

创建应用

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第1张

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第2张

创建Key

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第3张

输入Key的名称

服务平台选择Android平台

接下里获取SHA1

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第4张

PackageName输入项目的包名

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第5张

打开Android目录,并生成签名文件

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第6张

如果存在签名文件,如下图

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第7张

没有签名文件,则需要Create New 创建新的签名文件

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第8张

填写密码,别名、文件位置等信息

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第9张

创建完后,会发现目录下有签名文件,可以移到app目录下

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第10张

配置签名文件

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第11张

    signingConfigs {
        release {
            //keystore中key的别名
            keyAlias 'key0'
            //keystore中key的密码
            keyPassword '123456'
            //keystore的文件路径,可以是绝对路径也可以是相对路径
            storeFile file('./deman_mobo.jks')
            //keystore的密码l
            storePassword '123456'
        }
    }
    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.release
            minifyEnabled true //删除无用代码
            shrinkResources true //删除无用资源
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            signingConfig signingConfigs.release
            debuggable true
        }
    }

获取签名文件的SHA1

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第12张

keytool -list -v -keystore ./gaode_key.jks

引入依赖

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第13张

dependencies {
    implementation('com.amap.api:location:5.6.0')
}

Flutter 配置项目

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第14张

  amap_flutter_location: ^3.0.0
  permission_handler: ^11.3.0

申明权限

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第15张

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

配置服务

        

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第16张

测试代码

import 'dart:async';
import 'dart:io';
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:permission_handler/permission_handler.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State createState() => _HomePageState();
}
class _HomePageState extends State {
  final AMapFlutterLocation flutterLocation = AMapFlutterLocation();
  final AMapLocationOption aMapLocationOption = AMapLocationOption(
    needAddress: true,
    geoLanguage: GeoLanguage.DEFAULT,
    onceLocation: false,
    locationMode: AMapLocationMode.Hight_Accuracy,
    locationInterval: 2000,
    pausesLocationUpdatesAutomatically: false,
    desiredAccuracy: DesiredAccuracy.Best,
    desiredLocationAccuracyAuthorizationMode:
        AMapLocationAccuracyAuthorizationMode.FullAccuracy,
    distanceFilter: -1,
  );
  late final StreamSubscription subscription;
  late int count = 0;
  @override
  void initState() {
    AMapFlutterLocation.updatePrivacyShow(true, true);
    AMapFlutterLocation.updatePrivacyAgree(true);
    requestPermission();
    AMapFlutterLocation.setApiKey(
      "e51a737b3742762791f3c89f4dc61e6d",
      "cb341ecb2fb63ff6965c62a009979f29",
    );
    if (Platform.isIOS) {
      requestAccuracyAuthorization();
    }
    subscription = flutterLocation.onLocationChanged().listen((event) {
      print(event.toString());
    });
    super.initState();
  }
  @override
  void dispose() {
    subscription.cancel();
    flutterLocation.destroy();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: () {
                flutterLocation.setLocationOption(aMapLocationOption);
                Timer.periodic(const Duration(seconds: 1), (timer) {
                  count++;
                  print("定位序列号$count");
                  flutterLocation.startLocation();
                });
              },
              child: Text("开始定位"),
            ),
            ElevatedButton(
              onPressed: () {
                flutterLocation.stopLocation();
              },
              child: Text("停止定位"),
            ),
          ],
        ),
      ),
    );
  }
  /// 动态申请定位权限
  void requestPermission() async {
    bool hasLocationWhenInUsePermission =
        await requestIosLocationWhenInUserPermission();
    if (hasLocationWhenInUsePermission) {
      bool hasLocationAlwaysWhenInUsePermission =
          await requestIosLocationAlwaysWhenInUserPermission();
      if (hasLocationAlwaysWhenInUsePermission) {
      } else {}
    } else {}
  }
  /// 申请定位权限
  Future requestLocationPermission() async {
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.location.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationPermission() async {
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.location.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationWhenInUserPermission() async {
    var status = await Permission.locationWhenInUse.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.locationWhenInUse.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationAlwaysWhenInUserPermission() async {
    var status = await Permission.locationAlways.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.locationAlways.request();
      print("Permission.locationAlways - $status");
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  void requestAccuracyAuthorization() async {
    AMapAccuracyAuthorization currentAccuracyAuthorization =
        await flutterLocation.getSystemAccuracyAuthorization();
    if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
      print("精确定位类型");
    } else if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
      print("模糊定位类型");
    } else {
      print("未知定位类型");
    }
  }
}

运行结果

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第17张

IOS

创建Key

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第18张

Bundle ID为包名

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第19张

配置Podfile

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第20张

config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
          '$(inherited)',
          'PERMISSION_LOCATION=1',
        ]

配置info.plist

权限参考官方文档

下面是按照后台定位的标准来配置的,就是APP在后台,也能定位。

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第21张

	NSLocationTemporaryUsageDescriptionDictionary
    
        AnotherUsageDescription
        This app needs accurate location so it can show you relevant results.
        ExampleUsageDescription
        This app needs accurate location so it can verify that you are in a supported region.
    
	NSLocationAlwaysUsageDescription
	can I has location always?
	NSLocationWhenInUseUsageDescription
	need location when in use?
	NSLocationAlwaysAndWhenInUseUsageDescription
	always and when in use!
	NSLocationUsageDescription
	older devices need location.

权限对应

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第22张

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第23张

拒绝了上面的这个权限,那就没办法后台定位了

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第24张

其余几个权限申明也加上,点我查看参考链接

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第25张

Background Mode

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第26张

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第27张

勾上location updates

测试代码

import 'dart:async';
import 'dart:io';
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:permission_handler/permission_handler.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State createState() => _HomePageState();
}
class _HomePageState extends State {
  final AMapFlutterLocation flutterLocation = AMapFlutterLocation();
  final AMapLocationOption aMapLocationOption = AMapLocationOption(
    needAddress: true,
    geoLanguage: GeoLanguage.DEFAULT,
    onceLocation: false,
    locationMode: AMapLocationMode.Hight_Accuracy,
    locationInterval: 2000,
    pausesLocationUpdatesAutomatically: false,
    desiredAccuracy: DesiredAccuracy.Best,
    desiredLocationAccuracyAuthorizationMode:
        AMapLocationAccuracyAuthorizationMode.FullAccuracy,
    distanceFilter: -1,
  );
  late final StreamSubscription subscription;
  late int count = 0;
  @override
  void initState() {
    AMapFlutterLocation.updatePrivacyShow(true, true);
    AMapFlutterLocation.updatePrivacyAgree(true);
    requestPermission();
    AMapFlutterLocation.setApiKey(
      "e51a737b3742762791f3c89f4dc61e6d",
      "cb341ecb2fb63ff6965c62a009979f29",
    );
    if (Platform.isIOS) {
      requestAccuracyAuthorization();
    }
    subscription = flutterLocation.onLocationChanged().listen((event) {
      print(event.toString());
    });
    super.initState();
  }
  @override
  void dispose() {
    subscription.cancel();
    flutterLocation.destroy();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: () {
                flutterLocation.setLocationOption(aMapLocationOption);
                Timer.periodic(const Duration(seconds: 1), (timer) {
                  count++;
                  print("定位序列号$count");
                  flutterLocation.startLocation();
                });
              },
              child: Text("开始定位"),
            ),
            ElevatedButton(
              onPressed: () {
                flutterLocation.stopLocation();
              },
              child: Text("停止定位"),
            ),
          ],
        ),
      ),
    );
  }
  /// 动态申请定位权限
  void requestPermission() async {
    bool hasLocationWhenInUsePermission =
        await requestIosLocationWhenInUserPermission();
    if (hasLocationWhenInUsePermission) {
      bool hasLocationAlwaysWhenInUsePermission =
          await requestIosLocationAlwaysWhenInUserPermission();
      if (hasLocationAlwaysWhenInUsePermission) {
      } else {}
    } else {}
  }
  /// 申请定位权限
  Future requestLocationPermission() async {
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.location.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationPermission() async {
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.location.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationWhenInUserPermission() async {
    var status = await Permission.locationWhenInUse.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.locationWhenInUse.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  Future requestIosLocationAlwaysWhenInUserPermission() async {
    var status = await Permission.locationAlways.status;
    if (status == PermissionStatus.granted) {
      return true;
    } else {
      status = await Permission.locationAlways.request();
      print("Permission.locationAlways - $status");
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
  void requestAccuracyAuthorization() async {
    AMapAccuracyAuthorization currentAccuracyAuthorization =
        await flutterLocation.getSystemAccuracyAuthorization();
    if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
      print("精确定位类型");
    } else if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
      print("模糊定位类型");
    } else {
      print("未知定位类型");
    }
  }
}

运行结果

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第28张

地图

官方文档

引入插件

amap_flutter_map插件地址

amap_flutter_base插件地址

Android

引入依赖

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第29张

implementation('com.amap.api:3dmap:latest.integration')

测试代码(显示地图)

import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State createState() => _HomePageState();
}
class _HomePageState extends State {
  late AMapController _mapController;
  late AMapWidget mapWidget;
  @override
  void initState() {
    mapWidget = AMapWidget(
      apiKey: const AMapApiKey(
        iosKey: "cb341ecb2fb63ff6965c62a009979f29",
        androidKey: "e51a737b3742762791f3c89f4dc61e6d",
      ),
      privacyStatement: const AMapPrivacyStatement(
        hasContains: true,
        hasShow: true,
        hasAgree: true,
      ),
      onMapCreated: onMapCreated,
    );
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: Stack(
          children: [
            mapWidget,
            Positioned(
              right: 10,
              bottom: 10,
              child: FutureBuilder(
                future: getApprovalNumber(),
                builder: (ctx, snapshot) {
                  return Column(
                    children: [
                      Text("${snapshot.data}"),
                    ],
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
  void onMapCreated(AMapController controller) {
    CameraUpdate cameraUpdate = CameraUpdate.newCameraPosition(
      const CameraPosition(
        target: LatLng(30, 121.473658),
        zoom: 10,
        tilt: 30,
        bearing: 0,
      ),
    );
    controller.moveCamera(cameraUpdate);
    setState(() {
      _mapController = controller;
    });
  }
  Future getApprovalNumber() async {
    // 普通地图审图号
    String? mapContentApprovalNumber =
        await _mapController.getMapContentApprovalNumber();
    // // 卫星地图审图号
    // String? satelliteImageApprovalNumber =
    //     await _mapController.getSatelliteImageApprovalNumber();
    return mapContentApprovalNumber;
  }
}

运行结果

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第30张

地图标点

地图标点参考文档

测试代码(地图标点)

import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State createState() => _HomePageState();
}
class _HomePageState extends State {
  late AMapController _mapController;
  late Map markerMap;
  late double nowLatitude;
  late double nowLongitude;
  late AMapApiKey aMapApiKey;
  late AMapPrivacyStatement aMapPrivacyStatement;
  @override
  void initState() {
    markerMap = {};
    nowLatitude = 30;
    nowLongitude = 121.473658;
    aMapApiKey = const AMapApiKey(
      iosKey: "cb341ecb2fb63ff6965c62a009979f29",
      androidKey: "e51a737b3742762791f3c89f4dc61e6d",
    );
    aMapPrivacyStatement = const AMapPrivacyStatement(
      hasContains: true,
      hasShow: true,
      hasAgree: true,
    );
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: Stack(
          children: [
            AMapWidget(
              apiKey: aMapApiKey,
              privacyStatement: aMapPrivacyStatement,
              onMapCreated: onMapCreated,
              markers: Set.of(markerMap.values),
            ),
            Positioned(
              right: 10,
              bottom: 10,
              child: FutureBuilder(
                future: getApprovalNumber(),
                builder: (ctx, snapshot) {
                  return Column(
                    children: [
                      Text("${snapshot.data}"),
                    ],
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
  void onMapCreated(AMapController controller) {
    CameraUpdate cameraUpdate = CameraUpdate.newCameraPosition(
      CameraPosition(
        target: LatLng(nowLatitude, nowLongitude),
        zoom: 10,
        tilt: 30,
        bearing: 0,
      ),
    );
    controller.moveCamera(cameraUpdate);
    setState(() {
      _mapController = controller;
    });
    getMarker(
      nowLatitude,
      nowLongitude,
      image: "assets/images/my_position.png",
      title: "我",
    );
  }
  Future getApprovalNumber() async {
    // 普通地图审图号
    String? mapContentApprovalNumber =
        await _mapController.getMapContentApprovalNumber();
    // // 卫星地图审图号
    // String? satelliteImageApprovalNumber =
    //     await _mapController.getSatelliteImageApprovalNumber();
    return mapContentApprovalNumber;
  }
  Future getMarker(
    double latitude,
    double longitude, {
    String? image,
    String? title,
    String? snippet,
  }) async {
    LatLng position = LatLng(latitude, longitude);
    Marker marker = Marker(
      onTap: (s) {
        print(s);
      },
      infoWindow: InfoWindow(
        title: title,
        snippet: snippet,
      ),
      position: position,
      icon: image != null
          ? await getBitmapDescriptorFromAssetBytes(image, 100, 100)
          : BitmapDescriptor.defaultMarker,
    );
    markerMap[marker.id] = marker;
    setState(() {});
  }
  Future getBitmapDescriptorFromAssetBytes(
    String path,
    double width,
    double height,
  ) async {
    var imageFile = await rootBundle.load(path);
    var pictureRecorder = ui.PictureRecorder();
    var canvas = Canvas(pictureRecorder);
    var imageUint8List = imageFile.buffer.asUint8List();
    var codec = await ui.instantiateImageCodec(imageUint8List);
    var imageFI = await codec.getNextFrame();
    paintImage(
      canvas: canvas,
      rect: Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()),
      image: imageFI.image,
      filterQuality: FilterQuality.medium,
    );
    var image = await pictureRecorder
        .endRecording()
        .toImage(width.toInt(), height.toInt());
    var data = await image.toByteData(format: ui.ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(data!.buffer.asUint8List());
  }
}

运行结果

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第31张

Ios

配置pod

按照上面的步骤,用Xcode打开ios目录

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第32张

  pod 'AMapLocation'
  pod 'AMap3DMap'

最好加上,不加可能会在打包时出错

加上后pod install

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第33张

还有pod repo update也要试试(遇到一些bug时)

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第34张

以及

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第35张

测试代码(同Android)

import 'package:amap_flutter_map/amap_flutter_map.dart';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State createState() => _HomePageState();
}
class _HomePageState extends State {
  late AMapController _mapController;
  late Map markerMap;
  late double nowLatitude;
  late double nowLongitude;
  late AMapApiKey aMapApiKey;
  late AMapPrivacyStatement aMapPrivacyStatement;
  @override
  void initState() {
    markerMap = {};
    nowLatitude = 30;
    nowLongitude = 121.473658;
    aMapApiKey = const AMapApiKey(
      iosKey: "cb341ecb2fb63ff6965c62a009979f29",
      androidKey: "e51a737b3742762791f3c89f4dc61e6d",
    );
    aMapPrivacyStatement = const AMapPrivacyStatement(
      hasContains: true,
      hasShow: true,
      hasAgree: true,
    );
    super.initState();
  }
  @override
  void dispose() {
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        height: MediaQuery.of(context).size.height,
        width: MediaQuery.of(context).size.width,
        child: Stack(
          children: [
            AMapWidget(
              apiKey: aMapApiKey,
              privacyStatement: aMapPrivacyStatement,
              onMapCreated: onMapCreated,
              markers: Set.of(markerMap.values),
            ),
            Positioned(
              right: 10,
              bottom: 10,
              child: FutureBuilder(
                future: getApprovalNumber(),
                builder: (ctx, snapshot) {
                  return Column(
                    children: [
                      Text("${snapshot.data}"),
                    ],
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
  void onMapCreated(AMapController controller) {
    CameraUpdate cameraUpdate = CameraUpdate.newCameraPosition(
      CameraPosition(
        target: LatLng(nowLatitude, nowLongitude),
        zoom: 10,
        tilt: 30,
        bearing: 0,
      ),
    );
    controller.moveCamera(cameraUpdate);
    setState(() {
      _mapController = controller;
    });
    getMarker(
      nowLatitude,
      nowLongitude,
      image: "assets/images/my_position.png",
      title: "我",
    );
  }
  Future getApprovalNumber() async {
    // 普通地图审图号
    String? mapContentApprovalNumber =
        await _mapController.getMapContentApprovalNumber();
    // // 卫星地图审图号
    // String? satelliteImageApprovalNumber =
    //     await _mapController.getSatelliteImageApprovalNumber();
    return mapContentApprovalNumber;
  }
  Future getMarker(
    double latitude,
    double longitude, {
    String? image,
    String? title,
    String? snippet,
  }) async {
    LatLng position = LatLng(latitude, longitude);
    Marker marker = Marker(
      onTap: (s) {
        print(s);
      },
      infoWindow: InfoWindow(
        title: title,
        snippet: snippet,
      ),
      position: position,
      icon: image != null
          ? await getBitmapDescriptorFromAssetBytes(image, 100, 100)
          : BitmapDescriptor.defaultMarker,
    );
    markerMap[marker.id] = marker;
    setState(() {});
  }
  Future getBitmapDescriptorFromAssetBytes(
    String path,
    double width,
    double height,
  ) async {
    var imageFile = await rootBundle.load(path);
    var pictureRecorder = ui.PictureRecorder();
    var canvas = Canvas(pictureRecorder);
    var imageUint8List = imageFile.buffer.asUint8List();
    var codec = await ui.instantiateImageCodec(imageUint8List);
    var imageFI = await codec.getNextFrame();
    paintImage(
      canvas: canvas,
      rect: Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()),
      image: imageFI.image,
      filterQuality: FilterQuality.medium,
    );
    var image = await pictureRecorder
        .endRecording()
        .toImage(width.toInt(), height.toInt());
    var data = await image.toByteData(format: ui.ImageByteFormat.png);
    return BitmapDescriptor.fromBytes(data!.buffer.asUint8List());
  }
}

运行结果

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第36张

打包也没问题就行了

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第37张

发布apk

出现的闪退问题

再全部配置完后,发现一个bug,执行

 flutter build apk --no-tree-shake-icons --obfuscate --split-debug-info=./

安装完apk后,点开地图会直接闪退

并出现下面

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第38张

F/obo2.deman_mob(25374): java_vm_ext.cc:570] JNI DETECTED ERROR IN APPLICATION: java_class == null
F/obo2.deman_mob(25374): java_vm_ext.cc:570]     in call to GetStaticMethodID
F/obo2.deman_mob(25374): java_vm_ext.cc:570]     from java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader, java.lang.Class)
F/obo2.deman_mob(25374): thread.cc:2560] No pending exception expected: java.lang.ClassNotFoundException: com.autonavi.base.amap.mapcore.ClassTools
F/obo2.deman_mob(25374): thread.cc:2560]   at java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader, java.lang.Class) (Runtime.java:-2)
F/obo2.deman_mob(25374): thread.cc:2560]   at java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader) (Runtime.java:1115)
F/obo2.deman_mob(25374): thread.cc:2560]   at void java.lang.Runtime.loadLibrary0(java.lang.ClassLoader, java.lang.Class, java.lang.String) (Runtime.java:1069)
F/obo2.deman_mob(25374): thread.cc:2560]   at void java.lang.Runtime.loadLibrary0(java.lang.Class, java.lang.String) (Runtime.java:1007)
F/obo2.deman_mob(25374): thread.cc:2560]   at void java.lang.System.loadLibrary(java.lang.String) (System.java:1668)
F/obo2.deman_mob(25374): thread.cc:2560]   at boolean o5.a.k(android.content.Context) (:-1)
F/obo2.deman_mob(25374): thread.cc:2560]   at void z3.v7.N1(int, javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig) (:-1)
F/obo2.deman_mob(25374): thread.cc:2560]   at void z3.v7.F0(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig) (:-1)
F/obo2.deman_mob(25374): thread.cc:2560]   at void d5.c.onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig) (:-1)
F/obo2.deman_mob(25374): thread.cc:2560]   at void z3.p8$i.q() (:-1)
F/obo2.deman_mob(25374): thread.cc:2560]   at void z3.p8$i.run() (:-1)

去修改build.gradle

Flutter高德地图接入Android/IOS(定位&地图),Flutter高德地图集成定位与地图功能于Android/iOS应用 第39张

参考文章即可修复bug

这样就不会闪退了


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码