Oreo中的通知未显示

193

普通的通知构建器在Android O上不会显示通知。

如何在Android 8 Oreo上显示通知?

是否需要添加新代码以在Android O上显示通知?


3
我忘记在NotificationCompat.Builder中设置“.setChannelId”,现在它在Oreo(8.0)上可以工作了。 - varotariya vajsi
24个回答

278
在Android O中,使用通知构建器时必须使用频道
以下是示例代码:
// Sets an ID for the notification, so it can be updated.
int notifyID = 1; 
String CHANNEL_ID = "my_channel_01";// The id of the channel. 
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
// Create a notification and set the notification channel.
Notification notification = new Notification.Builder(MainActivity.this)
            .setContentTitle("New Message")
            .setContentText("You've received new messages.")
            .setSmallIcon(R.drawable.ic_notify_status)
            .setChannelId(CHANNEL_ID)
            .build();

通过以下方式处理兼容性:

NotificationCompat notification =
        new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!")
        .setChannelId(CHANNEL_ID).build();

现在使其通知。
NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 mNotificationManager.createNotificationChannel(mChannel);

// Issue the notification.
mNotificationManager.notify(notifyID , notification);

如果您想要一个简单的解决方案,可以使用以下代码:

NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
       mNotificationManager.createNotificationChannel(mChannel);
    }

更新: NotificationCompat.Builder 参考文档

NotificationCompat.Builder(Context context)

此构造函数已于 API 级别 26.0.0 中弃用,因此您应该使用

Builder(Context context, String channelId)

使用新的构造函数时不需要setChannelId

您应该使用当前最新的AppCompat库26.0.2。

compile "com.android.support:appcompat-v7:26.0.+"

参考来源:Android 开发者频道

另外,您可以查看官方 Android 文档


4
在使用前,您必须创建一个通道。请参见https://developer.android.com/reference/android/app/NotificationManager.html#createNotificationChannel(android.app.NotificationChannel)。 - Guillaume Perrot
2
setChannel已被弃用,建议使用setChannelId。 - Guillaume Perrot
1
如果您在应用程序安装生命周期中没有创建频道,将会出现错误。 - Guillaume Perrot
1
@amorenew 看来我之前的频道名称是错误的。现在它可以工作了。谢谢,但你的回答不完整...你必须首先使用mNotificationManager.createNotificationChannel(mChannel)创建一个频道(我在我的应用程序类中已经这样做了)...请参阅Google文档。也许将此添加到您的答案中。 - JPM
2
我应该针对哪些依赖项/版本来获取新的NotificationCompat.Builder(Context, String)构造函数?我正在使用(除其他外):
  • compileSdkVersion 26
  • buildToolsVersion '26.0.2'
  • compile 'com.android.support:appcompat-v7:26.0.0-beta2'
但仍然无法接受我的使用Context和String的构造函数。有什么想法吗?
- Loisaida Sam Sandberg
显示剩余9条评论

108

这里我发布一些带有意图处理的快速解决方案函数。

public void showNotification(Context context, String title, String body, Intent intent) {
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    int notificationId = 1;
    String channelId = "channel-01";
    String channelName = "Channel Name";
    int importance = NotificationManager.IMPORTANCE_HIGH;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(
                channelId, channelName, importance);
        notificationManager.createNotificationChannel(mChannel);
    }

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(body);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(intent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
    );
    mBuilder.setContentIntent(resultPendingIntent);

    notificationManager.notify(notificationId, mBuilder.build());
}

我也一样。只有这一个方法对我在FCM和Android> = 8上起作用。 - YingYang
2
快速简单 - alfianrehanusa
非常感谢。我花了几个小时来解决通知未显示的问题。所以,如果你只想要一个弹出窗口,确保你已经使用NotificationManager为Android Oreo+创建了NotificationChannel。 - Joxon
这段代码最容易实现和理解,截至2019年12月仍然是最新的。谢谢。 - Pradeep Dhawan
1
在Android中,notificationManager.notify和startForeground有什么区别? - user1090751
经过4小时的研究,终于对我有用了。非常感谢。 - sohanoor

77
除了这个答案,您需要在使用之前创建通知渠道。
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

      /* Create or update. */
      NotificationChannel channel = new NotificationChannel("my_channel_01",
          "Channel human readable title", 
          NotificationManager.IMPORTANCE_DEFAULT);
      mNotificationManager.createNotificationChannel(channel);
  }

