Android权限问题总结

Android6.0,及api23以上,Android系统有些权限需要运行时动态申请。

权限类型:

Android权限分为系统权限和特殊权限,而系统权限又分为正常(normal)权限和涉及用户隐私的危险权限(dangerous)。

两者的区别:

android系统认为normal权限不会威胁用户隐私,可以直接在清单文件中注册,系统就会默认授权这些权限,而dangerous权限则是系统认为此类权限访问会威胁到用户隐私,使用时不仅需要在清单文件中注册,还需要在具体调用代码的地方向系统发起请求授权。

dangerours权限(即需要动态申请的权限列表):

CALENDAR

CAMERA

CONTACTS

LOCATION

MICROPHONE

PHONE

SENSORS

SMS

STORAGE

申请权限的注意点:

1.如果系统版本是api23以下的,则由于不需要动态申请权限,仅仅判断一下需要的权限(=PermissionChecker.checkSelfPermission(this, Manifest.permission....) )。但实际上,只要清单文件里注册了需要判断的权限,这行代码返回一直是true,遇到的坑下面介绍。

2.如果系统版本是api23及以上的,则需要动态申请以上危险权限。

android sdk提供了相关api:

以录音为例:

//判断是否有权限,
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
       //如果有权限
       Log.e("tag", "有录音权限!");
} else {
        //如果没有权限,则需要申请
        ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.RECORD_AUDIO},
                    REQUEST_CODE_RECORD);
}

对于反馈结果处理,需要重写下Activity里的 onRequestPermissionsResult方法:

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[]             permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_RECORD:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.e("tag", "有录音权限!");
                    //todo
                } else {
                    Log.e("tag", "没有录音权限!");
                }
                break;
        }
    }

当然,github上也有很多封装好的第三方库,使用起来也非常方便,比如由严振杰写的权限管理库:

https://github.com/yanzhenjie/AndPermission

具体用法可参考上面的地址里的介绍。

3.对于1种的情况,api23以下的机型,就拿实际开发中录音举例来说,可能会导致无法正常录音。

解决方案:

public void start() throws IOException {
        if (mIsRecording) {
            return;
        }
        mIsRecording = true; // 提早,防止init或startRecording被多次调用
        initAudioRecorder();
        mAudioRecord.startRecording();
        if (!checkPermission()) {
            mListener.noRecordRight();
            return;
        } else {
            mListener.hasRecordRight();
        }
        new Thread() {
            @Override
            public void run() {
                //设置线程权限
                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
                while (mIsRecording) {
                    int readSize = mAudioRecord.read(mPCMBuffer, 0, mBufferSize);
                    if (readSize > 0) {
                        mEncodeThread.addTask(mPCMBuffer, readSize);
                        calculateRealVolume(mPCMBuffer, readSize);
                    }
                }
                // release and finalize audioRecord
                mAudioRecord.stop();
                mAudioRecord.release();
                mAudioRecord = null;
                // stop the encoding thread and try to wait
                // until the thread finishes its job
                mEncodeThread.sendStopMessage();
            }

            /**
             * 此计算方法来自samsung开发范例
             *
             * @param buffer buffer
             * @param readSize readSize
             */
            private void calculateRealVolume(short[] buffer, int readSize) {
                double sum = 0;
                for (int i = 0; i < readSize; i++) {
                    // 这里没有做运算的优化,为了更加清晰的展示代码
                    sum += buffer[i] * buffer[i];
                }
                if (readSize > 0) {
                    double amplitude = sum / readSize;
                    mVolume = (int) Math.sqrt(amplitude);
                }
            }
        }.start();
    }
public boolean checkPermission() {
        if (null != mAudioRecord) {
            return mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING;
        }
        return false;
    }

即通过:mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING判断此状态来判断下是否有录音权限。

4.实际开发中还碰到个坑:个别机型,如果手动去系统权限设置页将某个权限设置由其他状态设置成禁止,再次回到当前界面,会发现当前app进程会被kill掉,再此重启并恢复到当前界面(重新走onCreated方法),但是当前的界面之前的数据可能会导致丢失,进而会导致app各种空指针引发的崩溃。

解决方案:我们可以参考微信的设计思路,当权限在设置页被手动禁止掉后可以通过一下代码判断下,让app重启:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!isFullScreen) {
            applyKitKatTranslucency();
            initStatusBar();
        }
        //手动关闭权限-部分手机需要重新启动应用
        if (null != savedInstanceState) {
            Log.e("tag", "savedInstanceState");
            Intent intent = new Intent(this, StartActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            startActivity(intent);
        }
        //todo 正常逻辑...
}

参考地址:

https://github.com/yanzhenjie/AndPermission

https://blog.csdn.net/renlei0109/article/details/72684469

https://www.jianshu.com/p/cb68ca511776

猜你喜欢

转载自blog.csdn.net/qq_20089667/article/details/82822173