Android6.0中的許可權
前言
Android6.0相比之前的Android版本有一個很大的不同點,就是動態的獲取許可權。之前我們需要什麼許可權只需要在Manifest檔案中宣告即可,在6.0中,又新增了執行時許可權的動態檢測。
Android6.0分了兩種許可權Normal Permissions(安裝時自動授權,使用者也不能取消許可權) and Dangerous Permissions(詳情在文章最後):
使用環境
如果在 Android 6.0 以前的裝置上,我們之前在清單檔案中宣告許可權是沒有問題的,但是如果是在 Android 6.0 裝置上,並且專案targetSdkVersion你設定的是23,那再像之前那樣宣告許可權,是不起作用的
此時你肯定想到了 如果 targetSdkVersion 值設定的小於23是不是就不會奔潰了,恩,確實如此, 此時即使使用Android6.0的裝置,程式也不會奔潰,原因顯而易見,Android 的許可權機制是 Android M 後才加入的。從 Android M 開始 應用程式申請的許可權是在執行時動態賦給使用者的。所以就需要我們動態的申請許可權了
示例
之所以寫這篇文章是因為最近在寫一個APP的時候用到了百度定位,之前使用百度定位的SDK好好的,但是換了手機之後開始不行了,折騰半天,才意識到新手機是6.0的系統,搜尋一番,有所瞭解,寫下來,權作備份
一個簡單的例子,實現點選按鈕,螢幕出現當前位置
申請金鑰,配置環境就按照官網上面的來,我們按照之前的方法來
package cn.lixyz.testpermission;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener ;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.Poi;
import java.util.List;
public class MainActivity extends Activity /*implements BDLocationListener*/ {
private Button bt;
private TextView tv;
public LocationClient mLocationClient = null;
public BDLocationListener myListener = new MyLocationListener();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocationClient = new LocationClient(getApplicationContext()); // 宣告LocationClient類
mLocationClient.registerLocationListener(myListener); // 註冊監聽函式
initLocation();
bt = (Button) findViewById(R.id.bt);
tv = (TextView) findViewById(R.id.tv);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLocationClient.start();
}
});
}
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 可選,預設高精度,設定定位模式,高精度,低功耗,僅裝置
option.setCoorType("bd09ll");// 可選,預設gcj02,設定返回的定位結果座標系
int span = 1000;
option.setScanSpan(span);// 可選,預設0,即僅定位一次,設定發起定位請求的間隔需要大於等於1000ms才是有效的
option.setIsNeedAddress(true);// 可選,設定是否需要地址資訊,預設不需要
option.setOpenGps(true);// 可選,預設false,設定是否使用gps
option.setLocationNotify(true);// 可選,預設false,設定是否當gps有效時按照1S1次頻率輸出GPS結果
option.setIsNeedLocationDescribe(true);// 可選,預設false,設定是否需要位置語義化結果,可以在BDLocation.getLocationDescribe裡得到,結果類似於“在北京天安門附近”
option.setIsNeedLocationPoiList(true);// 可選,預設false,設定是否需要POI結果,可以在BDLocation.getPoiList裡得到
option.setIgnoreKillProcess(false);// 可選,預設true,定位SDK內部是一個SERVICE,並放到了獨立程序,設定是否在stop的時候殺死這個程序,預設不殺死
option.SetIgnoreCacheException(false);// 可選,預設false,設定是否收集CRASH資訊,預設收集
option.setEnableSimulateGps(false);// 可選,預設false,設定是否需要過濾gps模擬結果,預設需要
mLocationClient.setLocOption(option);
}
class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
// Receive Location
StringBuffer sb = new StringBuffer(256);
sb.append("time : ");
sb.append(location.getTime());
sb.append("\nerror code : ");
sb.append(location.getLocType());
sb.append("\nlatitude : ");
sb.append(location.getLatitude());
sb.append("\nlontitude : ");
sb.append(location.getLongitude());
sb.append("\nradius : ");
sb.append(location.getRadius());
if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位結果
sb.append("\nspeed : ");
sb.append(location.getSpeed());// 單位:公里每小時
sb.append("\nsatellite : ");
sb.append(location.getSatelliteNumber());
sb.append("\nheight : ");
sb.append(location.getAltitude());// 單位:米
sb.append("\ndirection : ");
sb.append(location.getDirection());// 單位度
sb.append("\naddr : ");
sb.append(location.getAddrStr());
sb.append("\ndescribe : ");
sb.append("gps定位成功");
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 網路定位結果
sb.append("\naddr : ");
sb.append(location.getAddrStr());
// 運營商資訊
sb.append("\noperationers : ");
sb.append(location.getOperators());
sb.append("\ndescribe : ");
sb.append("網路定位成功");
} else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 離線定位結果
sb.append("\ndescribe : ");
sb.append("離線定位成功,離線定位結果也是有效的");
} else if (location.getLocType() == BDLocation.TypeServerError) {
sb.append("\ndescribe : ");
sb.append("服務端網路定位失敗,可以反饋IMEI號和大體定位時間到[email protected],會有人追查原因");
} else if (location.getLocType() == BDLocation.TypeNetWorkException) {
sb.append("\ndescribe : ");
sb.append("網路不同導致定位失敗,請檢查網路是否通暢");
} else if (location.getLocType() == BDLocation.TypeCriteriaException) {
sb.append("\ndescribe : ");
sb.append("無法獲取有效定位依據導致定位失敗,一般是由於手機的原因,處於飛航模式下一般會造成這種結果,可以試著重啟手機");
}
sb.append("\nlocationdescribe : ");
sb.append(location.getLocationDescribe());// 位置語義化資訊
List<Poi> list = location.getPoiList();// POI資料
if (list != null) {
sb.append("\npoilist size = : ");
sb.append(list.size());
for (Poi p : list) {
sb.append("\npoi= : ");
sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
}
}
if (location.getCity() != null) {
Message msg = new Message();
msg.obj = location.getCity();
handler.sendMessage(msg);
}
}
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv.setText((String) msg.obj);
mLocationClient.stop();
}
};
}
我們點選按鈕,發現並沒有定位成功,檢視log,發現如下log
04-24 02:16:59.994 5329-5354/? W/System.err: java.lang.SecurityException: getAllCellInfo: Neither user 10198 nor current process has android.permission.ACCESS_COARSE_LOCATION.
04-24 02:16:59.994 5329-5354/? W/System.err: at android.app.ContextImpl.enforce(ContextImpl.java:1595)
04-24 02:16:59.994 5329-5354/? W/System.err: at android.app.ContextImpl.enforceCallingOrSelfPermission(ContextImpl.java:1627)
04-24 02:16:59.994 5329-5354/? W/System.err: at android.content.ContextWrapper.enforceCallingOrSelfPermission(ContextWrapper.java:675)
04-24 02:16:59.994 5329-5354/? W/System.err: at android.content.ContextWrapper.enforceCallingOrSelfPermission(ContextWrapper.java:675)
04-24 02:16:59.994 5329-5354/? W/System.err: at com.android.phone.PhoneInterfaceManager.enforceFineOrCoarseLocationPermission(PhoneInterfaceManager.java:1835)
04-24 02:16:59.994 5329-5354/? W/System.err: at com.android.phone.PhoneInterfaceManager.getAllCellInfoUsingSubId(PhoneInterfaceManager.java:1920)
04-24 02:16:59.994 5329-5354/? W/System.err: at com.android.phone.PhoneInterfaceManager.getAllCellInfo(PhoneInterfaceManager.java:1916)
04-24 02:16:59.994 5329-5354/? W/System.err: at com.android.internal.telephony.ITelephony$Stub.onTransact(ITelephony.java:732)
04-24 02:16:59.994 5329-5354/? W/System.err: at android.os.Binder.execTransact(Binder.java:453)
需要android.permission.ACCESS_COARSE_LOCATION許可權,我們在Manifest檔案中新增之後再執行,發現還是拋同樣的異常,依舊獲取不到位置
所以我們就需要針對6.0系統做出修改,來動態申請許可權了。
修改程式碼:
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startLocation();
}
});
private void startLocation() {
int checkPermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (checkPermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
Log.d("TTTT", "彈出提示");
return;
} else {
mLocationClient.start();
}
}
重新執行,點選按鈕,發現彈出提示:
並且Log提示
04-24 02:29:16.163 6134-6134/cn.lixyz.testpermission D/TTTT: 彈出提示
我們點選“始終允許”之後,退出程式再此進入,則可以定位了,我們如果我們像要在運行了許可權之後立即就可以獲取到位置資訊呢?
Android提供了onRequestPermissionsResult方法來幫我們實現我們執行了許可權規則之後的操作,這個方法和onActivityResult方法類似
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationClient.start();
} else {
Log.d("TTTT", "啊偶,被拒絕了,少年不哭,站起來擼");
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
當我們點選禁止按鈕的時候,Log提示”啊偶,被拒絕了,少年不哭,站起來擼”
當我們點選允許按鈕的時候,定位成功
完整程式碼如下
public class MainActivity extends Activity{
private Button bt;
private TextView tv;
public LocationClient mLocationClient = null;
public BDLocationListener myListener = new MyLocationListener();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocationClient = new LocationClient(getApplicationContext()); // 宣告LocationClient類
mLocationClient.registerLocationListener(myListener); // 註冊監聽函式
initLocation();
bt = (Button) findViewById(R.id.bt);
tv = (TextView) findViewById(R.id.tv);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//mLocationClient.start();
startLocation();
}
});
}
private void startLocation() {
if(Build.VERSION.SDK_INT>=23){
int checkPermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (checkPermission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
return;
} else {
mLocationClient.start();
}
}else{
mLocationClient.start();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationClient.start();
} else {
Log.d("TTTT", "啊偶,被拒絕了,少年不哭,站起來擼");
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void initLocation() {
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 可選,預設高精度,設定定位模式,高精度,低功耗,僅裝置
option.setCoorType("bd09ll");// 可選,預設gcj02,設定返回的定位結果座標系
int span = 1000;
option.setScanSpan(span);// 可選,預設0,即僅定位一次,設定發起定位請求的間隔需要大於等於1000ms才是有效的
option.setIsNeedAddress(true);// 可選,設定是否需要地址資訊,預設不需要
option.setOpenGps(true);// 可選,預設false,設定是否使用gps
option.setLocationNotify(true);// 可選,預設false,設定是否當gps有效時按照1S1次頻率輸出GPS結果
option.setIsNeedLocationDescribe(true);// 可選,預設false,設定是否需要位置語義化結果,可以在BDLocation.getLocationDescribe裡得到,結果類似於“在北京天安門附近”
option.setIsNeedLocationPoiList(true);// 可選,預設false,設定是否需要POI結果,可以在BDLocation.getPoiList裡得到
option.setIgnoreKillProcess(false);// 可選,預設true,定位SDK內部是一個SERVICE,並放到了獨立程序,設定是否在stop的時候殺死這個程序,預設不殺死
option.SetIgnoreCacheException(false);// 可選,預設false,設定是否收集CRASH資訊,預設收集
option.setEnableSimulateGps(false);// 可選,預設false,設定是否需要過濾gps模擬結果,預設需要
mLocationClient.setLocOption(option);
}
class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
// Receive Location
StringBuffer sb = new StringBuffer(256);
sb.append("time : ");
sb.append(location.getTime());
sb.append("\nerror code : ");
sb.append(location.getLocType());
sb.append("\nlatitude : ");
sb.append(location.getLatitude());
sb.append("\nlontitude : ");
sb.append(location.getLongitude());
sb.append("\nradius : ");
sb.append(location.getRadius());
if (location.getLocType() == BDLocation.TypeGpsLocation) {// GPS定位結果
sb.append("\nspeed : ");
sb.append(location.getSpeed());// 單位:公里每小時
sb.append("\nsatellite : ");
sb.append(location.getSatelliteNumber());
sb.append("\nheight : ");
sb.append(location.getAltitude());// 單位:米
sb.append("\ndirection : ");
sb.append(location.getDirection());// 單位度
sb.append("\naddr : ");
sb.append(location.getAddrStr());
sb.append("\ndescribe : ");
sb.append("gps定位成功");
} else if (location.getLocType() == BDLocation.TypeNetWorkLocation) {// 網路定位結果
sb.append("\naddr : ");
sb.append(location.getAddrStr());
// 運營商資訊
sb.append("\noperationers : ");
sb.append(location.getOperators());
sb.append("\ndescribe : ");
sb.append("網路定位成功");
} else if (location.getLocType() == BDLocation.TypeOffLineLocation) {// 離線定位結果
sb.append("\ndescribe : ");
sb.append("離線定位成功,離線定位結果也是有效的");
} else if (location.getLocType() == BDLocation.TypeServerError) {
sb.append("\ndescribe : ");
sb.append("服務端網路定位失敗,可以反饋IMEI號和大體定位時間到[email protected],會有人追查原因");
} else if (location.getLocType() == BDLocation.TypeNetWorkException) {
sb.append("\ndescribe : ");
sb.append("網路不同導致定位失敗,請檢查網路是否通暢");
} else if (location.getLocType() == BDLocation.TypeCriteriaException) {
sb.append("\ndescribe : ");
sb.append("無法獲取有效定位依據導致定位失敗,一般是由於手機的原因,處於飛航模式下一般會造成這種結果,可以試著重啟手機");
}
sb.append("\nlocationdescribe : ");
sb.append(location.getLocationDescribe());// 位置語義化資訊
List<Poi> list = location.getPoiList();// POI資料
if (list != null) {
sb.append("\npoilist size = : ");
sb.append(list.size());
for (Poi p : list) {
sb.append("\npoi= : ");
sb.append(p.getId() + " " + p.getName() + " " + p.getRank());
}
}
if (location.getCity() != null) {
Message msg = new Message();
msg.obj = location.getCity();
handler.sendMessage(msg);
}
}
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv.setText((String) msg.obj);
mLocationClient.stop();
}
};
}
6.0中的許可權分類
Normal Permissions
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
REQUEST_INSTALL_PACKAGES
Dangerous Permissions
Permission Group:CALENDAR
READ_CALENDAR
WRITE_CALENDAR
Permission Group:CAMERA
CAMERA
Permission Group:CONTACTS
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
Permission Group:LOCATION
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
Permission Group:MICROPHONE
RECORD_AUDIO
Permission Group:PHONE
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
Permission Group:SENSORS
BODY_SENSORS
Permission Group:SMS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
Permission Group:STORAGE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
相關推薦
Android6.0中設定許可權時候的SecurityException異常的處理
說來也巧了,今天碰到了一個特別奇怪的問題。上午寫了一個小demo其中有一個功能是獲取通訊的,大家肯定知道這時候肯定要新增一個許可權: <!-- 讀聯絡人許可權 --> <uses-permission android:name="andr
Android6.0中的許可權
前言 Android6.0相比之前的Android版本有一個很大的不同點,就是動態的獲取許可權。之前我們需要什麼許可權只需要在Manifest檔案中宣告即可,在6.0中,又新增了執行時許可權的動態檢測。 Android6.0分了兩種許可權Normal Per
Android6.0的許可權系統
Android6.0棉花糖,app將不會在安裝的時候授予許可權。取而代之,app不得不在執行的時候一個一個詢問使用者授予許可權。 只有在把 targetSdkVersion 23 以上的版本才會出現。 PROTECTI
Android6.0中的Handler訊息模型
在Android應用開發和系統功能開發中,經常用到多執行緒,而Handler訊息模型線上程間的訊息傳遞機制中佔有重要的地位。對於Handler的理解,最好的參考資料是Android Developer上面的Handler介紹。 通過一個Handler,可以允許我們傳送和處理一
Android6.0以上許可權申請
package com.hzl.libyuvdemo.util; import android.app.Activity; import android.content.Context; import android.content.Intent; import andro
Android6.0危險許可權(需要動態申請的)
1.危險許可權 group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS //寫入通訊錄 permission:android.permission.GET_ACCOUNTS
Android6.0動態許可權適配&XMPermissions
Android6.0動態許可權 簡介 從 Android 6.0(API 級別 23)開始,使用者開始在應用執行時向其授予許可權,而不是在應用安裝時授予。此方法可以簡化應用安裝過程,因為使用者在安裝或更新應用時不需要授予許可權。它還讓使用者可以對應用的功能進行
Android6.0動態許可權問題,使用PermissionDispatcher自動分配
Android 6.0 許可權問題 Android 6.0對許可權做了區分,將手機的許可權分為危險許可權和非危險許可權; 非危險許可權只要在AndroidManifest中加入許可權申請就可以使用了。 而危險許可權只在AndroidManifest中加入許可權申
Android6.0 申請許可權比較優雅的處理方法
android6.0以後許可權的申請改成了動態申請,如果你的targetSdkVersion 大於23且手機系統是6.0以上的就會變成動態申請.為了專案的需求我自己整理了一套許可權申請的方法.先上幾張圖片. 1.這是我第一次執行專案彈出許可權請求的介面,我都選
android6.0動態許可權申請工具類
一、分析 android6.0後,僅在manifest.xml清單中配置相關許可權時,如果將targetSdkVersion設定為23及以上,部分敏感許可權需要動態申請後才能使用;如果不想處理6.0以上的適配,請將targetSdkVersion設定為22
android6.0動態許可權設定
android6.0後就需要手動獲取許可權。主要有以下步驟:1、在menifests檔案加入相應許可權,如:<!-- 獲取照相機拍照許可權 --> <uses-permission a
android6.0動態許可權的設定——幾行程式碼搞定
只需要兩步走: 一、程式碼請求許可權 /** * android6.0執行時許可權,檢測 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//6.0以上 int checkPermission =
Android6.0 動態許可權申請步驟以及需要注意的一些坑
因為工作需要,簡單研究了一下Android6.0許可權申請,在Google提供的sample的基礎上,寫了一個簡單的demo。算是自己的筆記吧,可能會比較混亂,主要是方便以後檢視。後期有別的問題,隨時更新~ 6.0許可權的基本知識,以下是需要單獨申請的許可權,共分為9組,每組只要有一個許可權申請成功了,就
Android6.0動態許可權申請步驟以及需要注意的一些坑
簡單研究了一下Android6.0許可權申請,在Google提供的sample的基礎上,寫了一個簡單的demo。算是自己的筆記吧,可能會比較混亂,主要是方便以後檢視。 6.0許可權的基本知識,以下是需要單獨申請的許可權,共分為9組,每組只要有一個許可權申請成功了,就預設整組許可權都可以使用了。 gro
android6.0動態許可權申請
android6.0之前,所有的許可權都要求同意之後,app才能被安裝。6.0之後,動態許可權申請很好的處理了之前的強制行為,對使用者更加的友好。 新的許可權機制,將許可權分為兩大類,一種普通許可權,一種為危險許可權。普通許可權,在manifest中申請後,無需再主動申請;
Android 從相簿或者拍照設定頭像,相容Android6.0後許可權問題
平時開發中我們會需要設定使用者頭像 從手機相簿或者拍照設定,在Android6.0以前還不用考慮許可權問題,到了6.0後還需要考慮許可權問題,這裡我們就來給大家一起處理下。有些可能不完善大家自己完善
安卓開發——Android6.0動態許可權申請步驟以及需要注意的一些坑
因為工作需要,簡單研究了一下Android6.0許可權申請,在Google提供的sample的基礎上,寫了一個簡單的demo。算是自己的筆記吧,可能會比較混亂,主要是方便以後檢視。後期有別的問題,隨時更新~ 6.0許可權的基本知識,以下是需要單獨申請的許可權,共分為9組,每組只要
Android6.0網路許可權管理
Android 6.0 Marshmallow(棉花糖)是目前谷歌公佈的最新版本的作業系統,其中一項改進是針對程式呼叫許可權控制又進一步升級。 在之前的Android系統中,使用者在安裝應用時會收到一堆許可權申請,比如允許應用訪問相簿、位置、通訊錄等等。但是使用者一般都會忽
使用EasyPermissions 來打造簡單的android6.0動態許可權
EasyPermissions 的介紹 EasyPermissions是一個三方庫,用於android6.0動態許可權的使用。 在android6.0版本中,涉及到許可權問題的使用,都需要進行動態申請。 EasyPermissions 的使用
android6.0動態許可權管理案例-打電話案例
package com.example.phone2; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.ne