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就可以了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章