Browse Source

上传高德导航

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
d24f03fdb0
  1. 6
      lib/data/services/navigation_manager.dart
  2. 4
      lib/modules/agent/controllers/agent_controller.dart
  3. 145
      lib/modules/agent/views/message_bubble.dart
  4. 145
      lib/modules/agent/views/message_bubble_navigation.dart
  5. 8
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  6. 4
      local_plugins/amap_service/android/build.gradle
  7. 5
      local_plugins/amap_service/android/src/main/AndroidManifest.xml
  8. 114
      local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/AmapServicePlugin.kt
  9. 254
      local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationActivity.kt
  10. 479
      local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationService.kt
  11. 47
      local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationServiceHelper.kt
  12. 10
      local_plugins/amap_service/android/src/main/res/layout/activity_navigation.xml
  13. 5
      local_plugins/amap_service/android/src/main/res/values/colors.xml
  14. 9
      local_plugins/amap_service/android/src/main/res/values/styles.xml
  15. 174
      local_plugins/amap_service/lib/amap_controller.dart
  16. 12
      local_plugins/amap_service/lib/amap_service.dart
  17. 20
      local_plugins/amap_service/lib/amap_service_map.dart
  18. 425
      local_plugins/amap_service/lib/amap_widget.dart
  19. 41
      local_plugins/amap_service/lib/core/amap_flutter_platform.dart
  20. 77
      local_plugins/amap_service/lib/core/map_event.dart
  21. 274
      local_plugins/amap_service/lib/core/method_channel_amap_flutter_map.dart
  22. 29
      local_plugins/amap_service/lib/types/base_overlay.dart
  23. 140
      local_plugins/amap_service/lib/types/bitmap.dart
  24. 150
      local_plugins/amap_service/lib/types/camera.dart
  25. 249
      local_plugins/amap_service/lib/types/marker.dart
  26. 105
      local_plugins/amap_service/lib/types/marker_updates.dart
  27. 120
      local_plugins/amap_service/lib/types/polygon.dart
  28. 108
      local_plugins/amap_service/lib/types/polygon_updates.dart
  29. 198
      local_plugins/amap_service/lib/types/polyline.dart
  30. 108
      local_plugins/amap_service/lib/types/polyline_updates.dart
  31. 11
      local_plugins/amap_service/lib/types/types.dart
  32. 257
      local_plugins/amap_service/lib/types/ui.dart
  33. 2
      local_plugins/amap_service/pubspec.yaml
  34. BIN
      local_plugins/opus/.gradle/buildOutputCleanup/buildOutputCleanup.lock
  35. 4
      local_plugins/opus/.gradle/buildOutputCleanup/cache.properties

6
lib/data/services/navigation_manager.dart

@ -27,7 +27,11 @@ class NavigationManager extends GetxService {
}
//导航
Future<void> navigation(String org, String dis) async {
Future<void> start(String org, String dis) async {
// await _amapervice.navigation(org, dis);
}
//导航
Future<void> open() async {
await _amapervice.open();
}
}

4
lib/modules/agent/controllers/agent_controller.dart

@ -849,7 +849,7 @@ class AgentController extends GetxController {
}
//去导航
void gotoNavigation() {
Get.toNamed(Routes.navigation);
void openNavigation() {
_navigationManager.open();
}
}

145
lib/modules/agent/views/message_bubble.dart

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:deep_voice/modules/agent/views/message_bubble_navigation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
@ -1171,6 +1172,148 @@ class MessageBubble extends GetView<AgentController> {
// 默认或未知天气
return Icons.help_outline;
}
Widget navigationCard(
BuildContext context, {
required List<Map<String, dynamic>> modes,
Map<String, dynamic>? navigation,
double height = 300,
}) {
int currentIndex = 0;
return Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
boxShadow: const [
BoxShadow(
blurRadius: 8,
color: Colors.black12,
offset: Offset(0, 4),
),
],
),
child: StatefulBuilder(
builder: (context, setInnerState) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 路线图片
ClipRRect(
borderRadius:
const BorderRadius.vertical(top: Radius.circular(16)),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Image.network(
modes[currentIndex]["image"] as String,
key: ValueKey<String>(
modes[currentIndex]["ntype"] as String),
height: 160,
width: double.infinity,
fit: BoxFit.cover,
),
),
),
// 导航方式切换按钮
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(modes.length, (index) {
final isSelected = index == currentIndex;
return GestureDetector(
onTap: () {
setInnerState(() => currentIndex = index);
},
child: SizedBox(
width: 50,
child: Text(
modes[index]["ntype"] as String,
textAlign: TextAlign.center,
style: TextStyle(
color: isSelected ? Colors.blue : Colors.black87,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
);
}),
),
),
// 距离和耗时
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('距离:${modes[currentIndex]["distance"]}',
style:
const TextStyle(fontSize: 12, color: Colors.blue)),
IconButton(
icon: const Icon(Icons.turn_left,
color: Colors.blue, size: 20),
onPressed: () {
controller.openNavigation();
},
),
],
),
),
// 导航实时数据显示
if (navigation != null)
Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 圆形方向图标(如果有)
if (navigation["directionIcon"] != "")
Container(
width: 32,
height: 32,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
child: ClipOval(
child: Image.memory(
base64Decode(navigation["directionIcon"]),
fit: BoxFit.cover,
),
),
),
const SizedBox(width: 8),
// 文字信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (navigation["currentRoad"] != null)
Text('当前道路:${navigation["currentRoad"]}',
style: const TextStyle(fontSize: 12)),
if (navigation["nextRoad"] != null)
Text('下一道路:${navigation["nextRoad"]}',
style: const TextStyle(fontSize: 12)),
if (navigation["distanceText"] != null)
Text('剩余距离:${navigation["distanceText"]}',
style: const TextStyle(fontSize: 12)),
],
),
),
],
),
),
],
);
},
),
);
}
}
/// 动画点组件

145
lib/modules/agent/views/message_bubble_navigation.dart

@ -1,145 +0,0 @@
import 'dart:convert';
import 'package:deep_voice/routes/app_routes.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
/// A widget that displays a navigation card with different modes of transportation.
Widget navigationCard(
BuildContext context, {
required List<Map<String, dynamic>> modes,
Map<String, dynamic>? navigation,
double height = 300,
}) {
int currentIndex = 0;
return Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
boxShadow: const [
BoxShadow(
blurRadius: 8,
color: Colors.black12,
offset: Offset(0, 4),
),
],
),
child: StatefulBuilder(
builder: (context, setInnerState) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 路线图片
ClipRRect(
borderRadius:
const BorderRadius.vertical(top: Radius.circular(16)),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Image.network(
modes[currentIndex]["image"] as String,
key: ValueKey<String>(modes[currentIndex]["ntype"] as String),
height: 160,
width: double.infinity,
fit: BoxFit.cover,
),
),
),
// 导航方式切换按钮
Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(modes.length, (index) {
final isSelected = index == currentIndex;
return GestureDetector(
onTap: () {
setInnerState(() => currentIndex = index);
},
child: SizedBox(
width: 50,
child: Text(
modes[index]["ntype"] as String,
textAlign: TextAlign.center,
style: TextStyle(
color: isSelected ? Colors.blue : Colors.black87,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
);
}),
),
),
// 距离和耗时
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('距离:${modes[currentIndex]["distance"]}',
style: const TextStyle(fontSize: 12, color: Colors.blue)),
IconButton(
icon: const Icon(Icons.turn_left,
color: Colors.blue, size: 20),
onPressed: () {
Get.toNamed(Routes.navigation);
},
),
],
),
),
// 导航实时数据显示
if (navigation != null)
Padding(
padding: const EdgeInsets.all(8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 圆形方向图标(如果有)
if (navigation["directionIcon"] != "")
Container(
width: 32,
height: 32,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
child: ClipOval(
child: Image.memory(
base64Decode(navigation["directionIcon"]),
fit: BoxFit.cover,
),
),
),
const SizedBox(width: 8),
// 文字信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (navigation["currentRoad"] != null)
Text('当前道路:${navigation["currentRoad"]}',
style: const TextStyle(fontSize: 12)),
if (navigation["nextRoad"] != null)
Text('下一道路:${navigation["nextRoad"]}',
style: const TextStyle(fontSize: 12)),
if (navigation["distanceText"] != null)
Text('剩余距离:${navigation["distanceText"]}',
style: const TextStyle(fontSize: 12)),
],
),
),
],
),
),
],
);
},
),
);
}

8
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -7,17 +7,13 @@ import com.yunqiinnovation.azure_speech.AzureAsrHelper
import com.yunqiinnovation.open_ai_service.OpenAIService
import com.yunqiinnovation.chat_storage.ChatStorageHelper
import com.yunqiinnovation.music_service.MusicServiceStarter
import com.yunqiinnovation.amap_service.NavigationServiceStarter
import com.yunqiinnovation.amap_service.NavigationServiceHelper
import android.util.Log
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.*
import java.util.Collections
import kotlin.coroutines.CoroutineContext
import com.yunqiinnovation.ble_service.BleService
import android.media.MediaPlayer
import com.yunqiinnovation.agent_service.R
import android.os.Handler
import android.os.Looper
import com.deep_voice.speech.tts.TtsEvent
import com.deep_voice.speech.tts.TtsEventListener
import com.deep_voice.speech.tts.TtsEventType
@ -1190,7 +1186,7 @@ object AgentService : CoroutineScope {
// 如果 playlist 中有有效的歌曲,开始播放
if (!start.isNullOrEmpty() && !end.isNullOrEmpty()) {
Log.i(TAG, "启动导航服务 ${start} ${end}")
NavigationServiceStarter.startServiceWithCommand(context, command = "start", startpos = start, endpos = end)
NavigationServiceHelper.startNavigation(context, startpos = start, endpos = end)
} else {
Log.i(TAG, "启动导航服务失败")
}

4
local_plugins/amap_service/android/build.gradle

@ -65,3 +65,7 @@ android {
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0'
}

5
local_plugins/amap_service/android/src/main/AndroidManifest.xml

@ -39,6 +39,11 @@
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />
<service android:name="com.amap.api.location.APSService"/>
<activity
android:name=".NavigationActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation"
android:screenOrientation="portrait" />
<service
android:name=".NavigationService"
android:exported="true"

114
local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/AmapServicePlugin.kt

@ -2,17 +2,8 @@ package com.yunqiinnovation.amap_service
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import com.amap.api.navi.AMapNaviView
import com.amap.api.navi.AMapNaviViewListener
import com.amap.api.navi.model.NaviLatLng
import com.yunqiinnovation.amap_service.NavigationServiceStarter
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
@ -23,7 +14,7 @@ import org.json.JSONObject
/** MusicServicePlugin */
class AmapServicePlugin: FlutterPlugin, MethodCallHandler,EventChannel.StreamHandler, ActivityAware, NavigationListener {
class AmapServicePlugin: FlutterPlugin, MethodCallHandler,EventChannel.StreamHandler, NavigationListener {
private val TAG = "AmapServicePlugin"
private lateinit var context: Context
private lateinit var channel : MethodChannel
@ -39,8 +30,8 @@ class AmapServicePlugin: FlutterPlugin, MethodCallHandler,EventChannel.StreamHan
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "com.yunqiinnovation.amap_service/events")
eventChannel.setStreamHandler(this)
// 添加监听器
NavigationServiceStarter.addListener(this)
NavigationServiceHelper.init(context)
NavigationServiceHelper.addListener(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
@ -51,22 +42,26 @@ class AmapServicePlugin: FlutterPlugin, MethodCallHandler,EventChannel.StreamHan
val endpos = call.argument<String>("endpos")
val ntype = call.argument<String>("ntype")
if (startpos != null && endpos != null && ntype != null) {
NavigationServiceStarter.startServiceWithCommand(context, "start", startpos, endpos, ntype)
NavigationServiceHelper.startNavigation(context,startpos,endpos,ntype)
result.success(null)
} else {
result.error("INVALID_ARGUMENT", "Missing 'song' map", null)
}
}
"open" -> {
try {
NavigationServiceHelper.openNavigationUI()
}catch (e: Exception){
result.error("INVALID_ARGUMENT", "Try Exception ", e)
}
}
"stop" -> {
val songs = call.argument<List<Map<String, String>>>("songs")
if (songs != null && songs.isNotEmpty()) {
NavigationServiceStarter.startServiceWithCommand(context, "stop")
NavigationServiceHelper.stopNavigation()
result.success(null)
} else {
result.error("INVALID_ARGUMENT", "Missing or empty 'songs' list", null)
}
}
else -> result.notImplemented()
else -> {
result.notImplemented()
}
}
}
@ -99,84 +94,5 @@ class AmapServicePlugin: FlutterPlugin, MethodCallHandler,EventChannel.StreamHan
this.eventSink = null
}
private fun startNaviWithUI(lat: Double, lon: Double, name: String) {
val act = activity ?: return
// 起点坐标,这里写死了,可以改成你定位到的当前位置
val startPoint = NaviLatLng(39.909187, 116.397451)
val endPoint = NaviLatLng(lat, lon)
val startList = mutableListOf<NaviLatLng>().apply { add(startPoint) }
val endList = mutableListOf<NaviLatLng>().apply { add(endPoint) }
// 创建导航视图
aMapNaviView = AMapNaviView(act).apply {
setAMapNaviViewListener(object : AMapNaviViewListener {
override fun onNaviSetting() {
// TODO: 处理设置事件
}
override fun onNaviCancel() {
act.finish()
}
override fun onNaviBackClick(): Boolean {
act.finish()
return true // 返回true表示事件被消费
}
override fun onNaviMapMode(p0: Int) {
// TODO
}
override fun onNaviTurnClick() {
// TODO
}
override fun onNextRoadClick() {
// TODO
}
override fun onScanViewButtonClick() {
// TODO
}
override fun onLockMap(p0: Boolean) {
// TODO: 锁定地图时的处理,比如什么也不做
}
override fun onNaviViewLoaded() {
//TODO("Not yet implemented")
}
override fun onMapTypeChanged(p0: Int) {
//TODO("Not yet implemented")
}
override fun onNaviViewShowMode(p0: Int) {
//TODO("Not yet implemented")
}
})
onCreate(null)
}
// 设置导航页面为当前 Activity 的内容视图
act.setContentView(aMapNaviView, FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
))
// 启动导航(实时导航)
// aMapNavi.startNavi(NaviType.GPS)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
}
override fun onDetachedFromActivity() {
activity = null
}
}

