Mencoba memulai layanan saat boot di Android

332

Saya sudah mencoba untuk memulai layanan ketika perangkat melakukan booting di android, tetapi saya tidak bisa membuatnya berfungsi. Saya telah melihat sejumlah tautan daring tetapi tidak ada kode yang berfungsi. Apakah saya lupa sesuatu?

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

Penerima siaran

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
sumber
2
Saya tidak tahu apa yang saya lakukan tetapi saya pikir itu berfungsi sekarang mungkin android: permit = "android.permission.RECEIVE_BOOT_COMPLETED" untuk penerima
Alex
sudahkah Anda memeriksa "_" ekstra di <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld
Diekspor harus benar sehingga sistem dapat memanggil penerima, bukan? Atau apakah itu benar secara default?
Eugen Pechanec
untuk Oreo, lihat di sini: stackoverflow.com/questions/44502229/…
Andy Weinstein

Jawaban:

601

Jawaban lainnya terlihat bagus, tetapi saya pikir saya akan membungkus semuanya menjadi satu jawaban yang lengkap.

Anda perlu yang berikut ini di AndroidManifest.xmlfile Anda :

  1. Dalam <manifest>elemen Anda :

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. Dalam <application>elemen Anda (pastikan untuk menggunakan nama kelas [atau relatif] yang memenuhi syarat untuk Anda BroadcastReceiver):

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

    (Anda tidak perlu android:enabled, exported, dll, atribut: default Android sudah benar)

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

Dari pertanyaan awal:

  • tidak jelas apakah <receiver>elemen itu ada di dalam <application>elemen
  • tidak jelas apakah nama kelas yang benar-benar memenuhi syarat (atau relatif) untuk BroadcastReceiverditentukan
  • ada kesalahan ketik di <intent-filter>
Timo Bruck
sumber
2
Ini terlihat bagus. Saya akan menggunakan ini sebagai dasar, terima kasih :). Tidak ada tanda centang atau upvotes atau tanggapan sedih :(. Adakah yang memverifikasi ini?
Nanne
51
Hanya pelengkap: pastikan aplikasi Anda dipasang di memori internal <manifes xmlns: android = "..." package = "..." android: installLocation = "internalOnly">
Bao Le
2
Di Android Jellybean 4.2.2 di tag <receiver> saya harus menggunakan nama relatif kelas 'alih-alih nama yang sepenuhnya memenuhi syarat untuk memulai layanan, seperti yang tercantum dalam stackoverflow.com/questions/16671619/…
Piovezan
6
Jika penerima digunakan untuk hal-hal yang berbeda: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (intent.getAction ())) {Intent serviceIntent = new Intent (konteks, Service_Location.class); // i.putExtra ("KEY1", "Nilai yang akan digunakan oleh layanan"); context.startService (serviceIntent); }
Gunnar Bernstein
2
Anda harus memperluas developer.android.com/reference/android/support/v4/content/… . Ini adalah Helper untuk pola umum penerapan BroadcastReceiver yang menerima acara bangun perangkat dan kemudian mengalihkan pekerjaan ke Layanan, sambil memastikan bahwa perangkat tidak kembali tidur selama transisi. Kelas ini menangani pembuatan dan pengelolaan kunci bangun parsial untuk Anda; Anda harus meminta izin WAKE_LOCK untuk menggunakannya.
Damian
84

Sebagai info tambahan: BOOT_COMPLETE dikirim ke aplikasi sebelum penyimpanan eksternal dipasang. Jadi, jika aplikasi diinstal ke penyimpanan eksternal, ia tidak akan menerima pesan broadcast BOOT_COMPLETE.

Lebih detail di sini di bagian Penerima Siaran mendengarkan "boot selesai"

inazaruk
sumber
Untuk mencegah masalah di atas, pengembang dapat mengatur "android: installLocation =" internalOnly "di manifes untuk aplikasi. Apakah itu ide yang buruk? Untuk aplikasi smartphone, jika 99,9% (tebakan saya) dari semua pengguna menginstal aplikasi secara normal , dengan menggunakan penyimpanan internal daripada penyimpanan eksternal, maka tampaknya penambahan "internalOnly" ke manifes akan baik-baik saja. Saya akan menghargai setiap pemikiran atau ide yang Anda miliki tentang hal ini.
AJW
69

Cara memulai layanan pada boot perangkat (aplikasi autorun, dll.)

Untuk pertama: sejak versi Android 3.1+ Anda tidak menerima BOOT_COMPLETE jika pengguna tidak pernah memulai aplikasi Anda setidaknya sekali atau aplikasi "paksa ditutup" pengguna. Ini dilakukan untuk mencegah malware secara otomatis mendaftarkan layanan. Lubang keamanan ini ditutup di versi Android yang lebih baru.

Larutan:

Buat aplikasi dengan aktivitas. Ketika pengguna menjalankannya sekali aplikasi dapat menerima pesan broadcast BOOT_COMPLETE.

Untuk yang kedua: BOOT_COMPLETE dikirim sebelum penyimpanan eksternal dipasang. Jika aplikasi dipasang ke penyimpanan eksternal, ia tidak akan menerima pesan siaran BOOT_COMPLETE.

Dalam hal ini ada dua solusi:

  1. Instal aplikasi Anda ke penyimpanan internal
  2. Instal aplikasi kecil lain di penyimpanan internal. Aplikasi ini menerima BOOT_COMPLETE dan menjalankan aplikasi kedua pada penyimpanan eksternal.

Jika aplikasi Anda sudah terpasang di penyimpanan internal maka kode di bawah ini dapat membantu Anda memahami cara memulai layanan saat boot perangkat.


Di Manifest.xml

Izin:

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

Daftarkan penerima BOOT_COMPLETED Anda:

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

Daftarkan layanan Anda:

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

Di penerima 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);

    }

 }

