運行時異常之運行時權限

最近在工作中遇到一個異常,在Android N版本上進行開發,在短信應用中設置消息通知,這個操作需要訪問本地存儲,但是結果短信閃退,出現如下日誌:

----- timezone:GMT
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: FATAL EXCEPTION: main
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: Process: com.android.mms, PID: 2646
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: java.lang.RuntimeException: Unable to resume activity {com.android.mms/com.mediatek.setting.NotificationPreferenceActivity}: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media/171 from pid=2646, uid=10073 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3506)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3546)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1577)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:110)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:203)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6251)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media/171 from pid=2646, uid=10073 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.os.Parcel.readException(Parcel.java:1683)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:188)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:692)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1179)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:998)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:921)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.media.RingtoneManager.isRingtoneExist(RingtoneManager.java:998)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at com.mediatek.setting.NotificationPreferenceActivity.setRingtoneSummary(NotificationPreferenceActivity.java:189)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at com.mediatek.setting.NotificationPreferenceActivity.onResume(NotificationPreferenceActivity.java:124)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1269)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.Activity.performResume(Activity.java:6770)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3477)
06-08 16:05:55.464339  2646  2646 E AndroidRuntime: 	... 8 more
日誌是由於沒有權限引起,但是我們看AndroidManifest.xml裏面已經有READ_EXTERNAL_STORAGE這個權限了,爲什麼還報這個異常呢?後來查看資料,發現Android sdk版本>=23後,需要對權限進行動態授權,否則應用會出現crash。經過對代碼進行動態授權後,就解決了這個問題。加了如下代碼:

    @Override
    protected void onCreate(Bundle icicle) {
    	if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED)
        {
        	requestPermissions(
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
        }
        super.onCreate(icicle); ....
再進入下個Activity的時候,先判斷是否有那個READ_EXTERNAL_STORAGE權限,如果沒有這個權限,系統就會彈出請求權限的Dialog,選中同意後,會回調onRequestPermissionsResult(),重寫該方法。

private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;
	@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {

        if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)
        {
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED)
            {
            	 finish(); //關閉該Activity
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

當彈出Dialog的時候,第一次彈出和第二次彈出的現象不一致,如下:


第一次彈出Dialog如左圖,沒有不再詢問這個選項框。第二次彈出如右圖,有這個框。所以大家在開發的過程中,看到這種現象不要以爲是故障,其實這是正常現象,Android機制就是如此。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章