Próba uruchomienia usługi przy rozruchu na Androidzie


332

Próbowałem uruchomić usługę, gdy urządzenie uruchamia się na Androidzie, ale nie mogę go uruchomić. Przejrzałem kilka linków online, ale żaden kod nie działa. Czy coś zapomniałem?

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

Odbiornik transmisji

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
nie wiem, co zrobiłem, ale myślę, że teraz działa. Może to być android: pozwolenie = "android.permission.RECEIVE_BOOT_COMPLETED" dla odbiornika
Alex

czy zaznaczyłeś dodatkowe „_” w <działanie android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld

Wyeksportowane muszą być prawdziwe, aby system mógł wywołać odbiornik, nie? Czy jest to prawda domyślnie?
Eugen Pechanec

jeśli chodzi o Oreo, spójrz tutaj: stackoverflow.com/questions/44502229/…
Andy Weinstein

Odpowiedzi:


601

Pozostałe odpowiedzi wyglądają dobrze, ale pomyślałem, że zawinę wszystko w jedną pełną odpowiedź.

W twoim AndroidManifest.xmlpliku potrzebujesz :

  1. W twoim <manifest>elemencie:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. W swoim <application>elemencie (pamiętaj o użyciu w pełni kwalifikowanej [lub względnej] nazwy klasy BroadcastReceiver):

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

    (nie potrzebne android:enabled, exporteditd atrybuty: Android domyślne są poprawne)

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

Z pierwotnego pytania:

  • nie jest jasne, czy <receiver>element był w <application>elemencie
  • nie jest jasne, czy poprawne pełni kwalifikowana (lub względna) nazwę klasy dla BroadcastReceiverpodano
  • w literaturze było literówka <intent-filter>

2
To wygląda dobrze. Wykorzystam to jako podstawę, dzięki :). . Brak zaznaczenia lub upvotes lub odpowiedź niestety :( Ktoś to sprawdzić?
Nanne

51
Tylko uzupełnienie: upewnij się, że aplikacja jest zainstalowana w pamięci wewnętrznej <manifest xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le

2
W Androidzie Jellybean 4.2.2 w znaczniku <receiver> musiałem użyć względnej nazwy klasy zamiast pełnej nazwy, aby usługa mogła zostać uruchomiona, jak zauważono w stackoverflow.com/questions/16671619/...
Piovezan

6
Jeśli odbiornik jest używany do różnych rzeczy: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (kontekst, Service_Location.class); // i.putExtra („KEY1”, „Wartość do użycia przez usługę”); context.startService (serviceIntent); }
Gunnar Bernstein

2
Zamiast tego powinieneś rozszerzyć developer.android.com/reference/android/support/v4/content/… . Jest to pomocnik dla wspólnego wzorca wdrażania BroadcastReceiver, który odbiera zdarzenie budzenia urządzenia, a następnie przekazuje pracę do usługi, zapewniając jednocześnie, że urządzenie nie przejdzie w stan uśpienia podczas przejścia. Ta klasa zajmuje się tworzeniem i zarządzaniem częściową blokadą aktywacji; musisz poprosić o pozwolenie WAKE_LOCK, aby z niego korzystać.
Damian

84

Jako dodatkowe informacje: BOOT_COMPLETE jest wysyłany do aplikacji przed zamontowaniem pamięci zewnętrznej. Jeśli więc aplikacja zostanie zainstalowana w pamięci zewnętrznej, nie otrzyma komunikatu emisji BOOT_COMPLETE.

Więcej szczegółów tutaj w sekcji Odbiorniki emisji nasłuchują na „rozruch zakończony”


Aby zapobiec powyższemu problemowi, programista może ustawić w manifeście aplikacji „android: installLocation =„ internalOnly ”. Czy to zły pomysł? W przypadku aplikacji na smartfony, jeśli 99,9% (jak sądzę) wszystkich użytkowników instaluje aplikację normalnie , używając pamięci wewnętrznej zamiast pamięci zewnętrznej, wydaje się, że dodatek do manifestu „InternalOnly” byłby w porządku. Byłbym wdzięczny za wszelkie twoje przemyślenia i pomysły na ten temat.
AJW

69

Jak uruchomić usługę po uruchomieniu urządzenia (aplikacja autorun itp.)

Po pierwsze: od wersji Androida 3.1+ nie otrzymasz BOOT_COMPLETE, jeśli użytkownik nigdy nie uruchomił Twojej aplikacji przynajmniej raz lub użytkownik „wymusi zamknięcie” aplikacji. Zrobiono to, aby zapobiec automatycznemu rejestrowaniu usługi przez złośliwe oprogramowanie. Luka w zabezpieczeniach została zamknięta w nowszych wersjach Androida.

Rozwiązanie:

Utwórz aplikację z aktywnością. Gdy użytkownik uruchomi go raz, aplikacja może odebrać komunikat emisji BOOT_COMPLETE.

Po drugie: BOOT_COMPLETE jest wysyłane przed podłączeniem pamięci zewnętrznej. Jeśli aplikacja jest zainstalowana w pamięci zewnętrznej, nie otrzyma komunikatu emisji BOOT_COMPLETE.

W tym przypadku istnieją dwa rozwiązania:

  1. Zainstaluj aplikację w pamięci wewnętrznej
  2. Zainstaluj kolejną małą aplikację w pamięci wewnętrznej. Ta aplikacja otrzymuje BOOT_COMPLETE i uruchamia drugą aplikację na pamięci zewnętrznej.

Jeśli Twoja aplikacja jest już zainstalowana w pamięci wewnętrznej, poniższy kod może pomóc zrozumieć, jak uruchomić usługę po uruchomieniu urządzenia.


W pliku Manifest.xml

Pozwolenie:

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

Zarejestruj swój odbiornik BOOT_COMPLETED:

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

Zarejestruj swoją usługę:

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

W odbiorniku 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);

    }

 }