如果您的targetSdkVersion为26或更高版本,则只需使用通道。
如果您正在使用NotificationCompat.Builder,则还需要升级支持库的beta版本:https://developer.android.com/topic/libraries/support-library/revisions.html#26-0-0-beta2(以便在兼容构建器上调用setChannelId)。
请注意,此库更新将minSdkLevel提高到14。

如果最小API低于26,则会引发警告。在创建通道之前添加@TargetApi(26)以抑制警告。 - s-hunter
如果您在代码示例中使用了if,则不会产生警告,快速修复有不同的建议之一是通过if版本检查来包围代码。但是,如果您调整了if版本检查,Android Studio可能会感到困惑,无法检测到它。 - Guillaume Perrot

13
public class MyFirebaseMessagingServices extends FirebaseMessagingService {
    private NotificationChannel mChannel;
    private NotificationManager notifManager;
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        if (remoteMessage.getData().size() > 0) {
            try {
                JSONObject jsonObject = new JSONObject(remoteMessage.getData());
                displayCustomNotificationForOrders(jsonObject.getString("title"), jsonObject.getString("description"));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    private void displayCustomNotificationForOrders(String title, String description) {
        if (notifManager == null) {
            notifManager = (NotificationManager) getSystemService
                    (Context.NOTIFICATION_SERVICE);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationCompat.Builder builder;
            Intent intent = new Intent(this, Dashboard.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            PendingIntent pendingIntent;
            int importance = NotificationManager.IMPORTANCE_HIGH;
            if (mChannel == null) {
                mChannel = new NotificationChannel
                        ("0", title, importance);
                mChannel.setDescription(description);
                mChannel.enableVibration(true);
                notifManager.createNotificationChannel(mChannel);
            }
            builder = new NotificationCompat.Builder(this, "0");

            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
                    Intent.FLAG_ACTIVITY_SINGLE_TOP);
            pendingIntent = PendingIntent.getActivity(this, 1251, intent, PendingIntent.FLAG_ONE_SHOT);
            builder.setContentTitle(title)  
                    .setSmallIcon(getNotificationIcon()) // required
                    .setContentText(description)  // required
                    .setDefaults(Notification.DEFAULT_ALL)
                    .setAutoCancel(true)
                    .setLargeIcon(BitmapFactory.decodeResource
                            (getResources(), R.mipmap.logo))
                    .setBadgeIconType(R.mipmap.logo)
                    .setContentIntent(pendingIntent)
                    .setSound(RingtoneManager.getDefaultUri
                            (RingtoneManager.TYPE_NOTIFICATION));
            Notification notification = builder.build();
            notifManager.notify(0, notification);
        } else {

            Intent intent = new Intent(this, Dashboard.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            PendingIntent pendingIntent = null;

            pendingIntent = PendingIntent.getActivity(this, 1251, intent, PendingIntent.FLAG_ONE_SHOT);

            Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                    .setContentTitle(title)
                    .setContentText(description)
                    .setAutoCancel(true)
                    .setColor(ContextCompat.getColor(getBaseContext(), R.color.colorPrimary))
                    .setSound(defaultSoundUri)
                    .setSmallIcon(getNotificationIcon())
                    .setContentIntent(pendingIntent)
                    .setStyle(new NotificationCompat.BigTextStyle().setBigContentTitle(title).bigText(description));

            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.notify(1251, notificationBuilder.build());
        }
    }

    private int getNotificationIcon() {
        boolean useWhiteIcon = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
        return useWhiteIcon ? R.mipmap.logo : R.mipmap.logo;
    }
}

如果在 NotificationCompat.Builder 中未设置 setChannelId(CHANNEL_ID),通知将无法显示。 - Shihab Uddin

8

如果您在26+ SDK版本中无法收到推送通知?

您的解决方案在这里:

public static void showNotification(Context context, String title, String messageBody) {

        boolean isLoggedIn = SessionManager.getInstance().isLoggedIn();
        Log.e(TAG, "User logged in state: " + isLoggedIn);

        Intent intent = null;
        if (isLoggedIn) {
            //goto notification screen
            intent = new Intent(context, MainActivity.class);
            intent.putExtra(Extras.EXTRA_JUMP_TO, DrawerItems.ITEM_NOTIFICATION);
        } else {
            //goto login screen
            intent = new Intent(context, LandingActivity.class);
        }

        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);

        //Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        //Bitmap largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_app_notification_icon);

        String channel_id = createNotificationChannel(context);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, channel_id)
                .setContentTitle(title)
                .setContentText(messageBody)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(messageBody))
                /*.setLargeIcon(largeIcon)*/
                .setSmallIcon(R.drawable.app_logo_color) //needs white icon with transparent BG (For all platforms)
                .setColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
                .setVibrate(new long[]{1000, 1000})
                .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
                .setContentIntent(pendingIntent)
                .setPriority(Notification.PRIORITY_HIGH)
                .setAutoCancel(true);

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify((int) ((new Date(System.currentTimeMillis()).getTime() / 1000L) % Integer.MAX_VALUE) /* ID of notification */, notificationBuilder.build());
    }

