美文网首页
Notification相关操作

Notification相关操作

作者: 晓风残月酒醒 | 来源:发表于2018-08-18 17:37 被阅读0次

2018-08-18 组长安排我解决一下app的notification为什么有的手机可以展示,有的手机展示不出来的问题,解决方案如下(此处是在kotlin的Service中执行操作):

    import android.app.Notification
    import android.app.NotificationChannel
    import android.app.NotificationManager
    import android.app.PendingIntent
    import android.app.Service
    import android.content.Context
    import android.content.Intent
    import android.graphics.BitmapFactory
    import android.os.Build
    import android.os.IBinder
    import android.support.v7.app.NotificationCompat
    
    class BuySellService : Service() {
        private var manager: NotificationManager? = null                        // 通知管理器
        private val notificationChannelId = "channel_1"                         // Android8.0以后展示通知需要注册的通道编号
        private val notificationChannelName = "channel_name_1"                  // Android8.0以后展示通知需要注册的通道名称

        override fun onCreate() {
            super.onCreate()
            showNotification()
        }
    
        override fun onBind(intent: Intent?): IBinder? {
            return null
        }
    
        // 展示Notification的方法
        private fun showNotification() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                // 创建渠道
                createNotificationChannel()
                // 展示通知
                showHighNotification()
            } else {
                // 展示通知
                showSimpleNotification()
            }
        }
    
        // Android8.0以前的版本使用此方法启动Notification
        private fun showSimpleNotification() {
            val notification = NotificationCompat.Builder(this@BuySellService)
                    .setContentTitle("买卖客户端")
                    .setContentText("正在运行中...")
                    /**点击事件监听器**/
                    .setContentIntent(PendingIntent.getBroadcast(this@BuySellService, 0, Intent(Constant.FOREGROUND_NOTIFICATION_CLICKED), 0))
                    /**消失的监听器**/
                    .setDeleteIntent(PendingIntent.getBroadcast(this@BuySellService, 0, Intent(Constant.FOREGROUND_NOTIFICATION_DISMISS), 0))
                    .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.logo_buy_sell))
                    .setSmallIcon(R.drawable.logo_buy_sell) //设置小图标,4.x在右边,5.x在左边
                    /**通知产生的时间,会在通知信息里显示**/
                    .setWhen(System.currentTimeMillis())
                    /**设置该通知优先级**/
                    .setPriority(if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
                        NotificationCompat.PRIORITY_MAX
                    } else {
                        Notification.PRIORITY_MAX
                    })
                    /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                    .setAutoCancel(false)
                    /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                    .setOngoing(true)
                    /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                    /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                    .build().apply {
                        flags = flags or Notification.FLAG_ONGOING_EVENT or Notification.FLAG_NO_CLEAR or Notification.FLAG_FOREGROUND_SERVICE or Notification.FLAG_HIGH_PRIORITY
                    }
            startForeground(1, notification)
        }
    
        // Android8.0以后展示Notification需要创建渠道
        private fun createNotificationChannel() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                // 如果设置成 NotificationManager.IMPORTANCE_HIGH  或者 NotificationManager.IMPORTANCE_DEFAULT 的话会出现提示音,而且无法取消
                val channel = NotificationChannel(notificationChannelId, notificationChannelName, NotificationManager.IMPORTANCE_LOW)
                getNotificationManager().createNotificationChannel(channel)
            }
        }
    
        // Notification管理器
        private fun getNotificationManager(): NotificationManager {
            if (manager == null) {
                manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            }
            return manager!!
        }
    
        // Android8.0以后的版本使用此方法启动Notification
        private fun showHighNotification() {
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                val notification = Notification.Builder(this@BuySellService, notificationChannelId)
                        .setContentTitle("买卖客户端")
                        .setContentText("正在运行中...")
                        /**点击事件监听器**/
                        .setContentIntent(PendingIntent.getBroadcast(this@BuySellService, 0, Intent(Constant.FOREGROUND_NOTIFICATION_CLICKED), 0))
                        /**消失的监听器**/
                        .setDeleteIntent(PendingIntent.getBroadcast(this@BuySellService, 0, Intent(Constant.FOREGROUND_NOTIFICATION_DISMISS), 0))
                        .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.logo_buy_sell))
                        .setSmallIcon(R.drawable.logo_buy_sell) //设置小图标,4.x在右边,5.x在左边
                        /**通知产生的时间,会在通知信息里显示**/
                        .setWhen(System.currentTimeMillis())
                        .setShowWhen(true)
                        /**设置该通知优先级**/
                        .setPriority(Notification.PRIORITY_MAX)
                        /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                        .setAutoCancel(false)
                        /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                        .setOngoing(true)
                        /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                        /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                        .build().apply {
                            flags = flags or Notification.FLAG_ONGOING_EVENT or Notification.FLAG_NO_CLEAR or Notification.FLAG_FOREGROUND_SERVICE or Notification.FLAG_HIGH_PRIORITY
                        }
                startForeground(1, notification)
            }
        }
    
        override fun onDestroy() {
            super.onDestroy()
            // 删除通道
            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                getNotificationManager().deleteNotificationChannel(notificationChannelId)
            }
        }
    }

java版本:


import android.app.NotificationChannel;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.support.v4.app.NotificationCompat;

public class BuySellService extends Service {
    private NotificationManager manager = null;                                 // 通知管理器
    private String notificationChannelId = "channel_1";                         // Android8.0以后展示通知需要注册的通道编号
    private String notificationChannelName = "channel_name_1";                  // Android8.0以后展示通知需要注册的通道名称
    private Context context;                                                    // 上下文对象

