1. 程式人生 > >Android 高德地圖的定位功能,以及動態開啟許可權

Android 高德地圖的定位功能,以及動態開啟許可權

配置工程

配置AndroidManifest.xml

1、許可權


    <!--用於進行網路定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
    <!--用於訪問GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission
>
<!--用於獲取運營商資訊,用於支援提供運營商資訊相關的介面--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission> <!--用於訪問wifi網路資訊,wifi資訊會用於進行網路定位--> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<!--用於獲取wifi的獲取許可權,wifi資訊會用來進行網路定位--> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission> <!--用於訪問網路,網路定位需要上網--> <uses-permission android:name="android.permission.INTERNET"></uses-permission> <!--用於讀取手機當前的狀態-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <!--用於寫入快取資料到擴充套件儲存卡--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <!--用於申請呼叫A-GPS模組--> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"></uses-permission> <!--用於申請獲取藍芽資訊進行室內定位--> <uses-permission android:name="android.permission.BLUETOOTH"></uses-permission> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>

2.設定高德的key

  <!--設定高德地圖的key-->
        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="您的key" />
        <service android:name="com.amap.api.location.APSService" />

3.初始化定位

請在主執行緒中宣告AMapLocationClient類物件,需要傳Context型別的引數。推薦用getApplicationConext()方法獲取全程序有效的context。



//宣告AMapLocationClient類物件
public AMapLocationClient mLocationClient = null;
//宣告定位回撥監聽器
public AMapLocationListener mLocationListener = new AMapLocationListener();
//初始化定位
mLocationClient = new AMapLocationClient(getApplicationContext());
//設定定位回撥監聽
mLocationClient.setLocationListener(mLocationListener);

4.配置引數並啟動定位

建立AMapLocationClientOption物件
AMapLocationClientOption物件用來設定發起定位的模式和相關引數等。

案例效果圖

這裡寫圖片描述

下面是具體程式碼:

MainActivity

public class MainActivity extends AppCompatActivity {


    Button btn;
    TextView tv;


    /**
     * 需要進行檢測的許可權陣列
     */
    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;

    /**
     * 判斷是否需要檢測,防止不停的彈框
     */
    private boolean isNeedCheck = true;


    //宣告AMapLocationClient類物件
    public AMapLocationClient mLocationClient = null;
    //宣告定位回撥監聽器
    //public AMapLocationListener mLocationListener = new AMapLocationListener();
    // public AMapLocationListener mLocationListener;
    //宣告AMapLocationClientOption物件
    public AMapLocationClientOption mLocationOption = new AMapLocationClientOption();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button) findViewById(R.id.btn_get);
        tv = (TextView) findViewById(R.id.tv_text);


        //初始化定位

        initLocation();


        //設定定位模式為AMapLocationMode.Hight_Accuracy,高精度模式。
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //定位
                //啟動定位
                //            mLocationClient.startLocation();

                //設定引數
                //    mLocationClient.setLocationOption(getDefaultOption());
                Log.e("進入", "點選事件" + "=========================================================================");
                //定位監聽器