W przypadku HTC może być konieczne dodanie Manifestuj ten kod, jeśli urządzenie nie wyłapuje RECEIVE_BOOT_COMPLETED:

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

Odbiornik wygląda teraz tak:

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

Jak przetestować BOOT_COMPLETED bez restartu emulatora lub rzeczywistego urządzenia? To jest łatwe. Spróbuj tego:

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

Jak uzyskać identyfikator urządzenia? Uzyskaj listę podłączonych urządzeń o identyfikatorach:

adb devices

adb w ADT domyślnie można znaleźć w:

adt-installation-dir/sdk/platform-tools

Cieszyć się! )


Twój pierwszy akapit był kapitałem. Nie udało mi się uruchomić go w moim debuggerze.
estornes

34

Wraz z

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

Użyj również,

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

Wygląda na to, że urządzenia HTC nie łapią BOOT_COMPLETED


Chcesz dodać coś podobnego do uprawnień dla urządzeń HTC?
Nanda

2
Może to być przydatne w niektórych okolicznościach, ale rozumiem, że HTC Fast Boot jest formą hibernacji, w której stan systemu jest zapisywany w systemie plików i android.intent.action.QUICKBOOT_POWERONjest wysyłany tylko podczas przywracania z szybkiego rozruchu. Oznacza to, że nie trzeba wykonywać resetowania alarmów podczas odzyskiwania po szybkim rozruchu, ponieważ są one zachowane. Dlatego konieczne byłoby użycie, <action android:name="android.intent.action.QUICKBOOT_POWERON" />jeśli chcesz coś zrobić, gdy użytkownik myśli, że urządzenie zostało uruchomione.
HexAndBugs

2
Z perspektywy twórcy aplikacji nigdy nie powinniśmy tego używać, jeśli takie zachowanie istnieje tylko na urządzeniach HTC. Ponieważ BOOT_COMPLETED jest, zgodnie z dokumentacją, zawsze będzie wysyłany, gdy urządzenie się włączy. Niektórzy inni producenci mogliby wymyślić inną metodę szybkiego uruchamiania i skończylibyśmy na tym, że zepsuliśmy nasz kod specyfikacją każdego z nich.
Subin Sebastian,

@HexAndBugs Czy udało Ci się potwierdzić, że Fast Boot jest formą hibernacji, w której stan systemu jest zapisywany w systemie plików? Chcę mieć możliwość resetowania alarmów używanych w przyszłych powiadomieniach po szybkim rozruchu, jeśli stan systemu nie zostanie zapisany ... proszę o poradę.
AJW

20

zwróć uwagę, że na początku pytania występuje literówka:

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

zamiast :

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

jedno małe „_” i wszystkie te kłopoty :)


13

Właśnie się dowiedziałem, że może to wynikać z Fast Bootopcji w Settings>Power

Po wyłączeniu tej opcji moja aplikacja odbiera tę transmisję, ale nie inaczej.

Nawiasem mówiąc, mam Android 2.3.3na sobie HTC Incredible S.

Mam nadzieję, że to pomoże.


Zdecydowanie możliwa przyczyna problemu. Obserwowano również w telefonie HTC Desire C z systemem Android 4.0.3.
Zelimir


7

Po wypróbowaniu wszystkich wymienionych odpowiedzi i sztuczek w końcu odkrywam, dlaczego kod nie działa w moim telefonie. Niektóre telefony z Androidem, takie jak „Huawei Honor 3C Android 4.2.2 ”, mają menu Menedżera Statup w swoich ustawieniach, a twoja aplikacja musi być zaznaczona na liście. :)


5

Mam dodatkowy <category>znacznik, nie wiem, czy to coś zmienia.

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

Czy próbowałeś ominąć klauzulę „if” "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), ponieważ odbiorca prawdopodobnie i tak odbiera tę intencję?


próbowałem tego i nie zadziałało, bo zapomniałem wspomnieć, że mam również <uses-permission android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex

