国内第三方Rom在Android6.0以下系统的权限适配

来源:互联网 发布:日本代理ip地址和端口 编辑:程序博客网 时间:2024/05/21 10:00

我们都知道,在 Android 6.0 以下系统,在我们的 app 中需要使用到某权限时,只需要在 AndroidManifest 文件中声明,app 在安装时就会默认授权。但是在 Android 6.0 以后,Android 系统修改了权限机制,即原有的权限分为安全权限和危险权限,其中,危险权限不仅需要在 AndroidManifest 文件中声明,还需要在 app 运行时提示用户手动授权。

关于 Android 6.0 以上动态权限的申请,此类文章有很多,我就不多说了。我这里主要讲一下我在适配国内第三方 ROM 中遇到的一些坑。

在动态权限申请这一机制出现之后,国内的手机厂商也很快针对其系统进行了升级,也加入了这一机制,但是他们的 ROM 很多都是基于 Android 5.0 或 5.1 定制的,这就给开发者留下了一个大坑。我们在 6.0 以下系统调用 checkSelfPermission() 这样的 API 判断是否授权时,只要你在 AndroidManifest 文件中声明过,系统都是默认授权的,但是小米、魅族这样的第三方 ROM 中,权限可能已经被禁止,这时程序就可能会崩溃。所以我们无法通过系统提供的 API 来判断是否授权。这里我的处理方式就是在可能 Crash 的地方进行 try/catch 。在 catch 代码中弹出权限申请提示框,提示用户去打开相关权限。

Camera权限

在打开自定义相机时,需要使用 Camera 权限,这里又有一个坑。如果是打开系统相机,小米、魅族手机是不需要 Camera 权限的,可以直接打开,但是华为手机必须要开启 Camera 权限才可以,这里需要注意。如果权限被禁用,就会出现如下异常:

Caused by: java.lang.RuntimeException: Camera is being used after Camera.release() was called    at android.hardware.Camera.native_getParameters(Native Method)    at android.hardware.Camera.getParameters(Camera.java:3195)    at com.mine.app.activity.cargowork.TakePhotoActivity.setupCamera(TakePhotoActivity.java:559)    at com.mine.app.activity.cargowork.TakePhotoActivity.startPreview(TakePhotoActivity.java:542)    at com.mine.app.activity.cargowork.TakePhotoActivity.onResume(TakePhotoActivity.java:499)    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1317)    at cn.jiguang.a.a.c.a.a.d.callActivityOnResume(Unknown Source)    at android.app.Activity.performResume(Activity.java:6213)    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3376)    ... 11 more

这时最好的处理方式就是在把错误 try catch 出来,但是在哪里 try 呢?

每个自定义相机都要实现 SurfaceHolder.Callback 接口

我是在 surfaceChanged onResume 方法中对相机进行初始化的地方进行 try 的,在 catch 代码中弹出权限申请提示框,提示用户去授权。

悬浮窗权限

实际开发中,经常会需要在 Servcie 中弹出 Dialog ,这时我们需要给 Dialog 设置 TYPE_SYSTEM_ALERT 属性,设置该属性后,该 Dialog 就会变成系统提示框,想要正常显示的话需要开启悬浮窗权限。

app默认不授予该权限,其他型号手机没有权限时不会弹出对话框,但也不会报错,但是部分手机会崩溃,比如说乐视,错误日志如下:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@eaa60b4 -- permission denied for this window type    at android.view.ViewRootImpl.setView(ViewRootImpl.java:724)    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:322)    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)    at android.app.Dialog.show(Dialog.java:325)    at com.mine.app.jpush.MyReceiver.otherStateType(MyReceiver.java:978)    at com.mine.app.jpush.MyReceiver.onReceive(MyReceiver.java:219)    at android.app.ActivityThread.handleReceiver(ActivityThread.java:3016)    ... 8 more

不得不说吐槽一下 Android 的碎片化问题,各种机型适配到你想吐。

问题还是得解决,当然这里使用 try 的方法也可以,但我为了方便,就使用了一个 Dialog 样式的 Activity 来代替系统悬浮窗,这样就避免了很多问题。

<activity android:name=".activity.DialogActivity"                  android:launchMode="singleTop"                  android:theme="@style/dialogstyle"/>

将启动模式设置为 singleTop 是为了防止同时弹出多个 Dialog

<style name="dialogstyle">        <!--设置dialog的背景-->        <item name="android:windowBackground">@color/transport</item>        <!--设置Dialog的windowFrame框为无-->        <item name="android:windowFrame">@null</item>        <!--设置无标题-->        <item name="android:windowNoTitle">true</item>        <!--是否浮现在activity之上-->        <item name="android:windowIsFloating">true</item>        <!--是否半透明-->        <item name="android:windowIsTranslucent">true</item>        <!--设置窗口内容不覆盖-->        <item name="android:windowContentOverlay">@null</item>        <!--设置动画,在这里使用让它继承系统的Animation.Dialog-->        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>        <!--背景是否模糊显示-->        <item name="android:backgroundDimEnabled">true</item>    </style>

还需要注意一点,如果要在 Service 中启动 Activity 的话,要加上如下一句:

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 

以上就是我在进行权限适配时踩过的一些坑,本人还是菜鸟一枚,如果有什么不合理的地方,请多多指教。

原创粉丝点击