先贴出效果图。
自定义布局通知 普通通知 悬挂式通知
下面是普通通知的主要代码类NotificationTools1 ,如果需要拷贝到自己的项目里面使用还需要后面的工具类一起拷贝进入。
public class NotificationTools3 {
private String TAG = "NotificationTools3 ";
private Context context;
private static NotificationTools3 utils;
public NotificationTools3(Context context) {
this.context = context;
}
public static NotificationTools3 getInstance(Context context) {
if (utils == null) {
synchronized (NotificationTools.class) {
if (utils == null) {
utils = new NotificationTools3( context );
}
}
}
return utils;
}
/**
* 发送通知
*
* @param url 启动的H5链接
* @param cla 通知启动的Activity
*/
public void sendNotification(String url, Class> cla) {
NotificationManager notificationManager = NotificationUtile.getNotificationManager( context );
if (notificationManager == null) {
Logs.eprintln( TAG, "NotificationManager is null" );
return;
}
if (!NotificationUtile.isOpenPermission( context )) {
return;
}
NotificationCompat.Builder builder = new NotificationCompat.Builder( context, "push" );
Intent intent = new Intent( context, cla );//点击通知的时候启动Activity的意图
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
intent.putExtra( "key", url );//传递字段
intent.putExtra( "fromPush", "true" );//传递字段
int pushid = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getActivity( context, pushid, intent, PendingIntent.FLAG_CANCEL_CURRENT );
builder.setContentTitle( "消息的标题" );
builder.setContentText( "消息的具体内容:XXXXXXXX" );
builder.setDefaults( NotificationCompat.DEFAULT_VIBRATE );
builder.setAutoCancel( true );//点击通知后,状态栏是否自动删除通知。
builder.setSmallIcon( R.mipmap.ic_launcher_round );//设置小图标
builder.setLargeIcon( BitmapFactory.decodeResource( context.getResources(), R.mipmap.richudongfang ) );//设置大图
builder.setStyle( new NotificationCompat.BigPictureStyle().bigPicture( BitmapFactory.decodeResource( context.getResources(), R.mipmap.richudongfang ) ) );
builder.setOngoing( true );//设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与或以某种方式正在等待,因此占用设备。(当设置为true的时候就无法清除通知栏,若为false则可以清除。)
builder.setWhen( System.currentTimeMillis() );
builder.setContentIntent( pendingIntent );
builder.setChannelId( "push" );
//判断是否是8.0Android.O
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel chan1 = new NotificationChannel( "push", "Test Channel", NotificationManager.IMPORTANCE_HIGH );
chan1.enableLights( true );
chan1.enableVibration( true );
chan1.setDescription( "push" );
chan1.setLockscreenVisibility( Notification.VISIBILITY_PUBLIC );
notificationManager.createNotificationChannel( chan1 );
}
notificationManager.notify( pushid, builder.build() );
}
}
自定义布局主要代码NotificationTools2 。关于自定义布局通知栏参考文章: https://blog.csdn.net/u014407241/article/details/38795367
public class NotificationTools2 {
private Context context;
private static NotificationTools2 utils;
public NotificationTools2(Context context) {
this.context = context;
}
public static NotificationTools2 getInstance(Context context) {
if (utils == null) {
synchronized (NotificationTools2.class) {
if (utils == null) {
utils = new NotificationTools2( context );
}
}
}
return utils;
}
@NonNull
public NotificationCompat.Builder getNotificationBuilder() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel( "channel_id", "channel_name",
NotificationManager.IMPORTANCE_DEFAULT );
//是否绕过请勿打扰模式
channel.canBypassDnd();
//闪光灯
channel.enableLights( true );
//锁屏显示通知
channel.setLockscreenVisibility( VISIBILITY_SECRET );
//闪关灯的灯光颜色
channel.setLightColor( Color.RED );
//桌面launcher的消息角标
channel.canShowBadge();
//是否允许震动
channel.enableVibration( true );
//获取系统通知响铃声音的配置
channel.getAudioAttributes();
//获取通知取到组
channel.getGroup();
//设置可绕过 请勿打扰模式
channel.setBypassDnd( true );
//设置震动模式
channel.setVibrationPattern( new long[]{100, 100, 200} );
//是否会有灯光
channel.shouldShowLights();
NotificationUtile.getNotificationManager( context ).createNotificationChannel( channel );
}
NotificationCompat.Builder notification = new NotificationCompat.Builder( context, "channel_id" );
notification.setContentTitle( "新消息来了" );
notification.setContentText( "周末到了,不用上班了" );
notification.setSmallIcon( R.mipmap.ic_launcher );
notification.setAutoCancel( true );
return notification;
}
/**
* 自定义布局。RemoteViews介绍:https://www.jianshu.com/p/13d56fb221e2
*/
private static boolean isCreate = false;
private int notificationId = 1212121;
public void sendCustomNotification(String url) {
if (!NotificationUtile.isOpenPermission( context )) {
return;
}
if (isCreate) {
Logs.eprintln( "只能创建一个自定义Notification" );
isCreate = true;
return;
}
NotificationCompat.Builder builder = getNotificationBuilder();
RemoteViews remoteViews = new RemoteViews( context.getPackageName(), R.layout.layout_custom_notifition );
remoteViews.setTextViewText( R.id.notification_title, "标题" );
remoteViews.setTextViewText( R.id.notification_content, "内容:XXXXXXXXXX" );
Intent intent = new Intent( context, H5DetailActivity.class );
intent.putExtra( "key", url );
PendingIntent pendingIntent = PendingIntent.getActivity( context, -1, intent, PendingIntent.FLAG_UPDATE_CURRENT );
remoteViews.setOnClickPendingIntent( R.id.turn_next, pendingIntent );
Intent intent2 = new Intent( "close" );//过滤action为close
PendingIntent pendingIntentClose = PendingIntent.getBroadcast( context, 0, intent2, 0 );
remoteViews.setOnClickPendingIntent( R.id.iv_close, pendingIntentClose );
ListenerNotificationBrodcaseRecever.ListenerNotificationBrodcaseRecever( key -> {
Logs.eprintln( "关闭通知栏" );
NotificationUtile.getNotificationManager( context ).cancel( notificationId );
isCreate = false;
} );
builder.setOngoing( true );//设置无法取消
builder.setAutoCancel( false );//点击后不取消
builder.setCustomContentView( remoteViews );
NotificationUtile.getNotificationManager( context ).notify( notificationId, builder.build() );
}
/**
* 自定义布局的按钮广播注册
*
* @param con
*/
public static void registerBoradcastReceiver(Context con) {
IntentFilter myIntentFilter = new IntentFilter();
myIntentFilter.addAction( "close" );//如果之定义布局有多个按钮则可以定义多个过滤条件
myIntentFilter.addAction( "next" );
myIntentFilter.addAction( "previous" );
//注册广播
con.registerReceiver( new ListenerNotificationBrodcaseRecever(), myIntentFilter );
}
}
下面是自定义布局的点击事件的广播类。在通知栏里面的自定义布局用的是RemoteViews他的监听需要用广播才行。
这里注册广播最好是动态广播,静态广播在高版本的Android机上不能生效,具体是多高版本么有验证过。
public class ListenerNotificationBrodcaseRecever extends BroadcastReceiver {
private static ICallBack mCallBack;
public static void ListenerNotificationBrodcaseRecever(ICallBack iCallBack) {
mCallBack=iCallBack;
}
@Override
public void onReceive(Context context, Intent intent) {
String flag = intent.getAction();
if (flag != null && !"".equals( flag )) {
if ("close".equals( flag )) {
if (mCallBack != null) {
Logs.eprintln( "ListenerNotificationBrodcaseRecever ", " key=");
mCallBack.callBack( 1 );
}
}
}
}
interface ICallBack {
public void callBack(int key);
}
}
悬挂式通知代码,两种跳转方式一种跳转浏览器展示网页,一种跳转到Activity里面用webView展示网页。其他的Notification的方式也可以用这两种跳转方式。
悬挂式通知在Android 5.0以及以上的版本才支持。
public class NotificationTools3 {
private Context context;
private static NotificationTools3 utils;
public NotificationTools3(Context context) {
this.context = context;
}
public static NotificationTools3 getInstance(Context context) {
if (utils == null) {
synchronized (NotificationTools3.class) {
if (utils == null) {
utils = new NotificationTools3( context );
}
}
}
return utils;
}
@NonNull
public NotificationCompat.Builder getNotificationBuilder() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel( "channel_id", "channel_name",
NotificationManager.IMPORTANCE_DEFAULT );
//是否绕过请勿打扰模式
channel.canBypassDnd();
//闪光灯
channel.enableLights( true );
//锁屏显示通知
channel.setLockscreenVisibility( Notification.VISIBILITY_SECRET );
//闪关灯的灯光颜色
channel.setLightColor( Color.RED );
//桌面launcher的消息角标
channel.canShowBadge();
//是否允许震动
channel.enableVibration( true );
//获取系统通知响铃声音的配置
channel.getAudioAttributes();
//获取通知取到组
channel.getGroup();
//设置可绕过 请勿打扰模式
channel.setBypassDnd( true );
//设置震动模式
channel.setVibrationPattern( new long[]{100, 100, 200} );
//是否会有灯光
channel.shouldShowLights();
NotificationUtile.getNotificationManager( context ).createNotificationChannel( channel );
}
NotificationCompat.Builder notification = new NotificationCompat.Builder( context, "channel_id" );
notification.setContentTitle( "新消息来了" );
notification.setContentText( "周末到了,不用上班了" );
notification.setSmallIcon( R.mipmap.ic_launcher );
notification.setAutoCancel( true );
return notification;
}
/**
* 悬挂通知栏启动浏览器
*
* @param notifyId
* @param url 跳转浏览器的地址
*/
public void fullScreenNotification1(int notifyId, String url) {
if (!NotificationUtile.isOpenPermission( context )) {
return;
}
NotificationManager nm = NotificationUtile.getNotificationManager( context );
NotificationCompat.Builder builder3 = getNotificationBuilder();
Intent intent3 = new Intent( Intent.ACTION_VIEW, Uri.parse( url ) );
PendingIntent pendingIntent3 = PendingIntent.getActivity( context, 0, intent3, 0 );
builder3.setContentIntent( pendingIntent3 );
builder3.setSmallIcon( R.mipmap.ic_launcher );
builder3.setLargeIcon( BitmapFactory.decodeResource( context.getResources(), R.mipmap.ic_launcher ) );
builder3.setAutoCancel( true );
builder3.setContentTitle( "自定义消息标题" );
builder3.setContentText( "自定义消息内容" );
nm.notify( (int) System.currentTimeMillis(), builder3.build() );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//SDK版本大于等于21才有悬挂式通知栏
Intent XuanIntent = new Intent();
XuanIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
PendingIntent xuanpengdIntent = PendingIntent.getActivity( context, 0, XuanIntent, PendingIntent.FLAG_CANCEL_CURRENT );
builder3.setFullScreenIntent( xuanpengdIntent, true );
String notifyTag = notifyId + "10";
nm.notify( notifyTag, notifyId, builder3.build() );
new Thread( new Runnable() {
@Override
public void run() {
try {
Thread.sleep( 3000 );//五秒后悬挂式通知消失
nm.cancel( notifyTag, notifyId );//按tag id 来清除消息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} ).start();
}
}
/**
* 悬挂通知栏跳转自定义Activity的H5界面
*
* @param notifyId
* @param url
*/
public void fullScreenNotification(int notifyId, String url) {
if (!NotificationUtile.isOpenPermission( context )) {
return;
}
String notifyTag;
NotificationManager nm = NotificationUtile.getNotificationManager( context );
final NotificationCompat.Builder builder = getNotificationBuilder();
Intent intent = new Intent( context, H5DetailActivity.class );
intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
intent.putExtra( "key", url );
PendingIntent pendingIntent = PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT );
builder.setContentIntent( pendingIntent );//普通消息
builder.setWhen( System.currentTimeMillis() );
builder.setSmallIcon( R.mipmap.ic_launcher_round );
builder.setLargeIcon( BitmapFactory.decodeResource( context.getResources(), R.mipmap.richudongfang_4202829 ) );
builder.setAutoCancel( true );
builder.setDefaults( NotificationCompat.DEFAULT_ALL );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setVisibility( NotificationCompat.VISIBILITY_PUBLIC );
}
builder.setContentTitle( "自定义消息标题" );
builder.setContentText( "自定义消息内容" );
nm.notify( notifyId, builder.build() );//普通消息提示 显示在状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//SDK版本大于等于21才有悬挂式通知栏
Intent xintent = new Intent();
xintent.putExtra( "key", url );
xintent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
PendingIntent hangIntent = PendingIntent.getActivity( context, 0, xintent, PendingIntent.FLAG_CANCEL_CURRENT );
builder.setFullScreenIntent( hangIntent, true );//悬挂式通知 悬挂在手机屏上方
notifyTag = notifyId + "jpush";//由于同一条消息 id 一样 ,有针对悬挂式通知打了一个tag;
nm.notify( notifyTag, notifyId, builder.build() );
new Thread( new Runnable() {
@Override
public void run() {
try {
Thread.sleep( 3000 );//五秒后悬挂式通知消失
nm.cancel( notifyTag, notifyId );//按tag id 来清除消息
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} ).start();
}
}
}
下面是工具类
public class NotificationUtile {
private static String CHECK_OP_NO_THROW = "checkOpNoThrow";
private static String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
public static boolean isOpenPermission(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//API19+
if (!NotificationUtile.isNotifacationEnabled( context )) {
new AlertDialog.Builder( context )
.setIconAttribute( android.R.attr.alertDialogIcon )
.setTitle( "权限没有开" ).setMessage( "请手动打开通知栏的权限" )
.setPositiveButton( "确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent mIntent = new Intent()
.setAction( "android.settings.APPLICATION_DETAILS_SETTINGS" )//启动权限设置
.setData( Uri.fromParts( "package", context.getApplicationContext().getPackageName(), null ) );
context.startActivity( mIntent );
}
} ).show();
return false;
}
}
return true;
}
/**
* 判断通知栏的权限是否有打开
*
* @param con
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
//表示versionCode=19 也就是4.4的系统以及以上的系统生效。4.4以下系统默认全部打开状态。
public static boolean isNotifacationEnabled(Context con) {
if (Build.VERSION.SDK_INT >= 24) {//7.0
if (getNotificationManager( con ) != null) {
return getNotificationManager( con ).areNotificationsEnabled();
}
}
AppOpsManager mAppOps = (AppOpsManager) con.getSystemService( Context.APP_OPS_SERVICE );
ApplicationInfo info = con.getApplicationInfo();
String pag = con.getApplicationContext().getPackageName();
int uid = info.uid;
Class appOpsClass = null;
try {
appOpsClass = Class.forName( AppOpsManager.class.getName() );
Method meth = appOpsClass.getMethod( CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class );
Field field = appOpsClass.getDeclaredField( OP_POST_NOTIFICATION );
int value = (int) field.get( Integer.class );
return ((int) meth.invoke( mAppOps, value, uid, pag ) == AppOpsManager.MODE_ALLOWED);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static NotificationManager mNotificationManager;
public static NotificationManager getNotificationManager(Context context) {
if (mNotificationManager == null) {
synchronized (NotificationUtile.class) {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE );
}
}
}
return mNotificationManager;
}
}
Activity调用测试类
public class NotificationTestActivity extends AppCompatActivity {
NotificationTools1 notificationTools1;
NotificationTools2 notificationTools2;
NotificationTools3 notificationTools3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_notification_test );
notificationTools1 = NotificationTools1.getInstance( this.getApplicationContext() );
notificationTools2 = NotificationTools2.getInstance( this.getApplicationContext() );
notificationTools3 = NotificationTools3.getInstance( this.getApplicationContext() );
}
public void btnOnclick(View view) {
switch (view.getId()) {
case R.id.btn_1:
notificationTools1.sendNotification( "https://www.baidu.com", H5DetailActivity.class );
break;
case R.id.btn_2:
notificationTools2.sendCustomNotification( "https://www.baidu.com" );
break;
case R.id.btn_3:
notificationTools3.fullScreenNotification1( 2, "https://www.baidu.com" );
break;
case R.id.btn_4:
notificationTools3.fullScreenNotification( 1, "https://www.baidu.com/" );
break;
}
}
}
点击通知栏跳转的Activity
public class H5DetailActivity extends AppCompatActivity {
ActivityH5DetailBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
binding = DataBindingUtil.setContentView( this, R.layout.activity_h5_detail );
Intent intent = getIntent();
String url = intent.getStringExtra( "key" );
WebView webView = binding.webView;
webView.getSettings().setJavaScriptEnabled( true );
webView.loadUrl( url );
}
public void btn(View view) {
finish();
}
}
参考:https://blog.csdn.net/lj19851227/article/details/81013605