AlarmManager ne fonctionne pas sur plusieurs appareils

85

Mon application utilise AlarmManager et fonctionne depuis 4 ans. Mais j'ai remarqué que cela a commencé à échouer sur certains appareils.

Je suis presque sûr que le code est correct (j'utilise WakefulBroadcastReceiver et setExactAndAllowWhileIdle pour les appareils avec Doze) car il fonctionne parfaitement sur les appareils Nexus, mais il échoue dans les appareils de certains fabricants (Huawei, Xiaomi ...).

Les appareils Huawei, par exemple, ont une sorte de gestionnaire de batterie qui détruit les applications, et lorsqu'une application est tuée, les alarmes programmées sont annulées. Ainsi, définir une application comme «protégée» dans le gestionnaire de batterie Huawei résout le problème.

Mais récemment, j'ai remarqué que cela ne fonctionnait pas avec plus d'appareils: Xiaomi, Samsung (peut-être est-ce lié au nouveau "Smart Manager"?) ... Il semble que ce comportement devienne un standard: tuer les applications d'arrière-plan.

Quelqu'un connait-il quelque chose à propos de ça? Un moyen de s'assurer que l'alarme est déclenchée?

EDIT: Ce problème est causé par des "économiseurs de batterie" ajoutés par différents fabricants. Plus d'informations ici: https://dontkillmyapp.com/

Sergio Viudes
la source
8
Les fabricants blâment les applications pour la consommation d'énergie et continuent de commercialiser les cœurs Octa, qui consomment plus de batterie que le processeur avec moins de cœurs. Pensent-ils que simplement ajouter un noyau accélérerait leurs téléphones?
FrozenFire
1
@AviLevinshtein J'ai peut-être mal compris votre question. Je crée les alarmes dans mon activité. Ensuite, lorsque l'alarme se déclenche, un récepteur de diffusion est exécuté, et enfin, un WakefulIntentService (classe de @commonsware) est exécuté.
Sergio Viudes
2
@JFValdes Je cherche toujours une solution. AlarmManager fonctionne parfaitement sur les appareils avec Vanilla Android. Le problème est que les fabricants essaient "d'améliorer" les fonctionnalités d'Android, et ils ont cassé AlarmManager ... Les fabricants ne devraient pas implémenter leurs propres "économiseurs de batterie", s'ils utilisent le mode Doze standard, alors AlarmManager fonctionnerait parfaitement ... Toujours à la recherche pour une solution ...
Sergio Viudes
1
Y a-t-il encore une solution? Comment d'autres applications comme les rappels ou quelque chose font-elles cela? Il doit y avoir une autre option que setAlarm, qui est pour les alarmes, pas pour les rappels
kv1dr
1
@SergioViudes Je suis également confronté au même problème avec les appareils Xiomi pour le suivi. et si je garde mon application de la restriction d'économie de batterie que son fonctionnement correctement dans 3 appareils sur 4 en effectuant les paramètres suivants - -> Allez à la batterie -> Alimentation -> Économiseur de batterie de l'application -> votre application Sélectionnez maintenant Aucune restriction (pour les paramètres d'arrière-plan), puis l'option Autoriser pour l'emplacement d'arrière-plan
Imran Khan Saifi

Réponses:

17

J'essaye de le résoudre depuis plusieurs semaines déjà. Je n'ai rien trouvé. Huawei tue toutes les alarmes après un certain temps. Si je mets l'application sur l'application protégée dans leur économiseur de batterie, cela n'aide pas. Mais si je change le nom du package de mon application pour contenir des mots tels que réveil, horloge ou calendrier, cela fonctionne tout à fait normalement comme sur tout autre appareil. Je ne comprends pas comment Google peut donner une certification pour cette merde. Je pense que l'OEM ne devrait pas modifier la plate-forme principale de cette manière. Je comprends qu'ils ont leur propre économiseur de pâte qui tue l'application après un certain temps, lorsque l'utilisateur ne l'utilise pas. Mais cette tuerie alerte également des applications protégées.

SetAlarmClock () pour les alarmes de synchronisation exactes aide également. Mais il n'est pas possible de l'utiliser pour penser comme la mise à jour du widget.

Mise à jour: la protection par mots-clés de nom de package ne fonctionne déjà pas sur les appareils Huawei actuels, c'était vrai en 2017.

Atome
la source
Comme moi, je l'essaye aussi mais rien ne permet de résoudre ce problème sur certaines marques Xiaomi, Oppo, Huawei. Ils tuent parfois le processus d'arrière-plan et l'alarme pour économiser la batterie.
Andi Susilo
1
J'ai un téléphone Huawei, changer le nom du paquet en alarme / calendrier ne fait rien. Seul moyen de contourner cela, ajoutez votre application dans la liste des applications protégées du gestionnaire de téléphone
Ashish Pardhiye
9

Le problème est Smart Manager. Samsung dispose d'un gestionnaire de batterie qui empêche parfois certaines applications de s'exécuter en arrière-plan. Il a essayé de «reprendre» en revenant à l'application mais désactive complètement l'application ou peut reprendre toutes les 5 minutes environ (selon la façon dont Samsung l'a).

Cela fonctionnerait sur les versions stock d'Android car il n'y a pas de gestionnaire Samsung. Vous pouvez également installer une version personnalisée d'Android qui dispose de certaines fonctionnalités pour activer SM (en fonction de la rom).

SA
la source
Je deviens fou parce que je n'ai pas d'appareil Samsung pour le tester. Je ne sais que ce que les utilisateurs de mon application me disent. Savez-vous si le problème est que AlarmManager ne fonctionne pas parce que l'application est tuée? Ou le problème est que l'appareil ne peut pas se réveiller lorsque l'alarme se déclenche à cause de ce gestionnaire?
Sergio Viudes
@SergioViudes Récemment, de nombreuses entreprises ont mis en œuvre la leur. Comme LG en a un qui fonctionne comme Samsung, peut-être que votre téléphone en a un? Le problème n'est pas l'alarme, l'application d'alarme est poussée dans un état où elle est complètement inactive. Smart Manager pense que c'est juste une application aléatoire dont vous n'avez pas besoin. J'ai remarqué que certaines applications peuvent passer outre, peut-être que certaines applications sont acceptées par le gestionnaire intelligent.
SA
1
@SergioViudes J'ai un Samsung à tester et je peux vous dire que vous ne pouvez pas en tirer grand-chose. Lorsque le gestionnaire intelligent optimise votre application, il n'y a aucune erreur ou quoi que ce soit, il meurt juste, semblable à un arrêt forcé. Il est toujours dans la liste des applications récentes
Tim
Merci Tim. Ce serait formidable de résoudre ce problème sans avoir à exclure des applications de "Smart" Manager.
Sergio Viudes
des appareils comme xiaomi (miui), vivo et htc définissent tout un tas d'autorisations comme fausses par défaut, à moins qu'il ne s'agisse d'une application dans la liste des applications «de confiance» qu'elles semblent déterminer elles-mêmes (whatsapp, truecaller, etc. sont approuvées par défaut ). Cela devient un cauchemar de codeurs
desidigitalnomad
3

La plupart des appareils Android modernes sont livrés avec une application ou un mécanisme qui essaie automatiquement de déterminer comment économiser la batterie et, par conséquent, peut tuer certaines applications tierces. Cela peut entraîner la suppression des tâches et travaux planifiés (par exemple, les alarmes ne se déclenchent pas, la notification push ne fonctionne pas, etc.). Dans de nombreux cas, cela se produit complètement indépendamment des mécanismes d'économie de batterie d'Android.Dans mon cas, je ne pourrais pas optimiser davantage la batterie lorsque je détecte un modèle d'appareil, je redirige l'utilisateur vers le gestionnaire de démarrage pour mettre mon application sur liste blanche.

Vous avez trouvé dans ce lien pour chaque modèle l'intention que vous devez appeler https://android-arsenal.com/details/1/6771

baderkhane
la source
2

Utilisez AlarmManager pour les appareils <5.0 et JobScheduler pour les appareils 5.0+. Je ne peux pas dire avec certitude que JobScheduler ne sera pas affecté par les manigances des fabricants, mais cela me semblerait beaucoup moins probable, étant donné qu'Android tente d'éloigner les gens d'AlarmManager et de JobScheduler.

EDIT: Google a sorti une solution de première partie à ce problème appelée WorkManager . Il fait abstraction de plusieurs cadres de planification et utilise le plus approprié pour l'appareil.

À M
la source
2
Malheureusement, contrairement à la classe AlarmManager, le timing n'est pas exact lors de l'utilisation de JobScheduler. Dans mon application, le timing doit être exact :(
Sergio Viudes
Je l'ai essayé et certains optimiseurs (au moins samsung) tuent toutes les tâches en attente dans JobScheduler lorsque l'écran s'éteint. Donc c'est aussi cassé. Cela se produit sur 5.0. Après la mise à jour vers 6.0, cela fonctionne bien, je suppose qu'ils ont corrigé cela. Je n'ai pas encore pu le tester avec d'autres fabricants.
Sloy
Pour une synchronisation exacte, vous ne pouvez pas utiliser un service d'arrière-plan ou un service planifié. Vous pouvez essayer un service de premier plan, mais cela créera une notification persistante pour l'utilisateur (probablement indésirable) et certains téléphones ont des tueurs de tâches intégrés qui détruiront automatiquement le service de premier plan. WorkManager est la meilleure solution mais ne vous donnera malheureusement pas les horaires exacts.
Tom
1

J'ai aussi une application qui définit des alarmes. La solution est d'utiliser AlarmManager.setAlarmClock () sur api> = 21. Ceci n'est pas affecté par somnoler afaik et a l'avantage supplémentaire de mettre une icône de réveil dans la barre d'état système.

Tyler Pfaff
la source
Merci pour votre réponse. Existe-t-il un moyen de supprimer l'icône du réveil?
Sergio Viudes
Malheureusement, setAlarmClock ne fonctionne pas parfois. Je l'ai testé sur un appareil Oreo avec une mémoire faible.
Boris Salimov le
0

la plupart des nouveaux téléphones de nos jours sont livrés avec une sorte de gestionnaire de batterie / économie d'énergie qui fait la même chose que vous avez décrite. sans compter les duboosters et les clean masters.

Je pense que vous devez mettre une clause de non-responsabilité ou une FAQ dans la liste de votre application / Play Store indiquant que cette application doit être mise en exception de votre application de gestionnaire de batterie pour fonctionner correctement.

Eriuzo
la source
Il devrait y avoir une autre façon de le faire ... Les utilisateurs ne liront pas la clause de non-responsabilité. Je ne peux pas penser que les téléphones Samsung ne permettent pas aux applications d'utiliser AlarmManager ...
Sergio Viudes
Les alarmes ne se déclencheront pas "à l'heure", mais elles finiront par arriver
Gavriel
C'est (malheureusement) la réponse la plus utile, je dirais. J'aurais aimé qu'il y ait une meilleure solution, mais les fabricants de matériel endommagent l'Android vanilla parfaitement fonctionnel.
caw
0

J'ai arrêté d'utiliser AlarmManager il y a quelque temps ... une alternative meilleure et plus stable

  1. créer un service
  2. enregistrer un BroadcastReceiver pour BOOT_COMPLETED
  3. licencier votre service du récepteur
  4. démarrer un nouveau gestionnaire dans votre service qui se boucle toutes les X minutes ( Android - exécutant une méthode périodiquement en utilisant l'appel postDelayed () )
  5. vérifier si l'heure d'exécution de la tâche est arrivée: maintenant - temps d'exécution> 0 ( Comment trouver la durée de la différence entre deux dates en java? )
  6. si c'est le cas, exécutez la tâche et arrêtez le gestionnaire

oui ... c'est pénible ... mais le travail est fait PEU IMPORTE QUOI

ymz
la source
3
Merci pour votre suggestion, mais j'aimerais éviter cette approche, car l'utilisation d'AlarmManager ne consommera pas de RAM ni aucune ressource. Et, si votre application est tuée, le service s'arrêterait, non?
Sergio Viudes
Je n'ai pas dit que cette approche est BOOLETPROOF, mais au moins elle consiste en différentes versions d'API :)
ymz
Pour fonctionner de manière fiable, cette solution aurait probablement également besoin d'utiliser des verrous de réveil et cela consommerait d'énormes quantités de batterie.
Paweł Nadolski
Je suppose que vous avez raison sur celui-ci ... la seule question est: quel serait le pire - code non fiable ou mauvaises performances? de toute façon, je pense personnellement qu'il existe d' autres moyens de verrouillage qui peuvent convenir dans certains cas (par exemple: stackoverflow.com/questions/5346694/… )
ymz
0

Écoutez-vous BOOT_COMPLETED? Vous devez à nouveau définir des alarmes lorsqu'un périphérique est redémarré.

Tyler Pfaff
la source
Oui. Comme je l'ai dit, les alarmes fonctionnaient depuis 2012, jusqu'à maintenant. Lorsque l'appareil est redémarré, je reprogramme les alarmes dans le récepteur de diffusion BOOT_COMPLETED.
Sergio Viudes
1
Exiger un redémarrage pour que votre application fonctionne à nouveau n'est même pas une demi-solution
Tim
1
@TimCastelijns ce n'est pas du tout ce que je dis. SI l'appareil est redémarré, toutes les alarmes définies avec le gestionnaire d'alarmes doivent être à nouveau réglées.
Tyler Pfaff
@TylerPfaff oui mais le redémarrage de l'appareil n'est pas lié au problème dans cette question
Tim
0

Quelle version d'Android ces appareils fonctionnent-ils?

À partir de l'API 23, le système d'exploitation lui-même passera en mode veille à faible consommation lorsqu'il n'a pas été utilisé pendant un certain temps, et dans ce mode, les alarmes ne seront pas délivrées. Il existe cependant un moyen pour les applications de dire explicitement «J'ai besoin que cette alarme se déclenche à ce moment, quelle que soit l'utilisation de la batterie». les nouvelles méthodes AlarmManager appelées setAndAllowWhileIdle()et setExactAndAllowWhileIdle().

D'après votre description, il semble que cela ne soit peut-être pas la cause particulière de vos problèmes sur les appareils de certains OEM, mais c'est quelque chose dont tous les développeurs utilisant le gestionnaire d'alarmes devraient être conscients.

Enfin, de nombreuses utilisations du gestionnaire d'alarmes sont mieux traitées en utilisant les mécanismes du Job Scheduler. Pour des raisons de compatibilité ascendante, le Play Services "GCM Network Manager" est en fait très proche du Job Scheduler en termes de fonctionnalités - il utilise le Job Scheduler en interne sur les nouvelles versions d'Android - et ne concerne pas nécessairement la mise en réseau, malgré le nom de la classe.

ctate
la source
Les appareils Samsung dotés de Smart Manager exécutent Lollipop. J'utilise déjà setExactAndAllowWhileIdle pour les appareils Marshmallow. Je vais jeter un oeil à JobScheduler et GCM. Quoi qu'il en soit, je ne sais pas si le problème est que l'alarme ne se déclenche pas ou si cet appareil ne se réveille pas lorsque l'alarme se déclenche.
Sergio Viudes
0

Je ne pense pas que la suppression de l'application empêchera le gestionnaire d'alarmes de réveiller votre application.

Ce n'est que lorsque vous "forcez l'arrêt" ou désactivez l'application que vous ne recevez pas de rappel du gestionnaire d'alarme.

La cause première pourrait être autre chose.

Aussi sur M ... setExactAndAllowWhileIdle fait la limitation ... c'est-à-dire que si vous programmez une alarme toutes les 2 minutes, elle ne sera pas déclenchée. ..Il doit y avoir une fenêtre de 15 minutes. .

rupesh jain
la source
1
Merci pour votre réponse. Mais sinon, pourquoi l'application fonctionne-t-elle parfaitement lorsque «l'optimisation de la batterie» est désactivée dans Smart Manager?
Sergio Viudes
exécutez-vous l'application sur un appareil enraciné..si oui, le gestionnaire d'applications peut également désactiver l'application ..
rupesh jain
Non, je ne l'exécute pas sur un appareil enraciné.
Sergio Viudes
@rupeshjain "c'est-à-dire que si vous programmez une alarme toutes les 2 minutes, elle ne sera pas déclenchée. .. Il doit y avoir une fenêtre de 15 minutes." ce n'est pas tout à fait vrai, c'est un vrai problème si c'était vrai. Vous pouvez lire exactement la limite de temps de planification dans les documents Android pour la méthode setExactAndAllowWhileIdle. Il existe des restrictions sur la fréquence à laquelle ces alarmes se déclenchent pour une application particulière. Dans des conditions de fonctionnement normal du système, il ne diffusera pas ces alarmes plus d'une fois par minute environ lorsque, en mode veille à faible puissance, cette durée peut être considérablement plus longue de 15 minutes.
eyadMhanna
0

Pour Xiaomi, vous devrez peut-être activer AutoStart pour votre application. J'essaie de faire une liste de modifications Android (généralement du fabricant du téléphone) qui peuvent affecter un processus d'arrière-plan. Si vous avez quelque chose de nouveau, veuillez ajouter une réponse ici Liste des tueurs de tâches Android

Andrei Ciuca
la source
0

Nous devons activer notre application dans le gestionnaire de démarrage automatique du gestionnaire d'applications, certains combinés comme vivo v5,

In vivo v5, nous pouvons trouver ce menu dans iManager -> Gestionnaire d'applications -> Gestionnaire de démarrage automatique. Activez notre application ici.

Ensuite, votre alarm / alarmmanager déclenchera une alarme si l'application est tuée ou fermée.

Aneesh NN
la source
0

Je cherchais une réponse et après plusieurs heures j'ai trouvé ceci:

https://stackoverflow.com/a/35220476/3174791

En résumé, c'est un moyen de savoir si votre application a été tuée par des `` applications protégées '' et cela ne fonctionne que sur les appareils Huawei. faites-moi savoir s'il existe une solution pour d'autres appareils (Samsung, Sony, Xiaomi, etc.).

Edgar
la source
0

C'est peut-être tard mais j'espère que cela aide quelqu'un.

J'ai été coincé sur le même problème pendant si longtemps. Mais maintenant je sais comment résoudre ce problème. C'est pour toute personne qui pourrait avoir le même problème. Les gens ne cessent de dire que vous devez activer AutoStart mais j'ai réussi à le faire sans utiliser le démarrage automatique.

Tout d'abord, WakeFullBroadcastaReceiver est désormais obsolète et vous devez utiliser BroadcastReceiver. Deuxièmement, vous devez utiliser ForegroudService au lieu de BackgroundService.

Je vais vous donner l'exemple ci-dessous:

IntentService.class

public class NotificationService extends IntentService {


//In order to send notification when the app is close
//we use a foreground service, background service doesn't do the work.



public NotificationService() {
    super("NotificationService");
}

@Override
public void onCreate() {
    super.onCreate();

}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    //There is no difference in the result between start_sticky or start_not_sticky at the moment
    return START_NOT_STICKY;
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {

    //TODO check if the app is in foreground or not, we can use activity lifecyclecallbacks for this

    startForegroundServiceT();
    sendNotification(intent);
    stopSelf();
}


/***
 * you have to show the notification to the user when running foreground service
 * otherwise it will throw an exception
 */
private void startForegroundServiceT(){

    if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_channel_01";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT);

        ((NotificationManager) 
   getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

        Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();

        startForeground(1, notification);
    }
}

private void sendNotification(Intent intent){

    //Send notification
    //Use notification channle for android O+
}
}

démarrer le service de premier plan dans BroadcastReceiver.class

public class AlarmReceiver extends BroadcastReceiver {


@Override
public void onReceive(Context context, Intent intent) {


    Intent service = new Intent(context, NotificationService.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(service);
    } else {
        context.startService(service);
    }

}
}

Et le setAlarms comme ceci:

 public static void setAlarm(Context context, int requestCode, int hour, int minute){


    AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context//same activity should be used when canceling the alarm
            , AlarmReceiver.class);
    intent.setAction("android.intent.action.NOTIFY");

    //setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);

    Calendar time = getTime(hour, minute);

    //set Alarm for different API levels
    if (Build.VERSION.SDK_INT >= 23){
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }
    else{
        alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }

Ensuite, vous devez déclarer le récepteur et le service de premier plan dans le manifeste.

       <receiver android:name=".AlarmReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.NOTIFY">

            </action>
        </intent-filter>
    </receiver>
    <service
        android:name=".NotificationService"
        android:enabled="true"
        android:exported="true"></service>

J'espère que ça aidera quelqu'un.

Keivan.k
la source