Android 手機系統權限處理

本文主要介紹 Android 手機系統權限處理方式

前言

隨著 Android 設備的廣泛引用,Google 對于手機的安全問題也越來越重視 。從 Android M 開始添加了應用動態權限管理,手機的權限管理細粒度,更好的保護了用戶的個人隱私并且賦予了用戶更大的管理權限。但是各大 Android 手機本身有自己的應用權限管理,這就導致了 Android 開發小伙伴們,在開發工程中要盡可能多的去考慮問題,防止出現權限問題導致應用崩潰。

權限變化及影響

權限變化

  • 在 Android 的各個版本中,不論是普通權限還是敏感權限,都需要在manifest文件中聲明,例如權限聲明。然而,在不同版本的操作系統或不同的 target SDK level 中的結果是不同的。

  • 如果設備運行 Android M 以下版本的操作系統,或者你的 targetSDK 版本號小于或等于 22,當你在 manifest 文件中請求了一些權限,用戶必須在安裝過程時有的手機是授予全部權限,部分手機提示用戶選擇授權。

  • 如果設備運行在 Android M 或者更高版本,并且目標 SDK 版本號大于或等于 23,應用程序必須要在 manifest 文件中聲明需要的權限,當程序運行時,它必須要向用戶請求授權每個所需的敏感權限。用戶可以允許或拒絕每個權限,并且程序可以依賴用戶已經授權的權限繼續運行。

  • 關于compileSdk、minSdk、targetSdk的相關知識,建議看一下這篇文章:http://www.lxweimin.com/p/544d9f72883d

影響

  • 在公司的項目開發過程中確實遇到了不少的坑,由于公司項目集成某家第三方庫,導致公司的項目 targetSdkVersion 版本為 25 ,在 Adnroid 出現了動態權限管理后,發現項目在高版本的手機上調用權限崩潰的問題。最后參考其他其他一些應用,想出一個解決方案,為了防止用戶隨意改變應用權限導致程序崩潰,我們在 Base 層加了檢查權限方法,檢測到應用沒有開啟清單文件中的權限,就給出提示并且讓用戶跳轉到應用權限管理頁面。


    提示頁面
  • 大功告成發給測試,然而新的坑又出現了。前面說到的問題在不同版本的操作系統或不同的 target SDK level 中的結果是不同的。下面我們來總結一下都出現了那些坑。

    1. 檢測權限的代碼在一臺 Android 5.0 的華為手機一直返回 true , 原因很簡單 Android 5.0 它檢查這些權限如果你在清單文件里注冊過了,那就表明這個應用有了這個權限。但是這臺手機在安裝后手機廠商提示系統權限授權,測試人員選擇了拒絕。檢測權限代碼并沒有成效。
    2. 在 Android 6.0 以上的手機檢測權限代碼沒有問題,但是之前的解決方案是跳轉到應用權限管理頁面,后來發現只要在安裝后拒絕了廠商的系統權限,我在應用授權管理頁面每次打開這個權限后,再次查看都是無法打開的。這就很尷尬了,廠商的應用系統權限大于應用本身的權限。


      系統應用權限管理

      應用訪問權限

解決方案

  • 當然每次沒有好的決方式時,我第一想到的就是看看微信、QQ等應用是如何處理這樣的問題的,分別在我的測試機華為(5.0) 、小米(7.0)上安裝了很多應用,參考參考大神們是如何處理這些問題的。
  • 經過試驗發現微信的處理方式是很優好的,在小米(7.0)手機上關閉微信訪問權限和系統應用權限。再啟動微信的時候程序給出了提示,缺少相應權限讓用戶去設置。在華為(5.0)上我關閉了微信系統應用權限(定位、攝像頭的權限)也是檢測不到沒有任何的提示,但是在我使用到定位、獲取攝像頭功能時他會通過代碼判斷應用是否有這個功能的權限,然后提示給用戶,讓用戶自己去系統的授權管理里面去開啟相應的權限,要不然不能使用該功能。
  • 下面我舉個例子說明一下,我在項目中是如何判斷應用沒有錄音權限的,檢測語音錄制權限方法很多但是經過測試發現一定要通過獲取語音流的方式,如果獲取不到則說明沒有權限。這種方式是可以兼容所有手機的,代碼如下:
