有时候产品要求增加一个推送通知的开关(有些还要求具体到哪些通知,比如广告类? 比如重大热点等?)。
我们首先想到的肯定就是再推送回调接口里面判断开启的状态,进而进行过滤!没错,如果对于关闭通知肯定没问题。但是对于开启通知有个问题?就是即使你开启了这个状态值,但是如果系统关闭了该应用的通知权限,那么你开启了其实也没有用对吧?
所以正常的逻辑是:
1. 如果关闭,则不用判断权限,直接关闭就行
2. 如果开启,首先判断是否有通知权限,如果有则走关闭逻辑就行;如果没有,则把开关状态重置回来,然后申请通知权限 - 通知权限开启后再次开启就没有问题了
**a> **直接给判断权限的工具类:
public class NotificationsUtils {
private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean isNotificationEnabled(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
///< 8.0手机以上
if (((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).getImportance() == NotificationManager.IMPORTANCE_NONE) {
return false;
}
}
AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = context.getApplicationInfo();
String pkg = context.getApplicationContext().getPackageName();
int uid = appInfo.uid;
Class appOpsClass = null;
try {
appOpsClass = Class.forName(AppOpsManager.class.getName());
Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,
String.class);
Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
int value = (Integer) opPostNotificationValue.get(Integer.class);
return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
b> 跳转到通知设置的界面(自己做了下完善和测试)
/**
* 通知权限申请
* @param context
*/
public static void requestNotify(Context context) {
/**
* 跳到通知栏设置界面
* @param context
*/
Intent localIntent = new Intent();
///< 直接跳转到应用通知设置的代码
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
localIntent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
localIntent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
}
else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
localIntent.putExtra("app_package", context.getPackageName());
localIntent.putExtra("app_uid", context.getApplicationInfo().uid);
} else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
localIntent.addCategory(Intent.CATEGORY_DEFAULT);
localIntent.setData(Uri.parse("package:" + context.getPackageName()));
} else {
///< 4.4以下没有从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面,
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
localIntent.setAction(Intent.ACTION_VIEW);
localIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
}
}
context.startActivity(localIntent);
}
啊哈!!目前就是酱紫,这个应该有官方的吧,我找找看...有相关类的说明,但是具体的案例没有。不过有具体的一些个解释:
比如:Settings | Android Developers
再比如判断的方式:
ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED
Intent that is broadcast when a NotificationChannel is blocked
(when NotificationChannel.getImportance() is IMPORTANCE_NONE) or
unblocked (when NotificationChannel.getImportance() is anything other than IMPORTANCE_NONE).
意思就是说:当一个NotificationChannel 被阻塞时,这个getImportance()的值就是IMPORTANCE_NONE,其他情况则不是。所以8.0也就可以根据这个状态来做判断.8.0以下的话采用的是反射的方式 - 这个具体的大家可以研究一下。小白暂时不研究了,先做个记录和简单学习。
最后使用逻辑:Switch控件(selector_thumb, selector_track就是slector,里面就是一些个shape文件...)
<Switch
android:id="@+id/ass_pushSt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:switchMinWidth="40dp"
android:text=""
android:textOff=" "
android:textOn=" "
android:thumb="@drawable/selector_thumb"
android:track="@drawable/selector_track"
app:layout_constraintEnd_toEndOf="parent" />
pushSt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b){
if (!NotificationsUtils.isNotificationEnabled(MineSystemSettingActivity.this)){
runOnUiThread(new Runnable() {
@Override
public void run() {
pushSt.setChecked(false);
}
});
PermissionTool.requestNotify(MineSystemSettingActivity.this);
return;
}
}
UserInfoControlPresenter.setPushStatus(!b);
}
});
剩下的你可以测测了哟...小宝贝...