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