Untuk HTC, Anda mungkin perlu juga menambahkan Manifest kode ini jika perangkat tidak menangkap RECEIVE_BOOT_COMPLETED:

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

Penerima sekarang terlihat seperti ini:

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

Bagaimana cara menguji BOOT_COMPLETED tanpa me-restart emulator atau perangkat asli? Mudah. Coba ini:

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

Bagaimana cara mendapatkan id perangkat? Dapatkan daftar perangkat yang terhubung dengan id:

adb devices

adb di ADT secara default dapat Anda temukan di:

adt-installation-dir/sdk/platform-tools

Nikmati! )

pengguna3439968
sumber
Paragraf pertama Anda adalah modal. Saya tidak dapat membuatnya berjalan di debugger saya.
estornes
34

Bersama

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

juga menggunakan,

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

Perangkat HTC tampaknya tidak menangkap BOOT_COMPLETED

Tony
sumber
Perlu menambahkan sesuatu yang serupa dalam izin untuk perangkat HTC?
Nanda
2
Ini bisa bermanfaat dalam beberapa keadaan, tapi saya mengerti HTC Fast Boot adalah bentuk hibernasi di mana status sistem disimpan ke sistem file, dan android.intent.action.QUICKBOOT_POWERONhanya dikirim ketika memulihkan dari boot cepat. Ini berarti Anda tidak perlu melakukan hal-hal seperti mengatur ulang alarm saat memulihkan dari Fast Boot saat dipelihara. Karena itu hanya perlu digunakan <action android:name="android.intent.action.QUICKBOOT_POWERON" />jika Anda ingin melakukan sesuatu ketika pengguna berpikir perangkat telah di-boot.
HexAndBugs
2
Dari perspektif pengembang aplikasi, kita tidak boleh menggunakan ini, jika perilaku itu hanya ada pada perangkat HTC. Karena, BOOT_COMPLETED, sesuai dokumentasi, akan selalu dikirim ketika perangkat AKTIF. Beberapa pabrikan lain dapat menemukan metode lain untuk booting cepat dan kami akhirnya akan mengacaukan kode kami dengan spesifikasi masing-masing.
Subin Sebastian
@HexAndBugs Apakah Anda dapat mengonfirmasi bahwa Boot Cepat adalah bentuk hibernasi di mana status sistem disimpan ke sistem file? Saya ingin dapat mengatur ulang alarm yang digunakan untuk Pemberitahuan di masa mendatang setelah Boot Cepat jika status sistem tidak disimpan ... mohon saran.
AJW
20

perhatikan bahwa di awal pertanyaan, ada kesalahan ketik:

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

dari pada :

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

satu "_" kecil dan semua masalah ini :)

Evgeny Erlihman
sumber
13

Saya baru tahu bahwa itu mungkin karena Fast Bootopsi di Settings>Power

Ketika saya mematikan opsi ini, aplikasi saya menerima siaran ini tetapi tidak sebaliknya.

By the way, saya memiliki Android 2.3.3di HTC Incredible S.

Semoga ini bisa membantu.

Omer Akhter
sumber
Kemungkinan penyebab masalah. Diamati juga pada HTC Desire C yang menjalankan Android 4.0.3.
Zelimir
7

Setelah mencoba semua jawaban dan trik yang disebutkan, saya akhirnya menemukan mengapa kodenya tidak berfungsi di ponsel saya. Beberapa ponsel Android seperti "Huawei Honor 3C Android 4.2.2 " memiliki menu Statup Manager di pengaturannya dan aplikasi Anda harus diperiksa dalam daftar. :)

Amir
sumber
5

Saya memiliki <category>-tag tambahan , tidak tahu apakah itu membuat perbedaan.

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

Sudahkah Anda mencoba menghilangkan klausa if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), karena penerima mungkin hanya menerima maksud itu?

Nick
sumber
mencoba ini dan itu tidak berhasil tetapi saya lupa menyebutkan saya juga memiliki <menggunakan-izin android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
Alex
2
untuk berjaga-jaga: menambahkan android.intent.category.HOME ke tag apa pun di AndroidManifest akan menyebabkan Samsung Galaxy Tab menjalankan aplikasi dalam mode kompatibilitas, bahkan setelah menggunakan peretasan untuk mematikan mode kompatibilitas. tidak yakin apakah ini sama untuk tab lain. saya sarankan untuk tidak mengatur kategori HOME sama sekali. itu tidak perlu.
moonlightcheese
3