public static String createNotificationChannel(Context context) {

        // NotificationChannels are required for Notifications on O (API 26) and above.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            // The id of the channel.
            String channelId = "Channel_id";

            // The user-visible name of the channel.
            CharSequence channelName = "Application_name";
            // The user-visible description of the channel.
            String channelDescription = "Application_name Alert";
            int channelImportance = NotificationManager.IMPORTANCE_DEFAULT;
            boolean channelEnableVibrate = true;
//            int channelLockscreenVisibility = Notification.;

            // Initializes NotificationChannel.
            NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, channelImportance);
            notificationChannel.setDescription(channelDescription);
            notificationChannel.enableVibration(channelEnableVibrate);
//            notificationChannel.setLockscreenVisibility(channelLockscreenVisibility);

            // Adds NotificationChannel to system. Attempting to create an existing notification
            // channel with its original values performs no operation, so it's safe to perform the
            // below sequence.
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            assert notificationManager != null;
            notificationManager.createNotificationChannel(notificationChannel);

            return channelId;
        } else {
            // Returns null for pre-O (26) devices.
            return null;
        }
    }

NotificationCompat.Builder通知构建器 = new NotificationCompat.Builder(context, channel_id)

-> 在您的设备上使用channel_id,您将获得推送通知,该设备版本为26或更高版本。

-> 因为NotificationCompat.Builder(context)方法已被弃用,现在您需要使用更新的方法,该方法具有两个参数:一个是context,另一个是channel_id。

-> NotificationCompat.Builder(context, channel_id) 是更新后的方法。请试用它。

-> 在设备的26+ SDK版本中,您将每次创建一个channel_id。


谢谢,我之前使用了静态的通知ID来进行通知。 - pratham kesarkar

6
使用此类来发送 Android 8 通知。
public class NotificationHelper {

private Context mContext;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mBuilder;
public static final String NOTIFICATION_CHANNEL_ID = "10001";

public NotificationHelper(Context context) {
    mContext = context;
}

/**
 * Create and push the notification 
 */
public void createNotification(String title, String message)
{    
    /**Creates an explicit intent for an Activity in your app**/
    Intent resultIntent = new Intent(mContext , SomeOtherActivity.class);
    resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    PendingIntent resultPendingIntent = PendingIntent.getActivity(mContext,
            0 /* Request code */, resultIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    mBuilder = new NotificationCompat.Builder(mContext);
    mBuilder.setSmallIcon(R.mipmap.ic_launcher);
    mBuilder.setContentTitle(title)
            .setContentText(message)
            .setAutoCancel(false)
            .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
            .setContentIntent(resultPendingIntent);

    mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
    {
        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.enableVibration(true);
        notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        assert mNotificationManager != null;
        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        mNotificationManager.createNotificationChannel(notificationChannel);
    }
    assert mNotificationManager != null;
    mNotificationManager.notify(0 /* Request Code */, mBuilder.build());
  }
}

6

首先,如果您不知道,在Android Oreo即API级别26中,通知必须使用通知渠道进行注册。

在这种情况下,许多教程可能会让您感到困惑,因为它们展示了上下Oreo版本的不同通知示例。

因此,这里提供一段通用代码,可在Oreo以上和以下版本上运行:

String CHANNEL_ID = "MESSAGE";
String CHANNEL_NAME = "MESSAGE";

NotificationManagerCompat manager = NotificationManagerCompat.from(MainActivity.this);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
    NotificationManager.IMPORTANCE_DEFAULT);
    manager.createNotificationChannel(channel);
}