    @Override
    public void onCreate() {
        super.onCreate();
        context = BuySellService.this;
        if (NotificationUtil.isNotificationEnabled(context)) {
            showNotification();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // 展示Notification的方法
    private void showNotification() {
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            // 创建渠道
            createNotificationChannel();
            // 展示通知
            showHighNotification();
        } else {
            // 展示通知
            showSimpleNotification();
        }
    }

    // Android8.0以前的版本使用此方法启动Notification
    private void showSimpleNotification() {
        Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
                .setContentTitle("买卖客户端")
                .setContentText("正在运行中...")
                /**点击事件监听器**/
                .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(Constant.FOREGROUND_NOTIFICATION_CLICKED), 0))
                /**消失的监听器**/
                .setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(Constant.FOREGROUND_NOTIFICATION_DISMISS), 0))
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                .setSmallIcon(R.mipmap.ic_launcher) //设置小图标,4.x在右边,5.x在左边
                /**通知产生的时间,会在通知信息里显示**/
                .setWhen(System.currentTimeMillis())
                /**设置该通知优先级**/
                .setPriority(Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN ? NotificationCompat.PRIORITY_MAX : Notification.PRIORITY_MAX)
                /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                .setAutoCancel(false)
                /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                .setOngoing(true)
                /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                .build();
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_HIGH_PRIORITY;
        startForeground(1, notification);
    }

    // Android8.0以后展示Notification需要创建渠道
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            // 如果设置成 NotificationManager.IMPORTANCE_HIGH  或者 NotificationManager.IMPORTANCE_DEFAULT 的话会出现提示音,而且无法取消
            NotificationChannel channel = new NotificationChannel(notificationChannelId, notificationChannelName, NotificationManager.IMPORTANCE_LOW);
            getNotificationManager().createNotificationChannel(channel);
        }
    }

    // Notification管理器
    private NotificationManager getNotificationManager() {
        if (manager == null) {
            manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return manager;
    }

    // Android8.0以后的版本使用此方法启动Notification
    private void showHighNotification() {
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            Notification notification = new Notification.Builder(context, notificationChannelId)
                    .setContentTitle("买卖客户端")
                    .setContentText("正在运行中...")
                    /**点击事件监听器**/
                    .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(Constant.FOREGROUND_NOTIFICATION_CLICKED), 0))
                    /**消失的监听器**/
                    .setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(Constant.FOREGROUND_NOTIFICATION_DISMISS), 0))
                    .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                    .setSmallIcon(R.mipmap.ic_launcher) //设置小图标,4.x在右边,5.x在左边
                    /**通知产生的时间,会在通知信息里显示**/
                    .setWhen(System.currentTimeMillis())
                    .setShowWhen(true)
                    /**设置该通知优先级**/
                    .setPriority(Notification.PRIORITY_MAX)
                    /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                    .setAutoCancel(false)
                    /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                    .setOngoing(true)
                    /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                    /**.setDefaults(Notification.DEFAULT_VIBRATE or Notification.DEFAULT_SOUND)**/
                    .build();
            notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_HIGH_PRIORITY;
            startForeground(1, notification);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 删除通道
        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            getNotificationManager().deleteNotificationChannel(notificationChannelId);
        }
        // 停止前台服务--参数:表示是否移除之前的通知
        stopForeground(true);
    }
}

Notification工具类:

import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class NotificationUtil {

    /**
     * 打开通知的方式
     *
     * @param context
     */
    public static void openNotification(Context context) {
        Intent localIntent = new Intent();
        String packName = context.getPackageName();
        int uid = context.getApplicationInfo().uid;
        // 直接跳转到应用通知设置的代码:
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            localIntent.putExtra("app_package", packName);
            localIntent.putExtra("app_uid", 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:" + packName));
        } 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", packName, 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", packName);
            }
        }
        context.startActivity(localIntent);
    }

    /**
     * 8.0以上获取通知栏状态
     * @param context
     * @return
     */
    private static boolean isNotificationEnableV26(Context context) {
        ApplicationInfo appInfo = context.getApplicationInfo();
        String pkg = context.getApplicationContext().getPackageName();
        int uid = appInfo.uid;
        try {
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            Method sServiceField = notificationManager.getClass().getDeclaredMethod("getService");
            sServiceField.setAccessible(true);
            Object sService = sServiceField.invoke(notificationManager);
            Method method = sService.getClass().getDeclaredMethod("areNotificationsEnabledForPackage", String.class, Integer.TYPE);
            method.setAccessible(true);
            return (boolean) method.invoke(sService, pkg, uid);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 6.0以下通过反射获取通知的开关状态
     *
     * @param context
     * @return
     */
    private static boolean isNotificationEnableV24(Context context) {
        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; /* Context.APP_OPS_MANAGER */
        try {
            appOpsClass = Class.forName(AppOpsManager.class.getName());
            Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);
            Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION");
            int value = (int) opPostNotificationValue.get(Integer.class);
            return ((int) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 获取通知栏的状态
     *
     * @param context
     * @return
     */
    public static boolean isNotificationEnabled(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return isNotificationEnableV26(context);
        } else {
            return isNotificationEnableV24(context);
        }
    }
}

判定Service是否正在后台运行的工具类:

import android.app.ActivityManager;
import android.content.Context;

public class ServiceUtil {
    /**
     * @param context
     * @return
     */
    public static boolean isServiceRunning(String strServiceName, Context context) {
        ActivityManager manager = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (strServiceName.equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
}

特别鸣谢:https://github.com/linglongxin24/NotificationUtil
https://blog.csdn.net/z642385985/article/details/78583980?locationNum=9&fps=1

相关文章

网友评论

      本文标题:Notification相关操作

      本文链接:https://www.haomeiwen.com/subject/snbfiftx.html