前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Notification细思极恐的适配

Android Notification细思极恐的适配

作者头像
包子388321
发布2020-06-16 18:24:02
1.3K0
发布2020-06-16 18:24:02
举报
文章被收录于专栏:包子的书架包子的书架
背景

近期项目的迭代版本开发,部门惊喜的申请了一台9.0的机器,是目前部门有史以来第一台8.0以上的机器,满怀喜悦的跑起项目,惊讶地发现Notification的在9.0以上的机器突然不能弹出通知了,惊讶之余发现发通知管理的权限没有开启(就觉得在我的代码怎么会有问题),结果开启了仍然无法接收到通知(打脸了...),马上请教了google大神,发现了毛病

问题

·Android O上发不出来通知了 ·设置通知的震动、声音、呼吸灯都不起作用

问题一

从源码入手 查看 NotificationManagerService.java -> enqueueNotificationInternal() 发现channel空了

代码语言:javascript
复制
String channelId = notification.getChannelId();

final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
        notificationUid, channelId, false /* includeDeleted */);
if (channel == null) {
    final String noChannelStr = "No Channel found for "
            + "pkg=" + pkg
            + ", channelId=" + channelId
            + ", id=" + id
            + ", tag=" + tag
            + ", opPkg=" + opPkg
            + ", callingUid=" + callingUid
            + ", userId=" + userId
            + ", incomingUserId=" + incomingUserId
            + ", notificationUid=" + notificationUid
            + ", notification=" + notification;
    Log.e(TAG, noChannelStr);
    doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
            "Failed to post notification on channel \"" + channelId + "\"\n" +
            "See log for more details");
    return;
}

查看 RankingHelper.java -> createDefaultChannelIfNeeded()

代码语言:javascript
复制
private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
    final int userId = UserHandle.getUserId(r.uid);
    final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
    if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
        // O apps should not have the default channel.
        return false;
    }

    // Otherwise, this app should have the default channel.
    return true;
}

上面的源码可以看出: 当 targetSdk >= 26 时,系统是不会给你添加默认Channel的,反之低版本则会默认添加; 即使是targetSdk < 26,只要你的 compileSdk >= 26 ,也是可以设置Channel的,同样也会生效。

问题二

照旧看一下源码,因为用到了Channel这个东西,直接查看NotificationChannel源码,你会发现这个是继承Parcelable的一个实体类, 这个类就是用于存放通知的一些属性信息,比如提示音,知识灯,震动等

image.png

因为O之前是系统默认创建Channel,会将Builder的里面的属性都添加,如下:

代码语言:javascript
复制
Notification.Builder notification = new Notification
                            .Builder(applicationContext)
                            .setContentTitle("您有一条新消息")
                            .setContentText(title)
                            .setWhen(System.currentTimeMillis())
                            .setSmallIcon(idIco)
                            .setLargeIcon(BitmapFactory.decodeResource(applicationContext.getResources(), idIco))
                            .setVibrate(vibrate)
                            .setContentIntent(pendingIntent)
                            .setPriority(NotificationCompat.PRIORITY_HIGH)
                            .setDefaults(Notification.DEFAULT_ALL)

O之后就需要我们自己在自己创建的Channel中添加,然后将Channel对象传给NotificationManager去处理

代码语言:javascript
复制
// 传入参数:通道ID,通道名字,通道优先级(类似曾经的 builder.setPriority())
    NotificationChannel channel =
            new NotificationChannel(NOTIFICATION_CHANNELID, name, NotificationManager.IMPORTANCE_HIGH);

    // 配置通知渠道的属性
    channel.setDescription(description);
    // 设置通知出现时声音,默认通知是有声音的
    channel.setSound(null, null);
    // 设置通知出现时的闪灯(如果 android 设备支持的话)
    channel.enableLights(true);
    channel.setLightColor(Color.RED);
    // 设置通知出现时的震动(如果 android 设备支持的话)
    channel.enableVibration(true);
    channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});

    //最后在 notificationManager 中创建该通知渠道
    mNotificationManager.createNotificationChannel(channel);

这样一来声音和震动等问题都解决了

完整的代码例子:
代码语言:javascript
复制
public void createNotification(Context context, NotifyEntity entity) {

    String id = context.getPackageName();
    String title = DEFAULT_CHANNEL_NAME;
    Intent intent = getIntent(context, entity);
    PendingIntent pendingIntent;
    NotificationCompat.Builder builder;

    NotificationManager manager = (NotificationManager) context.getSystemService(
        Context.NOTIFICATION_SERVICE);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel mChannel = manager.getNotificationChannel(id);
      if (mChannel == null) {
        mChannel = new NotificationChannel(id, title, importance);
        mChannel.enableVibration(true);
        mChannel.setVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });
        manager.createNotificationChannel(mChannel);
      }
      builder = new NotificationCompat.Builder(context, id);
      pendingIntent = PendingIntent.getActivity(context, JPushUtils.code, intent,
          PendingIntent.FLAG_CANCEL_CURRENT);
      builder.setContentTitle(entity.getTitle())
          .setSmallIcon(R.mipmap.ic_launcher)
          .setLargeIcon(getLargeBitmap(context))
          .setContentText(entity.getContent())
          .setDefaults(Notification.DEFAULT_ALL)
          .setAutoCancel(true)
          .setContentIntent(pendingIntent)
          .setTicker(entity.getTitle())
          .setVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });
    } else {
      builder = new NotificationCompat.Builder(context);
      pendingIntent = PendingIntent.getActivity(context, JPushUtils.code, intent,
          PendingIntent.FLAG_CANCEL_CURRENT);
      builder.setContentTitle(entity.getTitle())
          .setSmallIcon(R.mipmap.ic_launcher)
          .setLargeIcon(getLargeBitmap(context))
          .setContentText(entity.getContent())
          .setDefaults(Notification.DEFAULT_ALL)
          .setAutoCancel(true)
          .setContentIntent(pendingIntent)
          .setTicker(entity.getTitle())
          .setVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
          .setPriority(Notification.PRIORITY_HIGH);
    }
    Notification notification = builder.build();
    manager.notify(JPushUtils.code + 1, notification);
  }

  private Intent getIntent(Context context, NotifyEntity entity) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    Log.i(TAG, "entity.getExtra() = " + entity.getExtra());
    Bundle bundle = new Bundle();
    if (entity.getExtra() != null) {
      bundle.putString(AppConstants.KEY_GAME_ID, entity.getExtra().getData());
      bundle.putString(AppConstants.KEY_TYPE, entity.getExtra().getType());
      intent.putExtras(bundle);
    }
    return intent;
  }

  private Bitmap getLargeBitmap(Context context) {
    Drawable drawable = ContextCompat.getDrawable(context,
        R.mipmap.ic_launcher);
    Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
    return bitmap;
  }

以上是我的一些个人总结和归纳,欢迎大家点评和指导,如果有错麻烦指出

参考:

https://www.jianshu.com/p/99bc32cd8ad6 https://blog.csdn.net/weixin_33698043/article/details/90858968

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 问题
  • 问题一
  • 问题二
  • 完整的代码例子:
  • 参考:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档