2019-10-23
關鍵字: APK申請權限、通過代碼獲取權限、定位權限、相機權限
這篇文章大部分的內容都搬自簡書某位大神的博客: https://www.jianshu.com/p/e36f686588d6 。搬運的目的有二:一是方便自己后續查閱,二是添加一些自己的使用經驗。感謝這位簡書大神的奉獻。
APK 開發中的權限主要有三種:
1、普通權限;
2、危險權限;
3、特殊權限;
這三種不同類型的權限都是單獨針對APK用的。這些權限的背后代表着一款 APK 的功能完整性。越靠后的權限 Android 系統對其的把控就越嚴格。
1、普通權限
普通權限就是那些可以直接在 AndroidManifest.xml 中配置一下即可獲得的權限。系統對它們的管理非常寬松。
常見的有使用網絡、更改網絡狀態等。
2、危險權限
危險權限除了要在 AndroidManife.xml 中聲明以外,還得額外通過代碼或用戶主動在系統權限管理設置中開啟。下圖是華為手機中某個應用的部分常用危險權限控制界面:

危險權限的各類如下表所示
| 權限組 | 權限詳情 |
| CALENDAR | READ_CALENDAR WRITE_CALENDAR |
| CAMERA | CAMERA |
| CONTACTS | READ_CONTACTS WRIGE_CONTACTS GET_ACCOUNTS |
| LOCATION | ACCESS_FINE_LOCATION ACCESS_CONARSE_LOCATION |
| MICROPHONE | RECORD_AUDIO |
| PHONE | READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
| SENSORS | BODY_SENSORS |
| SMS | SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
| STORAGE | READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
關於危險權限的限制,不同的 ROM 有不同的做法,有的嚴格有的寬松。但在 APK 開發中,為了應用的兼容性,還是很有必要去檢查這些權限的狀態,並在有必要的情況下彈出申請彈窗。
1、權限狀態檢查
import androidx.core.content.ContextCompat;
int perm = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
以上代碼用於檢查當前 APK 是否擁有使用攝像頭的權限。它的返回值是一個整型。這個整型有兩個值:PackageManager.PERMISSION_GRANTED 與 PackageManager.PERMISSION_DENIED ,分別代表着有權限與無權限。通常我們會根據當前權限的狀態來決定是否去申請相關權限。
2、申請危險權限
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CAMERA }, 0);
當執行了這段代碼以后,會有兩種情況:一種是所申請的權限在當前應用中確實沒有。另一種是所申請的權限在當前應用中已擁有。
對於第一種情況,執行以后會發現系統將會彈出如下圖所示的彈窗供用戶選擇:

對於第二種情況,執行以后系統不會有任何變化,一切就像沒有發生過什么一樣。
當權限申請結果出來以后,系統會通過回調 Activity 中的以下方法來回傳結果:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode == 0) { try { for(int i = 0; i < permissions.length; i++) { Logger.d(TAG, permissions[i] + ":" + grantResults[i]); } }catch(Exception e){ e.printStackTrace(); } } }
這段代碼就遍歷了所有申請的權限的結果,當然結果值僅會有值為數字 0 的 PackageManager.PERMISSION_GRANTED 以及值為數字 -1 的 PackageManager.PERMISSION_DENIED。
3、特殊權限
特殊權限主要包括:
1、通知欄;
2、自動啟動;
3、懸浮窗;
4、無障礙輔助。
略。
4、注意事項
在申請危險權限時有一些注意事項必須要提一下。
由於權限申請結果是回調到 Activity 的 onRequestPermissionsResult 方法中的,所以我們通常都會直接在 Activity 里來做申請操作。
當你執行了權限申請代碼以后,即執行了 ActivityCompat.requestPermissions(this, new String[]{}, 0); 以后,無論上面圖片所示的權限彈窗是否彈出,當前 Activity 的狀態都會進入到 onPause() 態。並且在權限申請結果出來以后,Activity 會回到 onResume() 態,即這一申請過程會導致 onPause() 與 onResume() 被執行一次。
如果你有在這兩個方法中做一些邏輯操作的話,一定要注意處理一下這種額外的調用。
筆者就是因為將權限申請操作放在 onResume() 中做的,導致了這個權限申請一直在無限調用。
參考:https://www.jianshu.com/p/e36f686588d6