//                mLocationListener = new AMapLocationListener() {
//                    @Override
//                    public void onLocationChanged(AMapLocation aMapLocation) {
//                        //
//                        Log.e("進入", "回撥" + "=========================================================================");
//                        if (aMapLocation != null) {
//                            if (aMapLocation.getErrorCode() == 0) {
//                                //可在其中解析amapLocation獲取相應內容。
//                                Log.e("進入", "回撥返回" + "aMapLocation != null=========================================================================");
//                                aMapLocation.getLocationType();//獲取當前定位結果來源,如網路定位結果,詳見定位型別表
//                                aMapLocation.getLatitude();//獲取緯度
//                                aMapLocation.getLongitude();//獲取經度
//                                aMapLocation.getAccuracy();//獲取精度資訊
//                                aMapLocation.getAddress();//地址,如果option中設定isNeedAddress為false,則沒有此結果,網路定位結果中會有地址資訊,GPS定位不返回地址資訊。
//                                aMapLocation.getCountry();//國家資訊
//                                aMapLocation.getProvince();//省資訊
//                                aMapLocation.getCity();//城市資訊
//                                aMapLocation.getDistrict();//城區資訊
//                                aMapLocation.getStreet();//街道資訊
//                                aMapLocation.getStreetNum();//街道門牌號資訊
//                                aMapLocation.getCityCode();//城市編碼
//                                aMapLocation.getAdCode();//地區編碼
//                                aMapLocation.getAoiName();//獲取當前定位點的AOI資訊
//                                aMapLocation.getBuildingId();//獲取當前室內定位的建築物Id
//                                aMapLocation.getFloor();//獲取當前室內定位的樓層
//                                //   aMapLocation.getGpsStatus();//獲取GPS的當前狀態
//                                //獲取定位時間
//                                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                                Date date = new Date(aMapLocation.getTime());
//                                df.format(date);
//                                tv.setText(aMapLocation.getAddress());
//
//                                String s = aMapLocation.getAddress();
//                                Log.e("定位成功,", "地址" + aMapLocation.getAddress());
////                                if (!TextUtils.isEmpty(s)) {
////                                    stopLocation();
////                                }
//
//
//                            } else {
//                                //定位失敗時,可通過ErrCode(錯誤碼)資訊來確定失敗的原因,errInfo是錯誤資訊,詳見錯誤碼錶。
//                                Log.e("AmapError", "location Error, ErrCode:"
//                                        + aMapLocation.getErrorCode() + ", errInfo:"
//                                        + aMapLocation.getErrorInfo());
//                            }
//                        }
//                    }
//                };

                //開始定位
                startLocation();

            }
        });

    }

    private void startLocation() {
        //根據控制元件的選擇,重新設定定位引數
        //resetOption();
        // 設定定位引數
        mLocationClient.setLocationOption(mLocationOption);
        // 啟動定位
        mLocationClient.startLocation();
    }

    private void initLocation() {
        //初始化client
        mLocationClient = new AMapLocationClient(this.getApplicationContext());
        //設定定位引數
        mLocationClient.setLocationOption(getDefaultOption());
        // 設定定位監聽
        mLocationClient.setLocationListener(mLocationListener);
    }

    /**
     * 停止定位
     *
     * @author
     * @since 2.8.0
     */
    private void stopLocation() {
        // 停止定位
        mLocationClient.stopLocation();
    }


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

    private void destroyLocation() {
        if (null != mLocationClient) {
            mLocationClient.onDestroy();
            mLocationClient = null;
            mLocationOption = null;


        }
    }

    /**
     * 預設的定位引數
     *
     * @author
     * @since 2.8.0
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可選,設定定位模式,可選的模式有高精度、僅裝置、僅網路。預設為高精度模式
        mOption.setGpsFirst(false);//可選,設定是否gps優先,只在高精度模式下有效。預設關閉
        //mOption.setHttpTimeOut(30000);//可選,設定網路請求超時時間。預設為30秒。在僅裝置模式下無效
        //   mOption.setInterval(2000);//可選,設定定位間隔。預設為2秒
        mOption.setNeedAddress(true);//可選,設定是否返回逆地理地址資訊。預設是true
        //   mOption.setOnceLocation(false);//可選,設定是否單次定位。預設是false
        mLocationOption.setOnceLocation(true);  //獲取一次定位結果:
        mOption.setOnceLocationLatest(false);//可選,設定是否等待wifi重新整理,預設為false.如果設定為true,會自動變為單次定位,持續定位時不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可選, 設定網路請求的協議。可選HTTP或者HTTPS。預設為HTTP
        mOption.setSensorEnable(false);//可選,設定是否使用感測器。預設是false
        mOption.setWifiScan(true); //可選,設定是否開啟wifi掃描。預設為true,如果設定為false會同時停止主動重新整理,停止以後完全依賴於系統重新整理,定位位置可能存在誤差
        mOption.setLocationCacheEnable(true); //可選,設定是否使用快取定位,預設為true
        return mOption;
    }

    /**
     * 定位監聽
     */

    AMapLocationListener mLocationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation aMapLocation) {
            if (null != aMapLocation) {
                //解析定位結果
                String result = Utils.getLocationStr(aMapLocation);
                tv.setText(result);
                Log.e("定位", "aMapLocation is null" + result);
            } else {
                tv.setText("定位失敗,aMapLocation is null");
                Log.e("定位失敗", "aMapLocation is null");
            }
        }
    };


    //----------以下動態獲取許可權---------
    @Override
    protected void onResume() {
        super.onResume();
        if (isNeedCheck) {
            checkPermissions(needPermissions);
        }
    }


    /**
     * 檢查許可權
     *
     * @param
     * @since 2.5.0
     */
    private void checkPermissions(String... permissions) {
        //獲取許可權列表
        List<String> needRequestPermissonList = findDeniedPermissions(permissions);
        if (null != needRequestPermissonList
                && needRequestPermissonList.size() > 0) {
            //list.toarray將集合轉化為陣列
            ActivityCompat.requestPermissions(this,
                    needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]),
                    PERMISSON_REQUESTCODE);
        }
    }


    /**
     * 獲取許可權集中需要申請許可權的列表
     *
     * @param permissions
     * @return
     * @since 2.5.0
     */
    private List<String> findDeniedPermissions(String[] permissions) {
        List<String> needRequestPermissonList = new ArrayList<String>();
        //for (迴圈變數型別 迴圈變數名稱 : 要被遍歷的物件)
        for (String perm : permissions) {
            if (ContextCompat.checkSelfPermission(this,
                    perm) != PackageManager.PERMISSION_GRANTED
                    || ActivityCompat.shouldShowRequestPermissionRationale(
                    this, perm)) {
                needRequestPermissonList.add(perm);
            }
        }
        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;
    }

    @Override
    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() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.notifyTitle);
        builder.setMessage(R.string.notifyMsg);

        // 拒絕, 退出應用
        builder.setNegativeButton(R.string.cancel,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });

        builder.setPositiveButton(R.string.setting,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startAppSettings();
                    }
                });

        builder.setCancelable(false);

        builder.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);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            this.finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}

