2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > flutter实现调用原生安卓的高德地图导航功能(插件化)

flutter实现调用原生安卓的高德地图导航功能(插件化)

时间:2022-04-21 17:00:05

相关推荐

flutter实现调用原生安卓的高德地图导航功能(插件化)

查看了高德地图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,高德的官方文档上面有示例,附上官网链接/api/android-navi-sdk/summary/

高德地图APIkey申请可参考/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><activityandroid: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包的方式,可参考官方文档的安卓工程手动部署/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.mon.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()&&params.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() {@Overridepublic void onInitNaviFailure() {}@Overridepublic void onGetNavigationText(String s) {}@Overridepublic void onLocationChange(AMapNaviLocation aMapNaviLocation) {}@Overridepublic void onArriveDestination(boolean b) {}@Overridepublic void onStartNavi(int i) {}@Overridepublic void onCalculateRouteSuccess(int[] ints) {}@Overridepublic void onCalculateRouteFailure(int i) {}@Overridepublic void onStopSpeaking() {}@Overridepublic void onReCalculateRoute(int i) {}@Overridepublic void onExitPage(int i) {}@Overridepublic void onStrategyChanged(int i) {}@Overridepublic void onArrivedWayPoint(int i) {}@Overridepublic void onMapTypeChanged(int i) {}@Overridepublic void onNaviDirectionChanged(int i) {}@Overridepublic void onDayAndNightModeChanged(int i) {}@Overridepublic void onBroadcastModeChanged(int i) {}@Overridepublic void onScaleAutoChanged(boolean b) {}@Overridepublic View getCustomMiddleView() {return null;}@Overridepublic View getCustomNaviView() {return null ;}@Overridepublic 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;}}@Overridepublic View getView() {return Nav;}@Overridepublic void dispose() {}}

在MyViewFactory类下面代码实现如下:

package com.example.amap_nav;import android.content.Context;import com.example.amap_nav.mapView;import java.util.Map;import io.mon.BinaryMessenger;import io.mon.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.mon.BasicMessageChannel;import io.mon.MethodCall;import io.mon.MethodChannel;import io.mon.MethodChannel.MethodCallHandler;import io.mon.MethodChannel.Result;import io.mon.StringCodec;import com.example.amap_nav.MyViewFactory;/** AmapNavPlugin */public class AmapNavPlugin implements FlutterPlugin, MethodCallHandler {private MethodChannel channel;@Overridepublic 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()));}@Overridepublic 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();}}@Overridepublic 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 {@Overridepublic 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);@overrideWidget 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.androidif (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地址/shenlan42/flutter_amap_nav

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。