Notification notification = new NotificationCompat.Builder(MainActivity.this,CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_android_black_24dp)
        .setContentTitle(TitleTB.getText().toString())
        .setContentText(MessageTB.getText().toString())
        .build();
manager.notify(getRandomNumber(), notification); // In case you pass a number instead of getRandoNumber() then the new notification will override old one and you wont have more then one notification so to do so u need to pass unique number every time so here is how we can do it by "getRandoNumber()"

private static int getRandomNumber() {
    Date dd= new Date();
    SimpleDateFormat ft =new SimpleDateFormat ("mmssSS");
    String s=ft.format(dd);
    return Integer.parseInt(s);
}

视频教程:YOUTUBE视频

如果您想下载此演示:GitHub链接


5

这是一款适用于Android O版本及低版本API的通知演示应用程序。以下是在GitHub-Demo 1GitHub-Demo 2上的最佳演示应用。

enter image description here


1
请考虑发布应用程序的最小代码片段,而不是提供没有归属/关联所有者来源的外部链接。(这些来源也可能随时下线,没有其他访问方式。) - Edric

5

尝试这段代码:

public class FirebaseMessagingServices extends com.google.firebase.messaging.FirebaseMessagingService {
    private static final String TAG = "MY Channel";
    Bitmap bitmap;

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        Utility.printMessage(remoteMessage.getNotification().getBody());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());

            String title = remoteMessage.getData().get("title");
            String body = remoteMessage.getData().get("body");
            String message = remoteMessage.getData().get("message");
            String imageUri = remoteMessage.getData().get("image");
            String msg_id = remoteMessage.getData().get("msg-id");
          

            Log.d(TAG, "1: " + title);
            Log.d(TAG, "2: " + body);
            Log.d(TAG, "3: " + message);
            Log.d(TAG, "4: " + imageUri);
          

            if (imageUri != null)
                bitmap = getBitmapfromUrl(imageUri);

            }

            sendNotification(message, bitmap, title, msg_id);
                    
        }


    }

    private void sendNotification(String message, Bitmap image, String title,String msg_id) {
        int notifyID = 0;
        try {
            notifyID = Integer.parseInt(msg_id);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }

        String CHANNEL_ID = "my_channel_01";            // The id of the channel.
        Intent intent = new Intent(this, HomeActivity.class);
        intent.putExtra("title", title);
        intent.putExtra("message", message);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);


        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "01")
                .setContentTitle(title)
                .setSmallIcon(R.mipmap.ic_notification)
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText(message))
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setChannelId(CHANNEL_ID)
                .setContentIntent(pendingIntent);

        if (image != null) {
            notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle()   //Set the Image in Big picture Style with text.
                    .bigPicture(image)
                    .setSummaryText(message)
                    .bigLargeIcon(null));
        }


        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {       // For Oreo and greater than it, we required Notification Channel.
           CharSequence name = "My New Channel";                   // The user-visible name of the channel.
            int importance = NotificationManager.IMPORTANCE_HIGH;

            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,name, importance); //Create Notification Channel
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(notifyID /* ID of notification */, notificationBuilder.build());
    }

    public Bitmap getBitmapfromUrl(String imageUrl) {     //This method returns the Bitmap from Url;
        try {
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            Bitmap bitmap = BitmapFactory.decodeStream(input);
            return bitmap;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;

        }

    }

}


我使用了这段代码,但是当应用程序在后台时,带有图像的通知并不可见。你有什么解决方案吗?请帮忙。 - Mohsin Khan
这取决于一些因素,例如:
  1. 你是否连接到网络..???
  2. 图像的URL是否正确(通过在浏览器上访问图像URL来检查)。
- Rohit Mhatre

3

我在Oreo上遇到了同样的问题,发现如果你首先使用NotificationManager.IMPORTANCE_NONE创建通道,然后稍后更新它,该通道将保留原始的重要性级别。

这得到了Google Notification training documentation的支持,其中指出:

创建通知渠道后,您无法更改通知行为-此时用户完全控制。

如果您想重置通道行为,最好删除并重新安装应用程序。

最好避免使用IMPORTANCE_NONE,除非您想抑制该通道的通知,即利用静默通知。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接