CocosCreator系列——接入高德地图sdk获取经纬度信息图文详解

CocosCreator接入高德地图sdk获取经纬度信息图文详解

先看效果
在这里插入图片描述

1.首先去 高德开放平台.申请key
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
点击添加
在这里插入图片描述
接下来该获取发布版和调试版的SHA1了,首先打开cmd命令窗口
输入命令:cd .android(首先进入用户系统的安卓文件夹)
然后输入命令:keytool -list -v -keystore debug.keystore
然后会提示输入密码,输入:android 然后回车注意:这个时候输入密码是不会显示的,输入完成以后直接回车就好,这个时候就可以看到这个时候就得到了调试版的SHA1,如下图

在这里插入图片描述
接下来是发布版的SHA1,我是用的Android studio来获取的,首先打开Android studio导入打开工程,选择Build,然后Generate Signed Bundle/APK
在这里插入图片描述
然后选择APK,Next
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
这个时候我们需要用到的jks文件已经输出好了,找到刚才自己定义的输出文件夹
在这里插入图片描述
这个时候再次打开cmd命令台重复调试版,输入cd .android进入安卓文件夹,然后输入命令keytool -list -v -keystore D:\Android\AndroidKey\test.jks(完整版文件路径),然后输入密码:android,然后回车

在这里插入图片描述
至此两个版本的SHA1全部获取完毕,接下来就是包名,包名就是自己打包apk文件是的包名,然后提交
在这里插入图片描述
提交后会得到key,到时配置sdk时会用到,记下来
在这里插入图片描述
至此前期全部准备工作全部完毕,接下来该写代码了
首先是js客户端代码

cc.Class({
    extends: cc.Component,

    properties: {
        label: {
            default: null,
            type: cc.Label
        },
        // defaults, set visually when attaching this script to the Canvas
        text: 'Hello, World!',
    },

    // use this for initialization
    onLoad: function () {
        this.label.string = this.text;
        if (cc.sys.isNative && cc.sys.os == cc.sys.OS_ANDROID) {
            this.schedule(() => {
                this.onGetLocation();
            }, 3)
        }
    },

    onGetLocation() {
        var localtionInfo = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "getLocationInfo", "()Ljava/lang/String;");
        if (!localtionInfo ) {
            cc.log("当前无返回!!!!!!!!!!!!!!!!!!!!!!!!");
            return
        }
        this.label.string = "拿到位置信息\n:" + localtionInfo ;
    },

把下载的高德sdk的jar文件导入到Android studio工程目录下app文件夹下的libs文件夹下,如果没有,则新建一个libs文件夹,如下图
在这里插入图片描述
然后配置AndroidManifest.xml文件权限

    <!-- Normal Permissions 不需要运行时注册 -->
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
    <!-- 请求网络 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- 不是SDK需要的权限,是示例中的后台唤醒定位需要的权限 -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <!-- 需要运行时注册的权限 -->
    <!-- 用于进行网络定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <!-- 用于访问GPS定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!-- 用于提高GPS定位速度 -->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
    <!-- 写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 读取缓存数据 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!-- 用于读取手机当前的状态 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <!-- 更改设置 -->
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
    <!--如果设置了target >= 28 如果需要启动后台定位则必须声明这个权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <!--如果您的应用需要后台定位权限,且有可能运行在Android Q设备上,并且设置了target>28,必须增加这个权限声明-->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

接下来把申请到的key写入application配置里面

<!-- 定位sdk需要配置 -->
      <meta-data
          android:name="com.amap.api.v2.apikey"
          android:value="这里写入高德开放平台申请的key"/>
<service android:name="com.amap.api.location.APSService"></service>

我这个做了安卓6.0以后及之前旧版的逻辑,因为6.0之后要动态申请权限,网上找了好多资料都搞不定(手动头大(ˉ▽ˉ;)…),然后下载了官方的demo研究了一下,瞬间搞定,在此也建议以后接sdk之前最好先到官网看一下文档,然后把德莫下载下来看一下,比直接在网上找其它资源效果会好很多,接下来看AppActivity.java原生代码,首先在onCreate()之前声明各种变量及初始化参数

    public static AMapLocationClient locationClient = null;
    public static AMapLocationClientOption locationOption = null;
    public static LocationManager locationManager;
    public static String tvLongitude = "";
    //是否需要检测后台定位权限,设置为true时,如果用户没有给予后台定位权限会弹窗提示
    private boolean needCheckBackLocation = false;
    //如果设置了target > 28,需要增加这个权限,否则不会弹出"始终允许"这个选择框
    private static String BACKGROUND_LOCATION_PERMISSION = "android.permission.ACCESS_BACKGROUND_LOCATION";
    /**
     * 需要进行检测的权限数组
     */
    protected String[] needPermissions = {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_STATE
    };

    private static final int PERMISSON_REQUESTCODE = 0;

接下来初始化定位

    /**
     * 初始化定位
     *
     * @since 2.8.0
     * @author hongming.wang
     *
     */
    private void initLocation(){
        //初始化client
        locationClient = new AMapLocationClient(this.getApplicationContext());
        locationOption = getDefaultOption();
        //设置定位参数
        locationClient.setLocationOption(locationOption);
        // 设置定位监听
        locationClient.setLocationListener(locationListener);
    }

配置默认的定位参数

    /**
     * 默认的定位参数
     * @since 2.8.0
     * @author hongming.wang
     *
     */
    private AMapLocationClientOption getDefaultOption(){
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(2000);//可选,设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
        mOption.setSensorEnable(false);//可选,设置是否使用传感器。默认是false
        mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差
        mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true
        mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);//可选,设置逆地理信息的语言,默认值为默认语言(根据所在地区选择语言)
        return mOption;
    }

