【Flutter】高德舆图接入Android/IOS(定位&舆图)
定位Android
参考链接
官方文档
创建应用
https://i-blog.csdnimg.cn/blog_migrate/75e5a705641c286271e4b5383cadfb90.png
https://i-blog.csdnimg.cn/blog_migrate/c54822e39cdb822fd74cb8407bea18ae.png
创建Key
https://i-blog.csdnimg.cn/blog_migrate/4f4de866f1011363819cbd86f150c983.png
输入Key的名称
服务平台选择Android平台
接下里获取SHA1
https://i-blog.csdnimg.cn/blog_migrate/38e7424b5dbde02ce35c1ff130e2bfd8.png
PackageName输入项目的包名
https://i-blog.csdnimg.cn/blog_migrate/4a7e34bc24233efaaa0706896b6e6098.png
打开Android目次,并生成签名文件
https://i-blog.csdnimg.cn/blog_migrate/b093391a628b64f03f2a03dd3b9081f7.png
假如存在签名文件,如下图
https://i-blog.csdnimg.cn/blog_migrate/609c22adf468b0236e2c568c65110b8d.png
若没有签名文件,则需要Create New 创建新的签名文件
https://i-blog.csdnimg.cn/blog_migrate/40865c2766091d1a534094bb9d86205c.png
填写密码,别名、文件位置等信息
https://i-blog.csdnimg.cn/blog_migrate/69e74c99cf759b2e8e7c02e1f324759d.png
创建完后,会发现目次下有签名文件,可以移到app目次下
https://i-blog.csdnimg.cn/blog_migrate/ec0be84facbddf670b8c9c5671717cbd.png
配置签名文件
https://i-blog.csdnimg.cn/blog_migrate/125d86c35b64386bd65fe6c1c01004c5.png
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
https://i-blog.csdnimg.cn/blog_migrate/84e667c83073a9e2977274a04ce97ed3.png
keytool -list -v -keystore ./gaode_key.jks
引入依赖
https://i-blog.csdnimg.cn/blog_migrate/c5663e1edb7d4c0ebd111bf0fcd8b800.png
dependencies {
implementation('com.amap.api:location:5.6.0')
}
Flutter 配置项目
https://i-blog.csdnimg.cn/blog_migrate/71f9e975956644fa472e8d41bd7a587e.png
amap_flutter_location: ^3.0.0
permission_handler: ^11.3.0
说明权限
https://i-blog.csdnimg.cn/blog_migrate/8231fd90290b14835a677d7dc2e6bebd.png
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取精确位置,精准定位必选-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--允许获取粗略位置,粗略定位必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--允许获取设备和运营商信息,用于问题排查和网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--后台获取位置信息,若需后台定位则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许写设备缓存,用于问题排查-->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!--允许写入扩展存储,用于写入缓存定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
配置服务
<!-- 配置定位Service -->
<service android:name="com.amap.api.location.APSService" />
https://i-blog.csdnimg.cn/blog_migrate/5df00762bc4d5b68254d9950b75b41a7.png
测试代码
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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
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<Map<String, Object>> 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<bool> 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<bool> 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<bool> 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<bool> 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("未知定位类型");
}
}
}
运行结果
https://i-blog.csdnimg.cn/blog_migrate/b2768c8207675addf5443d763cd23ef0.png
IOS
创建Key
https://i-blog.csdnimg.cn/blog_migrate/7c23a35e79cbedb34fa4cb2b98dbb42c.png
Bundle ID为包名
https://i-blog.csdnimg.cn/blog_migrate/3e8d72a1dcba93ba068640a5786abbd5.png
配置Podfile
https://i-blog.csdnimg.cn/blog_migrate/4b1c8b12f93372689a4662ac07552248.png
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'PERMISSION_LOCATION=1',
]
配置info.plist
权限参考官方文档
下面是按照后台定位的标准来配置的,就是APP在后台,也能定位。
https://i-blog.csdnimg.cn/blog_migrate/e5675375c4e91c8bc7e338ea9dc4ca49.png
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>AnotherUsageDescription</key>
<string>This app needs accurate location so it can show you relevant results.</string>
<key>ExampleUsageDescription</key>
<string>This app needs accurate location so it can verify that you are in a supported region.</string>
</dict>
<key>NSLocationAlwaysUsageDescription</key>
<string>can I has location always?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>need location when in use?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>always and when in use!</string>
<key>NSLocationUsageDescription</key>
<string>older devices need location.</string>
权限对应
https://i-blog.csdnimg.cn/blog_migrate/7fc254003f46d2f9cba8de739aa4e3aa.png
https://i-blog.csdnimg.cn/blog_migrate/33d80384a0633008393ba83b55191ad0.png
拒绝了上面的这个权限,那就没办法后台定位了
https://i-blog.csdnimg.cn/blog_migrate/392e1de104e83db51ae945fda85207da.png
其余几个权限说明也加上,点我检察参考链接
https://i-blog.csdnimg.cn/blog_migrate/f6fb616998b0fcf2a01f81de03d11f80.png
Background Mode
https://i-blog.csdnimg.cn/blog_migrate/2e3dbb2a41e65850cd216baaefda3395.png
https://i-blog.csdnimg.cn/blog_migrate/0e24dcbe9f6e7f774b9ca6426838f6e2.png
勾上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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
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<Map<String, Object>> 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<bool> 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<bool> 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<bool> 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<bool> 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("未知定位类型");
}
}
}
运行结果
https://i-blog.csdnimg.cn/blog_migrate/046dec98300f885a901675a2bf9fc21e.png
舆图
官方文档
引入插件
amap_flutter_map插件地点
amap_flutter_base插件地点
Android
引入依赖
https://i-blog.csdnimg.cn/blog_migrate/37773fbc58c095140df701b1d70e2c6c.png
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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
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<String?>(
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<String?> getApprovalNumber() async {
// 普通地图审图号
String? mapContentApprovalNumber =
await _mapController.getMapContentApprovalNumber();
// // 卫星地图审图号
// String? satelliteImageApprovalNumber =
// await _mapController.getSatelliteImageApprovalNumber();
return mapContentApprovalNumber;
}
}
运行结果
https://i-blog.csdnimg.cn/blog_migrate/2b0af95f0b3a78222f79004d2b45cd78.png
舆图标点
舆图标点参考文档
测试代码(舆图标点)
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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late AMapController _mapController;
late Map<String, Marker> 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<String?>(
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<String?> getApprovalNumber() async {
// 普通地图审图号
String? mapContentApprovalNumber =
await _mapController.getMapContentApprovalNumber();
// // 卫星地图审图号
// String? satelliteImageApprovalNumber =
// await _mapController.getSatelliteImageApprovalNumber();
return mapContentApprovalNumber;
}
Future<void> 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;
setState(() {});
}
Future<BitmapDescriptor> 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());
}
}
运行结果
https://i-blog.csdnimg.cn/blog_migrate/ccb0ca099b4b347db5b68b17fc153059.png
Ios
配置pod
按照上面的步骤,用Xcode打开ios目次
https://i-blog.csdnimg.cn/blog_migrate/8ddc3397ddc46e18cbe3262401f5016b.png
pod 'AMapLocation'
pod 'AMap3DMap'
最好加上,不加可能会在打包时堕落
加上后pod install
https://i-blog.csdnimg.cn/blog_migrate/2c7fe4e6b659a2d25141f04bba8dc131.png
另有pod repo update也要试试(遇到一些bug时)
https://i-blog.csdnimg.cn/blog_migrate/73f3aa4d230de4e35e81f93c121e576b.png
以及
https://i-blog.csdnimg.cn/blog_migrate/a601f8ae9a70a23a9a0ba35cb9d29ced.png
测试代码(同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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late AMapController _mapController;
late Map<String, Marker> 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<String?>(
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<String?> getApprovalNumber() async {
// 普通地图审图号
String? mapContentApprovalNumber =
await _mapController.getMapContentApprovalNumber();
// // 卫星地图审图号
// String? satelliteImageApprovalNumber =
// await _mapController.getSatelliteImageApprovalNumber();
return mapContentApprovalNumber;
}
Future<void> 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;
setState(() {});
}
Future<BitmapDescriptor> 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());
}
}
运行结果
https://i-blog.csdnimg.cn/blog_migrate/67f6a2b6bad0ed206d019b87ff2626d9.png
打包也没标题就行了
https://i-blog.csdnimg.cn/blog_migrate/f1a478570151ad49b8f100eeb08dc9ab.png
发布apk
出现的闪退标题
再全部配置完后,发现一个bug,实行
flutter build apk --no-tree-shake-icons --obfuscate --split-debug-info=./
安装完apk后,点开舆图会直接闪退
并出现下面
https://i-blog.csdnimg.cn/blog_migrate/853f1be81ee10fdebd00cf1cd0b36521.png
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
https://i-blog.csdnimg.cn/blog_migrate/f2d1ad296a3ce40e64e5119b405ade4a.png
参考文章即可修复bug
这样就不会闪退了
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]