254
local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationActivity.kt

@ -0,0 +1,254 @@
package com.yunqiinnovation.amap_service
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.amap.api.navi.AMapNavi
import com.amap.api.navi.AMapNaviListener
import com.amap.api.navi.AMapNaviView
import com.amap.api.navi.AMapNaviViewListener
import com.amap.api.navi.model.AMapCalcRouteResult
import com.amap.api.navi.model.AMapLaneInfo
import com.amap.api.navi.model.AMapModelCross
import com.amap.api.navi.model.AMapNaviCameraInfo
import com.amap.api.navi.model.AMapNaviCross
import com.amap.api.navi.model.AMapNaviLocation
import com.amap.api.navi.model.AMapNaviRouteNotifyData
import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo
import com.amap.api.navi.model.AMapServiceAreaInfo
import com.amap.api.navi.model.AimLessModeCongestionInfo
import com.amap.api.navi.model.AimLessModeStat
import com.amap.api.navi.model.NaviInfo
class NavigationActivity : AppCompatActivity(), AMapNaviListener, AMapNaviViewListener {
private lateinit var naviView: AMapNaviView
private var navi: AMapNavi? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
// 初始化导航视图
naviView = findViewById(R.id.navi_view)
naviView.onCreate(savedInstanceState)
naviView.setAMapNaviViewListener(this)
navi = NavigationService.sharedNavi
if (navi == null) {
finish() // 服务未启动,退出
return
}
navi?.addAMapNaviListener(this);
// 绑定当前 activity 到导航状态
}
override fun onResume() {
super.onResume()
naviView.onResume()
}
override fun onPause() {
super.onPause()
naviView.onPause()
}
override fun onDestroy() {
super.onDestroy()
naviView.onDestroy()
navi?.removeAMapNaviListener(this);
}
override fun onInitNaviFailure() {
// TODO("Not yet implemented")
}
override fun onInitNaviSuccess() {
// TODO("Not yet implemented")
}
override fun onStartNavi(p0: Int) {
// TODO("Not yet implemented")
}
override fun onTrafficStatusUpdate() {
// TODO("Not yet implemented")
}
override fun onLocationChange(p0: AMapNaviLocation?) {
// TODO("Not yet implemented")
}
override fun onGetNavigationText(p0: Int, p1: String?) {
// TODO("Not yet implemented")
}
override fun onGetNavigationText(p0: String?) {
// TODO("Not yet implemented")
}
override fun onEndEmulatorNavi() {
// TODO("Not yet implemented")
}
override fun onArriveDestination() {
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: Int) {
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForYaw() {
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForTrafficJam() {
// TODO("Not yet implemented")
}
override fun onArrivedWayPoint(p0: Int) {
// TODO("Not yet implemented")
}
override fun onGpsOpenStatus(p0: Boolean) {
// TODO("Not yet implemented")
}
override fun onNaviInfoUpdate(p0: NaviInfo?) {
// TODO("Not yet implemented")
}
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo>?) {
// TODO("Not yet implemented")
}
override fun updateIntervalCameraInfo(
p0: AMapNaviCameraInfo?,
p1: AMapNaviCameraInfo?,
p2: Int
) {
// TODO("Not yet implemented")
}
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo>?) {
// TODO("Not yet implemented")
}
override fun showCross(p0: AMapNaviCross?) {
// TODO("Not yet implemented")
}
override fun hideCross() {
// TODO("Not yet implemented")
}
override fun showModeCross(p0: AMapModelCross?) {
// TODO("Not yet implemented")
}
override fun hideModeCross() {
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: Array<out AMapLaneInfo>?, p1: ByteArray?, p2: ByteArray?) {
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: AMapLaneInfo?) {
// TODO("Not yet implemented")
}
override fun hideLaneInfo() {
// TODO("Not yet implemented")
}
override fun onCalculateRouteSuccess(p0: IntArray?) {
// TODO("Not yet implemented")
}
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
// TODO("Not yet implemented")
}
override fun notifyParallelRoad(p0: Int) {
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo>?) {
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
// TODO("Not yet implemented")
}
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
// TODO("Not yet implemented")
}
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
// TODO("Not yet implemented")
}
override fun onPlayRing(p0: Int) {
// TODO("Not yet implemented")
}
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
// TODO("Not yet implemented")
}
override fun onGpsSignalWeak(p0: Boolean) {
// TODO("Not yet implemented")
}
//UI事件----------------------------------------------------------------------------------------------
override fun onNaviSetting() {
// TODO("Not yet implemented")
}
override fun onNaviCancel() {
// TODO("Not yet implemented")
}
override fun onNaviBackClick(): Boolean {
// TODO("Not yet implemented")
return true
}
override fun onNaviMapMode(p0: Int) {
// TODO("Not yet implemented")
}
override fun onNaviTurnClick() {
// TODO("Not yet implemented")
}
override fun onNextRoadClick() {
// TODO("Not yet implemented")
}
override fun onScanViewButtonClick() {
// TODO("Not yet implemented")
}
override fun onLockMap(p0: Boolean) {
// TODO("Not yet implemented")
}
override fun onNaviViewLoaded() {
// TODO("Not yet implemented")
}
override fun onMapTypeChanged(p0: Int) {
// TODO("Not yet implemented")
}
override fun onNaviViewShowMode(p0: Int) {
// TODO("Not yet implemented")
}
}

479
local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationService.kt

