Tentando iniciar um serviço na inicialização no Android

332

Estou tentando iniciar um serviço quando um dispositivo é inicializado no Android, mas não consigo fazê-lo funcionar. Eu olhei para vários links online, mas nenhum código funciona. Estou esquecendo alguma coisa?

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

Receptor de radiodifusão

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
fonte
2
eu não sei o que eu fiz, mas eu acho que funciona agora que poderia ter sido o android: permission = "android.permission.RECEIVE_BOOT_COMPLETED" para o receptor
Alex
você verificou o "_" extra em <ação android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld 4/11
Exportado deve ser verdadeiro para que o sistema possa chamar o receptor, não? Ou é verdade por padrão?
Eugen Pechanec 15/09/16
para Oreo, veja aqui: stackoverflow.com/questions/44502229/…
Andy Weinstein

Respostas:

601

As outras respostas parecem boas, mas pensei em agrupar tudo em uma resposta completa.

Você precisa do seguinte em seu AndroidManifest.xmlarquivo:

  1. No seu <manifest>elemento:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. No seu <application>elemento (certifique-se de usar um nome de classe totalmente qualificado [ou relativo] para o seu BroadcastReceiver):

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

    (você não precisa o android:enabled, exportedetc., atributos: os padrões do Android estão corretas)

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

Da pergunta original:

  • não está claro se o <receiver>elemento estava no <application>elemento
  • não está claro se o nome correto da classe totalmente qualificado (ou relativo) para o BroadcastReceiverfoi especificado
  • houve um erro de digitação no <intent-filter>
Timo Bruck
fonte
2
Este parece ser bom. Vou usar isso como base, obrigado :). . Sem marca ou upvotes ou resposta, infelizmente :( Qualquer verificar isso?
Nanne
51
Apenas um complemento: Verifique se o seu aplicativo é instalar na memória interna <manifestam xmlns: android = "..." package = "..." android: installLocation = "InternalOnly">
Bao Le
2
No Android Jellybean 4.2.2 na tag <receiver>, eu tive que usar o nome relativo da classe em vez do nome completo para o serviço iniciar, conforme observado em stackoverflow.com/questions/16671619/…
Piovezan
6
Se o receptor for usado para coisas diferentes: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intenção serviceIntent = new Intent (contexto, Service_Location.class); // i.putExtra ("KEY1", "Valor a ser usado pelo serviço"); context.startService (serviceIntent); }
Gunnar Bernstein
2
Você deve estender o developer.android.com/reference/android/support/v4/content/… . É um Auxiliar para o padrão comum de implementação de um BroadcastReceiver que recebe um evento de ativação do dispositivo e passa o trabalho para um Serviço, garantindo que o dispositivo não volte a dormir durante a transição. Esta classe cuida de criar e gerenciar um bloqueio de ativação parcial para você; você deve solicitar a permissão WAKE_LOCK para usá-lo.
Damian
84

Como informações adicionais: BOOT_COMPLETE é enviado aos aplicativos antes da montagem do armazenamento externo. Portanto, se o aplicativo estiver instalado no armazenamento externo, ele não receberá a mensagem de difusão BOOT_COMPLETE.

Mais detalhes aqui na seção Receptores de transmissão que ouvem "inicialização concluída"

inazaruk
fonte
Para evitar o problema acima, o desenvolvedor pode definir "android: installLocation =" internalOnly "no manifesto de um aplicativo. É uma má idéia? Para um aplicativo de smartphone, se 99,9% (meu palpite) de todos os usuários instalarem o aplicativo normalmente , usando armazenamento interno ao invés de armazenamento externo, então parece que a adição "InternalOnly" para o manifesto seria bom eu gostaria de receber quaisquer pensamentos ou idéias que você tem sobre este assunto..
AJW
69

Como iniciar o serviço na inicialização do dispositivo (aplicativo de execução automática, etc.)

Primeiro: desde a versão Android 3.1+, você não recebe o BOOT_COMPLETE se o usuário nunca iniciou o aplicativo pelo menos uma vez ou se o aplicativo "força o fechamento". Isso foi feito para impedir que o malware registrasse automaticamente o serviço. Essa falha de segurança foi fechada nas versões mais recentes do Android.

Solução:

Crie aplicativo com atividade. Quando o usuário o executa, uma vez que o aplicativo pode receber a mensagem de transmissão BOOT_COMPLETE.

Por segundo: BOOT_COMPLETE é enviado antes da montagem do armazenamento externo. Se o aplicativo estiver instalado no armazenamento externo, ele não receberá a mensagem de difusão BOOT_COMPLETE.

Nesse caso, há duas soluções:

  1. Instale seu aplicativo no armazenamento interno
  2. Instale outro aplicativo pequeno no armazenamento interno. Este aplicativo recebe BOOT_COMPLETE e executa o segundo aplicativo no armazenamento externo.

Se seu aplicativo já estiver instalado no armazenamento interno, o código abaixo pode ajudá-lo a entender como iniciar o serviço na inicialização do dispositivo.


Em Manifest.xml

Permissão:

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

Registre seu receptor BOOT_COMPLETED:

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

Registre seu serviço:

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

No receptor 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);

    }

 }