Sebelum memasang penyimpanan eksternal, BOOT_COMPLETE dikirimkan, eksekusi.jika aplikasi Anda dipasang ke penyimpanan eksternal, aplikasi itu tidak akan menerima pesan siaran BOOT_COMPLETE. Untuk mencegah hal ini, Anda dapat menginstal aplikasi Anda di penyimpanan internal. Anda dapat melakukan ini hanya dengan menambahkan baris ini di menifest.xml

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

Beberapa perangkat HTC dapat mengaktifkan fitur "boot cepat" yang lebih seperti hibernasi yang dalam dan bukan reboot yang nyata dan karenanya tidak boleh memberikan maksud BOOT_COMPLETE. Untuk memulihkan ini, Anda dapat menambahkan filter maksud ini di dalam penerima Anda:

            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            </intent-filter>
Md. Sajedul Karim
sumber
Seperti yang Anda sarankan, untuk mencegah masalah di atas, pengembang dapat mengatur "android: installLocation =" internalOnly "di manifes untuk aplikasi. Apakah itu ide yang buruk? Untuk aplikasi ponsel cerdas, jika 99,9% (tebakan saya) dari semua pengguna instal aplikasi secara normal, dengan menggunakan penyimpanan internal daripada penyimpanan eksternal, maka tampaknya penambahan "internalOnly" ke manifes akan baik-baik saja. Saya akan sangat menghargai setiap pemikiran atau ide yang Anda miliki tentang hal ini. - AJW
AJW
3

Inilah yang saya lakukan

1. Saya membuat kelas Penerima

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. di manifes

<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.dan setelah SEMUA YANG ANDA BUTUHKAN untuk "mengatur" penerima di MainActivity Anda, mungkin di dalam 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);
...

steap terakhir yang saya pelajari dari ApiDemos

San Juan
sumber
2

Jika Anda menggunakan Android Studio dan Anda sangat menyukai pelengkapan otomatis maka saya harus memberi tahu Anda, saya menggunakan Android Studio v 1.1.0 dan saya menggunakan pelengkapan otomatis untuk izin berikut

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

Dan Android Studio Otomatis menyelesaikan RECEIVE_BOOT_COMPLETEDsemua dalam huruf kecil seperti receive_boot_completeddan saya terus menarik rambut saya karena saya sudah mencentang daftar saya untuk hal-hal yang harus dilakukan untuk memulai layanan saat boot. Saya baru saja mengkonfirmasi lagi

Android Studio TIDAK Lengkapi secara otomatis izin ini dalam huruf kecil.

Haroon Dilshad
sumber
2

Seperti yang dikomentari @Damian, semua jawaban di utas ini salah. Melakukannya secara manual seperti ini berisiko Layanan Anda terhenti di tengah dari perangkat yang akan tidur. Anda harus mendapatkan kunci bangun terlebih dahulu. Untungnya, perpustakaan Dukungan memberi kami kelas untuk melakukan ini:

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

kemudian, di Layanan Anda, pastikan untuk melepaskan kunci bangun:

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

Jangan lupa untuk menambahkan izin WAKE_LOCK ke mainfest Anda:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
phreakhead
sumber
Pertanyaan kecil saya ragu. Jika saya layanan adalah layanan dan tidak IntentService saya tidak bisa menggunakan cara ini, karena onHandleIntend metode tidak bisa menimpa di sederhana Layanan ?
paolo2988
Saya mengalami masalah yang sama. Apakah kamu keberatan membantu saya? Terima kasih! stackoverflow.com/questions/35373525/starting-my-service
Ruchir Baronia
Mungkin digunakan onNewIntent()? Atau Anda bisa melihat sumber untuk IntentService dan melihat apa yang perlu Anda lakukan agar Layanan Anda cocok dengan itu ...
phreakhead
1

Bahkan, saya mendapatkan masalah ini belum lama ini, dan itu benar-benar sangat mudah untuk diperbaiki, Anda benar-benar tidak melakukan kesalahan jika Anda mengatur "android.intent.action.BOOT_COMPLETED"izin dan maksud-filter.

Perhatikan bahwa jika Anda menggunakan Android 4.X, Anda harus menjalankan pendengar siaran sebelum memulai layanan saat boot, itu artinya, Anda harus menambahkan aktivitas terlebih dahulu, setelah penerima siaran Anda berjalan, aplikasi Anda harus berfungsi seperti yang Anda harapkan, Namun, pada Android 4.X, saya belum menemukan cara untuk memulai layanan saat boot tanpa aktivitas apa pun, saya pikir google melakukan itu untuk alasan keamanan.

David Hx
sumber
0

Saya menghadapi masalah ini jika saya meninggalkan konstruktor kosong di kelas penerima. Setelah menghapus contsructor kosong di methosRriveive mulai bekerja dengan baik.

redrom
sumber