36 changed files with 609 additions and 353 deletions
@ -1 +0,0 @@ |
|||
rootProject.name = 'amap_flutter' |
|||
@ -1,3 +0,0 @@ |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
|||
package="com.example.amap_flutter"> |
|||
</manifest> |
|||
@ -1,169 +0,0 @@ |
|||
package com.example.amap_flutter; |
|||
|
|||
import android.content.Context; |
|||
import androidx.annotation.NonNull; |
|||
import android.util.Log; |
|||
|
|||
import com.amap.api.location.AMapLocation; |
|||
import com.amap.api.location.AMapLocationClient; |
|||
import com.amap.api.location.AMapLocationClientOption; |
|||
import com.amap.api.location.AMapLocationListener; |
|||
|
|||
import io.flutter.embedding.engine.plugins.FlutterPlugin; |
|||
import io.flutter.plugin.common.EventChannel; |
|||
import io.flutter.plugin.common.MethodCall; |
|||
import io.flutter.plugin.common.MethodChannel; |
|||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; |
|||
import io.flutter.plugin.common.MethodChannel.Result; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** AmapFlutterPlugin */ |
|||
public class AmapFlutterPlugin implements FlutterPlugin, MethodCallHandler { |
|||
/// The MethodChannel that will the communication between Flutter and native Android
|
|||
///
|
|||
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
|
|||
/// when the Flutter Engine is detached from the Activity
|
|||
private MethodChannel methodChannel; |
|||
private EventChannel eventChannel; |
|||
private Context applicationContext; |
|||
private AMapLocationClient mLocationClient; |
|||
private EventChannel.EventSink eventSink; |
|||
|
|||
@Override |
|||
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { |
|||
applicationContext = flutterPluginBinding.getApplicationContext(); |
|||
methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "amap_flutter"); |
|||
methodChannel.setMethodCallHandler(this); |
|||
|
|||
// 初始化EventChannel
|
|||
eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "amap_flutter/events"); |
|||
eventChannel.setStreamHandler(new EventChannel.StreamHandler() { |
|||
@Override |
|||
public void onListen(Object arguments, EventChannel.EventSink events) { |
|||
eventSink = events; |
|||
} |
|||
|
|||
@Override |
|||
public void onCancel(Object arguments) { |
|||
eventSink = null; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { |
|||
switch (call.method) { |
|||
case "setApiKey": |
|||
setApiKey(call, result); |
|||
break; |
|||
case "initLocation": |
|||
initLocation(result); |
|||
break; |
|||
case "startLocation": |
|||
startLocation(result); |
|||
break; |
|||
case "stopLocation": |
|||
stopLocation(result); |
|||
break; |
|||
case "dispose": |
|||
dispose(result); |
|||
break; |
|||
default: |
|||
result.notImplemented(); |
|||
} |
|||
} |
|||
|
|||
private void setApiKey(MethodCall call, Result result) { |
|||
try { |
|||
String apiKey = call.argument("androidKey"); |
|||
AMapLocationClient.updatePrivacyShow(applicationContext, true, true); |
|||
AMapLocationClient.updatePrivacyAgree(applicationContext, true); |
|||
result.success(null); |
|||
} catch (Exception e) { |
|||
result.error("INIT_ERROR", "初始化失败", e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
private void initLocation(Result result) { |
|||
try { |
|||
mLocationClient = new AMapLocationClient(applicationContext); |
|||
|
|||
// 配置定位参数
|
|||
AMapLocationClientOption option = new AMapLocationClientOption(); |
|||
option.setOnceLocation(true); |
|||
option.setNeedAddress(true); |
|||
mLocationClient.setLocationOption(option); |
|||
|
|||
mLocationClient.setLocationListener(mLocationListener); |
|||
result.success(null); |
|||
} catch (Exception e) { |
|||
result.error("INIT_ERROR", "初始化失败", e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
private void startLocation(Result result) { |
|||
mLocationClient.startLocation(); |
|||
result.success(null); |
|||
} |
|||
|
|||
private void stopLocation(Result result) { |
|||
destroyLocationClient(); |
|||
result.success(null); |
|||
} |
|||
|
|||
private void dispose(Result result) { |
|||
try { |
|||
destroyLocationClient(); |
|||
result.success(null); |
|||
} catch (Exception e) { |
|||
result.error("DISPOSE_ERROR", "资源释放失败", e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
private void destroyLocationClient() { |
|||
if (mLocationClient != null) { |
|||
try { |
|||
// 停止定位
|
|||
mLocationClient.stopLocation(); |
|||
// 销毁定位客户端
|
|||
mLocationClient.onDestroy(); |
|||
mLocationClient = null; |
|||
|
|||
// 关闭事件通道
|
|||
if (eventSink != null) { |
|||
eventSink.endOfStream(); |
|||
eventSink = null; |
|||
} |
|||
} catch (Exception e) { |
|||
Log.e("AmapFlutter", "销毁定位客户端失败", e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
AMapLocationListener mLocationListener = new AMapLocationListener() { |
|||
@Override |
|||
public void onLocationChanged(AMapLocation amapLocation) { |
|||
if (eventSink == null) return; |
|||
|
|||
if (amapLocation != null) { |
|||
if (amapLocation.getErrorCode() == 0) { |
|||
Map<String, Object> locationData = new HashMap<>(); |
|||
locationData.put("latitude", amapLocation.getLatitude()); |
|||
locationData.put("longitude", amapLocation.getLongitude()); |
|||
locationData.put("city", amapLocation.getCity()); |
|||
locationData.put("address", amapLocation.getAddress()); |
|||
eventSink.success(locationData); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
@Override |
|||
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { |
|||
methodChannel.setMethodCallHandler(null); |
|||
eventChannel.setStreamHandler(null); |
|||
destroyLocationClient(); |
|||
} |
|||
} |
|||
@ -1,36 +0,0 @@ |
|||
import 'amap_flutter_platform_interface.dart'; |
|||
|
|||
class AmapFlutter { |
|||
// 初始化SDK |
|||
Future<void> initSdk({String? iosKey, String? androidKey}) async { |
|||
await AmapFlutterPlatform.instance.setApiKey( |
|||
iosKey: iosKey, |
|||
androidKey: androidKey, |
|||
); |
|||
} |
|||
|
|||
// 定位初始化 |
|||
Future<void> initLocation() async { |
|||
return AmapFlutterPlatform.instance.initLocation(); |
|||
} |
|||
|
|||
// 开始定位 |
|||
Future<void> startLocation() async { |
|||
return AmapFlutterPlatform.instance.startLocation(); |
|||
} |
|||
|
|||
// 监听定位返回位置 |
|||
Stream<dynamic> locationStream() { |
|||
return AmapFlutterPlatform.instance.locationStream(); |
|||
} |
|||
|
|||
// 停止定位 |
|||
Future<void> stopLocation() async { |
|||
await AmapFlutterPlatform.instance.stopLocation(); |
|||
} |
|||
|
|||
// 销毁 |
|||
Future<void> dispose() async { |
|||
await AmapFlutterPlatform.instance.dispose(); |
|||
} |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
import 'package:flutter/foundation.dart'; |
|||
import 'package:flutter/services.dart'; |
|||
|
|||
import 'amap_flutter_platform_interface.dart'; |
|||
|
|||
/// An implementation of [AmapFlutterPlatform] that uses method channels. |
|||
class MethodChannelAmapFlutter extends AmapFlutterPlatform { |
|||
/// The method channel used to interact with the native platform. |
|||
@visibleForTesting |
|||
final methodChannel = const MethodChannel('amap_flutter'); |
|||
final eventChannel = const EventChannel('amap_flutter/events'); |
|||
|
|||
@override |
|||
Future<void> setApiKey({String? iosKey, String? androidKey}) async { |
|||
await methodChannel.invokeMethod('setApiKey', { |
|||
"iosKey": iosKey, |
|||
"androidKey": androidKey, |
|||
}); |
|||
} |
|||
|
|||
@override |
|||
Future<void> initLocation() async { |
|||
return await methodChannel.invokeMethod('initLocation'); |
|||
} |
|||
|
|||
@override |
|||
Future<void> startLocation() async { |
|||
return await methodChannel.invokeMethod('startLocation'); |
|||
} |
|||
|
|||
@override |
|||
Stream<dynamic> locationStream() { |
|||
return eventChannel.receiveBroadcastStream(); |
|||
} |
|||
|
|||
@override |
|||
Future<void> stopLocation() async { |
|||
await methodChannel.invokeMethod('stopLocation'); |
|||
} |
|||
|
|||
@override |
|||
Future<void> dispose() async { |
|||
await methodChannel.invokeMethod('dispose'); |
|||
} |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; |
|||
|
|||
import 'amap_flutter_method_channel.dart'; |
|||
|
|||
abstract class AmapFlutterPlatform extends PlatformInterface { |
|||
/// Constructs a AmapFlutterPlatform. |
|||
AmapFlutterPlatform() : super(token: _token); |
|||
|
|||
static final Object _token = Object(); |
|||
|
|||
static AmapFlutterPlatform _instance = MethodChannelAmapFlutter(); |
|||
|
|||
/// The default instance of [AmapFlutterPlatform] to use. |
|||
/// |
|||
/// Defaults to [MethodChannelAmapFlutter]. |
|||
static AmapFlutterPlatform get instance => _instance; |
|||
|
|||
/// Platform-specific implementations should set this with their own |
|||
/// platform-specific class that extends [AmapFlutterPlatform] when |
|||
/// they register themselves. |
|||
static set instance(AmapFlutterPlatform instance) { |
|||
PlatformInterface.verifyToken(instance, _token); |
|||
_instance = instance; |
|||
} |
|||
|
|||
Future<void> setApiKey({String? iosKey, String? androidKey}) { |
|||
throw UnimplementedError('init() has not been implemented.'); |
|||
} |
|||
|
|||
Future<void> initLocation() { |
|||
throw UnimplementedError('initLocation() has not been implemented.'); |
|||
} |
|||
|
|||
Future<void> startLocation() { |
|||
throw UnimplementedError('startLocation() has not been implemented.'); |
|||
} |
|||
|
|||
Stream<dynamic> locationStream() { |
|||
throw UnimplementedError('locationStream() has not been implemented.'); |
|||
} |
|||
|
|||
Future<void> stopLocation() { |
|||
throw UnimplementedError('stopLocation() has not been implemented.'); |
|||
} |
|||
|
|||
Future<void> dispose() { |
|||
throw UnimplementedError('dispose() has not been implemented.'); |
|||
} |
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
# amap_flutter |
|||
# amap_service |
|||
|
|||
A new Flutter project. |
|||
|
|||
@ -0,0 +1 @@ |
|||
rootProject.name = 'amap_service' |
|||
@ -0,0 +1,48 @@ |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
|||
package="com.yunqiinnovation.amap_service"> |
|||
<!--允许访问网络,必选权限--> |
|||
<uses-permission android:name="android.permission.INTERNET" /> |
|||
|
|||
<!--允许获取精确位置,实时导航为必选--> |
|||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
|||
|
|||
<!--允许获取粗略位置,实时导航为必选--> |
|||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> |
|||
|
|||
<!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选--> |
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
|||
|
|||
<!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选--> |
|||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> |
|||
|
|||
<!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选--> |
|||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> |
|||
|
|||
<!--后台获取位置信息,若需后台定位或持续导航则必选--> |
|||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> |
|||
|
|||
<!--用于申请调用A-GPS模块,卫星定位加速--> |
|||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> |
|||
|
|||
<!--用于用户链接蓝牙时,在导航组件页面的蓝牙连接提醒,建立链接后开发者可选用蓝牙通道进行tts播报--> |
|||
<uses-permission android:name="android.permission.BLUETOOTH" /> |
|||
|
|||
<!--用与导航状态中保持屏幕常亮--> |
|||
<uses-permission android:name="android.permission.WAKE_LOCK"/> |
|||
|
|||
<!--允许写设备缓存,用于问题排查--> |
|||
<uses-permission android:name="android.permission.WRITE_SETTINGS" /> |
|||
|
|||
<application> |
|||
<activity |
|||
android:name="com.amap.api.navi.AmapRouteActivity" |
|||
android:theme="@android:style/Theme.NoTitleBar" |
|||
android:configChanges="orientation|keyboardHidden|screenSize|navigation" /> |
|||
<service android:name="com.amap.api.location.APSService"/> |
|||
<service |
|||
android:name=".NavigationService" |
|||
android:exported="true" |
|||
android:enabled="true" android:foregroundServiceType="location|mediaPlayback"> |
|||
</service> |
|||
</application> |
|||
</manifest> |
|||
@ -0,0 +1,54 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.content.Context |
|||
import android.content.Intent |
|||
import androidx.core.content.ContextCompat |
|||
// import com.yunqiinnovation.deepvoice_utils.FileLogger |
|||
import com.yunqiinnovation.amap_service.NavigationServiceStarter |
|||
import io.flutter.embedding.engine.plugins.FlutterPlugin |
|||
import io.flutter.plugin.common.MethodCall |
|||
import io.flutter.plugin.common.MethodChannel |
|||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler |
|||
|
|||
|
|||
/** MusicServicePlugin */ |
|||
class AmapServicePlugin: FlutterPlugin, MethodCallHandler { |
|||
private val TAG = "MusicServicePlugin" |
|||
private lateinit var context: Context |
|||
private lateinit var channel : MethodChannel |
|||
|
|||
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { |
|||
context = flutterPluginBinding.applicationContext |
|||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.yunqiinnovation.music_service") |
|||
channel.setMethodCallHandler(this) |
|||
} |
|||
|
|||
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { |
|||
// FileLogger.d(TAG, "Method call: ${call.method}") |
|||
when (call.method) { |
|||
"start" -> { |
|||
val startpos = call.argument<String>("startpos") |
|||
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) |
|||
result.success(null) |
|||
} else { |
|||
result.error("INVALID_ARGUMENT", "Missing 'song' map", null) |
|||
} |
|||
} |
|||
"stop" -> { |
|||
val songs = call.argument<List<Map<String, String>>>("songs") |
|||
if (songs != null && songs.isNotEmpty()) { |
|||
NavigationServiceStarter.startServiceWithCommand(context, "stop") |
|||
result.success(null) |
|||
} else { |
|||
result.error("INVALID_ARGUMENT", "Missing or empty 'songs' list", null) |
|||
} |
|||
} |
|||
else -> result.notImplemented() |
|||
} |
|||
} |
|||
|
|||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {} |
|||
} |
|||
@ -0,0 +1,314 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.app.NotificationChannel |
|||
import android.app.NotificationManager |
|||
import android.app.Service |
|||
import android.content.Context |
|||
import android.content.Intent |
|||
import android.os.Build |
|||
import android.os.IBinder |
|||
import android.util.Log |
|||
import androidx.core.app.NotificationCompat |
|||
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 |
|||
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 |
|||
import com.amap.api.navi.model.NaviLatLng |
|||
import java.io.FileNotFoundException |
|||
import java.util.concurrent.atomic.AtomicBoolean |
|||
|
|||
|
|||
class NavigationService: Service() { |
|||
|
|||
companion object { |
|||
private const val TAG = "NavigationService" |
|||
private const val CHANNEL_ID = "navigation_channel" |
|||
private const val CHANNEL_Name = "导航服务" |
|||
private const val NOTIFICATION_ID = 1003 |
|||
|
|||
private val isRunning = AtomicBoolean(false) |
|||
private var startpos: String = "" |
|||
private var endpos: String = "" |
|||
private var naviType: String? = null |
|||
private var playlist = mutableListOf<Map<String,String>>() |
|||
private var currentIndex = 0 |
|||
|
|||
fun isServiceRunning() = isRunning.get() |
|||
} |
|||
|
|||
|
|||
private lateinit var aMapNavi: AMapNavi |
|||
|
|||
override fun onCreate() { |
|||
super.onCreate() |
|||
startForegroundNotification() |
|||
} |
|||
|
|||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { |
|||
val command = intent.getStringExtra("command") ?: return START_NOT_STICKY |
|||
when (command) { |
|||
"start" -> { |
|||
try { |
|||
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" -> { |
|||
aMapNavi.stopNavi(); |
|||
} |
|||
} |
|||
return START_STICKY |
|||
} |
|||
|
|||
|
|||
private fun startForegroundNotification() { |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
|||
val channel = NotificationChannel( |
|||
CHANNEL_ID, |
|||
CHANNEL_Name, |
|||
NotificationManager.IMPORTANCE_LOW |
|||
).apply { |
|||
description = "用于导航的前台服务" |
|||
setShowBadge(false) |
|||
} |
|||
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager |
|||
manager.createNotificationChannel(channel) |
|||
} |
|||
|
|||
val notification = NotificationCompat.Builder(this, CHANNEL_ID) |
|||
.setContentTitle("导航进行中") |
|||
.setContentText("正在导航中,请保持应用运行") |
|||
.setSmallIcon(R.drawable.ic_navigation) // 使用你自己的图标资源 |
|||
.setOngoing(true) |
|||
.build() |
|||
|
|||
startForeground(NOTIFICATION_ID, notification) |
|||
} |
|||
|
|||
// 实现监听器,处理导航播报等 |
|||
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, "路径规划请求失败") |
|||
} |
|||
} |
|||
|
|||
override fun onStartNavi(p0: Int) { |
|||
Log.e(TAG, "onStartNavi!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onTrafficStatusUpdate() { |
|||
Log.e(TAG, "onTrafficStatusUpdate!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onLocationChange(location: AMapNaviLocation) { |
|||
Log.e(TAG, "onLocationChange! ${location}") |
|||
// 可通过广播发送位置信息到 Flutter |
|||
} |
|||
|
|||
override fun onGetNavigationText(p0: Int, p1: String?) { |
|||
Log.e(TAG, "onGetNavigationText! $p0 $p1") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGetNavigationText(p0: String?) { |
|||
Log.e(TAG, "onGetNavigationText! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onEndEmulatorNavi() { |
|||
Log.e(TAG, "onEndEmulatorNavi! ") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onArriveDestination() { |
|||
Log.e(TAG, "onArriveDestination! ") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteFailure(p0: Int) { |
|||
Log.e(TAG, "路径规划失败, 错误码: $p0") |
|||
// TODO: 可添加反馈机制给 Flutter 层或用户提示 |
|||
} |
|||
|
|||
override fun onCalculateRouteFailure(p0: AMapCalcRouteResult?) { |
|||
Log.e(TAG, "onCalculateRouteFailure! ${p0}") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onReCalculateRouteForYaw() { |
|||
Log.e(TAG, "onReCalculateRouteForYaw!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onReCalculateRouteForTrafficJam() { |
|||
Log.e(TAG, "onReCalculateRouteForTrafficJam!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onArrivedWayPoint(p0: Int) { |
|||
Log.e(TAG, "onArrivedWayPoint!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGpsOpenStatus(p0: Boolean) { |
|||
Log.e(TAG, "onGpsOpenStatus!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviInfoUpdate(p0: NaviInfo?) { |
|||
Log.e(TAG, "onNaviInfoUpdate! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateCameraInfo(p0: Array<out AMapNaviCameraInfo>?) { |
|||
Log.e(TAG, "updateCameraInfo! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateIntervalCameraInfo( |
|||
p0: AMapNaviCameraInfo?, |
|||
p1: AMapNaviCameraInfo?, |
|||
p2: Int |
|||
) { |
|||
Log.e(TAG, "updateIntervalCameraInfo! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onServiceAreaUpdate(p0: Array<out AMapServiceAreaInfo>?) { |
|||
Log.e(TAG, "onServiceAreaUpdate! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showCross(p0: AMapNaviCross?) { |
|||
Log.e(TAG, "showCross! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideCross() { |
|||
Log.e(TAG, "hideCross!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun showModeCross(p0: AMapModelCross?) { |
|||
Log.e(TAG, "showModeCross! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideModeCross() { |
|||
Log.e(TAG, "hideModeCross!") |
|||
// 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 showLaneInfo(p0: AMapLaneInfo?) { |
|||
Log.e(TAG, "showLaneInfo! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun hideLaneInfo() { |
|||
Log.e(TAG, "hideLaneInfo!") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onCalculateRouteSuccess(ids: IntArray?) { |
|||
Log.e(TAG, "onCalculateRouteSuccess! $ids") |
|||
aMapNavi.startNavi(NaviType.EMULATOR) |
|||
} |
|||
|
|||
override fun onCalculateRouteSuccess(p0: AMapCalcRouteResult?) { |
|||
Log.e(TAG, "onCalculateRouteSuccess! $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun notifyParallelRoad(p0: Int) { |
|||
Log.d(TAG, "是否在拥挤平行路段: $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun OnUpdateTrafficFacility(p0: Array<out AMapNaviTrafficFacilityInfo>?) { |
|||
Log.d(TAG, "OnUpdateTrafficFacility: $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun OnUpdateTrafficFacility(p0: AMapNaviTrafficFacilityInfo?) { |
|||
Log.d(TAG, "OnUpdateTrafficFacility: $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun updateAimlessModeStatistics(p0: AimLessModeStat?) { |
|||
// TODO("Not yet implemented") |
|||
Log.d(TAG, "updateAimlessModeStatistics: $p0") |
|||
} |
|||
|
|||
override fun updateAimlessModeCongestionInfo(p0: AimLessModeCongestionInfo?) { |
|||
// TODO("Not yet implemented") |
|||
Log.d(TAG, "updateAimlessModeCongestionInfo: $p0") |
|||
} |
|||
|
|||
override fun onPlayRing(p0: Int) { |
|||
Log.d(TAG, "onPlayRing: $p0") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onNaviRouteNotify(p0: AMapNaviRouteNotifyData?) { |
|||
Log.w(TAG, "GPS信号弱") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
|
|||
override fun onGpsSignalWeak(p0: Boolean) { |
|||
Log.w(TAG, "GPS信号弱") |
|||
// TODO("Not yet implemented") |
|||
} |
|||
} |
|||
|
|||
override fun onBind(intent: Intent?): IBinder? = null |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
package com.yunqiinnovation.amap_service |
|||
|
|||
import android.content.Context |
|||
import android.content.Intent |
|||
import android.util.Log |
|||
import androidx.core.content.ContextCompat |
|||
|
|||
object NavigationServiceStarter { |
|||
private val TAG = "NavigationServiceStarter" |
|||
//播放单曲 |
|||
fun startServiceWithCommand(context: Context, command: String, startpos: String? = null, endpos: String? = null, ntype: String? = null) { |
|||
Log.i(TAG, "liwei------------------- startServiceWithCommand: $command $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 |
|||
} |
|||
} |
|||
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") |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24" |
|||
android:viewportHeight="24"> |
|||
<path |
|||
android:fillColor="#FFFFFF" |
|||
android:pathData="M12,2L3,21h9v-6h6v6h3L12,2z" /> |
|||
</vector> |
|||
@ -1,10 +1,10 @@ |
|||
import Flutter |
|||
import UIKit |
|||
|
|||
public class AmapFlutterPlugin: NSObject, FlutterPlugin { |
|||
public class AmapServicePlugin: NSObject, FlutterPlugin { |
|||
public static func register(with registrar: FlutterPluginRegistrar) { |
|||
let channel = FlutterMethodChannel(name: "amap_flutter", binaryMessenger: registrar.messenger()) |
|||
let instance = AmapFlutterPlugin() |
|||
let channel = FlutterMethodChannel(name: "amap_service", binaryMessenger: registrar.messenger()) |
|||
let instance = AmapServicePlugin() |
|||
registrar.addMethodCallDelegate(instance, channel: channel) |
|||
} |
|||
|
|||
@ -0,0 +1,60 @@ |
|||
import 'package:flutter/services.dart'; |
|||
|
|||
class AmapService { |
|||
static final AmapService _instance = AmapService._internal(); |
|||
|
|||
/// 获取单例 |
|||
factory AmapService() => _instance; |
|||
|
|||
// 方法通道 |
|||
final MethodChannel _methodChannel = const MethodChannel( |
|||
'com.yunqiinnovation.amap_service', |
|||
); |
|||
|
|||
// 事件通道 - 简化为只使用数据和状态通道 |
|||
late final EventChannel _dataEventChannel; |
|||
late final EventChannel _statusEventChannel; |
|||
|
|||
// 事件流 |
|||
late final Stream<dynamic> _dataStream; |
|||
late final Stream<dynamic> _statusStream; |
|||
|
|||
// 获取事件流 |
|||
Stream<dynamic> get onDataReceived => _dataStream; |
|||
|
|||
// 状态流直接传递原始数据 |
|||
Stream<dynamic> get onStatusUpdated => _statusStream; |
|||
|
|||
// 内部构造函数 |
|||
AmapService._internal() { |
|||
_dataEventChannel = const EventChannel( |
|||
'com.yunqiinnovation.amap_service/data_events', |
|||
); |
|||
_statusEventChannel = const EventChannel( |
|||
'com.yunqiinnovation.amap_service/status_events', |
|||
); |
|||
|
|||
// 初始化事件流 |
|||
_dataStream = _dataEventChannel.receiveBroadcastStream(); |
|||
_statusStream = _statusEventChannel.receiveBroadcastStream(); |
|||
} |
|||
// 初始化SDK |
|||
Future<void> initSdk({String? iosKey, String? androidKey}) async {} |
|||
|
|||
// 定位初始化 |
|||
Future<void> initLocation() async {} |
|||
|
|||
// 开始定位 |
|||
Future<void> startLocation() async {} |
|||
|
|||
// 监听定位返回位置 |
|||
Stream<dynamic> locationStream() { |
|||
return _dataStream; |
|||
} |
|||
|
|||
// 停止定位 |
|||
Future<void> stopLocation() async {} |
|||
|
|||
// 销毁 |
|||
Future<void> dispose() async {} |
|||
} |
|||
Loading…
Reference in new issue