Android 6.0系統中權限問題調用 - Permission in Android M

安卓平臺權限一直有被流氓應用隨便利用詬病, android M的發布徹底解決了這一問題,取而代之的是,app不得不在運行時一個一個詢問用戶授予權限。

Android 6.0(api23)系統中,做了一些限制, 開發者在使用到每條權限時必須自己調用相關代碼請求.

如果沒有獲得某項權限,直接使用相關功能,則會導致自己程序crash.

見log

可見6.0以后的系統開發者必須對權限適配,否則軟件隨時都可能奔潰,那么問題來了~

已經發出去的版本或是targetSdkVersion小與23的apk怎么辦?

廢話,當然會崩了!!!

只要在滿足在Android M上直接使用為授權的功能,程序必須Crash. targetSdkVersion<23的應用在安裝時系統會默認全部授權應用在manifest中申請的權限,

不要應用這樣你的應用就完事大全了.用戶可以在以下頁面或是其他應用關閉相關權限,然后…你的應用就沒有然后了~

關閉權限頁


Android M 權限分類

安卓系統把權限分為了三類:

Normal Permissions

Dangerous Permissions

Special Permissions

Normal Permissions-一般權限

一般權限都是一些系統認為比較權限的權限,流氓應用就是擁有這些權限也干不出多大壞事,Normal 權限會在應用安裝是直接授權,

官網解釋:權限如下:

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

FLASHLIGHT

GET_PACKAGE_SIZE

INTERNET

KILL_BACKGROUND_PROCESSES

MODIFY_AUDIO_SETTINGS

NFC

READ_SYNC_SETTINGS

READ_SYNC_STATS

RECEIVE_BOOT_COMPLETED

REORDER_TASKS

REQUEST_INSTALL_PACKAGES

SET_TIME_ZONE

SET_WALLPAPER

SET_WALLPAPER_HINTS

TRANSMIT_IR

USE_FINGERPRINT

VIBRATE

WAKE_LOCK

WRITE_SYNC_SETTINGS

SET_ALARM

INSTALL_SHORTCUT

UNINSTALL_SHORTCUT

Dangerous Permissions-危險權限

這些權限都是一些敏感性權限,一些廣告平臺或是流氓應用會用這些權限干一些壞壞的事情,因此系統將這類權限分了幾個類別,

應用每次都要檢測下是否有權限,沒有的化必須彈出對話框申請,只要一個組別中的一個權限得到了授權,整個組的權限都會的到授權.

這部分權限也是我們重點在M系統上關注和適配的部分.

官網權威說明, 具體相關權限見圖:

Dangerous Permission


Special Permissions- 特殊權限

SYSTEM_ALERT_WINDOW and WRITE_SETTINGS, 這兩個權限比較特殊,不能通過代碼申請方式獲取,必須得用戶打開軟件設置頁手動打開,才能授權.

There are a couple of permissions that don’t behave like normal and dangerous permissions. SYSTEM_ALERT_WINDOW and WRITE_SETTINGS are particularly sensitive, so most apps should not use them. If an app needs one of these permissions, it must declare the permission in the manifest, and send an intent requesting the user’s authorization. The system responds to the intent by showing a detailed management screen to the user.

特殊權限官網推薦用法

實戰Android m權限申請用法

我們對相關申請方法封裝成了工具類,方便m系統適配隨時調用.

相關配置

compileSdkVersion and targetSdkVersion 設置為 23開始

調用相關權限

private void testAlertPermission() {

WindowManager mWindowManager = (WindowManager) getSystemService(

Context.WINDOW_SERVICE);

WindowManager.LayoutParams params = new WindowManager.LayoutParams();

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

mWindowManager.addView(new TextView(this), params);

}

權限申請相關代碼

// Here, thisActivity is the current activity

if (ContextCompat.checkSelfPermission(thisActivity,

Manifest.permission.READ_CONTACTS)

!= PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?

if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,

Manifest.permission.READ_CONTACTS)) {

// Show an expanation to the user *asynchronously* -- don't block

// this thread waiting for the user's response! After the user

// sees the explanation, try again to request the permission.

} else {

// No explanation needed, we can request the permission.

ActivityCompat.requestPermissions(thisActivity,

new String[]{Manifest.permission.READ_CONTACTS},

MY_PERMISSIONS_REQUEST_READ_CONTACTS);

// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an

// app-defined int constant. The callback method gets the

// result of the request.

}

}

requestPermissions方法調用時會彈出以下對話框.當用戶點擊拒絕并且勾選了不再彈出后這個對話框將不會再彈出,會直接拒絕掉該權限:

requestPermissions


shouldShowRequestPermissionRationale方法說明

用戶拒絕,或是不在彈出,這個方法會返回false.

返回說明


Activity activity = (Activity) cxt;

return ActivityCompat.checkSelfPermission(activity,

permission) == PackageManager.PERMISSION_GRANTED;

} else if (cxt instanceof Fragment) {

Fragment fragment = (Fragment) cxt;

return fragment.getActivity().checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;

} else {

throw new RuntimeException("cxt is net a activity or fragment");

}

}