设置定位监听,需要哪些参数就打开那些参数,不需要的注释掉就行了

    /**
     * 定位监听
     */
    AMapLocationListener locationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation location) {
            if (null != location) {

                StringBuffer sb = new StringBuffer();
                //errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明
                if(location.getErrorCode() == 0){
                    sb.append("定位成功" + "\n");
                    sb.append("定位类型: " + location.getLocationType() + "\n");
                    sb.append("经    度    : " + location.getLongitude() + "\n");
                    sb.append("纬    度    : " + location.getLatitude() + "\n");
                    sb.append("精    度    : " + location.getAccuracy() + "米" + "\n");
//                    sb.append("提供者    : " + location.getProvider() + "\n");
//                    sb.append("速    度    : " + location.getSpeed() + "米/秒" + "\n");
//                    sb.append("角    度    : " + location.getBearing() + "\n");
                    // 获取当前提供定位服务的卫星个数
//                    sb.append("星    数    : " + location.getSatellites() + "\n");
                    sb.append("国    家    : " + location.getCountry() + "\n");
                    sb.append("省            : " + location.getProvince() + "\n");
                    sb.append("市            : " + location.getCity() + "\n");
//                    sb.append("城市编码 : " + location.getCityCode() + "\n");
                    sb.append("区            : " + location.getDistrict() + "\n");
//                    sb.append("区域 码   : " + location.getAdCode() + "\n");
                    sb.append("地    址    : " + location.getAddress() + "\n");
//                    sb.append("兴趣点    : " + location.getPoiName() + "\n");
                } else {
                    //定位失败
                    sb.append("定位失败" + "\n");
                    sb.append("错误码:" + location.getErrorCode() + "\n");
                    sb.append("错误信息:" + location.getErrorInfo() + "\n");
                    sb.append("错误描述:" + location.getLocationDetail() + "\n");
                }
//                sb.append("***定位质量报告***").append("\n");
                sb.append("* WIFI开关:").append(location.getLocationQualityReport().isWifiAble() ? "开启":"关闭").append("\n");
                sb.append("* GPS状态:").append(getGPSStatusString(location.getLocationQualityReport().getGPSStatus())).append("\n");
//                sb.append("* GPS星数:").append(location.getLocationQualityReport().getGPSSatellites()).append("\n");
//                sb.append("* 网络类型:" + location.getLocationQualityReport().getNetworkType()).append("\n");
//                sb.append("* 网络耗时:" + location.getLocationQualityReport().getNetUseTime()).append("\n");
//                sb.append("****************").append("\n");
                //定位之后的回调时间

                //解析定位结果,
                tvLongitude = sb.toString();
            } else {

            }
        }
    };
    /**
     * 获取GPS状态的字符串
     * @param statusCode GPS状态码
     * @return
     */
    private String getGPSStatusString(int statusCode){
        String str = "";
        switch (statusCode){
            case AMapLocationQualityReport.GPS_STATUS_OK:
                str = "GPS状态正常";
                break;
            case AMapLocationQualityReport.GPS_STATUS_NOGPSPROVIDER:
                str = "手机中没有GPS Provider,无法进行GPS定位";
                break;
            case AMapLocationQualityReport.GPS_STATUS_OFF:
                str = "GPS关闭,建议开启GPS,提高定位质量";
                break;
            case AMapLocationQualityReport.GPS_STATUS_MODE_SAVING:
                str = "选择的定位模式中不包含GPS定位,建议选择包含GPS定位的模式,提高定位质量";
                break;
            case AMapLocationQualityReport.GPS_STATUS_NOGPSPERMISSION:
                str = "没有GPS定位权限,建议开启gps定位权限";
                break;
        }
        return str;
    }

再然后就是开启,停止,销毁定位

    /**
     * 开始定位
     *
     * @since 2.8.0
     * @author hongming.wang
     *
     */
    public static void startLocation(){
        // 设置定位参数
        locationClient.setLocationOption(locationOption);
        // 启动定位
        locationClient.startLocation();
    }

    /**
     * 停止定位
     *
     * @since 2.8.0
     * @author hongming.wang
     *
     */
    public static void stopLocation(){
        // 停止定位
        locationClient.stopLocation();
    }

    /**
     * 销毁定位
     *
     * @since 2.8.0
     * @author hongming.wang
     *
     */
    private void destroyLocation(){
        if (null != locationClient) {
            /**
             * 如果AMapLocationClient是在当前Activity实例化的,
             * 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
             */
            locationClient.onDestroy();
            locationClient = null;
            locationOption = null;
        }
    }

