先上flutter doctor:
flutter sdk版本为:3.19.4
引入依赖:
在app的build.gradle下,添加如下依赖:
implementation 'com.amap.api:navi-3dmap:10.0.700_3dmap10.0.700'
navi-3dmap里面包含了定位功能,地图功能,所以引入这一个包就行
1.在项目的android-app-src-包名 路径下,新建一个class,起名为:AMapNaviPlugin,
AMapNaviPlugin代码如下:
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Poi;
import com.amap.api.navi.AMapNavi;
import com.amap.api.navi.AmapNaviPage;
import com.amap.api.navi.AmapNaviParams;
import com.amap.api.navi.AmapNaviType;
import com.amap.api.navi.AmapPageType;
import com.amap.api.navi.INaviInfoCallback;
import com.amap.api.navi.NaviSetting;
import com.amap.api.navi.model.AMapNaviLocation;
import java.util.HashMap;
import java.util.Map;
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.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class AMapNaviPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
private static MethodChannel channel;
private static Context mContext = null;
//通讯名称,回到手机桌面
private static String CHANNEL = "com.kdcf.channel/aMapNavi";
private Activity activity;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
if (null == mContext) {
mContext = binding.getApplicationContext();
}
initMethodChannel(binding.getBinaryMessenger());
}
private void initMethodChannel(BinaryMessenger binaryMessenger) {
if (null == binaryMessenger) {
return;
}
channel = new MethodChannel(binaryMessenger, CHANNEL);
channel.setMethodCallHandler(this);
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
channel = null;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (mContext == null) {
result.error("-1", "context is null", null);
}
if (call.method.equals(NaviConstant.START_NAVI)) {
try {
Object arguments = call.arguments;
Map<String,Object> map= (Map<String, Object>) arguments;
Double endLongitude= (Double) map.get("endLongitude");
Double endLatitude= (Double) map.get("endLatitude");
String endPlaceName= (String) map.get("endPlaceName");
String endPoiId= (String) map.get("endPoiId");
Map<String,Object> extraParams= (Map<String, Object>) map.get("extraParams");
Log.e("AMapNaviPlugin","endLongitude:"+endLongitude);
Log.e("AMapNaviPlugin","endLatitude:"+endLatitude);
Log.e("AMapNaviPlugin","endPlaceName:"+endPlaceName);
Log.e("AMapNaviPlugin","endPoiId:"+endPoiId);
Log.e("AMapNaviPlugin","extraParams参数如下:");
for (Map.Entry<String, Object> entry : extraParams.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
startNavi(endLongitude,endLatitude,endPlaceName,endPoiId,extraParams);
} catch (Exception e) {
Log.e("AMapNaviPlugin","异常:"+e.toString());
result.error("ERROR","AMapNaviPlugin onMethodCall startNavi出错:"+e.toString(),null);
}
result.success(200);
}else if (call.method.equals(NaviConstant.AGREE_PRIVACY)) {
try {
NaviSetting.updatePrivacyShow(mContext, true, true);
NaviSetting.updatePrivacyAgree(mContext, true);
} catch (Exception e) {
Log.e("AMapNaviPlugin",e.toString());
result.error("ERROR","AMapNaviPlugin onMethodCall agreePrivacy出错:"+e.toString(),null);
}
result.success(200);
}else if (call.method.equals(NaviConstant.CANCEL_NAVI)) {
try {
AMapNavi.getInstance(mContext).playTTS("导航已结束",true);
//退出导航组件
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 这里是延时后需要执行的代码
//退出导航组件
AmapNaviPage.getInstance().exitRouteActivity();
}
}, 5000);
} catch (Exception e) {
Log.e("AMapNaviPlugin",e.toString());
result.error("ERROR","AMapNaviPlugin onMethodCall CANCEL_NAVI出错:"+e.toString(),null);
}
result.success(200);
}
}
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
activity = binding.getActivity();
}
@Override
public void onDetachedFromActivityForConfigChanges() {
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
}
@Override
public void onDetachedFromActivity() {
}
void startNavi(Double endLongitude,Double endLatitude,String endPlaceName,String endPoiId,Map<String,Object> extraParams){
//起点
// Poi start = new Poi("北京首都机场", new LatLng(40.080525,116.603039), "B000A28DAE");
//途经点
// List<Poi> poiList = new ArrayList();
// poiList.add(new Poi("故宫", new LatLng(39.918058,116.397026), "B000A8UIN8"));
//终点
Poi end = new Poi(endPlaceName, new LatLng(endLatitude,endLongitude),endPoiId);
// 组件参数配置
AmapNaviParams params = new AmapNaviParams(null, null, end, AmapNaviType.DRIVER, AmapPageType.NAVI);
// 启动组件
AmapNaviPage.getInstance().showRouteActivity(mContext.getApplicationContext(), params, new NaviInfoCallback(mContext,channel,extraParams));
}
}
新建NaviConstant类,代码如下:
public class NaviConstant {
//开始导航,flutter向原生传值
public static String START_NAVI="startNavi";
//同意隐私政策,flutter向原生传值
public static String AGREE_PRIVACY="agreePrivacy";
//到达目的地,原生向flutter传值
public static String ARRIVE_Destination="arriveDestination";
//取消导航
public static String CANCEL_NAVI="cancelNavi";
}
新建NaviInfoCallback类,代码如下:
package com.daohe.kdchufadriver.navi;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import com.amap.api.navi.INaviInfoCallback;
import com.amap.api.navi.model.AMapNaviLocation;
import com.amap.api.navi.AmapNaviPage;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodChannel;
public class NaviInfoCallback implements INaviInfoCallback {
Context context;
MethodChannel channel;
Map<String,Object> extraParams;
public NaviInfoCallback(Context context,MethodChannel channel,Map<String,Object> extraParams) {
this.context=context;
this.channel=channel;
this.extraParams=extraParams;
}
@Override
public void onInitNaviFailure() {
Log.e("NaviInfoCallback","onInitNaviFailure");
}
@Override
public void onGetNavigationText(String s) {
Log.e("onGetNavigationText","onGetNavigationText:"+s);
// //模拟到达终点
// Map<String,Object> result=new HashMap<>();
// result.put("result",extraParams);
// channel.invokeMethod(NaviConstant.ARRIVE_Destination,result);
// //退出导航组件
// Handler handler = new Handler();
// handler.postDelayed(new Runnable() {
// @Override
// public void run() {
// // 这里是延时后需要执行的代码
// //退出导航组件
// AmapNaviPage.getInstance().exitRouteActivity();
// }
// }, 5000);
}
@Override
public void onLocationChange(AMapNaviLocation aMapNaviLocation) {
Log.e("onGetNavigationText","onLocationChange");
}
//isEmulaterNavi - true代表是模拟导航到达目的地,false代表实时导航到达目的地
@Override
public void onArriveDestination(boolean isEmulaterNavi) {
Map<String,Object> result=new HashMap<>();
result.put("result",extraParams);
channel.invokeMethod(NaviConstant.ARRIVE_Destination,result);
//退出导航组件
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 这里是延时后需要执行的代码
//退出导航组件
AmapNaviPage.getInstance().exitRouteActivity();
}
}, 5000);
}
@Override
public void onStartNavi(int i) {
Log.e("onGetNavigationText","onStartNavi "+String.valueOf(i));
}
@Override
public void onCalculateRouteSuccess(int[] ints) {
Log.e("onGetNavigationText","onCalculateRouteSuccess "+String.valueOf(ints));
}
@Override
public void onCalculateRouteFailure(int i) {
Log.e("onGetNavigationText","onCalculateRouteFailure "+String.valueOf(i));
}
@Override
public void onStopSpeaking() {
Log.e("onGetNavigationText","onStopSpeaking");
}
@Override
public void onReCalculateRoute(int i) {
Log.e("onGetNavigationText","onReCalculateRoute "+String.valueOf(i));
}
@Override
public void onExitPage(int i) {
Log.e("onGetNavigationText","onExitPage "+String.valueOf(i));
}
@Override
public void onStrategyChanged(int i) {
Log.e("onGetNavigationText","onStrategyChanged "+String.valueOf(i));
}
@Override
public void onArrivedWayPoint(int i) {
Log.e("onGetNavigationText","onArrivedWayPoint "+String.valueOf(i));
}
@Override
public void onMapTypeChanged(int i) {
Log.e("onGetNavigationText","onMapTypeChanged "+String.valueOf(i));
}
@Override
public void onNaviDirectionChanged(int i) {
Log.e("onGetNavigationText","onNaviDirectionChanged "+String.valueOf(i));
}
@Override
public void onDayAndNightModeChanged(int i) {
Log.e("onGetNavigationText","onDayAndNightModeChanged "+String.valueOf(i));
}
@Override
public void onBroadcastModeChanged(int i) {
Log.e("onGetNavigationText","onBroadcastModeChanged "+String.valueOf(i));
}
@Override
public void onScaleAutoChanged(boolean b) {
Log.e("onGetNavigationText","onScaleAutoChanged "+b);
}
@Override
public View getCustomMiddleView() {
return null;
}
@Override
public View getCustomNaviView() {
return null;
}
@Override
public View getCustomNaviBottomView() {
return null;
}
}
android端的代码到这里就完了
下面是Flutter端的代码
在Flutter新建dart文件,起名amap_navi_plugin.dart
代码如下:
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
//司机到达目的地附近的回调
typedef OnArriveCallBack=void Function(dynamic params);
//高德导航插件
class AMapNaviPlugin {
//开始导航
static const START_NAVI="startNavi";
//同意隐私政策
static const AGREE_PRIVACY="agreePrivacy";
//到达目的地给flutter回调
static const ARRIVE_Destination="arriveDestination";
//取消导航
static const CANCEL_NAVI="cancelNavi";
//初始化通信管道
static const String CHANNEL = "com.kdcf.channel/aMapNavi";
static const platform = MethodChannel(CHANNEL);
//开始导航
//参数目的地经度、纬度、地点名称
static Future<void> startAmapNavi(double endLongitude,double endLatitude,String endPlaceName,String poiId,Map extraParams) async {
//通知安卓返回,到手机桌面
try {
Map map=Map();
map['endLongitude']=endLongitude;
map['endLatitude']=endLatitude;
map['endPlaceName']=endPlaceName;
map['extraParams']=extraParams;
map['endPoiId']=poiId;
// map['endLongitude']=103.85741;
// map['endLatitude']=36.05407;
// map['endPoiId']='';
final dynamic result = await platform.invokeMethod(START_NAVI,map);
if (result==200) {
debugPrint("导航成功");
}
} on PlatformException catch (e) {
debugPrint("通信失败 AMapNaviPlugin startAmapNavi:失败 ${e.toString()}");
print(e.toString());
}catch(e){
debugPrint("导航失败:${e.toString()}");
}
}
static void agreePrivacy() async {
//通知安卓返回,到手机桌面
try {
final int result=await platform.invokeMethod(AGREE_PRIVACY);
if (result==200) {
debugPrint("同意导航隐私政策成功");
}
} on PlatformException catch (e) {
debugPrint("通信失败 AMapNaviPlugin agreePrivacy:失败 ${e.toString()}");
print(e.toString());
}catch(e){
debugPrint("同意导航隐私政策失败:${e.toString()}");
}
}
//原生往flutter发消息,导航快到目的地的时候
static void arriveDestination(OnArriveCallBack onArriveCallBack) async {
//通知安卓返回,到手机桌面
try {
Future<dynamic> handler(MethodCall call) async {
debugPrint("flutter收到消息:arriveDestination");
switch (call.method) {
case ARRIVE_Destination:
Map result=call.arguments;
debugPrint("ARRIVE_Destination参数:"+jsonEncode(result));
onArriveCallBack(result);
break;
}
}
platform.setMethodCallHandler((call) => handler(call));
} on PlatformException catch (e) {
debugPrint("通信失败 AMapNaviPlugin arriveDestination:失败 ${e.toString()}");
print(e.toString());
}catch(e){
debugPrint("arriveDestination失败:${e.toString()}");
}
}
//flutter往原生发消息,取消订单的时候 取消导航
static void cancelNavi() async {
//通知安卓返回,到手机桌面
try {
final int result=await platform.invokeMethod(CANCEL_NAVI);
if (result==200) {
debugPrint("取消导航成功");
}
} on PlatformException catch (e) {
debugPrint("通信失败 AMapNaviPlugin cancelNavi:失败 ${e.toString()}");
print(e.toString());
}catch(e){
debugPrint("取消导航失败:${e.toString()}");
}
}
}
最后,使用方法
AMapNaviPlugin.startAmapNavi(longitude,latitude,destinationTitle,poiId,extraParams);
longitude为终点经度,latitude为终点纬度,destinationTitle为目的地的汉字名称,比如北京XXXX。poiId可以不传,extraParams可以不传。
最后,附上一个运行视频:
Flutter集成高德导航Android端插件
以后还会完成的相关文章如下:
目前本人已完成项目里面以下技术的实现,但是还没时间写博客,工作太忙了,以后会完善。。。待续。。。
1. Flutter集成高德导航SDK(IOS篇)(OC语法)
2. Flutter集成高德导航SDK并且自定义导航UI页面(Android篇)(JAVA语法)
3. Flutter集成高德导航SDK并且自定义导航UI页面(IOS篇)(OC语法)