Utils

public class Utils {
    /**
     *  開始定位
     */
    public final static int MSG_LOCATION_START = 0;
    /**
     * 定位完成
     */
    public final static int MSG_LOCATION_FINISH = 1;
    /**
     * 停止定位
     */
    public final static int MSG_LOCATION_STOP= 2;

    public final static String KEY_URL = "URL";
    public final static String URL_H5LOCATION = "file:///android_asset/location.html";
    /**
     * 根據定位結果返回定位資訊的字串
     * @param loc
     * @return
     */
    public synchronized static String getLocationStr(AMapLocation location){
        if(null == location){
            return null;
        }
        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");
            //定位完成的時間
            sb.append("定位時間: " + formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + "\n");
        } else {
            //定位失敗
            sb.append("定位失敗" + "\n");
            sb.append("錯誤碼:" + location.getErrorCode() + "\n");
            sb.append("錯誤資訊:" + location.getErrorInfo() + "\n");
            sb.append("錯誤描述:" + location.getLocationDetail() + "\n");
        }
        //定位之後的回撥時間
        sb.append("回撥時間: " + formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "\n");
        return sb.toString();
    }

    private static SimpleDateFormat sdf = null;
    public synchronized static String formatUTC(long l, String strPattern) {
        if (TextUtils.isEmpty(strPattern)) {
            strPattern = "yyyy-MM-dd HH:mm:ss";
        }
        if (sdf == null) {
            try {
                sdf = new SimpleDateFormat(strPattern, Locale.CHINA);
            } catch (Throwable e) {
            }
        } else {
            sdf.applyPattern(strPattern);
        }
        return sdf == null ? "NULL" : sdf.format(l);
    }
}

幾個String

 <string name="notifyTitle">提示</string>
    <string name="notifyMsg">當前應用缺少必要許可權。\n\n請點選\"設定\"-\"許可權\"-開啟所需許可權。</string>
    <string name="gpsNotifyMsg">當前應用需要開啟定位功能。\n\n請點選\"設定\"-\"定位服務\"-開啟定位功能。</string>
    <string name="setting">設定</string>
    <string name="cancel">取消</string>

關於動態許可權

1.檢查限限,如果沒有就申請,申請許可權的方法如下:
ActivityCompat.requestPermissions(this,needRequestPermissonList.toArray(newString[needRequestPermissonList.size()]),PERMISSON_REQUESTCODE);
第一個引數是activity,第二個引數是許可權的陣列,是陣列的格式,,第三個引數是requestCode,requestPermissions()方法內部已經做了判斷
2.回撥方法
onRequestPermissionsResult(int requestCode,String[] permissions, int[] paramArrayOfInt)
通過判斷int[] paramArrayOfInt返回的結果是否 == PackageManager.PERMISSION_GRANTED
如果不等於,則是沒有授權,彈出對話方塊,進行使用者選擇 如果==於,則說明已經授權完成