查看了高德地图flutter插件的文档,都没有能支持导航的功能,并且flutter的高德插件支持的功能特别少,没办法,只能使用安卓原生的导航,flutter去调用了,具体实现方式如下:
创建 Flutter 插件
使用--template=plugin 声明创建的是同时包含了 iOS 和 Android 代码的 plugin;
使用--org 选项指定组织,一般采用反向域名表示法;
使用-i 选项指定 iOS 平台开发语言,objc 或者 swift;
使用-a 选项指定 Android 平台开发语言,java 或者 kotlin。
flutter create --template=plugin --org com.tencent.game -i objc -a java flutter_amap_nav
项目结构

我们可以看到 Plugin 多出了一些目录,android 目录用于 Android 平台的代码实现,ios 目录用于 iOS 平台的代码实现,example 目录用于该组件的调试。
在androidStudio下,右键android目录,选择flutter,以安卓工程打开,具体如下:

此时,我们在打开的这个项目就可以进行远程的安卓开发了,关于安卓导航部分的SDK,高德的官方文档上面有示例,附上官网链接https://lbs.amap.com/api/android-navi-sdk/summary/
高德地图APIkey申请可参考https://lbs.amap.com/api/android-navi-sdk/guide/create-project/get-key,获取调试版本和发布版本的SHA1(在申请key的时候,这两个SHA1可填写一致),需要注意的是包名在AndroidManifest.xml的package获取
获取好Key之后,在AndroidManifest.xml文件中,添加如下权限
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取精确位置,实时导航为必选-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--允许获取粗略位置,实时导航为必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--允许获取设备和运营商信息,用于问题排查和网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许获取网络状态,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变,用于网络定位(无gps情况下的定位),若需网络定位功能则必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--后台获取位置信息,若需后台定位或持续导航则必选-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!--用于申请调用A-GPS模块,卫星定位加速-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许写入扩展存储,用于写入缓存定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--用于用户链接蓝牙时,在导航组件页面的蓝牙连接提醒,建立链接后开发者可选用蓝牙通道进行tts播报-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--用与导航状态中保持屏幕常亮-->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!--允许读设备等信息,用于问题排查-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
并且,需要添加地图定位的服务
<application>
<service android:name="com.amap.api.location.APSService"></service>
<activity
android:name="com.amap.api.navi.AmapRouteActivity"
android:theme="@android:style/Theme.NoTitleBar"
android:configChanges="orientation|keyboardHidden|screenSize|navigation" />
</application>
在build.gradle文件中添加导航SDK的依赖,需要需要build.gradle在安卓工程中有两个文件,不要写错位置了,我使用的方式是自动获取最新的依赖包,当然也可以采用手动引入jar包的方式,可参考官方文档的安卓工程手动部署https://lbs.amap.com/api/android-navi-sdk/guide/create-project/manual-configuration
implementation 'com.amap.api:navi-3dmap:latest.integration'


接着,我们在app目录下的AndroidManifest.xml添加apiKey