@ -6,17 +6,14 @@ import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.util.Base64
import android.util.Log
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.amap.api.navi.AMapNavi
import com.amap.api.navi.AMapNaviListener
import com.amap.api.navi.enums.NaviType
import com.amap.api.navi.enums.PathPlanningStrategy
import com.amap.api.navi.model.AMapCalcRouteResult
import com.amap.api.navi.model.AMapLaneInfo
@ -36,7 +33,7 @@ import java.io.FileNotFoundException
import java.util.concurrent.atomic.AtomicBoolean
class NavigationService: Service() {
class NavigationService: Service(),AMapNaviListener {
companion object {
private const val TAG = "NavigationService"
@ -48,53 +45,48 @@ class NavigationService: Service() {
private var startpos: String = ""
private var endpos: String = ""
private var naviType: String? = null
private var playlist = mutableListOf<Map<String,String>>()
private var currentIndex = 0
private var lastNotificationUpdateTime = 0L
private val notificationUpdateInterval = 1000L
var instance: NavigationService? = null
var sharedNavi: AMapNavi? = null
fun isServiceRunning() = isRunning.get()
}
private lateinit var aMapNavi: AMapNavi
override fun onCreate() {
super.onCreate()
instance = this
startForegroundNotification()
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val command = intent.getStringExtra("command") ?: return START_NOT_STICKY
when (command) {
"start" -> {
try {
if (::aMapNavi.isInitialized) {
Log.w(TAG, "已有导航进行中,先停止当前导航")
aMapNavi.stopNavi()
aMapNavi.removeAMapNaviListener(naviListener)
}
startpos = intent.getStringExtra("startpos").toString()
endpos = intent.getStringExtra("endpos").toString()
naviType = intent.getStringExtra("naviType");
Log.w(TAG, "开始导航 startpos:$startpos endpos:$endpos naviType:$naviType")
// 初始化导航
aMapNavi = AMapNavi.getInstance(applicationContext)
aMapNavi.setUseInnerVoice(true)
aMapNavi.setBroadcastMode(1)
aMapNavi.addAMapNaviListener(naviListener)
}catch (e: FileNotFoundException){
Log.w("NavigationService", "Custom voice bin not found: ${e.message}")
}
}
"stop" -> {
stopNavigation();
try {
startpos = intent.getStringExtra("startpos").toString()
endpos = intent.getStringExtra("endpos").toString()
naviType = intent.getStringExtra("naviType");
Log.w(TAG, "开始导航 startpos:$startpos endpos:$endpos naviType:$naviType")
if (startpos.isEmpty() || endpos.isEmpty()) {
Log.e(TAG, "Missing start or end position")
return START_NOT_STICKY
}
initializeAMapNavi()
}catch (e: FileNotFoundException){
Log.w("NavigationService", "Custom voice bin not found: ${e.message}")
}
return START_STICKY
}
private fun initializeAMapNavi() {
try {
sharedNavi = AMapNavi.getInstance(applicationContext).apply {
setUseInnerVoice(true)
setBroadcastMode(1)
addAMapNaviListener(this@NavigationService)
}
} catch (e: Exception) {
Log.e(TAG, "初始化AMapNavi失败: ${e.message}", e)
}
}
private fun startForegroundNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
@ -151,251 +143,250 @@ class NavigationService: Service() {
val byteArray = outputStream.toByteArray()
return Base64.encodeToString(byteArray, Base64.NO_WRAP)
}
// 实现监听器,处理导航播报等
private val naviListener = object : AMapNaviListener {
override fun onInitNaviFailure() {
Log.e(TAG, "onInitNaviFailure!")
// TODO("Not yet implemented")
}
override fun onInitNaviSuccess() {
Log.e(TAG, "onInitNaviSuccess!")
// 起点
val startParts: List<String> = startpos.split(",")
val startLng = startParts[0].toDouble()
val startLat = startParts[1].toDouble()
// 终点
val endParts: List<String> = endpos.split(",")
val endLng = endParts[0].toDouble()
val endLat = endParts[1].toDouble()
val startList: MutableList<NaviLatLng> = ArrayList()
val endList: MutableList<NaviLatLng> = ArrayList()
startList.add(NaviLatLng(startLat, startLng))
endList.add(NaviLatLng(endLat, endLng))
val success = aMapNavi.calculateDriveRoute(startList, endList, null, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT);
if (!success) {
Log.e(TAG, "路径规划请求失败")
}
private fun stopNavigation() {
if (sharedNavi != null) {
sharedNavi?.stopNavi()
sharedNavi?.removeAMapNaviListener(this)
}
isRunning.set(false)
stopSelf()
}
override fun onStartNavi(p0: Int) {
Log.e(TAG, "onStartNavi!")
// TODO("Not yet implemented")
}
override fun onBind(intent: Intent?): IBinder? = null
override fun onTrafficStatusUpdate() {
Log.e(TAG, "onTrafficStatusUpdate!")
// TODO("Not yet implemented")
}
override fun onLocationChange(location: AMapNaviLocation) {
Log.e(TAG, "onLocationChange! ${location}")
// 可通过广播发送位置信息到 Flutter
}
override fun onInitNaviFailure() {
Log.e(TAG, "onInitNaviFailure!")
// TODO("Not yet implemented")
}
override fun onGetNavigationText(p0: Int, p1: String?) {
Log.e(TAG, "onGetNavigationText! $p0 $p1")
// TODO("Not yet implemented")
}
override fun onInitNaviSuccess() {
Log.e(TAG, "onInitNaviSuccess!")
// 起点
val startParts: List<String> = startpos.split(",")
val startLng = startParts[0].toDouble()
val startLat = startParts[1].toDouble()
// 终点
val endParts: List<String> = endpos.split(",")
val endLng = endParts[0].toDouble()
val endLat = endParts[1].toDouble()
val startList: MutableList<NaviLatLng> = ArrayList()
val endList: MutableList<NaviLatLng> = ArrayList()
startList.add(NaviLatLng(startLat, startLng))
endList.add(NaviLatLng(endLat, endLng))
val success = sharedNavi?.calculateDriveRoute(startList, endList, null, PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT);
if (!success!!) {
Log.e(TAG, "路径规划请求失败")
}
// TODO("Not yet implemented")
}
override fun onGetNavigationText(p0: String?) {
Log.e(TAG, "onGetNavigationText! $p0")
// TODO("Not yet implemented")
}
override fun onStartNavi(p0: Int) {
Log.e(TAG, "onStartNavi! $p0")
// TODO("Not yet implemented")
}
override fun onEndEmulatorNavi() {
// Log.e(TAG, "onEndEmulatorNavi! ")
Log.e(TAG, "onEndEmulatorNavi!")
stopNavigation()
// TODO("Not yet implemented")
}
override fun onTrafficStatusUpdate() {
Log.e(TAG, "onTrafficStatusUpdate!")
// TODO("Not yet implemented")
}
override fun onArriveDestination() {
Log.e(TAG, "onArriveDestination!")
stopNavigation()
// TODO("Not yet implemented")
}
override fun onLocationChange(p0: AMapNaviLocation?) {
Log.e(TAG, "onLocationChange! $p0")
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: Int) {
Log.e(TAG, "路径规划失败, 错误码: $p0")
// TODO: 可添加反馈机制给 Flutter 层或用户提示
}
override fun onGetNavigationText(p0: Int, p1: String?) {
Log.e(TAG, "onGetNavigationText! $p0 $p1")
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
Log.e(TAG, "onCalculateRouteFailure! ${p0}")
// TODO("Not yet implemented")
}
override fun onGetNavigationText(p0: String?) {
Log.e(TAG, "onGetNavigationText! $p0")
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForYaw() {
Log.e(TAG, "onReCalculateRouteForYaw!")
// TODO("Not yet implemented")
}
override fun onEndEmulatorNavi() {
Log.e(TAG, "onEndEmulatorNavi!")
stopNavigation()
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForTrafficJam() {
Log.e(TAG, "onReCalculateRouteForTrafficJam!")
// TODO("Not yet implemented")
}
override fun onArriveDestination() {
Log.e(TAG, "onArriveDestination!")
stopNavigation()
// TODO("Not yet implemented")
}
override fun onArrivedWayPoint(p0: Int) {
Log.e(TAG, "onArrivedWayPoint!")
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: Int) {
Log.e(TAG, "onCalculateRouteFailure! $p0")
// TODO("Not yet implemented")
}
override fun onGpsOpenStatus(p0: Boolean) {
Log.e(TAG, "onGpsOpenStatus!")
// TODO("Not yet implemented")
}
private var lastNotificationUpdateTime = 0L
private val notificationUpdateInterval = 1000L // 1秒
override fun onNaviInfoUpdate(naviInfo: NaviInfo?) {
if (naviInfo == null) return
val currentTime = System.currentTimeMillis()
if (currentTime - lastNotificationUpdateTime < notificationUpdateInterval) {
// 距离上次更新不足1秒,跳过这次更新
return
}
val directionBitmap = naviInfo.iconBitmap
val currentRoad = naviInfo.currentRoadName
val nextRoad = naviInfo.nextRoadName
val remainingDistance = naviInfo.getCurStepRetainDistance()
val remainingTime = naviInfo.getPathRetainTime()
val distanceText = if (remainingDistance < 1000) {
"${remainingDistance} 米"
} else {
String.format("%.1f 千米", remainingDistance / 1000.0)
}
val contentText = "$distanceText \n进入:$nextRoad"
val directionBitmapBase64 = bitmapToBase64(directionBitmap)
val naviInfoMap: Map<String, Any> = mapOf(
"currentRoad" to currentRoad,
"nextRoad" to nextRoad,
"distanceText" to distanceText,
"directionIcon" to (directionBitmapBase64 ?: "")
)
NavigationServiceStarter.sendEvent("amap_update",naviInfoMap)
updateNotification(contentText, directionBitmap)
Log.e(TAG, "onNaviInfoUpdate! $contentText")
// Log.e(TAG, "onNaviInfoUpdate! $p0")
// TODO("Not yet implemented")
}
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) {
Log.e(TAG, "onCalculateRouteFailure! $p0")
// TODO("Not yet implemented")
}
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo>?) {
Log.e(TAG, "updateCameraInfo! $p0")
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForYaw() {
Log.e(TAG, "onReCalculateRouteForYaw!")
// TODO("Not yet implemented")
}
override fun updateIntervalCameraInfo(
p0: AMapNaviCameraInfo?,
p1: AMapNaviCameraInfo?,
p2: Int
) {
Log.e(TAG, "updateIntervalCameraInfo! $p0")
// TODO("Not yet implemented")
}
override fun onReCalculateRouteForTrafficJam() {
Log.e(TAG, "onReCalculateRouteForTrafficJam!")
// TODO("Not yet implemented")
}
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo>?) {
Log.e(TAG, "onServiceAreaUpdate! $p0")
// TODO("Not yet implemented")
}
override fun onArrivedWayPoint(p0: Int) {
Log.e(TAG, "onArrivedWayPoint! $p0")
// TODO("Not yet implemented")
}
override fun showCross(p0: AMapNaviCross?) {
Log.e(TAG, "showCross! $p0")
// TODO("Not yet implemented")
}
override fun onGpsOpenStatus(p0: Boolean) {
Log.e(TAG, "onGpsOpenStatus! $p0")
// TODO("Not yet implemented")
}
override fun hideCross() {
Log.e(TAG, "hideCross!")
// TODO("Not yet implemented")
}
override fun onNaviInfoUpdate(naviInfo: NaviInfo?) {
Log.e(TAG, "onNaviInfoUpdate! $naviInfo")
if (naviInfo == null) return
val currentTime = System.currentTimeMillis()
if (currentTime - lastNotificationUpdateTime < notificationUpdateInterval) {
// 距离上次更新不足1秒,跳过这次更新
return
}
val directionBitmap = naviInfo.iconBitmap
val currentRoad = naviInfo.currentRoadName
val nextRoad = naviInfo.nextRoadName
val remainingDistance = naviInfo.getCurStepRetainDistance()
val remainingTime = naviInfo.getPathRetainTime()
val distanceText = if (remainingDistance < 1000) {
"${remainingDistance} 米"
} else {
String.format("%.1f 千米", remainingDistance / 1000.0)
}
val contentText = "$distanceText \n进入:$nextRoad"
val directionBitmapBase64 = bitmapToBase64(directionBitmap)
val naviInfoMap: Map<String, Any> = mapOf(
"currentRoad" to currentRoad,
"nextRoad" to nextRoad,
"distanceText" to distanceText,
"directionIcon" to (directionBitmapBase64 ?: "")
)
NavigationServiceHelper.sendEvent("amap_update",naviInfoMap)
updateNotification(contentText, directionBitmap)
Log.e(TAG, "onNaviInfoUpdate! $contentText")
// TODO("Not yet implemented")
}
override fun showModeCross(p0: AMapModelCross?) {
Log.e(TAG, "showModeCross! $p0")
// TODO("Not yet implemented")
}
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo>?) {
Log.e(TAG, "updateCameraInfo! $p0")
// TODO("Not yet implemented")
}
override fun hideModeCross() {
Log.e(TAG, "hideModeCross!")
// TODO("Not yet implemented")
}
override fun updateIntervalCameraInfo(
p0: AMapNaviCameraInfo?,
p1: AMapNaviCameraInfo?,
p2: Int
) {
Log.e(TAG, "updateIntervalCameraInfo! $p0 $p1 $p2")
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: Array<out AMapLaneInfo>?, p1: ByteArray?, p2: ByteArray?) {
Log.e(TAG, "showLaneInfo! $p0")
// TODO("Not yet implemented")
}
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo>?) {
Log.e(TAG, "onServiceAreaUpdate! $p0")
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: AMapLaneInfo?) {
Log.e(TAG, "showLaneInfo! $p0")
// TODO("Not yet implemented")
}
override fun showCross(p0: AMapNaviCross?) {
Log.e(TAG, "showCross!")
// TODO("Not yet implemented")
}
override fun hideLaneInfo() {
Log.e(TAG, "hideLaneInfo!")
// TODO("Not yet implemented")
}
override fun hideCross() {
Log.e(TAG, "hideCross!")
// TODO("Not yet implemented")
}
override fun onCalculateRouteSuccess(ids: IntArray?) {
Log.e(TAG, "onCalculateRouteSuccess! $ids")
// AMapNavi.getInstance(this).startNavi(1);
aMapNavi.startNavi(2)
}
override fun showModeCross(p0: AMapModelCross?) {
Log.e(TAG, "showModeCross! $p0")
// TODO("Not yet implemented")
}
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
Log.e(TAG, "onCalculateRouteSuccess! $p0")
// TODO("Not yet implemented")
}
override fun hideModeCross() {
Log.e(TAG, "hideModeCross!")
// TODO("Not yet implemented")
}
override fun notifyParallelRoad(p0: Int) {
Log.d(TAG, "是否在拥挤平行路段: $p0")
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: Array<out AMapLaneInfo>?, p1: ByteArray?, p2: ByteArray?) {
Log.e(TAG, "showLaneInfo! $p0 $p1 $p2")
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo>?) {
Log.d(TAG, "OnUpdateTrafficFacility: $p0")
// TODO("Not yet implemented")
}
override fun showLaneInfo(p0: AMapLaneInfo?) {
Log.e(TAG, "showLaneInfo! $p0")
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
Log.d(TAG, "OnUpdateTrafficFacility: $p0")
// TODO("Not yet implemented")
}
override fun hideLaneInfo() {
Log.e(TAG, "hideLaneInfo!")
// TODO("Not yet implemented")
}
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
// TODO("Not yet implemented")
Log.d(TAG, "updateAimlessModeStatistics: $p0")
}
override fun onCalculateRouteSuccess(p0: IntArray?) {
Log.e(TAG, "onCalculateRouteSuccess! $p0")
sharedNavi?.startNavi(2);
// TODO("Not yet implemented")
}
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
// TODO("Not yet implemented")
Log.d(TAG, "updateAimlessModeCongestionInfo: $p0")
}
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) {
sharedNavi?.startNavi(2);
Log.e(TAG, "onCalculateRouteSuccess! $p0")
// TODO("Not yet implemented")
}
override fun onPlayRing(p0: Int) {
Log.d(TAG, "onPlayRing: $p0")
// TODO("Not yet implemented")
}
override fun notifyParallelRoad(p0: Int) {
Log.e(TAG, "notifyParallelRoad! $p0")
// TODO("Not yet implemented")
}
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
Log.w(TAG, "GPS信号弱")
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo>?) {
Log.e(TAG, "OnUpdateTrafficFacility! $p0")
// TODO("Not yet implemented")
}
override fun onGpsSignalWeak(p0: Boolean) {
Log.w(TAG, "GPS信号弱")
// TODO("Not yet implemented")
}
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) {
Log.e(TAG, "OnUpdateTrafficFacility! $p0")
// TODO("Not yet implemented")
}
private fun stopNavigation() {
if (::aMapNavi.isInitialized) {
aMapNavi.stopNavi()
aMapNavi.removeAMapNaviListener(naviListener)
}
isRunning.set(false)
stopSelf()
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) {
Log.e(TAG, "updateAimlessModeStatistics! $p0")
// TODO("Not yet implemented")
}
override fun onBind(intent: Intent?): IBinder? = null
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) {
Log.e(TAG, "updateAimlessModeCongestionInfo! $p0")
// TODO("Not yet implemented")
}
override fun onPlayRing(p0: Int) {
Log.e(TAG, "onPlayRing! $p0")
// TODO("Not yet implemented")
}
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) {
Log.e(TAG, "onNaviRouteNotify! $p0")
// TODO("Not yet implemented")
}
override fun onGpsSignalWeak(p0: Boolean) {
Log.e(TAG, "onGpsSignalWeak! $p0")
// TODO("Not yet implemented")
}
}

47
local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationServiceStarter.kt → local_plugins/amap_service/android/src/main/kotlin/com/yunqiinnovation/amap_service/NavigationServiceHelper.kt