private static String[] checkSelfPermissionArray(Object cxt, String[] permission) {

ArrayList permiList = new ArrayList<>();

for (String p : permission) {

if (!checkSelfPermissionWrapper(cxt, p)) {

permiList.add(p);

}

}

return permiList.toArray(new String[permiList.size()]);

Activity和Fragment的申請方法不一樣,所以我們對方法做了包裝如下:

@TargetApi(Build.VERSION_CODES.M)

public static boolean checkPermission(Object cxt, String permission, int requestCode) {

if (!checkSelfPermissionWrapper(cxt, permission)) {

if (!shouldShowRequestPermissionRationaleWrapper(cxt, permission)) {

requestPermissionsWrapper(cxt, new String[]{permission}, requestCode);

} else {

Log.d(TAG, "should show rational");

}

return false;

}

return true;

}

private static void requestPermissionsWrapper(Object cxt, String[] permission, int requestCode) {

if (cxt instanceof Activity) {

Activity activity = (Activity) cxt;

ActivityCompat.requestPermissions(activity, permission, requestCode);

} else if (cxt instanceof Fragment) {

Fragment fragment = (Fragment) cxt;

fragment.requestPermissions(permission, requestCode);

} else {

throw new RuntimeException("cxt is net a activity or fragment");

}

}

權限可以一次申請多個

如圖一次可以申請多個權限,但是用戶還是一個一個授權.我們對該請求也做了封裝:

multimulti




@TargetApi(23)

private static boolean checkSelfPermissionWrapper(Object cxt, String permission) {

if (cxt instanceof Activity) {

Activity activity = (Activity) cxt;

return ActivityCompat.checkSelfPermission(activity,

permission) == PackageManager.PERMISSION_GRANTED;

} else if (cxt instanceof Fragment) {

Fragment fragment = (Fragment) cxt;

return fragment.getActivity().checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;

} else {

throw new RuntimeException("cxt is net a activity or fragment");

}

}

private static String[] checkSelfPermissionArray(Object cxt, String[] permission) {

ArrayList permiList = new ArrayList<>();

for (String p : permission) {

if (!checkSelfPermissionWrapper(cxt, p)) {

permiList.add(p);

}

}

return permiList.toArray(new String[permiList.size()]);

}


權限返回處理

在activity或fragment 中重寫onRequestPermissionsResult,用戶處理相關權限后會回調該方法,當活取到相關應用后可以繼續原來的邏輯.

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

switch (requestCode) {

case PermissionUtils.PERMISSION_REQUEST_CODE:

if (PermissionUtils.verifyPermissions(grantResults)) {

// Permission Granted

// do you action

} else {

// Permission Denied

Toast.makeText(this, "WRITE_CONTACTS Denied", Toast.LENGTH_SHORT)

.show();

}

break;

default:

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

}

}

public static boolean verifyPermissions(int[] grantResults) {

// At least one result must be checked.

if (grantResults.length < 1) {

return false;

}

// Verify that each required permission has been granted, otherwise return false.

for (int result : grantResults) {

if (result != PackageManager.PERMISSION_GRANTED) {

return false;

}

}

return true;

}

特殊權限的申請

以前特殊權限說明地方已經支出,該類權限需求intent到具體的設置頁面,讓用戶手動打開,才能授權.

同樣重寫onActivityResult方法,返回該頁面時做回調處理.

sp

系統彈出權限,相關代碼實例:

/**

* 檢測系統彈出權限

* @param cxt

* @param req

* @return

*/

@TargetApi(23)

public static boolean checkSettingAlertPermission(Object cxt, int req) {

if (cxt instanceof Activity) {

Activity activity = (Activity) cxt;

if (!Settings.canDrawOverlays(activity.getBaseContext())) {

Log.i(TAG, "Setting not permission");

Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,

Uri.parse("package:" + activity.getPackageName()));

activity.startActivityForResult(intent, req);

return false;

}

} else if (cxt instanceof Fragment) {

Fragment fragment = (Fragment) cxt;

if (!Settings.canDrawOverlays(fragment.getActivity())) {

Log.i(TAG, "Setting not permission");

Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,

Uri.parse("package:" + fragment.getActivity().getPackageName()));

fragment.startActivityForResult(intent, req);

return false;

}

} else {

throw new RuntimeException("cxt is net a activity or fragment");

}

return true;

}

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

if (requestCode == PermissionUtils.PERMISSION_SETTING_REQ_CODE) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

if (Settings.canDrawOverlays(this)) {

// do something

} else {

Toast.makeText(this, "not has setting permission", Toast.LENGTH_LONG).show();

finish();

}

}

}

}

結語

Android 6.0系統權限管理是安卓系統的一大進步,為安卓手機用戶提供了一個安全干凈系統前提,鑒于google對未授權應用的奔潰方式處理,

安卓開發者應當盡早適配6.0系統,提示軟件體驗.

實戰整體代碼已提交到GitHub(https://github.com/CankingApp/PermissionDemo),歡迎下載交流學習~


博客:http://cankingapp.github.io/2016/03/18/android-permission/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容