【Android】權限請求處理

Android API23以上的時候,出現了動態請求權限的APP行爲,敏感權限要求用戶自己選擇允許或拒絕,以及如何提示用戶開啓相關服務。此文章以定位權限和服務爲例。

在AS開發中,可能會遇到一個坑,就是即使寫明瞭動態請求邏輯,還是喚不起系統的權限請求彈窗。在經過漫長的查找過程後,終於發現了原因:必須在build-config.gradle文件中將targetSDKVersion聲明爲23或者以上:

ext {
    config = [
            //app、sdk版本信息
            compileSdkVersion          : 25,
            minSdkVersion              : 14,
            targetSdkVersion           : 23,//22
            multidex                   : "1.0.3",
            gsonVersion                : "2.8.4",
            supportLibVersion          : "25.3.1",
            constraintLayoutVersion    : "1.1.2",
            orgApacheCommonsLangVersion: "2.6",
            baseLibrary                : ":uhome_base",
    ]
}

Activity中權限處理流程(在判斷有定位權限的情況下,再判斷是否開啓了定位服務,因定位服務的判斷會同時判斷定位權限,順序不能顛倒):

 @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.community_my);
        initView();
        initDatas();
        checkPermissions();//判斷定位權限和服務,然後定位
    }

 checkPermissions()方法定義如下:

/**
     * 獲取定位權限
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void checkPermissions() {
        PackageManager pm = getPackageManager();
        List<String> needRequestPermissonList = new ArrayList<>();
        for (String perm : permissions2) {
            if (pm.checkPermission(perm, getPackageName()) != PackageManager.PERMISSION_GRANTED) {//ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED || ActivityCompat.shouldShowRequestPermissionRationale(this, perm)
                needRequestPermissonList.add(perm);
            }
        }
//        show("size : " + needRequestPermissonList.size());
        //調用系統彈窗
        if (needRequestPermissonList.size() > 0) {
            ActivityCompat.requestPermissions(this,
                    needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]),
                    PERMISSON_REQUESTCODE);
        }else {
            //有定位權限的情況下,再判斷是否開啓了定位服務,因定位服務的判斷會同時判斷定位權限,順序不能顛倒
            checkLocationServices();
        }
    }

其中permissions2取自百度定位文檔中提出的需要動態獲取權限 :

private String[] permissions2 = {
            "android.permission.CALL_PHONE",
            "android.permission.ACCESS_COARSE_LOCATION",
            "android.permission.ACCESS_FINE_LOCATION",
            "android.permission.WRITE_EXTERNAL_STORAGE",
            "android.permission.READ_EXTERNAL_STORAGE"
    };

checkLocationServices()定義如下:

/**
     * 判斷是否有定位服務
     */
    private void checkLocationServices() {
        LocationManager locationManager = (LocationManager) getSystemService(this.LOCATION_SERVICE);
        //獲取所有可用的位置提供器
        List<String> providers = locationManager.getProviders(true);
        String locationProvider = null;
        boolean hasGPS = providers.contains(LocationManager.GPS_PROVIDER);
        boolean hasNETWORK = providers.contains(LocationManager.NETWORK_PROVIDER);
        //show("GPS : " + hasGPS + "; NETWORK : " + hasNETWORK);
        if (hasGPS || hasNETWORK) {
            //開啓了定位服務和獲取了定位權限
            startLocation();
        } else {
            showDialog(R.string.request_locat_service, new OnDailogListener() {
                @Override
                public void onPositiveButton() {
                    //跳轉開啓定位服務頁
                    Intent i = new Intent();
                    i.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivityForResult(i, SETTING_REQUESTCODE);
                }
                @Override
                public void onNegativeButton() {
                    stopLocation();
                    //拒絕打開定位服務,缺省是深圳市
                    curCity.setText("深圳市");
                }
            });
        }
    }

回調:

