声明:该方案只对API19及以上版本有效
一、目标需求
最近项目中在完善推送功能,需要进入APP时检测一下是否开启了推送权限,如果没有开启弹窗提醒,当用户点击弹窗时直接跳转到APP的通知设置界面,就像下面这种:
二、需求实现
1、检测是否开启通知权限
接到需求时一脸懵,不知道咋实现,先是一番搜索,搜索后得知可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限。
查阅官方文档可知 NotificationManagerCompat 在 android.support.v4.app包中,是API 22.1.0 中加入的。而 areNotificationsEnabled()则是在 API 24.1.0之后加入的。
areNotificationsEnabled 只对 API 19 及以上版本有效,低于API 19 会一直返回true
2、跳转到通知设置界面
假设没有开启通知权限,点击之后就需要跳转到 APP的通知设置界面,对应的Action是:Settings.ACTION_APP_NOTIFICATION_SETTINGS, 这个Action是 API 26 后增加的。APP的通知设置界面如下图:

如果在部分手机中无法精确的跳转到 APP对应的通知设置界面,那么我们就考虑直接跳转到 APP信息界面,对应的Action是:Settings.ACTION_APPLICATION_DETAILS_SETTINGS。APP信息界面如下图:
3、代码实现:
public class NotificationsUtils { public static boolean isNotificationEnabled(Context context) { return NotificationManagerCompat.from(context.getApplicationContext()).areNotificationsEnabled(); } public static void openPush(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Intent intent = new Intent(); intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName()); intent.putExtra(Settings.EXTRA_CHANNEL_ID, activity.getApplicationInfo().uid); activity.startActivity(intent); } else { PermissionUtil.toPermissionSetting(activity); } } }
PermissionUtil的部分代码
public static void toPermissionSetting(Activity activity) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { toSystemConfig(activity); } else { try { toApplicationInfo(activity); } catch (Exception e) { e.printStackTrace(); toSystemConfig(activity); } } } public static void toApplicationInfo(Activity activity) { Intent localIntent = new Intent(); localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null)); activity.startActivity(localIntent); } public static void toSystemConfig(Activity activity) { try { Intent intent = new Intent(Settings.ACTION_SETTINGS); activity.startActivity(intent); } catch (Exception e) { e.printStackTrace(); } }
4、踩坑记录
A: com.android.support包的版本
因为 NotificationManagerCompat 是 22.1.0才有的,其中的 areNotificaitonEnabled() 是 24.1.0 才有的,Settings.ACTION_APP_NOTIFICATION_SETTINGS 是 26 才有的,所以,为了保证这些内容在不同版本中生效,最好在 gradle文件中 support 的版本升级到最新。如:
implementation ‘com.android.support:appcompat-v7:27.1.1’
B: 部分国产手机中没有APP通知设置页面
在部分国产手机系统中,Settings.ACTION_APPLICATION_DETAILS_SETTINGS对应的Activity是不存在的,比如:锤子坚果3——OC105 API25。
所以,在坚果3手机上,最终会走我们代码中的 catch 节点,然后进入到 应用信息界面。
下面两张图分别是 锤子坚果3 手机的截图。第一张是 设置–通知中心的界面,点击之后只是一个开关的开启和关闭,并没有再进入详细的通知设置界面。第二张是 应用管理–应用程序管理–应用信息界面, 点击其中的 允许推送通知时也只是开关的开启和关闭。

C: 部分国产手机 APP通知设置界面中没有开启和关闭的操作
部分国产手机中Settings.ACTION_APPLICATION_DETAILS_SETTINGS对应的Activity并不是我们期望的通知设置界面。比如,小米6。小米6中 Settings.ACTION_APPLICATION_DETAILS_SETTINGS对应的通知设置界面如下:

这完全不是我们需要的界面啊。。。里面并没有我们想要的开关啊。而且,在小米6中 Settings.ACTION_APPLICATION_DETAILS_SETTINGS 对应的应用信息界面中,点击其中的 通知管理 之后跳转的也是上面图中的样子。
但是,如果我们手动的从 设置–通知和状态栏–通知管理 进入我们应用的通知设置界面时,就可以正常的看到 允许通知的开关,如下图:
对于小米6手机的这个情况,分析了一阵子之后还是没找到解决办法。本来想着通过log确认一下上图中的界面到底是哪个Activity,但非常郁闷的是Log中只得到了com.android.settings/.SubSettings 这么一个地址,之前没见过这个地址,然后继续搜索。
在看完 https://www.cnblogs.com/Lefter/archive/2013/04/27/3048010.html 和 https://blog.csdn.net/hfreeman2008/article/details/52778992 之后,明白了 .SubSettings 是干啥的了。也大致推断出为啥在小米6上得不到我们想要的界面了——他们在定制系统时更改了通知设置界面对应的Fragment!!!!
此时,真想对雷布斯说一句:I’m not ok!!!
三、附录
1、测试结果说明
|
手机型号
|
系统版本
|
测试结果
|
|
Vivo X9s
|
7.1.2
|
正常跳转到通知设置界面
|
|
荣耀10
|
8.1.0
|
正常跳转到通知设置界面
|
|
红米note4x
|
7.0
|
正常跳转到通知设置界面
|
|
Oppo R7 plus
|
5.0
|
正常跳转到通知设置界面
|
|
ZTE BA910
|
5.1
|
正常跳转到通知设置界面
|
|
Oppo R15
|
8.1.0
|
正常跳转到通知设置界面
|
|
三星盖乐世On5
|
7.1.1
|
正常跳转到通知设置界面
|
|
360Vizza
|
7.1.1
|
正常跳转到通知设置界面
|
|
魅族Mx3
|
4.4
|
进入APP设置界面
|
|
华为荣耀4X
|
4.4
|
进入APP设置界面
|
|
锤子坚果3
|
7.1.2
|
进入APP设置界面
|
|
小米6
|
8.0.0
|
进入的页面中没有通知开关!!!!
|
2、参考链接
(1)通知设置的参考链接
(2)SubSettings 和 Settings 的参考链接
发表评论