2
na wszelki wypadek: dodanie android.intent.category.HOME do dowolnego znacznika w AndroidManifest spowoduje, że Samsung Galaxy Tab uruchomi aplikację w trybie zgodności, nawet po użyciu włamania do wyłączenia trybu zgodności. Nie jestem pewien, czy jest tak samo w przypadku innych kart. zalecam, aby w ogóle nie ustawiać kategorii DOM. to niepotrzebne.
moonlightcheese,


3

Przed zainstalowaniem pamięci zewnętrznej BOOT_COMPLETE jest wysyłane jako wykonanie. Jeśli aplikacja jest zainstalowana w pamięci zewnętrznej, nie otrzyma komunikatu emisji BOOT_COMPLETE. Aby temu zapobiec, możesz zainstalować aplikację w pamięci wewnętrznej. możesz to zrobić po prostu dodając ten wiersz w menifest.xml

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

Niektóre urządzenia HTC mogą włączyć funkcję „szybkiego rozruchu”, która bardziej przypomina głęboką hibernację i nie jest prawdziwym ponownym uruchomieniem, a zatem nie powinna dawać intencji BOOT_COMPLETE. Aby to odzyskać, możesz dodać ten filtr intencji do odbiornika:

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

Jak sugerujesz, aby zapobiec powyższemu problemowi, programista może ustawić w manifeście aplikacji „android: installLocation =„ internalOnly ”. Czy to zły pomysł? W przypadku aplikacji na smartfony, jeśli 99,9% (zgaduję) wszystkich użytkowników zainstaluj aplikację normalnie, używając pamięci wewnętrznej zamiast zewnętrznej, wtedy wydaje się, że dodatek do manifestu „internalOnly” byłby w porządku. Byłbym wdzięczny za wszelkie twoje przemyślenia i pomysły na ten temat. - AJW
AJW

3

Oto co zrobiłem

1. Zrobiłem klasę Odbiornika

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. w manifeście

<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. i po WSZYSTKIM, CO POTRZEBUJESZ „ustawić” odbiornik w MainActivity, może on znajdować się w

...
 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);
...

ostatnia kupa, której nauczyłem się od ApiDemos


2

Jeśli korzystasz z Android Studio i bardzo lubisz autouzupełnianie, muszę Cię poinformować, że korzystam z Android Studio w wersji 1.1.0 i użyłem autouzupełniania dla następujących uprawnień

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

Android Studio automatycznie ukończył RECEIVE_BOOT_COMPLETEDwszystko małymi literami, receive_boot_completeda ja wciąż wyciągałem włosy, ponieważ już zaznaczyłem moją listę kontrolną, aby dowiedzieć się, co zrobić, aby rozpocząć obsługę przy rozruchu. Właśnie potwierdziłem ponownie

Android Studio NIE wypełnia automatycznie tego uprawnienia małymi literami.


2

Jak skomentował @Damian, wszystkie odpowiedzi w tym wątku robią to źle. Wykonanie tego ręcznie w ten sposób grozi zatrzymaniem Usługi na środku z powodu uśpienia urządzenia. Najpierw musisz uzyskać blokadę aktywacji. Na szczęście biblioteka Wsparcia daje nam klasę, aby to zrobić:

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

następnie w swojej usłudze pamiętaj o zwolnieniu blokady aktywacji:

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

Nie zapomnij dodać uprawnienia WAKE_LOCK do swojego Mainfest:

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

Małe pytanie, mam wątpliwości. Jeśli moja usługa jest usługą, a nie IntentService, nie mogę korzystać z tej metody, ponieważ metody onHandleIntend nie można zastąpić w prostej usłudze ?
paolo2988,

Mam ten sam problem. Czy możesz mi pomóc? Dzięki! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia

Może użyć onNewIntent()? Lub możesz spojrzeć na źródło IntentService i zobaczyć, co musisz zrobić, aby Twoja usługa się dopasowała ...
phreakhead

1

W rzeczywistości ostatnio wpadłem w ten problem i naprawdę bardzo łatwo go naprawić, właściwie nie robisz nic złego, jeśli skonfigurujesz "android.intent.action.BOOT_COMPLETED"zezwolenie i filtr celowy.

Pamiętaj, że jeśli korzystasz z systemu Android 4.X, musisz uruchomić nasłuchiwanie rozgłoszeniowe przed uruchomieniem usługi przy rozruchu, co oznacza, że ​​musisz najpierw dodać aktywność, po uruchomieniu odbiornika rozgłoszeniowego aplikacja powinna działać zgodnie z oczekiwaniami, jednak na Androidzie 4.X nie znalazłem sposobu na uruchomienie usługi przy rozruchu bez żadnej aktywności, myślę, że Google zrobiło to ze względów bezpieczeństwa.


0

Napotkałem ten problem, jeśli zostawię pusty konstruktor w klasie odbiornika. Po usunięciu pustego contsructor onOdbiorczy metos zaczął działać dobrze.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.