@ -6,7 +6,6 @@ import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.core.content.ContextCompat
import com.yunqiinnovation.amap_service.NavigationService.Companion
import java.util.Collections
/**
@ -22,34 +21,34 @@ interface NavigationListener {
fun onEvent(eventName: String, data: Map<String, Any>)
}
object NavigationServiceStarter {
object NavigationServiceHelper {
private val TAG = "NavigationServiceStarter"
private lateinit var context: Context
private val listeners = Collections.synchronizedSet(mutableSetOf<NavigationListener>())
//播放单曲
fun startServiceWithCommand(context: Context, command: String, startpos: String? = null, endpos: String? = null, ntype: String? = null) {
Log.i(TAG, "liwei------------------- startServiceWithCommand: $command $startpos $endpos $ntype")
fun init(appContext: Context) {
context = appContext
}
//启动导航
fun startNavigation(context: Context, startpos: String? = null, endpos: String? = null, ntype: String? = null) {
Log.i(TAG, "liwei------------------- startNavigation: $startpos $endpos $ntype")
val intent = Intent(context, NavigationService::class.java).apply {
putExtra("command", command)
startpos?.let {
putExtra("startpos",it) // 只有非 null 时才 putExtra
}
endpos?.let {
putExtra("endpos", it) // 只有非 null 时才 putExtra
}
ntype?.let {
putExtra("ntype",it) // 只有非 null 时才 putExtra
}
putExtra("startpos", startpos)
putExtra("endpos", endpos)
putExtra("ntype", ntype)
}
val success = try {
ContextCompat.startForegroundService(context, intent)
true
} catch (e: Exception) {
Log.e(TAG, "liwei------------------- Failed to start service", e)
false
}
Log.d(TAG, "liwei------------------- Service start success: $success")
context.startForegroundService(intent)
}
//停止导航
fun stopNavigation() {
val intent = Intent(context, NavigationService::class.java)
context.stopService(intent)
}
//打开导航页面
fun openNavigationUI() {
val intent = Intent(context, NavigationActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
/**
* 添加事件监听器

10
local_plugins/amap_service/android/src/main/res/layout/activity_navigation.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.amap.api.navi.AMapNaviView
android:id="@+id/navi_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

5
local_plugins/amap_service/android/src/main/res/values/colors.xml

@ -12,4 +12,9 @@
<color name="red_500">#F44336</color>
<color name="green_500">#4CAF50</color>
<color name="blue_500">#2196F3</color>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>

9
local_plugins/amap_service/android/src/main/res/values/styles.xml

@ -0,0 +1,9 @@
<resources>
<!-- 基础应用主题 -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- 自定义主题属性 -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

174
local_plugins/amap_service/lib/amap_controller.dart

@ -1,174 +0,0 @@
part of amap_service_map;
final MethodChannelAMapFlutterMap _methodChannel =
AMapFlutterPlatform.instance as MethodChannelAMapFlutterMap;
/// 地图通信中心
class AMapController {
final int mapId;
final _MapState _mapState;
AMapController._(
CameraPosition initCameraPosition,
this._mapState, {
required this.mapId,
}) {
_connectStreams(mapId);
}
///根据传入的id初始化[AMapController]
/// 主要用于在[AMapWidget]初始化时在[AMapWidget.onMapCreated]中初始化controller
static Future<AMapController> init(
int id,
CameraPosition initialCameration,
_MapState mapState,
) async {
await _methodChannel.init(id);
return AMapController._(initialCameration, mapState, mapId: id);
}
///只用于测试
///用于与native的通信
@visibleForTesting
MethodChannel get channel {
return _methodChannel.channel(mapId);
}
void _connectStreams(int mapId) {
if (_mapState.widget.onLocationChanged != null) {
_methodChannel
.onLocationChanged(mapId: mapId)
.listen(
(LocationChangedEvent e) =>
_mapState.widget.onLocationChanged!(e.value),
);
}
if (_mapState.widget.onCameraMove != null) {
_methodChannel
.onCameraMove(mapId: mapId)
.listen(
(CameraPositionMoveEvent e) =>
_mapState.widget.onCameraMove!(e.value),
);
}
if (_mapState.widget.onCameraMoveEnd != null) {
_methodChannel
.onCameraMoveEnd(mapId: mapId)
.listen(
(CameraPositionMoveEndEvent e) =>
_mapState.widget.onCameraMoveEnd!(e.value),
);
}
if (_mapState.widget.onTap != null) {
_methodChannel
.onMapTap(mapId: mapId)
.listen(((MapTapEvent e) => _mapState.widget.onTap!(e.value)));
}
if (_mapState.widget.onLongPress != null) {
_methodChannel
.onMapLongPress(mapId: mapId)
.listen(
((MapLongPressEvent e) => _mapState.widget.onLongPress!(e.value)),
);
}
if (_mapState.widget.onPoiTouched != null) {
_methodChannel
.onPoiTouched(mapId: mapId)
.listen(
((MapPoiTouchEvent e) => _mapState.widget.onPoiTouched!(e.value)),
);
}
_methodChannel
.onMarkerTap(mapId: mapId)
.listen((MarkerTapEvent e) => _mapState.onMarkerTap(e.value));
_methodChannel
.onMarkerDragEnd(mapId: mapId)
.listen(
(MarkerDragEndEvent e) =>
_mapState.onMarkerDragEnd(e.value, e.position),
);
_methodChannel
.onPolylineTap(mapId: mapId)
.listen((PolylineTapEvent e) => _mapState.onPolylineTap(e.value));
}
void disponse() {
_methodChannel.dispose(id: mapId);
}
Future<void> _updateMapOptions(Map<String, dynamic> optionsUpdate) {
return _methodChannel.updateMapOptions(optionsUpdate, mapId: mapId);
}
Future<void> _updateMarkers(MarkerUpdates markerUpdates) {
return _methodChannel.updateMarkers(markerUpdates, mapId: mapId);
}
Future<void> _updatePolylines(PolylineUpdates polylineUpdates) {
return _methodChannel.updatePolylines(polylineUpdates, mapId: mapId);
}
Future<void> _updatePolygons(PolygonUpdates polygonUpdates) {
return _methodChannel.updatePolygons(polygonUpdates, mapId: mapId);
}
///改变地图视角
///
///通过[CameraUpdate]对象设置新的中心点、缩放比例、放大缩小、显示区域等内容
///
///(注意:iOS端设置显示区域时,不支持duration参数,动画时长使用iOS地图默认值350毫秒)
///
///可选属性[animated]用于控制是否执行动画移动
///
///可选属性[duration]用于控制执行动画的时长,默认250毫秒,单位:毫秒
Future<void> moveCamera(
CameraUpdate cameraUpdate, {
bool animated = true,
int duration = 250,
}) {
return _methodChannel.moveCamera(
cameraUpdate,
mapId: mapId,
animated: animated,
duration: duration,
);
}
///设置地图每秒渲染的帧数
Future<void> setRenderFps(int fps) {
return _methodChannel.setRenderFps(fps, mapId: mapId);
}
///地图截屏
Future<Uint8List?> takeSnapshot() {
return _methodChannel.takeSnapshot(mapId: mapId);
}
/// 获取地图审图号(普通地图)
///
/// 任何使用高德地图API调用地图服务的应用必须在其应用中对外透出审图号
///
/// 如高德地图在"关于"中体现
Future<String?> getMapContentApprovalNumber() {
return _methodChannel.getMapContentApprovalNumber(mapId: mapId);
}
/// 获取地图审图号(卫星地图)
///
/// 任何使用高德地图API调用地图服务的应用必须在其应用中对外透出审图号
///
/// 如高德地图在"关于"中体现
Future<String?> getSatelliteImageApprovalNumber() {
return _methodChannel.getSatelliteImageApprovalNumber(mapId: mapId);
}
/// 清空缓存
Future<void> clearDisk() {
return _methodChannel.clearDisk(mapId: mapId);
}
}

12
local_plugins/amap_service/lib/amap_service.dart

@ -94,8 +94,16 @@ class AmapService {
}
}
Future<void> show() async {
await _methodChannel.invokeMethod('show');
Future<void> start() async {
await _methodChannel.invokeMethod('start');
}
Future<void> open() async {
await _methodChannel.invokeMethod('open');
}
Future<void> stop() async {
await _methodChannel.invokeMethod('stop');
}
// 销毁

20
local_plugins/amap_service/lib/amap_service_map.dart

@ -1,20 +0,0 @@
/// 高德地图Flutter插件入口文件
library amap_service_map;
import 'dart:async';
import 'dart:typed_data';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_map/src/core/amap_flutter_platform.dart';
import 'package:amap_flutter_map/src/core/map_event.dart';
import 'package:amap_flutter_map/src/core/method_channel_amap_flutter_map.dart';
import 'package:amap_flutter_map/src/types/types.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
export 'package:amap_flutter_map/src/types/types.dart';
part 'amap_controller.dart';
part 'amap_widget.dart';

425
local_plugins/amap_service/lib/amap_widget.dart

@ -1,425 +0,0 @@
part of amap_service_map;
typedef void MapCreatedCallback(AMapController controller);
///用于展示高德地图的Widget
class AMapWidget extends StatefulWidget {
///高德开放平台的key
///
final AMapApiKey? apiKey;
/// 初始化时的地图中心点
final CameraPosition initialCameraPosition;
///地图类型
final MapType mapType;
///自定义地图样式
final CustomStyleOptions? customStyleOptions;
///定位小蓝点
final MyLocationStyleOptions? myLocationStyleOptions;
///缩放级别范围
final MinMaxZoomPreference? minMaxZoomPreference;
///地图显示范围
final LatLngBounds? limitBounds;
///显示路况开关
final bool trafficEnabled;
/// 地图poi是否允许点击
final bool touchPoiEnabled;
///是否显示3D建筑物
final bool buildingsEnabled;
///是否显示底图文字标注
final bool labelsEnabled;
///是否显示指南针
final bool compassEnabled;
///是否显示比例尺
final bool scaleEnabled;
///是否支持缩放手势
final bool zoomGesturesEnabled;
///是否支持滑动手势
final bool scrollGesturesEnabled;
///是否支持旋转手势
final bool rotateGesturesEnabled;
///是否支持倾斜手势
final bool tiltGesturesEnabled;
/// 地图上显示的Marker
final Set<Marker> markers;
/// 地图上显示的polyline
final Set<Polyline> polylines;
/// 地图上显示的polygon
final Set<Polygon> polygons;
/// 地图创建成功的回调, 收到此回调之后才可以操作地图
final MapCreatedCallback? onMapCreated;
/// 相机视角持续移动的回调
final ArgumentCallback<CameraPosition>? onCameraMove;
/// 相机视角移动结束的回调
final ArgumentCallback<CameraPosition>? onCameraMoveEnd;
/// 地图单击事件的回调
final ArgumentCallback<LatLng>? onTap;
/// 地图长按事件的回调
final ArgumentCallback<LatLng>? onLongPress;
/// 地图POI的点击回调,需要`touchPoiEnabled`true,才能回调
final ArgumentCallback<AMapPoi>? onPoiTouched;
///位置回调
final ArgumentCallback<AMapLocation>? onLocationChanged;
///需要应用到地图上的手势集合
final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers;
///高德合规声明配置
///
/// 高德SDK合规使用方案请参考:https://lbs.amap.com/news/sdkhgsy
final AMapPrivacyStatement? privacyStatement;
/// 创建一个展示高德地图的widget
///
/// 如果使用的高德地图SDK的版本是8.1.0及以上版本,
/// 在app首次启动时必须传入高德合规声明配置[privacyStatement],后续如果没有变化不需要重复设置
/// <li>[privacyStatement.hasContains] 隐私权政策是否包含高德开平隐私权政策</li>
/// <li>[privacyStatement.hasShow] 是否已经弹窗展示给用户</li>
/// <li>[privacyStatement.hasAgree] 隐私权政策是否已经取得用户同意</li>
/// 以上三个值,任何一个为false都会造成地图插件不工作(白屏情况)
///
/// 高德SDK合规使用方案请参考:https://lbs.amap.com/news/sdkhgsy
///
/// [AssertionError] will be thrown if [initialCameraPosition] is null;
const AMapWidget({
Key? key,
this.privacyStatement,
this.apiKey,
this.initialCameraPosition = const CameraPosition(
target: LatLng(39.909187, 116.397451),
zoom: 10,
),
this.mapType = MapType.normal,
this.buildingsEnabled = true,
this.compassEnabled = false,
this.labelsEnabled = true,
this.limitBounds,
this.minMaxZoomPreference,
this.rotateGesturesEnabled = true,
this.scaleEnabled = true,
this.scrollGesturesEnabled = true,
this.tiltGesturesEnabled = true,
this.touchPoiEnabled = true,
this.trafficEnabled = false,
this.zoomGesturesEnabled = true,
this.onMapCreated,
this.gestureRecognizers = const <Factory<OneSequenceGestureRecognizer>>{},
this.customStyleOptions,
this.myLocationStyleOptions,
this.onCameraMove,
this.onCameraMoveEnd,
this.onLocationChanged,
this.onTap,
this.onLongPress,
this.onPoiTouched,
this.markers = const <Marker>{},
this.polylines = const <Polyline>{},
this.polygons = const <Polygon>{},
}) : super(key: key);
///
@override
State<StatefulWidget> createState() => _MapState();
}
class _MapState extends State<AMapWidget> {
Map<String, Marker> _markers = <String, Marker>{};
Map<String, Polyline> _polylines = <String, Polyline>{};
Map<String, Polygon> _polygons = <String, Polygon>{};
final Completer<AMapController> _controller = Completer<AMapController>();
late _AMapOptions _mapOptions;
@override
Widget build(BuildContext context) {
AMapUtil.init(context);
final Map<String, dynamic> creationParams = <String, dynamic>{
'privacyStatement': widget.privacyStatement?.toMap(),
'apiKey': widget.apiKey?.toMap(),
'initialCameraPosition': widget.initialCameraPosition.toMap(),
'options': _mapOptions.toMap(),
'markersToAdd': serializeOverlaySet(widget.markers),
'polylinesToAdd': serializeOverlaySet(widget.polylines),
'polygonsToAdd': serializeOverlaySet(widget.polygons),
};
Widget mapView = _methodChannel.buildView(
creationParams,
widget.gestureRecognizers,
onPlatformViewCreated,
);
return mapView;
}
@override
void initState() {
super.initState();
_mapOptions = _AMapOptions.fromWidget(widget);
_markers = keyByMarkerId(widget.markers);
_polygons = keyByPolygonId(widget.polygons);
_polylines = keyByPolylineId(widget.polylines);
print('initState AMapWidget');
}
@override
void dispose() async {
super.dispose();
AMapController controller = await _controller.future;
controller.disponse();
print('dispose AMapWidget with mapId: ${controller.mapId}');
}
@override
void reassemble() {
super.reassemble();
print('reassemble AMapWidget');
}
@override
void deactivate() async {
super.deactivate();
print('deactivate AMapWidget}');
}
@override
void didUpdateWidget(covariant AMapWidget oldWidget) {
super.didUpdateWidget(oldWidget);
_updateOptions();
_updateMarkers();
_updatePolylines();
_updatePolygons();
}
Future<void> onPlatformViewCreated(int id) async {
final AMapController controller = await AMapController.init(
id,
widget.initialCameraPosition,
this,
);
_controller.complete(controller);
final MapCreatedCallback? _onMapCreated = widget.onMapCreated;
if (_onMapCreated != null) {
_onMapCreated(controller);
}
}
void onMarkerTap(String markerId) {
final Marker? _marker = _markers[markerId];
if (_marker != null) {
final ArgumentCallback<String>? _onTap = _marker.onTap;
if (_onTap != null) {
_onTap(markerId);
}
}
}
void onMarkerDragEnd(String markerId, LatLng position) {
final Marker? _marker = _markers[markerId];
if (_marker != null) {
final MarkerDragEndCallback? _onDragEnd = _marker.onDragEnd;
if (_onDragEnd != null) {
_onDragEnd(markerId, position);
}
}
}
void onPolylineTap(String polylineId) {
final Polyline? _polyline = _polylines[polylineId];
if (_polyline != null) {
final ArgumentCallback<String>? _onTap = _polyline.onTap;
if (_onTap != null) {
_onTap(polylineId);
}
}
}
void _updateOptions() async {
final _AMapOptions newOptions = _AMapOptions.fromWidget(widget);
final Map<String, dynamic> updates = _mapOptions._updatesMap(newOptions);
if (updates.isEmpty) {
return;
}
final AMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateMapOptions(updates);
_mapOptions = newOptions;
}
void _updateMarkers() async {
final AMapController controller = await _controller.future;
// ignore: unawaited_futures
controller._updateMarkers(
MarkerUpdates.from(_markers.values.toSet(), widget.markers),
);
_markers = keyByMarkerId(widget.markers);
}
void _updatePolylines() async {
final AMapController controller = await _controller.future;
controller._updatePolylines(
PolylineUpdates.from(_polylines.values.toSet(), widget.polylines),
);
_polylines = keyByPolylineId(widget.polylines);
}
void _updatePolygons() async {
final AMapController controller = await _controller.future;
controller._updatePolygons(
PolygonUpdates.from(_polygons.values.toSet(), widget.polygons),
);
_polygons = keyByPolygonId(widget.polygons);
}
}
//高德地图参数设置
class _AMapOptions {
///地图类型
final MapType mapType;
///自定义地图样式
final CustomStyleOptions? customStyleOptions;
///定位小蓝点
final MyLocationStyleOptions? myLocationStyleOptions;
//缩放级别范围
final MinMaxZoomPreference? minMaxZoomPreference;
///地图显示范围
final LatLngBounds? limitBounds;
///显示路况开关
final bool? trafficEnabled;
/// 地图poi是否允许点击
final bool? touchPoiEnabled;
///是否显示3D建筑物
final bool? buildingsEnabled;
///是否显示底图文字标注
final bool? labelsEnabled;
///是否显示指南针
final bool? compassEnabled;
///是否显示比例尺
final bool? scaleEnabled;
///是否支持缩放手势
final bool? zoomGesturesEnabled;
///是否支持滑动手势
final bool? scrollGesturesEnabled;
///是否支持旋转手势
final bool? rotateGesturesEnabled;
///是否支持仰角手势
final bool? tiltGesturesEnabled;
_AMapOptions({
this.mapType = MapType.normal,
this.buildingsEnabled,
this.customStyleOptions,
this.myLocationStyleOptions,
this.compassEnabled,
this.labelsEnabled,
this.limitBounds,
this.minMaxZoomPreference,
this.scaleEnabled,
this.touchPoiEnabled,
this.trafficEnabled,
this.rotateGesturesEnabled,
this.scrollGesturesEnabled,
this.tiltGesturesEnabled,
this.zoomGesturesEnabled,
});
static _AMapOptions fromWidget(AMapWidget map) {
return _AMapOptions(
mapType: map.mapType,
buildingsEnabled: map.buildingsEnabled,
compassEnabled: map.compassEnabled,
labelsEnabled: map.labelsEnabled,
limitBounds: map.limitBounds,
minMaxZoomPreference: map.minMaxZoomPreference,
scaleEnabled: map.scaleEnabled,
touchPoiEnabled: map.touchPoiEnabled,
trafficEnabled: map.trafficEnabled,
rotateGesturesEnabled: map.rotateGesturesEnabled,
scrollGesturesEnabled: map.scrollGesturesEnabled,
tiltGesturesEnabled: map.tiltGesturesEnabled,
zoomGesturesEnabled: map.zoomGesturesEnabled,
customStyleOptions: map.customStyleOptions?.clone(),
myLocationStyleOptions: map.myLocationStyleOptions?.clone(),
);
}
Map<String, dynamic> toMap() {
final Map<String, dynamic> optionsMap = <String, dynamic>{};
void addIfNonNull(String fieldName, dynamic value) {
if (value != null) {
optionsMap[fieldName] = value;
}
}
addIfNonNull('mapType', mapType.index);
addIfNonNull('buildingsEnabled', buildingsEnabled);
addIfNonNull('customStyleOptions', customStyleOptions?.clone().toMap());
addIfNonNull('compassEnabled', compassEnabled);
addIfNonNull('labelsEnabled', labelsEnabled);
addIfNonNull('limitBounds', limitBounds?.toJson());
addIfNonNull('minMaxZoomPreference', minMaxZoomPreference?.toJson());
addIfNonNull('scaleEnabled', scaleEnabled);
addIfNonNull('touchPoiEnabled', touchPoiEnabled);
addIfNonNull('trafficEnabled', trafficEnabled);
addIfNonNull('rotateGesturesEnabled', rotateGesturesEnabled);
addIfNonNull('scrollGesturesEnabled', scrollGesturesEnabled);
addIfNonNull('tiltGesturesEnabled', tiltGesturesEnabled);
addIfNonNull('zoomGesturesEnabled', zoomGesturesEnabled);
addIfNonNull('myLocationStyle', myLocationStyleOptions?.clone().toMap());
return optionsMap;
}
Map<String, dynamic> _updatesMap(_AMapOptions newOptions) {
final Map<String, dynamic> prevOptionsMap = toMap();
return newOptions.toMap()..removeWhere(
(String key, dynamic value) =>
(_checkChange(key, prevOptionsMap[key], value)),
);
}
bool _checkChange(String key, dynamic preValue, dynamic newValue) {
if (key == 'myLocationStyle' || key == 'customStyleOptions') {
return preValue?.toString() == newValue?.toString();
} else {
return preValue == newValue;
}
}
}

41
local_plugins/amap_service/lib/core/amap_flutter_platform.dart

@ -1,41 +0,0 @@
import 'package:amap_flutter_map/src/core/method_channel_amap_flutter_map.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
/// “amap_flutter_map”平台特定实现必须扩展的接口
abstract class AMapFlutterPlatform extends PlatformInterface {
static final Object _token = Object();
AMapFlutterPlatform() : super(token: _token);
static AMapFlutterPlatform _instance = MethodChannelAMapFlutterMap() as AMapFlutterPlatform;
/// The default instance of [AMapFlutterPlatform] to use.
///
/// Defaults to [MethodChannelAMapFlutterMap].
static AMapFlutterPlatform get instance => _instance;
static set instance(AMapFlutterPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
/// /// Initializes the platform interface with [id].
///
/// This method is called when the plugin is first initialized.
Future<void> init(int id) {
throw UnimplementedError('init() has not been implemented.');
}
void dispose({required int id}) {
throw UnimplementedError('dispose() has not been implemented.');
}
Widget buildView(
Map<String, dynamic> creationParams,
Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
PlatformViewCreatedCallback onPlatformViewCreated) {
throw UnimplementedError('buildView() has not been implemented.');
}
}

77
local_plugins/amap_service/lib/core/map_event.dart

@ -1,77 +0,0 @@
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_map/amap_flutter_map.dart';
///地图事件处理
class MapEvent<T> {
/// 地图id
final int mapId;
///返回的内容,对应的[MethodCall]中的[[arguments]]
final T value;
/// 构造一个event
///
/// `mapId` 当前地图的id
/// `value` 需要传输的值,可以为`null`.
MapEvent(this.mapId, this.value);
}
///定位回调接口
class LocationChangedEvent extends MapEvent<AMapLocation> {
LocationChangedEvent(int mapId, AMapLocation value) : super(mapId, value);
}
///地图移动回调
class CameraPositionMoveEvent extends MapEvent<CameraPosition> {
CameraPositionMoveEvent(int mapId, CameraPosition value)
: super(mapId, value);
}
///地图移动结束回调
class CameraPositionMoveEndEvent extends MapEvent<CameraPosition> {
CameraPositionMoveEndEvent(int mapId, CameraPosition value)
: super(mapId, value);
}
///点击地图回调
class MapTapEvent extends MapEvent<LatLng> {
MapTapEvent(int mapId, LatLng value) : super(mapId, value);
}
///长按地图回调
class MapLongPressEvent extends MapEvent<LatLng> {
MapLongPressEvent(int mapId, LatLng value) : super(mapId, value);
}
/// 带位置回调的地图事件
class _PositionedMapEvent<T> extends MapEvent<T> {
/// 事件中带的位置信息
final LatLng position;
/// 构造一个带位置的地图事件,
///
/// `mapId` 当前地图的id
/// `value` 需要传输的值,可以为`null`.
_PositionedMapEvent(int mapId, this.position, T value) : super(mapId, value);
}
/// [Marker] 的点击事件
class MarkerTapEvent extends MapEvent<String> {
MarkerTapEvent(int mapId, String markerId) : super(mapId, markerId);
}
/// [Marker] 的拖拽结束事件,附带拖拽结束时的位置信息[LatLng].
class MarkerDragEndEvent extends _PositionedMapEvent<String> {
MarkerDragEndEvent(int mapId, LatLng position, String markerId)
: super(mapId, position, markerId);
}
/// [Polyline] 的点击事件
class PolylineTapEvent extends MapEvent<String> {
PolylineTapEvent(int mapId, String polylineId) : super(mapId, polylineId);
}
/// Poi点击事件
class MapPoiTouchEvent extends MapEvent<AMapPoi> {
MapPoiTouchEvent(int mapId, AMapPoi poi) : super(mapId, poi);
}

274
local_plugins/amap_service/lib/core/method_channel_amap_flutter_map.dart

@ -1,274 +0,0 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_map/src/core/amap_flutter_platform.dart';
import 'package:amap_flutter_map/src/types/types.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:stream_transform/stream_transform.dart';
import 'map_event.dart';
const VIEW_TYPE = 'com.amap.flutter.map';
/// 使用[MethodChannel]与Native代码通信的[AMapFlutterPlatform]的实现。
class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
final Map<int, MethodChannel> _channels = {};
MethodChannel channel(int mapId) {
return _channels[mapId]!;
}
@override
Future<void> init(int mapId) {
MethodChannel? channel = _channels[mapId];
if (channel == null) {
channel = MethodChannel('amap_flutter_map_$mapId');
channel.setMethodCallHandler((call) => _handleMethodCall(call, mapId));
_channels[mapId] = channel;
}
return channel.invokeMethod<void>('map#waitForMap');
}
///更新地图参数
Future<void> updateMapOptions(
Map<String, dynamic> newOptions, {
required int mapId,
}) {
return channel(mapId).invokeMethod<void>(
'map#update',
<String, dynamic>{
'options': newOptions,
},
);
}
/// 更新Marker的数据
Future<void> updateMarkers(
MarkerUpdates markerUpdates, {
required int mapId,
}) {
return channel(mapId).invokeMethod<void>(
'markers#update',
markerUpdates.toMap(),
);
}
/// 更新polyline的数据
Future<void> updatePolylines(
PolylineUpdates polylineUpdates, {
required int mapId,
}) {
return channel(mapId).invokeMethod<void>(
'polylines#update',
polylineUpdates.toMap(),
);
}
/// 更新polygon的数据
Future<void> updatePolygons(
PolygonUpdates polygonUpdates, {
required int mapId,
}) {
return channel(mapId).invokeMethod<void>(
'polygons#update',
polygonUpdates.toMap(),
);
}
@override
void dispose({required int id}) {
if (_channels.containsKey(id)) {
_channels.remove(id);
}
}
@override
Widget buildView(
Map<String, dynamic> creationParams,
Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
void Function(int id) onPlatformViewCreated) {
if (defaultTargetPlatform == TargetPlatform.android) {
creationParams['debugMode'] = kDebugMode;
return AndroidView(
viewType: VIEW_TYPE,
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
return UiKitView(
viewType: VIEW_TYPE,
onPlatformViewCreated: onPlatformViewCreated,
gestureRecognizers: gestureRecognizers,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}
return Text('当前平台:$defaultTargetPlatform, 不支持使用高德地图插件');
}
// handleMethodCall的`broadcast`
final StreamController<MapEvent> _mapEventStreamController =
StreamController<MapEvent>.broadcast();
// 根据mapid返回相应的event.
Stream<MapEvent> _events(int mapId) =>
_mapEventStreamController.stream.where((event) => event.mapId == mapId);
//定位回调
Stream<LocationChangedEvent> onLocationChanged({required int mapId}) {
return _events(mapId).whereType<LocationChangedEvent>();
}
//Camera 移动回调
Stream<CameraPositionMoveEvent> onCameraMove({required int mapId}) {
return _events(mapId).whereType<CameraPositionMoveEvent>();
}
///Camera 移动结束回调
Stream<CameraPositionMoveEndEvent> onCameraMoveEnd({required int mapId}) {
return _events(mapId).whereType<CameraPositionMoveEndEvent>();
}
Stream<MapTapEvent> onMapTap({required int mapId}) {
return _events(mapId).whereType<MapTapEvent>();
}
Stream<MapLongPressEvent> onMapLongPress({required int mapId}) {
return _events(mapId).whereType<MapLongPressEvent>();
}
Stream<MapPoiTouchEvent> onPoiTouched({required int mapId}) {
return _events(mapId).whereType<MapPoiTouchEvent>();
}
Stream<MarkerTapEvent> onMarkerTap({required int mapId}) {
return _events(mapId).whereType<MarkerTapEvent>();
}
Stream<MarkerDragEndEvent> onMarkerDragEnd({required int mapId}) {
return _events(mapId).whereType<MarkerDragEndEvent>();
}
Stream<PolylineTapEvent> onPolylineTap({required int mapId}) {
return _events(mapId).whereType<PolylineTapEvent>();
}
Future<dynamic> _handleMethodCall(MethodCall call, int mapId) async {
switch (call.method) {
case 'location#changed':
try {
_mapEventStreamController.add(LocationChangedEvent(
mapId, AMapLocation.fromMap(call.arguments['location'])!));
} catch (e) {
print("location#changed error=======>" + e.toString());
}
break;
case 'camera#onMove':
try {
_mapEventStreamController.add(CameraPositionMoveEvent(
mapId, CameraPosition.fromMap(call.arguments['position'])!));
} catch (e) {
print("camera#onMove error===>" + e.toString());
}
break;
case 'camera#onMoveEnd':
try {
_mapEventStreamController.add(CameraPositionMoveEndEvent(
mapId, CameraPosition.fromMap(call.arguments['position'])!));
} catch (e) {
print("camera#onMoveEnd error===>" + e.toString());
}
break;
case 'map#onTap':
_mapEventStreamController
.add(MapTapEvent(mapId, LatLng.fromJson(call.arguments['latLng'])!));
break;
case 'map#onLongPress':
_mapEventStreamController.add(MapLongPressEvent(
mapId, LatLng.fromJson(call.arguments['latLng'])!));
break;
case 'marker#onTap':
_mapEventStreamController.add(MarkerTapEvent(
mapId,
call.arguments['markerId'],
));
break;
case 'marker#onDragEnd':
_mapEventStreamController.add(MarkerDragEndEvent(
mapId,
LatLng.fromJson(call.arguments['position'])!,
call.arguments['markerId']));
break;
case 'polyline#onTap':
_mapEventStreamController
.add(PolylineTapEvent(mapId, call.arguments['polylineId']));
break;
case 'map#onPoiTouched':
try {
_mapEventStreamController.add(
MapPoiTouchEvent(mapId, AMapPoi.fromJson(call.arguments['poi'])!));
} catch (e) {
print('map#onPoiTouched error===>' + e.toString());
}
break;
}
}
///移动镜头到一个新的位置
Future<void> moveCamera(
CameraUpdate cameraUpdate, {
required int mapId,
bool animated = true,
int duration = 0,
}) {
return channel(mapId).invokeMethod<void>('camera#move', <String, dynamic>{
'cameraUpdate': cameraUpdate.toJson(),
'animated': animated,
'duration': duration
});
}
///设置地图每秒渲染的帧数
Future<void> setRenderFps(int fps, {required int mapId}) {
return channel(mapId)
.invokeMethod<void>('map#setRenderFps', <String, dynamic>{
'fps': fps,
});
}
///截屏
Future<Uint8List?> takeSnapshot({
required int mapId,
}) {
return channel(mapId).invokeMethod<Uint8List>('map#takeSnapshot');
}
//获取地图审图号(普通地图)
Future<String?> getMapContentApprovalNumber({
required int mapId,
}) {
return channel(mapId).invokeMethod<String>('map#contentApprovalNumber');
}
//获取地图审图号(卫星地图)
Future<String?> getSatelliteImageApprovalNumber({
required int mapId,
}) {
return channel(mapId)
.invokeMethod<String>('map#satelliteImageApprovalNumber');
}
Future<void> clearDisk({
required int mapId,
}) {
return channel(mapId).invokeMethod<void>('map#clearDisk');
}
}

29
local_plugins/amap_service/lib/types/base_overlay.dart

@ -1,29 +0,0 @@
/// 地图覆盖物基类
class BaseOverlay {
/// overlay id
late String _id;
String get id => _id;
BaseOverlay() {
this._id = this.hashCode.toString();
}
void setIdForCopy(String copyId) => _id = copyId;
BaseOverlay clone() {
throw UnimplementedError(
'BaseOverlay subClass should implement this methed.');
}
Map<String, dynamic> toMap() {
throw UnimplementedError(
'BaseOverlay subClass should implement this methed.');
}
}
List<Map<String, dynamic>>? serializeOverlaySet(Set<BaseOverlay> overlays) {
return overlays
.map<Map<String, dynamic>>((BaseOverlay overlay) => overlay.toMap())
.toList();
}

140
local_plugins/amap_service/lib/types/bitmap.dart

@ -1,140 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async' show Future;
import 'dart:typed_data' show Uint8List;
import 'dart:ui';
import 'package:amap_flutter_base/amap_flutter_base.dart' show AMapUtil;
import 'package:flutter/material.dart'
show ImageConfiguration, AssetImage, AssetBundleImageKey;
import 'package:flutter/services.dart' show AssetBundle;
import 'package:flutter/foundation.dart' show kIsWeb;
/// Bitmap工具类
class BitmapDescriptor {
const BitmapDescriptor._(this._json);
/// 红色.
static const double hueRed = 0.0;
/// 橙色.
static const double hueOrange = 30.0;
/// 黄色.
static const double hueYellow = 60.0;
/// 绿色.
static const double hueGreen = 120.0;
/// 青色.
static const double hueCyan = 180.0;
/// 天蓝色.
static const double hueAzure = 210.0;
/// 蓝色.
static const double hueBlue = 240.0;
/// 紫色.
static const double hueViolet = 270.0;
/// 酒红色.
static const double hueMagenta = 300.0;
/// 玫瑰红.
static const double hueRose = 330.0;
/// 创建默认的marker 图标的 bitmap 描述信息对象.
static const BitmapDescriptor defaultMarker =
BitmapDescriptor._(<dynamic>['defaultMarker']);
/// 创建引用默认着色的BitmapDescriptor
static BitmapDescriptor defaultMarkerWithHue(double hue) {
assert(0.0 <= hue && hue < 360.0);
String filename = "BLUE.png";
if (hue == hueRed) {
filename = "RED.png";
} else if (hue == hueOrange) {
filename = "ORANGE.png";
} else if (hue == hueYellow) {
filename = "YELLOW.png";
} else if (hue == hueGreen) {
filename = "GREEN.png";
} else if (hue == hueCyan) {
filename = "CYAN.png";
} else if (hue == hueAzure) {
filename = "AZURE.png";
} else if (hue == hueBlue) {
filename = "BLUE.png";
} else if (hue == hueViolet) {
filename = "VIOLET.png";
} else if (hue == hueMagenta) {
filename = "MAGENTA.png";
} else if (hue == hueRose) {
filename = "ROSE.png";
}
return BitmapDescriptor._(<dynamic>[
'fromAssetImage',
"packages/amap_flutter_map/res/$filename",
AMapUtil.devicePixelRatio
]);
}
///根据输入的icon路径[iconPath]创建[BitmapDescriptor]
static BitmapDescriptor fromIconPath(String iconPath) {
return BitmapDescriptor._(<dynamic>[
'fromAsset',
iconPath,
]);
}
///从资源图像创建[BitmapDescriptor]。
///
///Flutter中的assert的资产图像按以下方式存储:
/// https://flutter.dev/docs/development/ui/assets and images声明-分辨率感知图像资源
///该方法考虑了各种资产解决方案
///并根据dpi将图像缩放到正确的分辨率。
///将`mipmaps1设置为false可加载图像的精确dpi版本,默认情况下,`mipmap`为true。
static Future<BitmapDescriptor> fromAssetImage(
ImageConfiguration configuration,
String assetName, {
AssetBundle? bundle,
String? package,
bool mipmaps = true,
}) async {
if (!mipmaps && configuration.devicePixelRatio != null) {
return BitmapDescriptor._(<dynamic>[
'fromAssetImage',
assetName,
configuration.devicePixelRatio,
]);
}
final AssetImage assetImage =
AssetImage(assetName, package: package, bundle: bundle);
final AssetBundleImageKey assetBundleImageKey =
await assetImage.obtainKey(configuration);
final Size? size = configuration.size;
return BitmapDescriptor._(<dynamic>[
'fromAssetImage',
assetBundleImageKey.name,
assetBundleImageKey.scale,
if (kIsWeb && size != null)
[
size.width,
size.height,
],
]);
}
/// 根据将PNG图片转换后的二进制数据[byteData]创建BitmapDescriptor
static BitmapDescriptor fromBytes(Uint8List byteData) {
return BitmapDescriptor._(<dynamic>['fromBytes', byteData]);
}
final dynamic _json;
dynamic toMap() => _json;
}

150
local_plugins/amap_service/lib/types/camera.dart

@ -1,150 +0,0 @@
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:flutter/cupertino.dart';
/// 相机位置,包含可视区域的位置参数。
class CameraPosition {
/// 构造一个CameraPosition 对象
///
/// 如果[bearing], [target], [tilt], 或者 [zoom] 为null时会返回[AssertionError]
const CameraPosition({
this.bearing = 0.0,
required this.target,
this.tilt = 0.0,
this.zoom = 10,
});
/// 可视区域指向的方向,以角度为单位,从正北向逆时针方向计算,从0 度到360 度。
final double bearing;
/// 目标位置的屏幕中心点经纬度坐标。
final LatLng target;
/// 目标可视区域的倾斜度,以角度为单位。范围从0到360度
final double tilt;
/// 目标可视区域的缩放级别
final double zoom;
/// 将[CameraPosition]装换成Map
///
/// 主要在插件内部使用
dynamic toMap() => <String, dynamic>{
'bearing': bearing,
'target': target.toJson(),
'tilt': tilt,
'zoom': zoom,
};
/// 从Map转换成[CameraPosition]
///
/// 主要在插件内部使用
static CameraPosition? fromMap(dynamic json) {
if (json == null || !(json is Map<dynamic, dynamic>)) {
return null;
}
final LatLng? target = LatLng.fromJson(json['target']);
if (target == null) {
return null;
}
return CameraPosition(
bearing: json['bearing'],
target: target,
tilt: json['tilt'],
zoom: json['zoom'],
);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
final CameraPosition typedOther = other;
return bearing == typedOther.bearing &&
target == typedOther.target &&
tilt == typedOther.tilt &&
zoom == typedOther.zoom;
}
@override
int get hashCode => Object.hash(bearing, target, tilt, zoom);
@override
String toString() =>
'CameraPosition(bearing: $bearing, target: $target, tilt: $tilt, zoom: $zoom)';
}
/// 描述地图状态将要发生的变化
class CameraUpdate {
CameraUpdate._(this._json);
///返回根据新的[CameraPosition]移动后的[CameraUpdate].
///
///主要用于改变地图的中心点、缩放级别、倾斜角、角度等信息
static CameraUpdate newCameraPosition(CameraPosition cameraPosition) {
return CameraUpdate._(<dynamic>[
'newCameraPosition',
cameraPosition.toMap(),
]);
}
///移动到一个新的位置点[latLng]
///
///主要用于改变地图的中心点
static CameraUpdate newLatLng(LatLng latLng) {
return CameraUpdate._(<dynamic>['newLatLng', latLng.toJson()]);
}
///根据指定到摄像头显示范围[bounds]和边界值[padding]创建一个CameraUpdate对象
///
///主要用于根据指定的显示范围[bounds]以最佳的视野显示地图
static CameraUpdate newLatLngBounds(LatLngBounds bounds, double padding) {
return CameraUpdate._(<dynamic>[
'newLatLngBounds',
bounds.toJson(),
padding,
]);
}
/// 根据指定的新的位置[latLng]和缩放级别[zoom]创建一个CameraUpdate对象
///
/// 主要用于同时改变中心点和缩放级别
static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) {
return CameraUpdate._(<dynamic>['newLatLngZoom', latLng.toJson(), zoom]);
}
/// 按照指定到像素点[dx]和[dy]移动地图中心点
///
/// [dx]是水平移动的像素数。正值代表可视区域向右移动,负值代表可视区域向左移动
///
/// [dy]是垂直移动的像素数。正值代表可视区域向下移动,负值代表可视区域向上移动
///
/// 返回包含x,y方向上移动像素数的cameraUpdate对象。
static CameraUpdate scrollBy(double dx, double dy) {
return CameraUpdate._(<dynamic>['scrollBy', dx, dy]);
}
/// 创建一个在当前地图显示的级别基础上加1的CameraUpdate对象
///
///主要用于放大地图缩放级别,在当前地图显示的级别基础上加1
static CameraUpdate zoomIn() {
return CameraUpdate._(<dynamic>['zoomIn']);
}
/// 创建一个在当前地图显示的级别基础上加1的CameraUpdate对象
///
/// 主要用于减少地图缩放级别,在当前地图显示的级别基础上减1
static CameraUpdate zoomOut() {
return CameraUpdate._(<dynamic>['zoomOut']);
}
/// 创建一个指定缩放级别[zoom]的CameraUpdate对象
///
/// 主要用于设置地图缩放级别
static CameraUpdate zoomTo(double zoom) {
return CameraUpdate._(<dynamic>['zoomTo', zoom]);
}
final dynamic _json;
dynamic toJson() => _json;
}

249
local_plugins/amap_service/lib/types/marker.dart

@ -1,249 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show Offset;
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'base_overlay.dart';
import 'bitmap.dart';
/// Marker拖动回调
typedef void MarkerDragEndCallback(String id, LatLng endPosition);
///Marker的气泡
///
///Android和iOS的实现机制有差异,仅在接口层面拉齐,效果一致
class InfoWindow {
/// 为 [Marker] 产生一个不可修改的文本气泡.
const InfoWindow({this.title, this.snippet});
/// 无文本的气泡
static const InfoWindow noText = InfoWindow();
/// 气泡的title
final String? title;
/// 气泡的详细信息
final String? snippet;
/// 气泡copy方法
///
InfoWindow copyWith({String? titleParam, String? snippetParam}) {
return InfoWindow(
title: titleParam ?? title,
snippet: snippetParam ?? snippet,
);
}
Map<String, dynamic> _toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('title', title);
addIfPresent('snippet', snippet);
return json;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is! InfoWindow) {
return false;
}
final InfoWindow typedOther = other;
return title == typedOther.title && snippet == typedOther.snippet;
}
@override
int get hashCode => Object.hash(title, snippet);
@override
String toString() {
return 'InfoWindow{title: $title, snippet: $snippet}';
}
}
/// 点覆盖物的类
class Marker extends BaseOverlay {
Marker({
required this.position,
double alpha = 1.0,
Offset anchor = const Offset(0.5, 1.0),
this.clickable = true,
this.draggable = false,
this.icon = BitmapDescriptor.defaultMarker,
this.infoWindowEnable = true,
this.infoWindow = InfoWindow.noText,
this.rotation = 0.0,
this.visible = true,
this.zIndex = 0.0,
this.onTap,
this.onDragEnd,
}) : this.alpha =
// ignore: unnecessary_null_comparison
(alpha != null ? (alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)) : alpha),
// ignore: unnecessary_null_comparison
this.anchor =
(anchor == null
? Offset(0.5, 1.0)
: ((anchor.dx < 0 ||
anchor.dx > 1 ||
anchor.dy < 0 ||
anchor.dy > 1)
? Offset(0.5, 1.0)
: anchor)),
super();
/// 透明度
final double alpha;
/// 覆盖物视图相对地图上的经纬度位置的锚点
final Offset anchor;
/// 是否可点击,默认为true
final bool clickable;
/// 是否可拖拽,默认为false
final bool draggable;
/// 覆盖物的图标
final BitmapDescriptor icon;
/// 是否显示气泡,如果为true,则点击[Marker]后,会显示该气泡[InfoWindow]
/// 如果为false,则始终不会显示该气泡
final bool infoWindowEnable;
/// 覆盖物上的气泡,当被点击时,如果infoWindowEnable为true,则会显示出来
final InfoWindow infoWindow;
/// 位置,不能为空
final LatLng position;
/// 旋转角度,以锚点为中心,顺时针旋转(单位:度数)
///
/// 注意:iOS端目前仅支持绕marker中心点旋转
final double rotation;
/// 是否可见
final bool visible;
/// z轴的值,用于调整该覆盖物的相对绘制层级关系
/// 值越小,图层越靠下,iOS该值不支持动态修改,仅能在初始化时指定
final double zIndex;
/// 回调的参数是对应的id
final ArgumentCallback<String>? onTap;
/// Marker被拖拽结束的回调
final MarkerDragEndCallback? onDragEnd;
/// copy的真正复制的参数,主要用于需要修改某个属性参数时使用
Marker copyWith({
double? alphaParam,
Offset? anchorParam,
bool? clickableParam,
bool? draggableParam,
BitmapDescriptor? iconParam,
bool? infoWindowEnableParam,
InfoWindow? infoWindowParam,
LatLng? positionParam,
double? rotationParam,
bool? visibleParam,
ArgumentCallback<String?>? onTapParam,
MarkerDragEndCallback? onDragEndParam,
}) {
Marker copyMark = Marker(
alpha: alphaParam ?? alpha,
anchor: anchorParam ?? anchor,
clickable: clickableParam ?? clickable,
draggable: draggableParam ?? draggable,
icon: iconParam ?? icon,
infoWindowEnable: infoWindowEnableParam ?? infoWindowEnable,
infoWindow: infoWindowParam ?? infoWindow,
position: positionParam ?? position,
rotation: rotationParam ?? rotation,
visible: visibleParam ?? visible,
zIndex: zIndex,
onTap: onTapParam ?? onTap,
onDragEnd: onDragEndParam ?? onDragEnd,
);
copyMark.setIdForCopy(id);
return copyMark;
}
Marker clone() => copyWith();
@override
Map<String, dynamic> toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('id', id);
addIfPresent('alpha', alpha);
addIfPresent('anchor', _offsetToJson(anchor));
addIfPresent('clickable', clickable);
addIfPresent('draggable', draggable);
addIfPresent('icon', icon.toMap());
addIfPresent('infoWindowEnable', infoWindowEnable);
addIfPresent('infoWindow', infoWindow._toMap());
addIfPresent('position', position.toJson());
addIfPresent('rotation', rotation);
addIfPresent('visible', visible);
addIfPresent('zIndex', zIndex);
return json;
}
dynamic _offsetToJson(Offset offset) {
return <dynamic>[offset.dx, offset.dy];
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is! Marker) return false;
final Marker typedOther = other;
return id == typedOther.id &&
alpha == typedOther.alpha &&
anchor == typedOther.anchor &&
clickable == typedOther.clickable &&
draggable == typedOther.draggable &&
icon == typedOther.icon &&
infoWindowEnable == typedOther.infoWindowEnable &&
infoWindow == typedOther.infoWindow &&
position == typedOther.position &&
rotation == typedOther.rotation &&
visible == typedOther.visible &&
zIndex == typedOther.zIndex;
}
@override
int get hashCode => super.hashCode;
@override
String toString() {
return 'Marker{id: $id, alpha: $alpha, anchor: $anchor, '
'clickable: $clickable, draggable: $draggable,'
'icon: $icon, infoWindowEnable: $infoWindowEnable, infoWindow: $infoWindow, position: $position, rotation: $rotation, '
'visible: $visible, zIndex: $zIndex, onTap: $onTap}';
}
}
Map<String, Marker> keyByMarkerId(Iterable<Marker> markers) {
return Map<String, Marker>.fromEntries(
markers.map(
(Marker marker) => MapEntry<String, Marker>(marker.id, marker.clone()),
),
);
}

105
local_plugins/amap_service/lib/types/marker_updates.dart

@ -1,105 +0,0 @@
import 'dart:ui' show hashValues;
import 'package:flutter/foundation.dart' show setEquals;
import 'types.dart';
import 'marker.dart';
/// 用以描述Marker的更新项
class MarkerUpdates {
/// 根据之前的marker列表[previous]和当前的marker列表[current]创建[MakerUpdates].
MarkerUpdates.from(Set<Marker> previous, Set<Marker> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Marker>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Marker>.identity();
}
final Map<String, Marker> previousMarkers = keyByMarkerId(previous);
final Map<String, Marker> currentMarkers = keyByMarkerId(current);
final Set<String> prevMarkerIds = previousMarkers.keys.toSet();
final Set<String> currentMarkerIds = currentMarkers.keys.toSet();
Marker idToCurrentMarker(String id) {
return currentMarkers[id]!;
}
final Set<String> _markerIdsToRemove = prevMarkerIds.difference(
currentMarkerIds,
);
final Set<Marker> _markersToAdd =
currentMarkerIds
.difference(prevMarkerIds)
.map(idToCurrentMarker)
.toSet();
bool hasChanged(Marker current) {
final Marker? previous = previousMarkers[current.id];
return current != previous;
}
final Set<Marker> _markersToChange =
currentMarkerIds
.intersection(prevMarkerIds)
.map(idToCurrentMarker)
.where(hasChanged)
.toSet();
markersToAdd = _markersToAdd;
markerIdsToRemove = _markerIdsToRemove;
markersToChange = _markersToChange;
}
/// 想要添加的marker集合.
Set<Marker>? markersToAdd;
/// 想要删除的marker的id集合
Set<String>? markerIdsToRemove;
/// 想要更新的marker集合.
Set<Marker>? markersToChange;
Map<String, dynamic> toMap() {
final Map<String, dynamic> updateMap = <String, dynamic>{};
void addIfNonNull(String fieldName, dynamic value) {
if (value != null) {
updateMap[fieldName] = value;
}
}
addIfNonNull('markersToAdd', serializeOverlaySet(markersToAdd!));
addIfNonNull('markersToChange', serializeOverlaySet(markersToChange!));
addIfNonNull('markerIdsToRemove', markerIdsToRemove?.toList());
return updateMap;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is! MarkerUpdates) return false;
final MarkerUpdates typedOther = other;
return setEquals(markersToAdd, typedOther.markersToAdd) &&
setEquals(markerIdsToRemove, typedOther.markerIdsToRemove) &&
setEquals(markersToChange, typedOther.markersToChange);
}
@override
int get hashCode =>
Object.hash(markersToAdd, markerIdsToRemove, markersToChange);
@override
String toString() {
return '_MarkerUpdates{markersToAdd: $markersToAdd, '
'markerIdsToRemove: $markerIdsToRemove, '
'markersToChange: $markersToChange}';
}
}

120
local_plugins/amap_service/lib/types/polygon.dart

@ -1,120 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart' show listEquals;
import 'package:flutter/material.dart' show Color;
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'base_overlay.dart';
import 'polyline.dart';
/// 线相关的覆盖物类,内部的属性,描述了覆盖物的纹理、颜色、线宽等特征
class Polygon extends BaseOverlay {
/// 默认构造函数
Polygon(
{required this.points,
double strokeWidth = 10,
this.strokeColor = const Color(0xCC00BFFF),
this.fillColor = const Color(0xC487CEFA),
this.visible = true,
this.joinType = JoinType.bevel})
: assert(points.length > 0),
this.strokeWidth = (strokeWidth <= 0 ? 10 : strokeWidth),
super();
/// 覆盖物的坐标点数组,不能为空
final List<LatLng> points;
/// 边框宽度,单位为逻辑像素,同Android中的dp,iOS中的point
final double strokeWidth;
/// 边框颜色,默认值为(0xCCC4E0F0)
final Color strokeColor;
/// 填充颜色,默认值为(0xC4E0F0CC)
final Color fillColor;
/// 是否可见
final bool visible;
/// 连接点类型,该参数不支持copy时修改,仅能在初始化时设置一次
final JoinType joinType;
/// 实际copy函数
Polygon copyWith({
List<LatLng>? pointsParam,
double? strokeWidthParam,
Color? strokeColorParam,
Color? fillColorParam,
bool? visibleParam,
}) {
Polygon copyPolyline = Polygon(
points: pointsParam ?? points,
strokeWidth: strokeWidthParam ?? strokeWidth,
strokeColor: strokeColorParam ?? strokeColor,
fillColor: fillColorParam ?? fillColor,
visible: visibleParam ?? visible,
joinType: joinType,
);
copyPolyline.setIdForCopy(id);
return copyPolyline;
}
Polygon clone() => copyWith();
/// 转换成可以序列化的map
@override
Map<String, dynamic> toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('id', id);
json['points'] = _pointsToJson();
addIfPresent('strokeWidth', strokeWidth);
addIfPresent('strokeColor', strokeColor.value);
addIfPresent('fillColor', fillColor.value);
addIfPresent('visible', visible);
addIfPresent('joinType', joinType.index);
return json;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is !Polygon) return false;
final Polygon typedOther = other;
return id == typedOther.id &&
listEquals(points, typedOther.points) &&
strokeWidth == typedOther.strokeWidth &&
strokeColor == typedOther.strokeColor &&
fillColor == typedOther.fillColor &&
visible == typedOther.visible &&
joinType == typedOther.joinType;
}
@override
int get hashCode => super.hashCode;
dynamic _pointsToJson() {
final List<dynamic> result = <dynamic>[];
for (final LatLng point in points) {
result.add(point.toJson());
}
return result;
}
}
Map<String, Polygon> keyByPolygonId(Iterable<Polygon> polylines) {
// ignore: unnecessary_null_comparison
if (polylines == null) {
return <String, Polygon>{};
}
return Map<String, Polygon>.fromEntries(polylines.map((Polygon polyline) =>
MapEntry<String, Polygon>(polyline.id, polyline.clone())));
}

108
local_plugins/amap_service/lib/types/polygon_updates.dart

@ -1,108 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show hashValues;
import 'package:flutter/foundation.dart' show setEquals;
import 'types.dart';
/// 该类主要用以描述[Polygon]的增删改等更新操作
class PolygonUpdates {
/// 通过Polygon的前后更新集合构造一个PolygonUpdates
PolygonUpdates.from(Set<Polygon> previous, Set<Polygon> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Polygon>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Polygon>.identity();
}
final Map<String, Polygon> previousPolygons = keyByPolygonId(previous);
final Map<String, Polygon> currentPolygons = keyByPolygonId(current);
final Set<String> prevPolygonIds = previousPolygons.keys.toSet();
final Set<String> currentPolygonIds = currentPolygons.keys.toSet();
Polygon idToCurrentPolygon(String id) {
return currentPolygons[id]!;
}
final Set<String> _polygonIdsToRemove = prevPolygonIds.difference(
currentPolygonIds,
);
final Set<Polygon> _polygonsToAdd =
currentPolygonIds
.difference(prevPolygonIds)
.map(idToCurrentPolygon)
.toSet();
bool hasChanged(Polygon current) {
final Polygon previous = previousPolygons[current.id]!;
return current != previous;
}
final Set<Polygon> _polygonsToChange =
currentPolygonIds
.intersection(prevPolygonIds)
.map(idToCurrentPolygon)
.where(hasChanged)
.toSet();
polygonsToAdd = _polygonsToAdd;
polygonIdsToRemove = _polygonIdsToRemove;
polygonsToChange = _polygonsToChange;
}
/// 想要添加的polygon对象集合.
Set<Polygon>? polygonsToAdd;
/// 想要删除的polygon的id集合
Set<String>? polygonIdsToRemove;
/// 想要更新的polygon对象集合
Set<Polygon>? polygonsToChange;
/// 转换成可以序列化的map
Map<String, dynamic> toMap() {
final Map<String, dynamic> updateMap = <String, dynamic>{};
void addIfNonNull(String fieldName, dynamic value) {
if (value != null) {
updateMap[fieldName] = value;
}
}
addIfNonNull('polygonsToAdd', serializeOverlaySet(polygonsToAdd!));
addIfNonNull('polygonsToChange', serializeOverlaySet(polygonsToChange!));
addIfNonNull('polygonIdsToRemove', polygonIdsToRemove?.toList());
return updateMap;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is! PolygonUpdates) return false;
final PolygonUpdates typedOther = other;
return setEquals(polygonsToAdd, typedOther.polygonsToAdd) &&
setEquals(polygonIdsToRemove, typedOther.polygonIdsToRemove) &&
setEquals(polygonsToChange, typedOther.polygonsToChange);
}
@override
int get hashCode =>
Object.hash(polygonsToAdd, polygonIdsToRemove, polygonsToChange);
@override
String toString() {
return '_PolygonUpdates{polygonsToAdd: $polygonsToAdd, '
'polygonIdsToRemove: $polygonIdsToRemove, '
'polygonsToChange: $polygonsToChange}';
}
}

198
local_plugins/amap_service/lib/types/polyline.dart

@ -1,198 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:amap_flutter_map/src/types/bitmap.dart';
import 'package:flutter/foundation.dart' show listEquals;
import 'package:flutter/material.dart' show Color;
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'base_overlay.dart';
/// 虚线类型
enum DashLineType {
/// 不画虚线
none,
/// 方块样式
square,
/// 圆点样式
circle,
}
/// 线头类型
enum CapType {
/// 普通头
butt,
/// 扩展头
square,
/// 箭头
arrow,
/// 圆形头
round,
}
/// 连接点类型
enum JoinType {
/// 斜面连接点
bevel,
/// 斜接连接点
miter,
/// 圆角连接点
round,
}
/// 线相关的覆盖物类,内部的属性,描述了覆盖物的纹理、颜色、线宽等特征
class Polyline extends BaseOverlay {
/// 默认构造函数
Polyline({
required this.points,
double width = 10,
this.visible = true,
this.geodesic = false,
double alpha = 1.0,
this.dashLineType = DashLineType.none,
this.capType = CapType.butt,
this.joinType = JoinType.bevel,
this.customTexture,
this.onTap,
this.color = const Color(0xCCC4E0F0),
}) : assert(points.length > 0),
this.width = (width <= 0 ? 10 : width),
this.alpha =(alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)),
super();
/// 覆盖物的坐标点数组,points不能为空
final List<LatLng> points;
/// 线宽,单位为逻辑像素,同Android中的dp,iOS中的point
final double width;
/// 是否可见
final bool visible;
/// 透明度
final double alpha;
/// 覆盖物颜色,默认值为(0xCCC4E0F0).
final Color color;
/// 自定义纹理图片,注意: 如果设置了自定义纹理图片,则color的设置将无效;
final BitmapDescriptor? customTexture;
/// 是否为大地曲线
final bool geodesic;
/// 虚线类型
final DashLineType dashLineType;
/// 连接点类型
final JoinType joinType;
/// 线头类型
final CapType capType;
/// 点击回调(回调参数为id)
final ArgumentCallback<String>? onTap;
/// 实际copy函数
Polyline copyWith({
List<LatLng>? pointsParam,
double? widthParam,
int? zIndexParam,
bool? visibleParam,
double? alphaParam,
DashLineType? dashLineTypeParam,
CapType? capTypeParam,
JoinType? joinTypeParam,
BitmapDescriptor? customTextureParam,
ArgumentCallback<String>? onTapParam,
Color? colorParam,
}) {
Polyline copyPolyline = Polyline(
points: pointsParam ?? points,
width: widthParam ?? width,
visible: visibleParam ?? visible,
geodesic: geodesic,
alpha: alphaParam ?? alpha,
dashLineType: dashLineTypeParam ?? dashLineType,
capType: capTypeParam ?? capType,
joinType: joinTypeParam ?? joinType,
customTexture: customTextureParam ?? customTexture,
onTap: onTapParam ?? onTap,
color: colorParam ?? color,
);
copyPolyline.setIdForCopy(id);
return copyPolyline;
}
Polyline clone() => copyWith();
/// 将对象转换为可序列化的map.
@override
Map<String, dynamic> toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('id', id);
json['points'] = _pointsToJson();
addIfPresent('width', width);
addIfPresent('visible', visible);
addIfPresent('geodesic', geodesic);
addIfPresent('alpha', alpha);
addIfPresent('dashLineType', dashLineType.index);
addIfPresent('capType', capType.index);
addIfPresent('joinType', joinType.index);
addIfPresent('customTexture', customTexture?.toMap());
addIfPresent('color', color.value);
return json;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is !Polyline) return false;
final Polyline typedOther = other;
return id == typedOther.id &&
listEquals(points, typedOther.points) &&
width == typedOther.width &&
visible == typedOther.visible &&
geodesic == typedOther.geodesic &&
alpha == typedOther.alpha &&
dashLineType == typedOther.dashLineType &&
capType == typedOther.capType &&
joinType == typedOther.joinType &&
color == typedOther.color;
}
@override
int get hashCode => super.hashCode;
dynamic _pointsToJson() {
final List<dynamic> result = <dynamic>[];
for (final LatLng point in points) {
result.add(point.toJson());
}
return result;
}
}
Map<String, Polyline> keyByPolylineId(Iterable<Polyline> polylines) {
// ignore: unnecessary_null_comparison
if (polylines == null) {
return <String, Polyline>{};
}
return Map<String, Polyline>.fromEntries(polylines.map((Polyline polyline) =>
MapEntry<String, Polyline>(polyline.id, polyline.clone())));
}

108
local_plugins/amap_service/lib/types/polyline_updates.dart

@ -1,108 +0,0 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart' show setEquals;
import 'polyline.dart';
import 'types.dart';
/// 该类主要用以描述[Polyline]的增删改等更新操作
class PolylineUpdates {
/// 通过polyline的前后更新集合构造一个polylineUpdates
PolylineUpdates.from(Set<Polyline> previous, Set<Polyline> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Polyline>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Polyline>.identity();
}
final Map<String, Polyline> previousPolylines = keyByPolylineId(previous);
final Map<String, Polyline> currentPolylines = keyByPolylineId(current);
final Set<String> prevPolylineIds = previousPolylines.keys.toSet();
final Set<String> currentPolylineIds = currentPolylines.keys.toSet();
Polyline idToCurrentPolyline(String id) {
return currentPolylines[id]!;
}
final Set<String> _polylineIdsToRemove = prevPolylineIds.difference(
currentPolylineIds,
);
final Set<Polyline> _polylinesToAdd =
currentPolylineIds
.difference(prevPolylineIds)
.map(idToCurrentPolyline)
.toSet();
bool hasChanged(Polyline current) {
final Polyline previous = previousPolylines[current.id]!;
return current != previous;
}
final Set<Polyline> _polylinesToChange =
currentPolylineIds
.intersection(prevPolylineIds)
.map(idToCurrentPolyline)
.where(hasChanged)
.toSet();
polylinesToAdd = _polylinesToAdd;
polylineIdsToRemove = _polylineIdsToRemove;
polylinesToChange = _polylinesToChange;
}
/// 用于添加polyline的集合
Set<Polyline>? polylinesToAdd;
/// 需要删除的plyline的id集合
Set<String>? polylineIdsToRemove;
/// 用于更新polyline的集合
Set<Polyline>? polylinesToChange;
/// 将对象装换为可序列化的对象
Map<String, dynamic> toMap() {
final Map<String, dynamic> updateMap = <String, dynamic>{};
void addIfNonNull(String fieldName, dynamic value) {
if (value != null) {
updateMap[fieldName] = value;
}
}
addIfNonNull('polylinesToAdd', serializeOverlaySet(polylinesToAdd!));
addIfNonNull('polylinesToChange', serializeOverlaySet(polylinesToChange!));
addIfNonNull('polylineIdsToRemove', polylineIdsToRemove?.toList());
return updateMap;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other.runtimeType != runtimeType) return false;
if (other is! PolylineUpdates) return false;
final PolylineUpdates typedOther = other;
return setEquals(polylinesToAdd, typedOther.polylinesToAdd) &&
setEquals(polylineIdsToRemove, typedOther.polylineIdsToRemove) &&
setEquals(polylinesToChange, typedOther.polylinesToChange);
}
@override
int get hashCode =>
Object.hash(polylinesToAdd, polylineIdsToRemove, polylinesToChange);
@override
String toString() {
return '_PolylineUpdates{polylinesToAdd: $polylinesToAdd, '
'polylineIdsToRemove: $polylineIdsToRemove, '
'polylinesToChange: $polylinesToChange}';
}
}

11
local_plugins/amap_service/lib/types/types.dart

@ -1,11 +0,0 @@
export 'camera.dart';
export 'ui.dart';
export 'base_overlay.dart';
export 'marker.dart';
export 'marker_updates.dart';
export 'polyline.dart';
export 'polyline_updates.dart';
export 'polygon.dart';
export 'polygon_updates.dart';
export 'camera.dart';
export 'bitmap.dart';

257
local_plugins/amap_service/lib/types/ui.dart

@ -1,257 +0,0 @@
import 'dart:typed_data';
import 'dart:ui' show Color;
import 'package:amap_flutter_base/amap_flutter_base.dart';
import 'package:amap_flutter_map/amap_flutter_map.dart';
/// 地图类型
enum MapType {
/// 普通地图
normal,
/// 卫星地图
satellite,
/// 夜间视图
night,
/// 导航视图
navi,
/// 公交视图
bus,
}
// 设置摄像机的边界.
class CameraTargetBounds {
/// 使用指定的边界框或空值创建摄影机目标边界
///
/// 设置为null时代表不指定边界
const CameraTargetBounds(this.bounds);
/// 摄像机的边界.
///
/// null代表不指定边界
final LatLngBounds? bounds;
/// 取消指定边界
static const CameraTargetBounds unbounded = CameraTargetBounds(null);
/// 转换成json对象
dynamic toJson() => <dynamic>[bounds?.toJson()];
@override
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
final CameraTargetBounds typedOther = other;
return bounds == typedOther.bounds;
}
@override
int get hashCode => bounds.hashCode;
@override
String toString() {
return 'CameraTargetBounds(bounds: $bounds)';
}
}
/// 地图最大最小缩放级别的封装对象
class MinMaxZoomPreference {
/// 为地图创建一个不可变的最大最小缩放范围
///
/// 缩放级别范围为[3, 20],超出范围取边界值
///
const MinMaxZoomPreference(double minZoom, double maxZoom)
: this.minZoom =
((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
? maxZoom
: minZoom),
this.maxZoom =
((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
? minZoom
: maxZoom);
/// 最小zoomLevel
final double? minZoom;
/// 最大zoomLevel
final double? maxZoom;
/// 高德地图默认zoomLevel的范围.
static const MinMaxZoomPreference defaultPreference = MinMaxZoomPreference(
3,
20,
);
/// JSON序列化.
dynamic toJson() => <dynamic>[minZoom, maxZoom];
@override
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
final MinMaxZoomPreference typedOther = other;
return minZoom == typedOther.minZoom && maxZoom == typedOther.maxZoom;
}
@override
int get hashCode => Object.hash(minZoom, maxZoom);
@override
String toString() {
return 'MinMaxZoomPreference(minZoom: $minZoom, maxZoom: $maxZoom)';
}
}
///定位小蓝点配置项
class MyLocationStyleOptions {
///是否显示定位小蓝点
bool enabled;
///精度圈填充色
Color? circleFillColor;
///精度圈边框色
Color? circleStrokeColor;
///精度圈边框宽度
double? circleStrokeWidth;
///小蓝点图标
BitmapDescriptor? icon;
MyLocationStyleOptions(
this.enabled, {
this.circleFillColor,
this.circleStrokeColor,
this.circleStrokeWidth,
this.icon,
});
MyLocationStyleOptions clone() {
return MyLocationStyleOptions(
enabled,
circleFillColor: circleFillColor,
circleStrokeColor: circleStrokeColor,
circleStrokeWidth: circleStrokeWidth,
icon: icon,
);
}
static MyLocationStyleOptions? fromMap(dynamic json) {
if (null == json) {
return null;
}
return MyLocationStyleOptions(
json['enabled'] ?? false,
circleFillColor: json['circleFillColor'] ?? null,
circleStrokeColor: json['circleStrokeColor'] ?? null,
circleStrokeWidth: json['circleStrokeWidth'] ?? null,
icon: json['icon'] ?? null,
);
}
Map<String, dynamic> toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('enabled', enabled);
addIfPresent('circleFillColor', circleFillColor?.value);
addIfPresent('circleStrokeColor', circleStrokeColor?.value);
addIfPresent('circleStrokeWidth', circleStrokeWidth);
addIfPresent('icon', icon?.toMap());
return json;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
if (other is! MyLocationStyleOptions) return false;
final MyLocationStyleOptions typedOther = other;
return enabled == typedOther.enabled &&
circleFillColor == typedOther.circleFillColor &&
circleStrokeColor == typedOther.circleStrokeColor &&
icon == typedOther.icon;
}
@override
String toString() {
return 'MyLocationOptionsStyle{'
'enabled: $enabled,'
'circleFillColor: $circleFillColor,'
'circleStrokeColor: $circleStrokeColor,'
'icon: $icon, }';
}
@override
int get hashCode =>
Object.hash(enabled, circleFillColor, circleStrokeColor, icon);
}
///地图自定义样式
class CustomStyleOptions {
///开关项,是否开启自定义地图
bool enabled;
///自定义样式的二进制数据,对应下载的自定义地图文件中的style.data中的二进制数据
Uint8List? styleData;
///自定义扩展样式的二进制数据,对应下载的自定义地图文件中的style_extra.data中的二进制数据
Uint8List? styleExtraData;
CustomStyleOptions(this.enabled, {this.styleData, this.styleExtraData});
static CustomStyleOptions? fromMap(dynamic json) {
if (json == null) {
return null;
}
return CustomStyleOptions(
json['enabled'] ?? false,
styleData: json['styleData'] ?? null,
styleExtraData: json['styleExtraData'] ?? null,
);
}
dynamic toMap() {
final Map<String, dynamic> json = <String, dynamic>{};
void addIfPresent(String fieldName, dynamic value) {
if (value != null) {
json[fieldName] = value;
}
}
addIfPresent('enabled', enabled);
addIfPresent('styleData', styleData);
addIfPresent('styleExtraData', styleExtraData);
return json;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
if (other is! CustomStyleOptions) return false;
final CustomStyleOptions typedOther = other;
return enabled == typedOther.enabled &&
styleData == typedOther.styleData &&
styleExtraData == typedOther.styleExtraData;
}
@override
int get hashCode => Object.hash(enabled, styleData, styleExtraData);
CustomStyleOptions clone() {
return CustomStyleOptions(
enabled,
styleData: styleData,
styleExtraData: styleExtraData,
);
}
}

2
local_plugins/amap_service/pubspec.yaml

@ -16,8 +16,6 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
amap_flutter_base: ^3.0.0
amap_flutter_map: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

BIN
local_plugins/opus/.gradle/buildOutputCleanup/buildOutputCleanup.lock

Binary file not shown.

4
local_plugins/opus/.gradle/buildOutputCleanup/cache.properties

@ -1,2 +1,2 @@
#Sun May 18 21:39:38 IST 2025
gradle.version=8.10
#Wed May 21 01:03:35 CST 2025
gradle.version=8.9

Loading…
Cancel
Save