Попытка запустить сервис при загрузке на Android

332

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

AndroidManifest.xml

<receiver
    android:name=".StartServiceAtBootReceiver"
    android:enabled="true"
    android:exported="false"
    android:label="StartServiceAtBootReceiver" >
    <intent-filter>
        <action android:name="android.intent.action._BOOT_COMPLETED" />
    </intent-filter>
</receiver>

<service
    android:name="com.test.RunService"
    android:enabled="true" />

BroadcastReceiver

public void onReceive(Context context, Intent intent) {
    if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
        Intent serviceLauncher = new Intent(context, RunService.class);
        context.startService(serviceLauncher);
        Log.v("TEST", "Service loaded at start");
    }
}
Alex
источник
2
я не знаю, что я сделал, но я думаю, что это работает, теперь это мог быть android :mission = "android.permission.RECEIVE_BOOT_COMPLETED" для получателя
Алекс
Вы проверили дополнительные "_" в <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld
Экспорт должен быть истинным, чтобы система могла вызывать получателя, не так ли? Или это правда по умолчанию?
Евгений Печанец
для Oreo, смотрите здесь: stackoverflow.com/questions/44502229/…
Энди Вайнштейн

Ответы:

601

Остальные ответы выглядят неплохо, но я подумал, что все это оберну в один полный ответ.

Вам нужно следующее в вашем AndroidManifest.xmlфайле:

  1. В вашей <manifest>стихии:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. В вашем <application>элементе (обязательно используйте полное имя [или относительного] класса для вашего BroadcastReceiver):

    <receiver android:name="com.example.MyBroadcastReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.BOOT_COMPLETED" />  
        </intent-filter>  
    </receiver>

    (вам не нужно android:enabled, exportedи т.д., атрибуты: андроид по умолчанию является правильным)

    В MyBroadcastReceiver.java:

    package com.example;
    
    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Intent startServiceIntent = new Intent(context, MyService.class);
            context.startService(startServiceIntent);
        }
    }

Из оригинального вопроса:

  • не ясно, был ли <receiver>элемент в <application>элементе
  • это не ясно , если правильно полностью квалифицирован (или относительное) имя класса для BroadcastReceiverбыло указано
  • была опечатка в <intent-filter>
Тимо Брук
источник
2
Это выглядит хорошо. Я собираюсь использовать это как основу, спасибо :). . Ни одна галочка или upvotes или ответ печально :( Кто - нибудь не проверить это?
Nanne
51
Просто дополнение: убедитесь, что ваше приложение установлено во внутренней памяти <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Бао Ле
2
В Android Jellybean 4.2.2 в теге <receiver> мне пришлось использовать относительное имя класса вместо полного имени для запуска службы, как отмечено в stackoverflow.com/questions/16671619/…
Piovezan
6
Если получатель используется для разных вещей: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (context, Service_Location.class); // i.putExtra ("KEY1", "Значение, которое будет использоваться службой"); context.startService (serviceIntent); }
Гуннар Бернштейн
2
Вместо этого вы должны расширить developer.android.com/reference/android/support/v4/content/… Он является помощником для общего шаблона реализации BroadcastReceiver, который получает событие активации устройства, а затем передает работу сервису, гарантируя, что устройство не переходит в спящий режим во время перехода. Этот класс заботится о создании и управлении частичной блокировкой пробуждения для вас; Вы должны запросить разрешение WAKE_LOCK, чтобы использовать его.
Дамиан
84

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

Подробнее здесь, в разделе Приемники вещания, прослушивающие "загрузка завершена"

inazaruk
источник
Чтобы предотвратить вышеуказанную проблему, разработчик может установить «android: installLocation =« internalOnly »в манифесте для приложения. Это плохая идея? Для приложения для смартфонов, если 99,9% (мое предположение) всех пользователей устанавливают приложение нормально Если использовать внутреннее хранилище, а не внешнее хранилище, то кажется, что дополнение "internalOnly" к манифесту будет в порядке. Буду признателен за любые ваши мысли или идеи по этому
поводу
69

Как запустить службу при загрузке устройства (приложение автозапуска и т. Д.)

Для начала: начиная с версии Android 3.1+ вы не получите BOOT_COMPLETE, если пользователь никогда не запускал ваше приложение или пользователь «принудительно закрывал» приложение. Это было сделано для того, чтобы вредоносная программа автоматически не регистрировала сервис. Эта дыра в безопасности была закрыта в новых версиях Android.

Решение:

Создать приложение с активностью. Когда пользователь запускает его один раз, приложение может получить широковещательное сообщение BOOT_COMPLETE.

Для второго: BOOT_COMPLETE отправляется до монтирования внешнего хранилища. Если приложение установлено во внешнее хранилище, оно не получит широковещательное сообщение BOOT_COMPLETE.

В этом случае есть два решения:

  1. Установите приложение во внутреннее хранилище
  2. Установите другое маленькое приложение во внутреннем хранилище. Это приложение получает BOOT_COMPLETE и запускает второе приложение на внешнем хранилище.

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


В Manifest.xml

Разрешение:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Зарегистрируйте своего получателя BOOT_COMPLETED:

<receiver android:name="org.yourapp.OnBoot">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>

Зарегистрируйте свой сервис:

<service android:name="org.yourapp.YourCoolService" />

В получателе 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);

    }

 }

