Récepteur de radiodiffusion ne fonctionne pas après redémarrage de L'appareil dans Android
j'ai déjà vérifié toutes les questions connexes et n'ont pas trouvé de solution pour ce problème. C'est donc un absolument nouveau problème pour moi.
Ce Que J'Ai
j'ai une application Android qui enregistre quelques récepteurs de radiodiffusion dans son manifeste. C'est ce que mon manifeste ressemble.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.app.myapp">
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<application
android:name=".base.MyApp"
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/label_app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="label, allowBackup">
<receiver android:name=".mics.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<receiver android:name=".PhoneCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<receiver
android:name=".mics.DeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
</receiver>
<receiver
android:name="com.clevertap.android.sdk.InstallReferrerBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<meta-data
android:name="com.app.myapp.utils.ImageLoaderModule"
android:value="GlideModule" />
<meta-data
android:name="com.app.myapp.utils.AudioCoverLoaderModule"
android:value="GlideModule" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<activity
android:name=".core.activities.SplashActivity"
android:excludeFromRecents="true"
android:label="@string/label_app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity-alias
android:name=".core.activities.SplashActivity-Alias"
android:icon="@drawable/ic_launcher"
android:label="@string/label_app_name"
android:noHistory="true"
android:targetActivity="com.app.myapp.core.activities.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
</intent-filter>
</activity-alias>
<activity
android:name=".core.flow.authFlow.activities.AuthFlowActivity"
android:excludeFromRecents="true"
android:label="@string/label_app_name"
android:screenOrientation="portrait" />
<service android:name=".features.fileCloudSync.KillNotificationService" />
</application>
</manifest>
il y a 10 à 15 autres activités, mais elles ont été supprimées pour des raisons de simplicité. Et c'est la classe Basic boot receiver. Je démarrer un service à partir d'ici.
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
AlertUtils.showToast(context, "BOOT COMPLETED", Toast.LENGTH_LONG);
}
}
}
et le coup de téléphone du récepteur de classe ressemble à quelque chose comme ceci (il a été simplifiée (ainsi),
public class PhoneCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
AlertUtils.showToast(context, "PHONE CALL RECEIVED", Toast.LENGTH_LONG);
// Simplified for brevity
}
}
}
Le Problème
Tous ces récepteurs fonctionnent bien quand j'ai installer l'application et commencer une fois. Mais après avoir redémarré mon appareil, ces récepteurs ne fonctionnent plus du tout. Ni la BootCompleteReceiver
ni PhoneCallReceiver
leur onReceive()
méthode appelée.
Mon hypothèse était que ces récepteurs serait enregistré automatiquement après redémarrage, mais il ne fonctionne tout simplement pas. J'ai besoin de l' BootCompleteReceiver
pour que je puisse démarrer un service important dans mon application.
Mes Observations
j'ai testé cela en profondeur. Après avoir redémarré l'appareil, les récepteurs fonctionnent très bien dans mon Nexus 5X (Nougat), Nexus 6P (Nougat), YU Yuphoria (Lollipop) mais pas dans mon OnePlus 3 (Nougat) et Mi 4i (Lollipop).
Comment l' même code fonctionne parfaitement sur quelques appareils et ne fonctionne pas du tout sur les autres appareils? Je n'ai rien changé du tout.
Ce que je fais mal? Mon application est fortement dépendante de ces émissions et commence des services basés sur ceux-ci. Toute aide sera très appréciée.
EDIT 1
pour mieux comprendre le problème, je viens de créer un très petit projet de test avec une seule activité et exactement la même BootCompleteReceiver
et PhoneCallReceiver
.
mais bizarrement, ce projet fonctionne parfaitement sur mon OnePlus 3 où les récepteurs de mon application ne fonctionnent pas après un redémarrage. J'ai d'abord supposé que le problème était dans le système D'exploitation ou l'appareil, mais ce n'est pas le cas.
Alors, où est le problème? Est-il dans mon application (mais il fonctionne parfaitement sur d'autres appareils) ou dans L'OS et l'appareil (le petit projet de test fonctionne bien sur le même OS et le même appareil)?
c'est vraiment déroutant pour moi. Je voudrais besoin d'un spécialiste de l'aide sur ce.
EDIT 2
j'ai essayé la suggestion de @shadygoneinsane. Voici mes observations.
1) j'ai essayé d'envoyer la diffusion BOOT_COMPLETED via ADB.
./adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.app.myapp
Et j'ai eu cette trace de la pile
Broadcasting: Intent { act=android.intent.action.BOOT_COMPLETED pkg=com.app.myapp }
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.BOOT_COMPLETED from pid=25378, uid=2000
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3696)
at com.android.commands.am.Am.sendBroadcast(Am.java:778)
at com.android.commands.am.Am.onRun(Am.java:404)
at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
at com.android.commands.am.Am.main(Am.java:121)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:276)
Peut-être parce que mon appareil n'est pas enracinée. Je ne peux en aucun cas Envoyer cette émission.
2) j'ai essayé avec la diffusion de PROCESS_OUTGOING_CALLS après que.
./adb shell am broadcast -a android.intent.action.PROCESS_OUTGOING_CALLS -p com.app.myapp
j'ai eu ce,
Broadcasting: Intent { act=android.intent.action.PROCESS_OUTGOING_CALLS pkg=com.app.myapp }
Broadcast completed: result=0
il semble que l'émission ait eu du succès, mais je ne vois pas de Toast ou de journal. J'ai ensuite ouvert mon dialer pour composer un numéro et je peux alors voir le pain et le journal.
il semble donc que l'envoi de la diffusion via ADB n'a pas fonctionné, mais ouvrir le composeur et composer un numéro à fait.
EDIT 3
selon la suggestion de @ChaitanyaAtkuri, j'ai aussi essayé d'ajouter la priorité aux filtres d'intention mais cela n'a pas fonctionné aussi bien.
j'ai utilisé des priorités comme 500, 999 et même la plus haute valeur entière, mais rien ne fonctionne. Ce problème se produit également dans certaines applications de mes amis. Ils travaillent dans certains appareils et ne travaillent pas dans d'autres.
EDIT 4
j'ai finalement découvert la cause profonde du problème qui se produit dans mon OnePlus 3. Mon OnePlus 3 a récemment été mis à jour à Nougat et ils ont introduit une fonctionnalité similaire aux périphériques Mi qui empêchent certaines applications de démarrer automatiquement après le redémarrage.
en désactivant cette fonctionnalité, Mon application a commencé à recevoir des émissions après redémarrage parfaitement. Mais ça n'explique toujours pas deux choses.
1) Mon petit projet de test est automatiquement mis en liste blanche dans la liste des applications AutoLaunch et c'est pourquoi il fonctionne comme prévu. Mais comment est-ce possible? Pourquoi l'EO considère cette petite application digne d'être démarrée automatiquement?
2) Il y a quelques applications comme LockDown Pro, 500 Firepaper qui est mis sur liste noire dans L'écran des applications AutoLaunch mais tout de même, il reçoit des émissions après redémarrage dans mon OnePlus 3 et Mi 4i. Comment est-ce possible maintenant? Est-il possible de programmer le lancement automatique de mon application sur ces appareils (OnePlus Et Mi)?
EDIT 5
j'ai essayé la solution proposée par @Rahul Chowdhury et il vraiment semble fonctionner très bien. Après avoir ajouté le service d'accessibilité, le problème est résolu.
mais si l'utilisateur révoque la permission d'accessibilité après l'avoir accordée, y a-t-il un moyen pour moi de vérifier programmatiquement si la permission d'accessibilité est disponible pour mon application?
5 réponses
Voici une solution testée et fonctionnelle sur les deux appareils que vous avez mentionnés, OnePlus et Mi.
Comme vous l'avez dit le démarrage automatique de prévention de la fonctionnalité sur OnePlus et Mi les appareils empêchent les applications de démarrer leurs services automatiquement au démarrage afin d'améliorer la vitesse de démarrage globale de l'appareil et les performances de la batterie. Cependant, il y a une solution pour faire fonctionner votre application même lorsque cette fonctionnalité est activée.
j'ai remarqué que si vous avez un AccessibilityService
dans votre application et il est activé par l'utilisateur, alors votre application passe le filtre que ces fabricants appliquent et l'application reçoit son événement de démarrage complet et tout autre BroadcastReceiver
fonctionne comme prévu.
L'explication possible de cette astuce peut être que depuis AccessibilityService
est un système de niveau de service, de sorte que par l'enregistrement de votre propre service vous sont passage de la certaines filtre appliqué par ces fabricants et dès que votre personnalisé AccessibilityService
est déclenché par L'OS, votre application devient active dans la réception de l'eligible BroadcastReceiver
que vous aviez enregistré.
Donc, voici comment faire,
commencez par ajouter cette permission à votre AndroidManifest.xml
,
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"/>
Cela vous permettra d'enregistrer votre application AccessibilityService
avec le système.
Maintenant, ajoutez une configuration très basique pour votre AccessibilityService
en créant un fichier par exemple my_accessibility_service.xml
à L'intérieur du dossier XML sous votre dossier res dans votre projet.
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackSpoken"
android:description="@string/service_desc"
android:notificationTimeout="100"/>
il ne reste plus qu'un pas à faire, définissez votre coutume AccessibilityService
dans votre projet,
public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) { }
@Override
public void onInterrupt() {
}
}
Remarque, puisque tu n'as pas besoin de l' AccessibilityService
pour n'importe quelle raison plutôt que cette solution, vous pouvez laisser les méthodes overridden vides.
enfin, déclarez juste votre AccessibilityService
dans votre AndroidManifest.xml
,
<service
android:name=".MyAccessibilityService"
android:label="@string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/my_accessibility_service"/>
</service>
C'est tout. Maintenant dans votre application, il suffit de demander à vos utilisateurs d'activer le service d'accessibilité pour votre application à partir de la les paramètres et le laisser sur et le tour est joué! Votre application fonctionne très bien sur tous les appareils, même lorsque le système d'exploitation place un filtre sur lequel les applications devraient démarrer automatiquement au démarrage.
EDIT 1
Voici comment vous pouvez vérifier si l'accessibilité est activé ou pas pour votre application,
private static final int ACCESSIBILITY_ENABLED = 1;
public static boolean isAccessibilitySettingsOn(Context context) {
int accessibilityEnabled = 0;
final String service = context.getPackageName() + "/" + MyAccessibilityService.class.getCanonicalName();
try {
accessibilityEnabled = Settings.Secure.getInt(
context.getApplicationContext().getContentResolver(),
android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
Log.e("AU", "Error finding setting, default accessibility to not found: "
+ e.getMessage());
}
TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
if (accessibilityEnabled == ACCESSIBILITY_ENABLED) {
String settingValue = Settings.Secure.getString(
context.getApplicationContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (settingValue != null) {
mStringColonSplitter.setString(settingValue);
while (mStringColonSplitter.hasNext()) {
String accessibilityService = mStringColonSplitter.next();
if (accessibilityService.equalsIgnoreCase(service)) {
return true;
}
}
}
}
return false;
}
J'espère que cela vous aidera.
Salut je suis en retard à la fête mais je suivais cette question depuis le début. Je sais que One-plus
et certains autres équipementiers maintiennent une liste d'applications qui peuvent recevoir BOOT_COMPLETED broadcast. Si votre application n'est pas listée en blanc, votre application ne sera pas démarrée au démarrage. Maintenant j'ai une solution qui est très efficace en termes de mémoire et de ressources et garantie de commencer votre tâche ou service après redémarrage ou démarrage dur aussi n'a pas besoin AccessibilityService
comme proposé dans ce réponse. Ici il va..
- Ajouter
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
l'autorisation dans votremanifest
fichier.
2.Si vous n'avez pas de dépendance sur com.google.android.gms:play-services-gcm
, ajouter ce qui suit à votre Compilation.section des dépendances de gradle:
compile 'com.firebase:firebase-jobdispatcher:0.5.2'
sinon, ajouter ce qui suit:
compile 'com.firebase:firebase-jobdispatcher-with-gcm-dep:0.5.2'
C'est un bibliothèquefirebase
l'équipe qui dépend de l' google-play-service
bibliothèque pour programmer vos travaux et de mon point de vue.google-play-service
a la permission de démarrer au démarrage ainsi, au lieu de système google-play-service
exécutera votre travail dès que l'appareil redémarré.
maintenant cette étape est facile définissez juste une classe JobService
public class MyJobService extends JobService { @Override public boolean onStartJob(JobParameters job) { Log.v("Running", "====>>>>MyJobService"); return false; // Answers the question: "Is there still work going on?" } @Override public boolean onStopJob(JobParameters job) { Log.v("Stopping", "====>>>>MyJobService"); return true; // Answers the question: "Should this job be retried?" }
}
ajouter votre service D'emploi dans le fichier de manifeste.
<service android:exported="false" android:name=".MyJobService"> <intent-filter> <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/> </intent-filter> </service>
planifiez ce travail où vous voulez pour E. g quand votre application démarre.
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(getApplicationContext())); Bundle myExtrasBundle = new Bundle(); myExtrasBundle.putString("some_key", "some_value"); Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("my-unique-tag-test") // repeat the job .setRecurring(true) // persist past a device reboot .setLifetime(Lifetime.FOREVER) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) // constraints that need to be satisfied for the job to run .setExtras(myExtrasBundle) .build(); dispatcher.mustSchedule(myJob);
6.Ça y est!! Vous pouvez maintenant exécuter votre tâche ou service on device boot peu importe que vous soyez sur liste blanche ou non.
il y a un point à noter que le service Google Play doit être installé sur le périphérique sinon il ne fonctionnera pas.
@Aritra, Essayez ce
<receiver
android:name=".mics.BootReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter android:priority="500" >
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Supprimer quickBoot intention filter et essayer de l'exécuter, selon la documentation, Nous avons seulement demandé BootCompleted pour l'atteindre. Peut-être que c'est l'interruption de ce.
un autre point important à noter:
ne vous fiez pas complètement ou ne testez pas sur les appareils Mi car ils ont leur propre système D'exploitation qui arrête les fonctionnalités de base D'Android, comme ils arrêtent les services de notification Push et les services d'arrière-plan juste pour optimiser la batterie utilisation. Pour tester cela sur le périphérique Mi, marquez votre application comme "AutoStart" dans l'application de sécurité, puis essayez.
IntentFilter
s le travail est que chacun <intent-filter></intent-filter>
contient une façon d'allumer le composant. Si vous avez plusieurs façons de tir (comme les deux actions que vous souhaitez écouter dans un BroadcastReceiver
), vous aurez besoin d'un indépendant <intent-filter></intent-filter>
définition pour chacun d'eux.
par conséquent, vous pouvez essayer de changer:
<receiver android:name=".mics.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
à:
<receiver android:name=".mics.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
Lire la suite ici: filtres D'intention et D'intention | Androïde Les développeurs
EDIT
si cela ne fonctionne toujours pas, vous pouvez essayer de tester si votre déclaration de manifeste est faite correctement. Essayez d'exécuter la commande suivante dans votre terminal, en gardant l'appareil de test connecté à l'ordinateur:
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.app.myapp/.mics.BootReceiver
si cela ne fonctionne pas, vous devriez revérifier la déclaration relative du paquet du destinataire dans votre fichier de manifeste.
EDIT 2
cela peut sembler bizarre mais essayez de suivre ces étapes:
- désinstallez l'application de votre téléphone (assurez-vous qu'elle est désinstallée pour tous les utilisateurs)
- Redémarrez votre téléphone
- Nettoyer le projet
- Construire et exécuter le projet dans votre appareil
Comment démarrer le service sur le démarrage d'un périphérique (application autorun, etc.)
pour la première fois: depuis la version Android 3.1+ vous ne recevez pas BOOT_COMPLETE si l'utilisateur n'a jamais commencé votre application au moins une fois ou l'application "force closed" de l'utilisateur. Cela a été fait pour empêcher les logiciels malveillants enregistrer automatiquement le service. Ce trou de sécurité a été fermé dans les nouvelles versions D'Android.
Solution:
Créer une application avec l'activité. Lorsque l'utilisateur l'exécute une fois l'application peut recevoir la diffusion BOOT_COMPLETE message.
pour la seconde: BOOT_COMPLETE est envoyé avant que le stockage externe ne soit monté. Si app est installé sur un stockage externe, il ne recevra pas de message de diffusion BOOT_COMPLETE.
Dans ce cas il y a deux solution:
- installez votre application sur le stockage interne
- installer une autre petite application dans le stockage interne. Cette application reçoit BOOT_COMPLETE et exécute la seconde application sur le stockage externe.
Si votre application est déjà installée dans le stockage interne puis le code ci-dessous peut vous aider à comprendre comment démarrer le service sur le démarrage de périphérique.
Dans Le Manifeste.xml
Autorisation:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
enregistrez votre récepteur BOOT_COMPLETED:
<receiver android:name="org.yourapp.OnBoot">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
inscrivez votre service:
<service android:name="org.yourapp.YourCoolService" />
récepteur OnBoot.java:
public class OnBoot extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
// Create Intent
Intent serviceIntent = new Intent(context, YourCoolService.class);
// Start service
context.startService(serviceIntent);
}
}
pour HTC vous avez peut-être aussi besoin d'ajouter dans le manifeste ce code si l'appareil n'attrape pas RECEIVE_BOOT_COMPLETED:
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
le récepteur ressemble maintenant à ceci:
<receiver android:name="org.yourapp.OnBoot">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
comment tester BOOT_COMPLETED sans redémarrer l'émulateur ou le périphérique réel? Il est facile. Essayez ceci:
adb -s device-or-emulator-id shell am broadcast -a android.intent.action.BOOT_COMPLETED
comment obtenir l'ID de périphérique? Obtenez la liste des périphériques connectés avec des id:
adb devices
bad dans ADT, par défaut, vous pouvez le trouver dans:
adt-installation-dir/sdk/platform-tools
Profitez-en! )