Уведомления не получены на Android - PullRequest
0 голосов
/ 03 мая 2018

Я занимаюсь разработкой Android-приложения, основным назначением которого является отображение уведомлений в установленное время (какое-то конкретное приложение-календарь). Одна из основных претензий заключается в том, что пользователи не (всегда) получают уведомления , и я нахожусь в тупике.

Мы внутренне протестировали приведенный ниже код на Android 4.4, 6, 7.0, 7.1, 8.0, 8.1 на эмуляторах и использовали около 10 реальных устройств (от 6 до 8.1), и все устройства получали свои уведомления вовремя. Даже при перезагрузке все уведомления были получены вовремя.

Одной из вещей, с которой мы столкнулись, было исключение SecurityException на устройствах Samsung (> 500 зарегистрированных аварийных сигналов), которое мы ранее сработали из-за неправильной отмены. Похоже, это больше не проблема.

Итак, в чем может быть причина этих пропущенных уведомлений? Это специфичная для устройства настройка, это простая ошибка? Или здесь есть другие факторы?

Это код, который мы используем:

private void cancelAlarm(String notificationId, Class<? extends AbstractReceiver> receiverClass)
        throws BroadcastException {
    /*
     * Create an intent that looks similar, to the one that was registered using add. Making sure the notification id in the action is the same. Now we can search for
     * such an intent using the 'getService' method and cancel it.
     */
    final Intent intent = new Intent(this.context, receiverClass);
    intent.setAction(notificationId);

    final PendingIntent pi = PendingIntent.getBroadcast(this.context, 0, intent, 0);
    final AlarmManager am = getAlarmManager();

    try {
        am.cancel(pi);
    } catch (Exception e) {
        Log.e(this.getClass().getSimpleName(), e.getMessage());
        throw new BroadcastException(e.getMessage());
    }
}

private void addOrUpdateAlarm(...){
    try {
        cancelAlarm(notificationId, OurReceiver.class);
    } catch (BroadcastException e) {
        Log.e(AlarmHelper.class.getSimpleName(), "addOrUpdateAlarm: Can't cancel current alarm before reinserting.", e);
    }

    Intent intent = new Intent(this.context, receiverClass);
    intent.setAction(notificationId);
    // some intent.setExtra() calls.
    PendingIntent sender = PendingIntent.getBroadcast(this.context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    /* Get the AlarmManager service */
    final AlarmManager am = getAlarmManager();

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
    }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        am.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
    }else{
        am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
    }

}

и затем в OurReceiver мы создаем канал уведомления:

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

        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel mChannel = new NotificationChannel(id, name, importance);
        // Configure the notification channel.
        mChannel.setDescription(description);
        mChannel.enableLights(true);
        // Sets the notification light color for notifications posted to this
        // channel, if the device supports this feature.
        mChannel.setLightColor(Color.RED);
        mChannel.enableVibration(true);
        mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
        mNotificationManager.createNotificationChannel(mChannel);
    }

и наконец отправьте уведомление:

    PendingIntent pIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), intent, 0);

    Notification n = new NotificationCompat.Builder(context, channel)
            .setContentTitle(notificationTitle)
            .setContentText(notificationSubText)
            .setSmallIcon(R.drawable.logo)
            .setContentIntent(pIntent)
            .setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE)
            .setAutoCancel(true).build();

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

            notificationManager.notify(0, n); 

Ответы [ 5 ]

0 голосов
/ 18 июня 2018

@ Марс Эстрада права, проблема в реализации телефона. У Huawei есть программное обеспечение для вызова powergenie, которое может убить (в терминах Linux) ваш сервис. Так что реализация явно не соблюдает режим дозировки. Приложение Somme просто информирует пользователя о том, что "поскольку у вас есть huawei, обязательно настройте управление питанием". То же самое касается Xiaomi и Samsung. Поскольку эта реализация не соответствует Android SDK, нет возможности управлять фоновым приложением. Для Моего приложения для разных Huawei (HOnor 8x, Huawei P20, P10, P9, P9 lite), если приложение не защищено для фонового выполнения в настройках, даже невозможно запустить службу с помощью Context.startService (или startFroegroundService, когда имеется в наличии). С уважением Чарльз

0 голосов
/ 15 мая 2018

Проблема, по которой вы через некоторое время не получаете никаких уведомлений, связана с DOZE .