Для HTC вам может понадобиться добавить этот код в манифест, если устройство не перехватывает RECEIVE_BOOT_COMPLETED:

<action android:name="android.intent.action.QUICKBOOT_POWERON" />

Приемник теперь выглядит так:

<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>

Как проверить BOOT_COMPLETED без перезагрузки эмулятора или реального устройства? Это просто. Попробуй это:

adb -s device-or-emulator-id shell am broadcast -a android.intent.action.BOOT_COMPLETED

Как получить идентификатор устройства? Получить список подключенных устройств с идентификаторами:

adb devices

ADB в ADT по умолчанию вы можете найти в:

adt-installation-dir/sdk/platform-tools

Наслаждайтесь! )

user3439968
источник
Ваш первый абзац был заглавным. Я не смог заставить его работать в моем отладчике.
Estornes
34

Вместе с

<action android:name="android.intent.action.BOOT_COMPLETED" />  

также использовать,

<action android:name="android.intent.action.QUICKBOOT_POWERON" />

Устройства HTC, кажется, не ловят BOOT_COMPLETED

Тони
источник
Нужно добавить что-нибудь подобное в разрешениях для устройств HTC?
Нанда
2
Это может быть полезно в некоторых случаях, но я понимаю, что быстрая загрузка HTC - это форма гибернации, когда состояние системы сохраняется в файловой системе, а android.intent.action.QUICKBOOT_POWERONотправляется только при восстановлении из быстрой загрузки. Это означает, что нет необходимости выполнять такие действия, как сброс аварийных сигналов при восстановлении из быстрой загрузки, поскольку они сохраняются. Поэтому использовать его нужно только в том <action android:name="android.intent.action.QUICKBOOT_POWERON" />случае, если вы хотите что-то сделать, когда пользователь считает, что устройство загружено.
HexAndBugs
2
С точки зрения разработчика приложений, мы никогда не должны использовать это, если такое поведение существует только на устройствах HTC. Потому что BOOT_COMPLETED, согласно документации, всегда будет отправляться при включении устройства. Какой-то другой производитель мог бы предложить другой метод быстрой загрузки, и мы бы в итоге испортили наш код со спецификациями каждого из них.
Субин Себастьян
@HexAndBugs Удалось ли вам подтвердить, что быстрая загрузка является формой гибернации, когда состояние системы сохраняется в файловой системе? Я хочу иметь возможность сброса аварийных сигналов, которые используются для будущих уведомлений после быстрой загрузки, если состояние системы не сохраняется ... пожалуйста, сообщите.
AJW
20

обратите внимание, что в начале вопроса есть ошибка опечатки:

<action android:name="android.intent.action._BOOT_COMPLETED"/>

вместо того :

<action android:name="android.intent.action.BOOT_COMPLETED"/>

одна маленькая "_" и все это беда :)

Евгений Эрлихман
источник
13

Я только сейчас узнал, что это может быть из-за Fast Bootварианта вSettings >Power

Когда эта опция отключена, мое приложение получает эту трансляцию, но не иначе.

Кстати, у меня есть Android 2.3.3наHTC Incredible S .

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

Омер Ахтер
источник
Определенно возможная причина проблемы. Наблюдается также на HTC Desire C под управлением Android 4.0.3.
Зелимир,
12

Я думаю, что ваш манифест должен добавить:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
RickNotFred
источник
У меня та же проблема. Вы не против помочь мне? Спасибо! stackoverflow.com/questions/35373525/starting-my-service
Ручир Барония
7

Перепробовав все упомянутые ответы и хитрости, я, наконец, выяснил, почему код не работает в моем телефоне. Некоторые телефоны Android, такие как «Huawei Honor 3C Android 4.2.2 », имеют в своем меню меню Statup Manager, и ваше приложение должно быть проверено в списке. :)

эмир
источник
5

У меня есть дополнительный <category>-tag, не знаю, имеет ли это какое-то значение.

<receiver android:name="BootIntentReceiver">  
        <intent-filter>  
            <action android:name="android.intent.action.BOOT_COMPLETED" />  
            <category android:name="android.intent.category.HOME" />  
        </intent-filter>  
</receiver>

Вы пытались опустить предложение if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), так как получатель, вероятно, в любом случае получает только это намерение?

Ник
источник
попробовал это, и это не сработало, кстати, я забыл упомянуть, у меня также есть <использовании-разрешения android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Алекс
2
на всякий случай: добавление android.intent.category.HOME к любому тегу в AndroidManifest приведет к тому, что на вкладке Samsung Galaxy Tab приложение будет запущено в режиме совместимости, даже после взлома, чтобы отключить режим совместимости. не уверен, если это то же самое для других вкладок. я рекомендую вообще не устанавливать категорию HOME. это не нужно
Moonlightcheese
3