Para a HTC, talvez você também precise adicionar no manifesto esse código se o dispositivo não capturar RECEIVE_BOOT_COMPLETED:

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

O receptor agora fica assim:

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

Como testar o BOOT_COMPLETED sem reiniciar o emulador ou dispositivo real? É fácil. Tente o seguinte:

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

Como obter o ID do dispositivo? Obtenha a lista de dispositivos conectados com IDs:

adb devices

adb no ADT, por padrão, você pode encontrar em:

adt-installation-dir/sdk/platform-tools

Aproveitar! )

user3439968
fonte
Seu primeiro parágrafo foi em maiúscula. Não consegui fazê-lo funcionar no meu depurador.
estornes 27/07
34

Junto com

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

também use,

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

Os dispositivos HTC parecem não pegar BOOT_COMPLETED

Tony
fonte
Precisa adicionar algo semelhante nas permissões para dispositivos HTC?
Nanda
2
Isso pode ser útil em algumas circunstâncias, mas entendo que o HTC Fast Boot é uma forma de hibernação em que o estado do sistema é salvo no sistema de arquivos e android.intent.action.QUICKBOOT_POWERONé enviado apenas ao restaurar a partir da inicialização rápida. Isso significa que não é necessário executar ações como redefinir alarmes ao se recuperar do Fast Boot à medida que eles são preservados. Portanto, só seria necessário usar <action android:name="android.intent.action.QUICKBOOT_POWERON" />se você quiser fazer algo quando o usuário achar que o dispositivo foi inicializado.
HexAndBugs
2
Da perspectiva de um desenvolvedor de aplicativos, nunca devemos usar isso, se o comportamento existir apenas em dispositivos HTC. Como BOOT_COMPLETED é, conforme a documentação, sempre será enviado quando o dispositivo LIGAR. Algum outro fabricante poderia criar outro método de inicialização rápida e acabaríamos mexendo no nosso código com as especificações de cada um.
Subin Sebastian
@HexAndBugs Você conseguiu confirmar que a Inicialização Rápida é uma forma de hibernação em que o estado do sistema é salvo no sistema de arquivos? Desejo redefinir os alarmes usados ​​para futuras Notificações após uma Inicialização Rápida, se o estado do sistema não for salvo ... por favor, informe.
AJW
20

Observe que, no início da pergunta, há um erro de digitação:

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

ao invés de :

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

um pequeno "_" e todo esse problema :)

Evgeny Erlihman
fonte
13

Eu descobri agora que isso pode ser por causa da Fast Bootopção em Settings>Power

Quando essa opção está desativada, meu aplicativo recebe uma transmissão desta, mas não o contrário.

By the way, eu tenho Android 2.3.3em HTC Incredible S.

Espero que ajude.

Omer Akhter
fonte
Definitivamente possível causa do problema. Observado também no HTC Desire C com Android 4.0.3.
Zelimir
7

Depois de tentar todas as respostas e truques mencionados, finalmente descubro por que o código não está funcionando no meu telefone. Alguns telefones Android como "Huawei Honor 3C Android 4.2.2 " têm um menu do Statup Manager em suas configurações e seu aplicativo deve ser verificado na lista. :)

Amir
fonte
5

Eu tenho uma <category>marca adicional , não sei se isso faz alguma diferença.

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

Você já tentou omitir a cláusula if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), pois o receptor provavelmente só recebe essa intenção de qualquer maneira?

