Flutter implementa la función de navegación del mapa de Gaode llamando Android nativo (complemento)

Después de verificar la documentación del complemento flutter de mapa de Gaode, no hay función de navegación, y el complemento flutter Gaode admite muy pocas funciones. No hay forma, solo puede usar la navegación nativa de Android, y flutter lo llama. La implementación específica método es el siguiente:

  1. Crear un complemento de Flutter

El uso de la instrucción --template=plugin crea un complemento que contiene código de iOS y Android;

Use la opción --org para especificar la organización, generalmente usando notación de nombre de dominio inversa;

Use la opción -i para especificar el lenguaje de desarrollo de la plataforma iOS, objc o swift;

Use la opción -a para especificar el lenguaje de desarrollo de la plataforma Android, java o kotlin.

flutter create --template=plugin --org com.tencent.game -i objc -a java flutter_amap_nav
  1. estructura del proyecto

Podemos ver que hay algunos directorios más en el complemento, el directorio android se usa para la implementación del código de la plataforma Android, el directorio ios se usa para la implementación del código de la plataforma iOS y el directorio de ejemplo se usa para depurar el componente. .

  1. En androidStudio, haga clic con el botón derecho en el directorio de Android, seleccione flutter y ábralo como un proyecto de Android, de la siguiente manera:

  1. En este punto, el proyecto que estamos abriendo se puede utilizar para el desarrollo remoto de Android. Con respecto al SDK de la parte de navegación de Android, hay ejemplos en la documentación oficial de AutoNavi, y se adjunta el enlace del sitio web oficial https: //lbs.amap .com/api/android-navi-sdk/resumen/

Para la aplicación clave de API de mapa de Gaode, consulte https://lbs.amap.com/api/android-navi-sdk/guide/create-project/get-key para obtener el SHA1 de la versión de depuración y la versión de lanzamiento (cuando solicitando la clave, estos dos SHA1 se pueden completar en el mismo), cabe señalar que el nombre del paquete se obtiene en el paquete de AndroidManifest.xml

Después de obtener la clave, agregue los siguientes permisos en el archivo 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" />

Además, es necesario añadir un servicio de posicionamiento en mapas

  <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()&&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() {

                @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

Supongo que te gusta

Origin blog.csdn.net/m0_60546228/article/details/129464642
Recomendado
Clasificación