/**
     * 權限獲取回調
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] paramArrayOfInt) {
        if (requestCode == PERMISSON_REQUESTCODE) {
            //獲得權限
            if (verifyPermissions(paramArrayOfInt)) {
                startLocation();
            }else {
                //沒有權限時的操作
            }
        }
    }

    /**
     * 檢測是否所有的權限都已經授權
     */
    private boolean verifyPermissions(int[] grantResults) {
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

 

ps:此Activity封裝了百度定位的操作: 

/**
 * 定位基類Activity
 */
public abstract class BaseLocationActivity extends BaseActivity {

	protected LocationService locationService;


	protected MyOrientationListener orientationListener;

	protected BDLocation mLocation;

	@Override
	protected void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		// -----------location config ------------
		locationService = UHomeApp.mLocationClient;
		//獲取locationservice實例,建議應用中只初始化1個location實例,然後使用,可以參考其他示例的activity,都是通過此種方式獲取locationservice實例的
		locationService.registerListener(mListener);
		//註冊監聽
		locationService.setLocationOption(locationService.getDefaultLocationClientOption());

	}

	@Override
	protected void onResume() {
		super.onResume();
		locationService.registerListener(mListener);

	}

	@Override
	protected void onPause() {
		super.onPause();
		locationService.unregisterListener(mListener); //註銷掉監聽
		stopLocation(); //停止定位服務
	}

	@Override
	protected void onStop() {
		super.onStop();
		stopLocation();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		locationService.unregisterListener(mListener);
	}

	/**
	 * 定位成功回調
	 * @param location
     */
	protected abstract void locationSuccessResult(BDLocation location);
	
	/**
	 * 定位失敗回調
	 * @param location
	 */
	protected abstract void locationFailResult(BDLocation location);

	/**
	 * 開啓定位
	 */
	protected void startLocation() {
		if (null != locationService) {
			locationService.start();// 定位SDK
		}
	}
	
	/**
	 * 關閉定位
	 */
	protected void stopLocation() {
		if (null != locationService) {
			locationService.stop();// 定位SDK
		}
	}
	
	/**
	 * 設置方向傳感器監聽
	 */
	protected void setOrientationListener() {
		orientationListener = new MyOrientationListener(this);
		orientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener()
				{
					@Override
					public void onOrientationChanged(float x)
					{
						if(null != mLocation){
//							addMyLocation((int) x);
						}
					}
				});
		// 開啓方向傳感器
		orientationListener.start();
	}




	

	/*****
	 * 61 : GPS定位結果,GPS定位成功。
	 * 62 : 無法獲取有效定位依據,定位失敗,請檢查運營商網絡或者wifi網絡是否正常開啓,嘗試重新請求定位。
	 * 63 : 網絡異常,沒有成功向服務器發起請求,請確認當前測試手機網絡是否通暢,嘗試重新請求定位。
	 * 65 : 定位緩存的結果。
	 * 66 : 離線定位結果。通過requestOfflineLocaiton調用時對應的返回結果。
	 * 67 : 離線定位失敗。通過requestOfflineLocaiton調用時對應的返回結果。
	 * 68 : 網絡連接失敗時,查找本地離線定位時對應的返回結果。
	 * 161: 網絡定位結果,網絡定位定位成功。
	 * 162: 請求串密文解析失敗。
	 * 167: 服務端定位失敗,請您檢查是否禁用獲取位置信息權限,嘗試重新請求定位。
	 * 502: key參數錯誤,請按照說明文檔重新申請KEY。
	 * 505: key不存在或者非法,請按照說明文檔重新申請KEY。
	 * 601: key服務被開發者自己禁用,請按照說明文檔重新申請KEY。
	 * 602: key mcode不匹配,您的ak配置過程中安全碼設置有問題,請確保:sha1正確,“;”分號是英文狀態;且包名是您當前運行應用的包名,請按照說明文檔重新申請KEY。
	 * 501~700:key驗證失敗,請按照說明文檔重新申請KEY。
	 * 定位結果回調,重寫onReceiveLocation方法,可以直接拷貝如下代碼到自己工程中修改
	 *
	 */
	private BDLocationListener mListener = new BDLocationListener() {

		@Override
		public void onReceiveLocation(BDLocation location) {
			mLocation = location;
			if (location.getLocType() == BDLocation.TypeServerError
					|| location.getLocType() == BDLocation.TypeNetWorkException
					|| location.getLocType() == BDLocation.TypeCriteriaException) {
				locationFailResult(location);
			}else{
				locationSuccessResult(location);
			}
		}

	};


}

 

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