接下拿起你的小本本记重点了(手动敲黑板 咳咳咳)
在onCreate()方法加入当前sdk判断

if(Build.VERSION.SDK_INT > 28 && getApplicationContext().getApplicationInfo().targetSdkVersion > 28) {
            needPermissions = new String[] {
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.READ_PHONE_STATE,
                    BACKGROUND_LOCATION_PERMISSION
            };
        }

然后是判断sdk版本号的方法和让用户动态注册开启权限的逻辑

   /**
     *
     * @param permissions
     * @since 2.5.0
     *
     */
    private void checkPermissions(String... permissions) {
        try {
            if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
                List<String> needRequestPermissonList = findDeniedPermissions(permissions);
                if (null != needRequestPermissonList && needRequestPermissonList.size() > 0) {
                    String[] array = needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]);
                    Method method = getClass().getMethod("requestPermissions", new Class[]{String[].class,int.class});
                    method.invoke(this, array, PERMISSON_REQUESTCODE);
                }
            }
        } catch (Throwable e) {
        }
    }
    /**
     * 获取权限集中需要申请权限的列表
     *
     * @param permissions
     * @return
     * @since 2.5.0
     *
     */
    private List<String> findDeniedPermissions(String[] permissions) {
        List<String> needRequestPermissonList = new ArrayList<String>();
        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23){
            try {
                for (String perm : permissions) {
                    Method checkSelfMethod = getClass().getMethod("checkSelfPermission", String.class);
                    Method shouldShowRequestPermissionRationaleMethod = getClass().getMethod("shouldShowRequestPermissionRationale",
                            String.class);
                    if ((Integer)checkSelfMethod.invoke(this, perm) != PackageManager.PERMISSION_GRANTED || (Boolean)shouldShowRequestPermissionRationaleMethod.invoke(this, perm)) {
                        if(!needCheckBackLocation && BACKGROUND_LOCATION_PERMISSION.equals(perm)) {
                            continue;
                        }
                        needRequestPermissonList.add(perm);
                    }
                }
            } catch (Throwable e) {

            }
        }
        return needRequestPermissonList;
    }

    /**
     * 检测是否所有的权限都已经授权
     * @param grantResults
     * @return
     * @since 2.5.0
     *
     */
    private boolean verifyPermissions(int[] grantResults) {
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    @TargetApi(23)
    public void onRequestPermissionsResult(int requestCode,String[] permissions, int[] paramArrayOfInt) {
        if (requestCode == PERMISSON_REQUESTCODE) {
            if (!verifyPermissions(paramArrayOfInt)) {
                showMissingPermissionDialog();
                isNeedCheck = false;
            }
        }
    }
    /**
     * 显示提示信息
     *
     * @since 2.5.0
     *
     */
    private void showMissingPermissionDialog() {
    //注意CocosCreator刷新ui的逻辑要写在ui线程里!!!!!!!!!!!!!!!!!!!
        app.runOnUiThread(new Runnable() {
            @Override
            public void run() {
            //手动绘制一个安卓原生对话框,不懂的话自行去Cocos官网看Java原生反射机制
                AlertDialog alertDialog = new AlertDialog.Builder(app).create();
                alertDialog.setMessage("GPS获取失败,请授权当前APP位置权限");
                alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
                        //当点击了OK按钮是,如果用户刚开始进入游戏的时候没有开启gps权限,那么就再次动态让他开始权限,根据自己的项目实际需求来,不需要的话就注释掉就行了
                            checkPermissions(needPermissions);
                        }
                    }
                });
                alertDialog.show();
            }
        });

    }

    /**
     *  启动应用的设置
     *
     * @since 2.5.0
     *
     */
    private void startAppSettings() {
        Intent intent = new Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
    }

    private boolean isNeedCheck = true;
    @Override
    protected void onResume() {
        if (Build.VERSION.SDK_INT >= 23 && getApplicationInfo().targetSdkVersion >= 23) {
            if (isNeedCheck) {
                checkPermissions(needPermissions);
            }
        }
        super.onResume();
        SDKWrapper.getInstance().onResume();

    }

最后别忘了在onDestroy()中移除监听,调一下destroyLocation()方法就行了

    @Override
    protected void onDestroy() {
        destroyLocation();
        super.onDestroy();
        SDKWrapper.getInstance().onDestroy();
    }

至此全部完成,代码拷到项目里直接能用,真是不容易,中途踩了好多坑,以后还是要多看官方文档啊,哪里不明白的可以关注我一波,然后私信我,我给你讲解( ̄▽ ̄)"。

//补充一点:用Android studio打开工程,哪里报红,就把鼠标点到报红的字段,然后alt+回车import class就可以了

猜你喜欢

转载自blog.csdn.net/liupengxunzhuanshu/article/details/105731854