編輯:關於android開發
(1).由於MIUI等部分國產定制系統也有權限管理,沒有相關api,故無法判斷用戶是否允許獲取聯系人等隱私。在Android 6.0之後,新增權限管理可以通過官方api判斷用戶的運行狀態;
(2).我們指定targetSdkVersion為23或者之後我們還需要在運行時請求這些所需的權限。這很重要,因為已經出現了很多開發者把targetSdkVersion飙到了最新,然後發現自己的app瘋狂的崩潰,這是由於他們沒有實現執行運行時權限請求的代碼。當你已經把一個targeting API 為23或者之後的app發布到了Google Play上,這更是一個問題,你無法立即把那個apk的targeting API替換成更早的版本。
2.權限分析
從Android6.0開始,權限分為普通權限和許可權限。許可權限分類歸組,一個權限授權之後,該組下的權限均可使用。
(1)普通權限
只需要在xml申請即可,使用方法和之前6.0以前的一樣。在應用安裝應用時,會默認獲得許可。
(2)許可權限
可執行 $adb shell pm list permissions -d -g
Permission Group Permissions android.permission-group.CALENDAR
android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
android.permission.CAMERA
android.permission-group.CONTACTS
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS
android.permission-group.LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
android.permission.RECORD_AUDIO
android.permission-group.PHONE
android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
android.permission.BODY_SENSORS
android.permission-group.SMS
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_CELL_BROADCASTS
android.permission-group.STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
同一組的任何一個權限被授權了,其他權限也自動被授權。例如,一旦WRITE_CONTACTS被授權了,app也有READ_CONTACTS和GET_ACCOUNTS了。
源碼中被用來檢查和請求權限的方法分別是Activity的checkSelfPermission和requestPermissions,這些方法api23引入。
(1).ContextCompat.checkSelfPermission()
檢查應用是否擁有該權限,被授權返回值為PERMISSION_GRANTED,否則返回PERMISSION_DENIED
(2).ActivityCompat.requestPermissions()
將彈出請求授權對話框,這個方法在M之前版本調用,OnRequestPermissionsResultCallback 直接被調用,帶著正確的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。
(3).AppCompatActivity.onRequestPermissionsResult()
該方法類似於Activity的OnActivityResult()的回調方法,主要接收請求授權的返回
- //版本判斷
- if(Build.VERSION.SDK_INT>=23){
- //減少是否擁有權限
- intcheckCallPhonePermission=ContextCompat.checkSelfPermission(getApplicationContext(),permission);
- if(checkCallPhonePermission!=PackageManager.PERMISSION_GRANTED){
- //彈出對話框接收權限
- ActivityCompat.requestPermissions(BaseActivity.this,newString[]{permission},id);
- return;
- }
- @Override
- publicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){
- super.onRequestPermissionsResult(requestCode,permissions,grantResults);
- if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
- //TODO:已授權
- }else{
- //TODO:用戶拒絕
- }
- }
- publicclassBaseActivityextendsAppCompatActivity{
- privateMap
allowablePermissionRunnables=newHashMap<>(); - privateMap
disallowablePermissionRunnables=newHashMap<>(); - @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- }
- /**
- *請求權限
- *@paramid請求授權的id唯一標識即可
- *@parampermission請求的權限
- *@paramallowableRunnable同意授權後的操作
- *@paramdisallowableRunnable禁止權限後的操作
- */
- protectedvoidrequestPermission(intid,Stringpermission,RunnableallowableRunnable,RunnabledisallowableRunnable){
- if(allowableRunnable==null){
- thrownewIllegalArgumentException("allowableRunnable==null");
- }
- allowablePermissionRunnables.put(id,allowableRunnable);
- if(disallowableRunnable!=null){
- disallowablePermissionRunnables.put(id,disallowableRunnable);
- }
- //版本判斷
- if(Build.VERSION.SDK_INT>=23){
- //減少是否擁有權限
- intcheckCallPhonePermission=ContextCompat.checkSelfPermission(getApplicationContext(),permission);
- if(checkCallPhonePermission!=PackageManager.PERMISSION_GRANTED){
- //彈出對話框接收權限
- ActivityCompat.requestPermissions(BaseActivity.this,newString[]{permission},id);
- return;
- }else{
- allowableRunnable.run();
- }
- }else{
- allowableRunnable.run();
- }
- }
- @Override
- publicvoidonRequestPermissionsResult(intrequestCode,@NonNullString[]permissions,@NonNullint[]grantResults){
- super.onRequestPermissionsResult(requestCode,permissions,grantResults);
- if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
- RunnableallowRun=allowablePermissionRunnables.get(requestCode);
- allowRun.run();
- }else{
- RunnabledisallowRun=disallowablePermissionRunnables.get(requestCode);
- disallowRun.run();
- }
- }
- }
- publicclassMainActivityextendsBaseActivityimplementsView.OnClickListener{
- privateButtonbtCallPhone;
- privateButtonbtContact;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btCallPhone=(Button)findViewById(R.id.call_phone);
- btContact=(Button)findViewById(R.id.contact);
- btCallPhone.setOnClickListener(this);
- btContact.setOnClickListener(this);
- }
- @Override
- publicvoidonClick(Viewv){
- if(v==btCallPhone){
- //撥打電話
- requestPermission(1,Manifest.permission.CALL_PHONE,newRunnable(){
- @Override
- publicvoidrun(){
- callPhone();
- }
- },newRunnable(){
- @Override
- publicvoidrun(){
- callPhoneDenied();
- }
- });
- }elseif(v==btContact){
- //讀取聯系人信息
- requestPermission(2,Manifest.permission.WRITE_CONTACTS,newRunnable(){
- @Override
- publicvoidrun(){
- readContact();
- }
- },newRunnable(){
- @Override
- publicvoidrun(){
- readContactDenied();
- }
- });
- }
- }
- privatevoidcallPhone(){
- Toast.makeText(MainActivity.this,"CALL_PHONEOK",Toast.LENGTH_SHORT)
- .show();
- }
- privatevoidcallPhoneDenied(){
- Toast.makeText(MainActivity.this,"CALL_PHONEDenied",Toast.LENGTH_SHORT)
- .show();
- }
- privatevoidreadContact(){
- ContentResolvercr=getContentResolver();
- Stringstr[]={ContactsContract.CommonDataKinds.Phone.CONTACT_ID,ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,
- ContactsContract.CommonDataKinds.Phone.PHOTO_ID};
- Cursorcur=cr.query(
- ContactsContract.CommonDataKinds.Phone.CONTENT_URI,str,null,
- null,null);
- intcount=cur.getCount();
- cur.close();
- Toast.makeText(MainActivity.this,String.format("發現%s條",count),Toast.LENGTH_SHORT)
- .show();
- }
- privatevoidreadContactDenied(){
- Toast.makeText(MainActivity.this,"ContactDenied",Toast.LENGTH_SHORT)
- .show();
- }
- }
Android技巧2:登錄注冊模塊解決方案 前言 幾乎每個app都會有登錄注冊的功能,可以看看筆者開發的『南方周末新聞閱讀器』,登錄、手機注冊、忘記密碼這些入口,這些功能
我的Android進階之旅之Android自定義View來實現解析lrc歌詞同步滾動、上下拖動、縮放歌詞等功能 前言 最近有個項目有關於播放音樂時候
git詳解,gitgit詳解 git是從android出現,就作為版本管理工具。由於很多人從svn開始使用,簡單的check in & check out操作,很
手勢交互之GestureOverlayView,gestureoverlayview一種用於手勢輸入的透明覆蓋層,可以覆蓋在其他空間的上方,也可包含在其他控件 andro