usuario
fonte
tentei isso e não funcionou btw i esqueceu de mencionar também tenho a <usos-permissão Android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex
2
por precaução: adicionar android.intent.category.HOME a qualquer tag no AndroidManifest fará com que o Samsung Galaxy Tab execute o aplicativo no modo de compatibilidade, mesmo depois de usar o hack para desativar o modo de compatibilidade. não tenho certeza se isso é o mesmo para outras guias. eu recomendo não definir a categoria HOME. é desnecessário.
moonlightcheese
3

Antes de montar o armazenamento externo, o BOOT_COMPLETE é enviado, execute. Se o aplicativo estiver instalado no armazenamento externo, ele não receberá a mensagem de difusão do BOOT_COMPLETE. Para evitar isso, você pode instalar seu aplicativo no armazenamento interno. você pode fazer isso apenas adicionando esta linha no menifest.xml

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

Alguns dispositivos HTC podem ativar um recurso de "inicialização rápida" que é mais como uma hibernação profunda e não uma reinicialização real e, portanto, não deve dar a intenção BOOT_COMPLETE. Para recuperar isso, você pode adicionar este filtro de intenção dentro do seu receptor:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
Md. Sajedul Karim
fonte
Como você sugere, para evitar o problema acima, o desenvolvedor pode definir "android: installLocation =" internalOnly "no manifesto de um aplicativo. É uma má idéia? Para um aplicativo de smartphone, se 99,9% (meu palpite) de todos os usuários instalar o aplicativo normalmente, usando armazenamento interno ao invés de armazenamento externo, então parece que a adição "InternalOnly" para o manifesto seria bom eu gostaria de receber quaisquer pensamentos ou idéias que você tem sobre isso -.. AJW
AJW
3

Foi o que eu fiz

1. Eu fiz a classe Receiver

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.no manifesto

<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.e depois de TUDO que você precisa "configurar" o receptor em sua MainActivity, ele pode estar dentro do 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);
...

o último salto que aprendi com o ApiDemos

San Juan
fonte
2

Se você estiver usando o Android Studio e gosta muito do preenchimento automático, devo informá-lo, estou usando o Android Studio v 1.1.0 e usei o preenchimento automático para a seguinte permissão

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

E o Android Studio completou automaticamente RECEIVE_BOOT_COMPLETEDtudo em letras minúsculas receive_boot_completede eu continuei puxando meu cabelo porque já tinha marcado minha lista de verificação para saber o que fazer para iniciar o serviço na inicialização. Acabei de confirmar novamente

O Android Studio COMPLETA automaticamente esta permissão em minúsculas.

Haroon Dilshad
fonte
2

Como o @Damian comentou, todas as respostas neste tópico estão fazendo errado. Se você fizer isso manualmente, corre o risco de o Serviço ser parado no meio do dispositivo que entra no modo de suspensão. Você precisa obter um bloqueio de ativação primeiro. Felizmente, a biblioteca de suporte nos fornece uma classe para fazer isso:

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

em seu serviço, certifique-se de liberar o bloqueio de ativação:

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

Não se esqueça de adicionar a permissão WAKE_LOCK ao seu festival principal:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
fonte
Pequena pergunta, eu tenho uma dúvida. Se o meu serviço é um Serviço e não o IntentService, não posso usá-lo dessa maneira, porque o método onHandleIntend não pode ser substituído no Serviço simples ?
precisa saber é o seguinte
Eu estou tendo o mesmo problema. Você se importa de me ajudar? Obrigado! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
Talvez usar onNewIntent()? Ou você pode olhar para a fonte para IntentService e ver o que você precisa fazer para o seu serviço para torná-lo coincidir com ...
phreakhead
1

De fato, eu entrei nesse problema há pouco tempo e é realmente muito fácil de corrigir, você realmente não faz nada errado se configurar a "android.intent.action.BOOT_COMPLETED"permissão e o filtro de intenção.

Lembre-se de que, no Android 4.X, é necessário executar o ouvinte de transmissão antes de iniciar o serviço na inicialização, ou seja, você deve adicionar uma atividade primeiro. Depois que o receptor de transmissão estiver em execução, seu aplicativo funcionará conforme o esperado, No entanto, no Android 4.X, não encontrei uma maneira de iniciar o serviço na inicialização sem nenhuma atividade; acho que o Google fez isso por razões de segurança.

David Hx
fonte
0

Eu enfrentei esse problema se eu deixar o construtor vazio na classe do receptor. Após a remoção, o contsructor vazio noRreceive methos começou a funcionar bem.

redrom
fonte