У вас есть 2 варианта решения вашей проблемы:

  • «Удалить» Doze из вашего приложения (https://www.greenbot.com/article/2993199/android/how-to-turn-off-doze-mode-for-specific-apps-in-android-marshmallow.html) (не рекомендуется, это должен делать каждый пользователь, вы не можете установить его по умолчанию)

  • Использовать высокий приоритет FCM согласно документации:

    * Контрольный список доз

    Если возможно, используйте FCM для нисходящего обмена сообщениями. Если ваши пользователи должны сразу увидеть уведомление, убедитесь, что вы используете FCM сообщение с высоким приоритетом . Предоставьте достаточную информацию в исходной полезной нагрузке сообщения, поэтому последующий доступ к сети не требуется. Установите критические тревоги с помощью setAndAllowWhileIdle () и setExactAndAllowWhileIdle (). Протестируйте свое приложение в Doze. *

0 голосов
/ 14 мая 2018

Об уведомлениях могу вам сказать следующее:

После долгого времени разработки приложения, которое использует Alarms от AlarmManager, я обнаружил много вещей о некоторых конфликтующих устройствах. (Я не пробовал JobScheduler, но в большинстве случаев эта технология также не работает).

Некоторые производители (хорошо известные, Huawei, Xiaomi, Samsung и т. Д.) Вмешиваются в жизненный цикл AlarmManager.

Huawei и Xiaomi

Huawei по умолчанию убивает все незащищенные приложения при блокировке экрана. Вот и все, убивает все ресурсы приложения, в том числе alarms, boradcast receivers и services. Приложение полностью убито после блокировки экрана, поэтому alarms не получаются и уведомления не отображаются логически. Чтобы избежать этой ситуации, Huawei предоставляет способ перевести приложения в защищенный режим, что означает, что при заблокированном экране эти защищенные приложения не уничтожаются. Таким образом, защищенные приложения по-прежнему получают alarms и broadcast receivers.

.

Samsung

У Samsung есть «функция» (нежелательная функция для разработчиков), которая делает «то же самое», что и устройства Huawei и Xiaomi, с небольшой разницей. Samsung не убивает незащищенные приложения при блокировке экрана, но когда приложение не открывается в течение 3 дней. После 3 дней бездействия пользователя приложение убивается, как Huawei и Xiaomi, поэтому уведомления (alarms) не принимаются. Samsung также предоставляет способ защитить приложения и избежать этой ситуации.

Заключение

Есть другие производители с таким же поведением, но я не знаю всех их. Я могу сказать, что Huawei, Xiaomi и Samsung являются самыми известными из них.

Итак, сначала попытайтесь узнать, все ли неисправные устройства изготовлены этими конфликтующими производителями.

Тогда есть несколько способов сообщить пользователю, что уведомления могут не срабатывать на этих устройствах, и предложить им поместить ваше приложение в защищенное приложение.

Программно, вы можете сделать что-то подобное ( source ):

if("huawei".equalsIgnoreCase(android.os.Build.MANUFACTURER)) { 
    AlertDialog.Builder builder  = new AlertDialog.Builder(this);
    builder.setTitle(R.string.huawei_headline).setMessage(R.string.huawei_text)
            .setPositiveButton(R.string.go_to_protected, new DialogInterface.OnClickListener() {
                @Override 
                public void onClick(DialogInterface dialogInterface, int i) {
                    Intent intent = new Intent();
                    intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
                    startActivity(intent);
                } 
            }).create().show(); 
}

И вы можете сделать то же самое с другими конфликтующими производителями. Вот как я справляюсь с такой ситуацией на этих устройствах, и уведомления работают хорошо, в большинстве случаев.

Надеюсь, это поможет.

0 голосов
/ 15 мая 2018

Причиной этого может быть Доза . Он работает, когда устройство устойчиво и не используется, Android делает фоновые звонки вместе с другим приложением, чтобы сэкономить время пробуждения телефона и сэкономить заряд батареи. Я не совсем уверен, если это ваш случай, но вы можете посмотреть на это.

Этот ответ может помочь вам в этом.

0 голосов
/ 14 мая 2018

В некоторых документах написано, что приложение может обработать максимум 50 уведомлений. (не уверен)

Но если вы попытаетесь указать другой идентификатор уведомления:

for (int i...>500)
 notificationManager.notify(i, n);

Надеюсь, что это работает

...