Спроба запустити послугу з завантаження на 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" />

Трансляція приймача

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");
    }
}

2
я не знаю, що я зробив, але я думаю, що це працює зараз, можливо, це був андроїд: дозвіл = "android.permission.RECEIVE_BOOT_COMPLETED" для одержувача
Алекс

ви перевірили зайвий "_" в <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld

Експорт повинен бути правдивим, щоб система могла викликати приймач, ні? Або це правда за замовчуванням?
Євген Печанець

Відповіді:


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
Це добре виглядає. Я буду використовувати це як основу, дякую :) Ні відмітки, ні заявок, ні відповіді сумно :(. Хтось це підтвердить?
Нанна

51
Просто доповнення: переконайтесь, що ваш додаток встановлено у внутрішній пам'яті <manifest xmlns: android = "..." package = "..." android: installLocation = "InternalOnly">
Бао Ле

2
В Android Jellybean 4.2.2 в тезі <приймач> Я повинен був використовувати відносне ім'я класу замість повністю кваліфіковане ім'я для служби , щоб почати, як зазначено в stackoverflow.com/questions/16671619 / ...
Piovezan

6
Якщо приймач використовується для різних матеріалів: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = новий намір (контекст, 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 широкомовного повідомлення.

Детальніше тут у розділі Трансляції приймачів, які слухають "завершено завантаження"


Щоб запобігти вищевказаній проблемі, розробник міг встановити "маніфест для програми" android: installLocation = "InternalOnly". Це погана ідея? Для програми для смартфонів 99,9% (наскільки я здогадуюсь) усіх користувачів нормально встановлюють додаток , використовуючи внутрішнє сховище, а не зовнішнє сховище, тоді, здається, додаток "внутрішнього" до маніфесту було б чудово. Я буду вдячний за всі ваші думки чи ідеї щодо цього.
AJW

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 вам може знадобитися також додати в Manifest цей код, якщо пристрій не застане 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

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


Ваш перший абзац був капіталом. Мені не вдалося змусити його запуститись у налагоджувачі.
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 Чи вдалося вам підтвердити, що Fast Boot - це форма сплячки, де стан системи зберігається у файловій системі? Я хочу мати змогу скинути сигнали тривоги, які використовуються для майбутніх сповіщень після швидкого завантаження, якщо стан системи не збережено ... будь ласка, порадьте.
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.
Зелімир


7

Перепробувавши всі згадані відповіді та хитрощі, я нарешті з’ясував, чому код не працює у моєму телефоні. У деяких телефонах Android, таких як "Huawei Honor 3C Android 4.2.2 ", у своїх налаштуваннях є меню " Менеджер статусів", і ваш додаток має бути зареєстровано у списку. :)


5

У мене є додатковий <category>тег, не знаю, чи це має значення.

<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. це зайве.
місячний


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 Auto завершив 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" />

Маленьке запитання, у мене є сумніви. Якщо моя служба є службою і не IntentService я не можу використовувати цей спосіб, тому що onHandleIntend метод не може бути перевизначенням в простій службі ?
paolo2988

У мене така ж проблема. Ви не проти мені допомогти? Дякую! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia

Може використовувати onNewIntent()? Або ви можете подивитися джерело для IntentService і подивитися, що вам потрібно зробити для вашої послуги, щоб вона відповідала ...
phreakhead

1

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

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


0

Я зіткнувся з цією проблемою, якщо я залишу порожній конструктор у класі приймача. Після вилучення порожнього конструктора наRreceive метос почав працювати добре.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.