Перед монтированием внешнего хранилища отправляется BOOT_COMPLETE execute.Если ваше приложение установлено во внешнее хранилище, оно не получит широковещательное сообщение BOOT_COMPLETE. Чтобы предотвратить это, вы можете установить приложение во внутреннем хранилище. Вы можете сделать это, просто добавив эту строку в menifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
... >

Некоторые устройства HTC могут включать функцию «быстрой загрузки», которая больше похожа на глубокую спячку, а не на реальную перезагрузку и поэтому не должна давать намерение BOOT_COMPLETE. Чтобы восстановить это, вы можете добавить этот фильтр намерений внутри вашего приемника:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
Г-н Саджедул Карим
источник
Как вы предлагаете, чтобы предотвратить вышеупомянутую проблему, разработчик может установить "android: installLocation =" internalOnly "в манифесте для приложения. Это плохая идея? Для приложения для смартфонов, если 99,9% (мое предположение) от всех пользователей обычно устанавливайте приложение, используя внутреннее хранилище, а не внешнее хранилище, тогда кажется, что дополнение "internalOnly" к манифесту будет в порядке. Буду признателен за любые ваши мысли или идеи по этому поводу. - AJW
AJW
3

Это то что я сделал

1. Я сделал класс приемника

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //whatever you want to do on boot
       Intent serviceIntent = new Intent(context, YourService.class);
       context.startService(serviceIntent);
    }
}

2. в манифесте

<manifest...>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <application...>
        <receiver android:name=".BootReceiver" android:enabled="true" android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    ...

3.И после ВСЕГО, ЧТО ВАМ НУЖНО «установить» приемник в MainActivity, он может находиться внутри onCreate.

...
 final ComponentName onBootReceiver = new ComponentName(getApplication().getPackageName(), BootReceiver.class.getName());
        if(getPackageManager().getComponentEnabledSetting(onBootReceiver) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
        getPackageManager().setComponentEnabledSetting(onBootReceiver,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
...

последний шаг, который я узнал от ApiDemos

Сан Хуан
источник
2

Если вы используете Android Studio и очень любите автозаполнение, я должен сообщить вам, что я использую Android Studio v 1.1.0 и использовал автозаполнение для получения следующего разрешения.

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

И Android Studio автоматически заполнял RECEIVE_BOOT_COMPLETEDвсе в нижнем регистре, как receive_boot_completedи я продолжал вырывать волосы, потому что я уже отмечал свой контрольный список для вещей, чтобы сделать, чтобы начать обслуживание при загрузке Я только что подтвердил еще раз

Android Studio автоматически заполняет это разрешение в нижнем регистре.

Харун Дильшад
источник
2

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

public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // This is the Intent to deliver to our service.
        Intent service = new Intent(context, SimpleWakefulService.class);

        // Start the service, keeping the device awake while it is launching.
        Log.i("SimpleWakefulReceiver", "Starting service @ " + SystemClock.elapsedRealtime());
        startWakefulService(context, service);
    }
}

затем, в вашем Сервисе, обязательно снимите блокировку пробуждения:

    @Override
    protected void onHandleIntent(Intent intent) {
        // At this point SimpleWakefulReceiver is still holding a wake lock
        // for us.  We can do whatever we need to here and then tell it that
        // it can release the wakelock.

...
        Log.i("SimpleWakefulReceiver", "Completed service @ " + SystemClock.elapsedRealtime());
        SimpleWakefulReceiver.completeWakefulIntent(intent);
    }

Не забудьте добавить разрешение WAKE_LOCK на свой основной фестиваль:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
источник
Маленький вопрос, у меня есть сомнения. Если мой сервис является Сервисом, а не IntentService, я не могу использовать этот способ, потому что метод onHandleIntend не может быть переопределен в простом Сервисе ?
paolo2988
У меня та же проблема. Вы не против помочь мне? Спасибо! stackoverflow.com/questions/35373525/starting-my-service
Ручир Барония
Может быть, использовать onNewIntent()? Или вы можете посмотреть на источник IntentService и посмотреть, что вам нужно сделать, чтобы ваш Сервис соответствовал ...
phreakhead
1

На самом деле, я попал в эту проблему не так давно, и это действительно очень легко исправить, вы на самом деле ничего не делаете неправильно, если вы настраиваете "android.intent.action.BOOT_COMPLETED" разрешение и намеренный фильтр.

Обратите внимание, что если вы работаете на Android 4.X, вам нужно запустить широковещательный приемник, прежде чем запускать службу при загрузке, это означает, что вы должны сначала добавить действие, как только ваш широковещательный приемник запустится, ваше приложение должно функционировать так, как вы ожидали, однако в Android 4.X я не нашел способа запустить службу при загрузке без какой-либо активности, я думаю, что Google сделал это по соображениям безопасности.

Дэвид Хх
источник
0

Я столкнулся с этой проблемой, если я оставлю пустой конструктор в классе получателя. После удаления пустого contsructor onRreceive методы начали работать нормально.

redrom
источник