public boolean isHasAudioRecordingPermission(Context context) {
        isHasPermission = false;
        count = 0;
        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                SAMPLE_RATE_IN_HZ, AudioFormat.CHANNEL_IN_DEFAULT,
                AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE);
        if (mAudioRecord == null) {
            MyLog.e("sound", "mAudioRecord初始化失敗");
        }
        isGetVoiceRun = true;
        try {
            mAudioRecord.startRecording();
            short[] buffer = new short[BUFFER_SIZE];
            while (isGetVoiceRun) {

                count++;

                if (count++ > 10) {
                    isGetVoiceRun = false;
                }
                //r是實際讀取的數據長度,一般而言r會小于buffersize
                int r = mAudioRecord.read(buffer, 0, BUFFER_SIZE);
                long v = 0;
                // 將 buffer 內容取出,進行平方和運算
                for (short aBuffer : buffer) {
                    v += aBuffer * aBuffer;
                }
                // 平方和除以數據總長度,得到音量大小。
                double mean = v / (double) r;
                double volume = 10 * Math.log10(mean);
                MyLog.d(TAG, "-------分貝值:" + volume + "----v" + v + "------r" + r);
                if (v > 0 && r > 0) {
                    // 有錄音
                    isHasPermission = true;
                    mAudioRecord.stop();
                    mAudioRecord.release();
                    mAudioRecord = null;
                    return isHasPermission;
                }
                // 大概一秒十次
                synchronized (mLock) {
                    try {
                        mLock.wait(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            mAudioRecord.stop();
            mAudioRecord.release();
            mAudioRecord = null;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return isHasPermission;
    }
  • 所以接下就是在項目中每個調用的權限的地方都加上判斷,給用戶提示去系統授權中打開相應的權限。
  • 下面是整理了一些不同手機跳轉到對應的權限管理頁面的方法(僅供參照,不排除個別廠家有作更改,希望小伙伴們多來指正)
 switch (Build.MANUFACTURER) {
            case Constants.ROM_HUAWEI: // 華為
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                comp = new ComponentName("com.huawei.systemmanager",
                        "com.huawei.permissionmanager.ui.MainActivity");
                intent.setComponent(comp);
                startActivity(intent);
                break;
            case Constants.ROM_MEIZU: // 魅族
                intent.setAction("com.meizu.safe.security.SHOW_APPSEC");
                intent.addCategory(Intent.CATEGORY_DEFAULT);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                startActivity(intent);
                break;
            case Constants.ROM_XIAOMI: // 小米
                intent.setAction("miui.intent.action.APP_PERM_EDITOR");
                intent.setClassName("com.miui.securitycenter",
                        "com.miui.permcenter.permissions.PermissionsEditorActivity");
                intent.putExtra("extra_pkgname", getPackageName());
                startActivity(intent);
                break;
            case Constants.ROM_SONY: // 索尼
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                comp = new ComponentName("com.sonymobile.cta",
                        "com.sonymobile.cta.SomcCTAMainActivity");
                intent.setComponent(comp);
                startActivity(intent);
                break;
            case Constants.ROM_OPPO: // oppo
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                comp = new ComponentName("com.color.safecenter",
                        "com.color.safecenter.permission.PermissionManagerActivity");
                intent.setComponent(comp);
                startActivity(intent);
                break;
            case Constants.ROM_LG: // LG
                intent.setAction("android.intent.action.MAIN");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                comp = new ComponentName("com.android.settings",
                        "com.android.settings.Settings$AccessLockSummaryActivity");
                intent.setComponent(comp);
                startActivity(intent);
                break;
            case Constants.ROM_LETV: // 樂視
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
                comp = new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps");
                intent.setComponent(comp);
                startActivity(intent);
                break;
            default:
                // 跳轉權限設置界面
                intent.setAction(Settings.ACTION_SETTINGS);
                startActivity(intent);
                break;
        }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容