现在, 我们就可以写安卓代码了,在java目录下,新建mapView和MyViewFactory类,在mapView类下面代码实现如下:
package com.example.amap_nav;
import android.content.Context;
import android.view.View;
import android.webkit.WebView;
import android.widget.TextView;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Poi;
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.NaviSetting;
import com.amap.api.navi.INaviInfoCallback;
import com.amap.api.navi.model.AMapNaviLocation;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
public class mapView implements PlatformView {
private final View Nav;
private final AmapNaviParams naviParams;
public mapView(Context context, BinaryMessenger messenger, int id, Map<String, Object> params){
Poi start;
Poi end;
TextView textView = new TextView(context);
// 隐私合规检查
NaviSetting.updatePrivacyShow(context, true, true);
NaviSetting.updatePrivacyAgree(context, true);
if (params!=null&&!params.isEmpty()&¶ms.containsKey("start")) {
String start1 = (String) params.get("start");
String end1 = (String) params.get("end");
textView.setText(start1+end1);
double a = Double.parseDouble(start1.split(",")[0]) ;
double b = Double.parseDouble(start1.split(",")[1]) ;
double c = Double.parseDouble(end1.split(",")[0]) ;
double d = Double.parseDouble(end1.split(",")[1]) ;
start = new Poi(null, new LatLng(a,b), null);
end = new Poi(null, new LatLng(c,d), null);
// 组件参数配置
//构建导航组件配置类,没有传入起点,所以起点默认为 “我的位置”
naviParams = new AmapNaviParams(start,null,end, AmapNaviType.DRIVER, AmapPageType.ROUTE);
naviParams.setUseInnerVoice(true);
naviParams.setMultipleRouteNaviMode(true);
naviParams.setNeedDestroyDriveManagerInstanceWhenNaviExit(true);
//启动导航组件
AmapNaviPage.getInstance().showRouteActivity(context.getApplicationContext(), naviParams,new INaviInfoCallback() {
@Override
public void onInitNaviFailure() {
}
@Override
public void onGetNavigationText(String s) {
}
@Override
public void onLocationChange(AMapNaviLocation aMapNaviLocation) {
}
@Override
public void onArriveDestination(boolean b) {
}
@Override
public void onStartNavi(int i) {
}
@Override
public void onCalculateRouteSuccess(int[] ints) {
}
@Override
public void onCalculateRouteFailure(int i) {
}
@Override
public void onStopSpeaking() {
}
@Override
public void onReCalculateRoute(int i) {
}
@Override
public void onExitPage(int i) {
}
@Override
public void onStrategyChanged(int i) {
}
@Override
public void onArrivedWayPoint(int i) {
}
@Override
public void onMapTypeChanged(int i) {
}
@Override
public void onNaviDirectionChanged(int i) {
}
@Override
public void onDayAndNightModeChanged(int i) {
}
@Override
public void onBroadcastModeChanged(int i) {
}
@Override
public void onScaleAutoChanged(boolean b) {
}
@Override
public View getCustomMiddleView() {
return null;
}
@Override
public View getCustomNaviView() {
return null ;
}
@Override
public View getCustomNaviBottomView() {
TextView textView1 = new TextView(context);
String a = "123123213123123";
textView1.setText(a);
return textView1 ;
}
});
// 拿到flutter传递过来的参数
this.Nav = textView;
} else {
textView.setText(null);
this.Nav = textView;
naviParams = null;
}
}
@Override
public View getView() {
return Nav;
}
@Override
public void dispose() {
}
}
在MyViewFactory类下面代码实现如下:
package com.example.amap_nav;
import android.content.Context;
import com.example.amap_nav.mapView;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
public class MyViewFactory extends PlatformViewFactory {
private final BinaryMessenger messenger;
public MyViewFactory(BinaryMessenger messenger) {
super(StandardMessageCodec.INSTANCE);
this.messenger = messenger;
}
@Override
@SuppressWarnings("unchecked")
public PlatformView create(Context context, int id, Object o) {
Map<String, Object> params = (Map<String, Object>) o;
return new mapView(context, messenger, id, params);
}
}
接着,我们去flutter自动创建plugin

的代码实现如下:
package com.example.amap_nav;
import android.util.Log;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BasicMessageChannel;
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 io.flutter.plugin.common.StringCodec;
import com.example.amap_nav.MyViewFactory;
/** AmapNavPlugin */
public class AmapNavPlugin implements FlutterPlugin, MethodCallHandler {
private MethodChannel channel;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
// 需要注册的视图的唯一标识
final String key = "karl_info";
// 创建MethodChannel通道,amap_nav与yaml的name是需要对应的
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "amap_nav");
channel.setMethodCallHandler(this);
// 注册原生view,通过注册视图工厂(viewFactory),需要传入唯一标识和ViewFactory类
flutterPluginBinding.getPlatformViewRegistry().registerViewFactory(key,new MyViewFactory(flutterPluginBinding.getBinaryMessenger()));
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE +call.arguments);
}
else if (call.method.equals("startEnd")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
}
else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
}
然后在MainActivity.java里面注册一下视图
package com.example.amap_nav_example;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}
到这里,安卓部分的代码已经完成了,然后我们回到flutter目录,在lib目录下添加load.dart文件,代码如下:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class navWidget extends StatelessWidget {
const navWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
String viewType = 'karl_info'; // 唯一标识符
var creationParams = {
'start':'30.501258, 114.414684',
'end': '30.511258,114.434684'
};// 视图创建参数,可以被插件用来传递构造函数参数到嵌入式Android视图
// 视图创建完毕的回调
PlatformViewCreatedCallback callback = (id) {};
// 判断设备类型,也可用:defaultTargetPlatform == TargetPlatform.android
if (Platform.isAndroid) {
return AndroidView(
viewType: viewType,
onPlatformViewCreated: callback,
creationParams: creationParams,
//参数的编码方式
creationParamsCodec: const StandardMessageCodec(),
);
} else if (Platform.isIOS) {
return UiKitView(
viewType: viewType,
onPlatformViewCreated: callback,
);
} else {
return Text('您的设备暂不支持此软件');
}
}
}
在flutter自动创建lib目录下的dart文件中实现方式如下:
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
class AmapNav {
static const MethodChannel _channel = MethodChannel('amap_nav');
static Future<String?> get platformVersion async {
//invokeMethod传参方式
final String? version = await _channel.invokeMethod('getPlatformVersion',666);
return version;
}
static Future<String?> get startEnd async {
}
}
大功告成,项目跑起来的页面如下,后续各种导航的功能可参考官网实现定制化开发,github地址https://github.com/shenlan42/flutter_amap_nav


