Android 6.0動態許可權申請
1.Android6.0動態許可權的由來
一直以來,Android的許可權系統都是最大的安全問題之一,因為在進行安裝的時候,所有的許可權都會統一進行請求,你必須允許這些許可權請求才能進行安裝.應用安裝後,就可以在使用者毫不知情的情況下,訪問這些許可權.所以有很多應用利用這一漏洞,偷偷地進行蒐集使用者個人資訊或者其他進行其他用途,可以自行腦補一下.
Android開發團隊顯然也意識到這個問題了,於是重新設計了許可權系統.在最新的Android6.0Marshmallow中,安裝應用的時候不再需要允許任何許可權的請求了.相反,應用程式必須在執行的時候獲取應用的許可權許可.注意:這樣使用者就會意識到應用正在獲取許可權,如果是敏感許可權,就會引起使用者的注意,而不是之前的情況,使用者對應用獲取敏感許可權毫無察覺.
動態許可權的彈出和許可權管理如下圖所示
我這個應用需要位置和儲存兩個動態許可權,在這裡可以取消掉.取消掉再次開啟也應用如下圖所示:
2.Android6.0動態許可權給開發者帶來的問題?
新的動態許可權可能會引起你的恐慌,”我3年前的應用怎麼辦,如果把它安裝在Android6.0的機器上,它是否正常執行,還是會崩潰?”
不必擔心,Android開發團隊已經考慮過這個問題了,如果應用的targetSDKVersion小於23,那麼它就會被假定為並未通過動態許可權系統的測試,它依然會使用之前的許可權系統:在安裝的時候向用戶請求所有需要的許可權,使用者必須接受這些許可權請求才能進行安裝.
結果就是應用依然會像之前那樣執行良好,但是請注意,此時使用者依然可以在安裝之後撤銷賦予應用的許可權,雖然系統會在使用者這麼做的時候發出警告.
下一刻,你可能擔心自己的應用在使用者撤銷許可權之後發生崩潰了.
Android開發團隊給我們送了一個福利,在應用的targetSdkVersion小於23,使用者撤銷了某項許可權之後,我們呼叫需要該項許可權的方法後,不會丟擲任何異常.呼叫的方法什麼也不會做,而返回值則是看情況返回null或者0.
不要高興的太早,儘管呼叫方法不會產生異常,但是你很可能在處理返回值的時候發生問題.(注:這個時候可以體現出對返回值檢查判斷的重要性了).
目前來說,由於新版本的普及問題,發生這種事的機率很小.使用者撤銷許可權後,可能就會意識到將會產生問題,就像系統警告的那樣.但是將來肯定會發生很多使用者撤銷許可權許可的問題,我們必須對應用進行適配以便在新的手機上進行使用.
在你完成對Android6.0動態許可權的適配之前,切勿將應targetSdkVersion設為23,否則將會使你陷入到適配問題中去.
注意在你使用AndroidStudio建立新工程的時候,它會自動地將工程的targetSdkVersion設為最新的版本,因此在你的應用支援動態許可權之前,建議你修改一下targetSdkVersion.
3.獲取動態許可權的核心程式碼.
public class WelcomeActivity extends AppCompatActivity {
public static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1000;
public static final int PERMISSIONS_REQUEST_LOCATION = 2000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//判斷targetSDK的版本是否小於23,大於等於23時才會執行該類中的邏輯判斷,也就是檢查手機是不是Android6.0以上的系統
//先價差是否獲取了儲存許可權
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//請求儲存和位置許可權
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
} else {
//檢查是否獲取了位置許可權
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
//申請位置許可權
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_LOCATION);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
startActivity();
}
}
}
//請求許可權的回撥函式
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//根據請求碼做不同的邏輯處理
if (requestCode == PERMISSIONS_REQUEST_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
new AlertDialog.Builder(WelcomeActivity.this)
.setTitle("警告!")
.setMessage("缺少許可權,不能定位")
.setPositiveButton("OK", null)
.create().show();
}
startActivity();
}
if (requestCode == PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startActivity();
} else {
new AlertDialog.Builder(WelcomeActivity.this)
.setTitle("警告!")
.setMessage("缺少許可權,程式即將關閉,請手動開啟許可權。")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// finishAll();
}
}).create().show();
}
}
}
private void startActivity() {
Intent intent = new Intent(this,MainActivity.class);
startActivity(intent);
finish();
}
}
程式碼片中有詳細的註釋,在此我就不多做闡述了!
4.預設許可許可權和動態許可權.
預設許可許可權就是指安裝的時候預設許可並且不可撤銷的,我們把它們叫做普通許可權,,這些許可權如下:
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
這些許可權和以前一樣使用,你無需檢查它們是否被撤銷了
需要申請的動態許可權如下圖所示:
當然不止上面一種實現方法,github上有許多大神開源的封裝庫,可以很方便的實現許可權適配。我推薦兩個庫,大家根據需求選擇:
不足之處請指出,謝謝!