กำลังพยายามเริ่มบริการเมื่อบู๊ตบน 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");
    }
}

2
ฉันไม่ได้ทำอะไร แต่ฉันคิดว่ามันใช้งานได้ตอนนี้มันอาจจะเป็น Android: ได้รับอนุญาต = "android.permission.RECEIVE_BOOT_COMPLETED" สำหรับผู้รับ
อเล็กซ์

คุณได้ตรวจสอบเครื่องหมาย "_" พิเศษใน <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld

การส่งออกต้องเป็นจริงเพื่อให้ระบบสามารถเรียกใช้ตัวรับได้ไม่ หรือเป็นจริงตามค่าเริ่มต้น
Eugen Pechanec

สำหรับโอรีโอดูที่นี่: stackoverflow.com/questions/44502229/…
Andy Weinstein

คำตอบ:


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ฯลฯ แอตทริบิวต์: ค่าเริ่มต้นของ Android ที่ถูกต้อง)

    ใน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">
Bao Le

2
ใน Android Jellybean 4.2.2 ในแท็ก <receiver> ฉันต้องใช้ชื่อที่สัมพันธ์กันของคลาสแทนชื่อที่ผ่านการรับรองสำหรับบริการที่จะเริ่มต้นดังที่ระบุไว้ในstackoverflow.com/questions/16671619/ …
Piovezan

6
หากผู้รับใช้สำหรับสิ่งของต่าง ๆ : <br> if ("android.intent.action.BOOT_COMPLETED" .equal (intent.getAction ())) {Intent serviceIntent = Intent ใหม่ (บริบท Service_Location.class); // i.putExtra ("KEY1", "ค่าที่จะใช้โดยบริการ"); context.startService (serviceIntent); }
Gunnar Bernstein

2
คุณควรขยายdeveloper.android.com/reference/android/support/v4/content/ ...... แทน เป็นผู้ช่วยสำหรับรูปแบบทั่วไปของการใช้ BroadcastReceiver ที่ได้รับเหตุการณ์การปลุกอุปกรณ์แล้วส่งงานออกไปยังบริการในขณะที่มั่นใจว่าอุปกรณ์จะไม่กลับไปนอนในระหว่างการเปลี่ยนแปลง คลาสนี้ดูแลการสร้างและจัดการล็อคการปลุกบางส่วนให้คุณ คุณต้องขออนุญาต WAKE_LOCK เพื่อใช้งาน
เดเมียน

84

เป็นข้อมูลเพิ่มเติม: BOOT_COMPLETE ถูกส่งไปยังแอปพลิเคชันก่อนที่จะติดตั้งที่เก็บข้อมูลภายนอก ดังนั้นหากติดตั้งแอปพลิเคชันลงในที่จัดเก็บข้อมูลภายนอกแล้วจะไม่ได้รับข้อความออกอากาศ BOOT_COMPLETE

รายละเอียดเพิ่มเติมที่นี่ในส่วนBroadcast Receivers ฟังสำหรับ "boot boot"


เพื่อป้องกันปัญหาข้างต้นผู้พัฒนาสามารถตั้งค่า "android: installLocation =" internalOnly "ในรายการสำหรับแอปนั่นเป็นความคิดที่ไม่ดีหรือไม่สำหรับแอปสมาร์ทโฟนถ้า 99.9% (เดาของฉัน) ของผู้ใช้ทั้งหมดติดตั้งแอปตามปกติ โดยใช้การจัดเก็บภายในมากกว่าการจัดเก็บข้อมูลภายนอกแล้วดูเหมือนว่า "internalOnly" นอกจากชัดแจ้งจะดีฉันอยากจะขอบคุณความคิดใด ๆ หรือความคิดคุณมีเกี่ยวกับเรื่องนี้..
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 หรือไม่
Nanda

2
สิ่งนี้อาจมีประโยชน์ในบางสถานการณ์ แต่ฉันเข้าใจว่า HTC Fast Boot เป็นรูปแบบของการไฮเบอร์เนตที่สถานะของระบบถูกบันทึกไว้ในระบบไฟล์และandroid.intent.action.QUICKBOOT_POWERONจะถูกส่งเมื่อเรียกคืนจากการบูตอย่างรวดเร็วเท่านั้น ซึ่งหมายความว่าไม่จำเป็นที่จะต้องทำสิ่งต่าง ๆ เช่นการรีเซ็ตการเตือนเมื่อกู้คืนจาก Fast Boot เนื่องจากมีการเก็บรักษาไว้ ดังนั้นจึงจำเป็นต้องใช้เฉพาะ<action android:name="android.intent.action.QUICKBOOT_POWERON" />เมื่อคุณต้องการทำบางสิ่งเมื่อผู้ใช้คิดว่าอุปกรณ์ได้ทำการบูทแล้ว
HexAndBugs

2
จากมุมมองของนักพัฒนาแอปเราไม่ควรใช้สิ่งนี้หากพฤติกรรมมีเฉพาะในอุปกรณ์ HTC เนื่องจาก BOOT_COMPLETED เป็นไปตามเอกสารประกอบจะถูกส่งเมื่ออุปกรณ์เปิดอยู่เสมอ ผู้ผลิตรายอื่นอาจหาวิธีอื่นในการบูทอย่างรวดเร็วและเราจะทำให้โค้ดของเรายุ่งกับข้อกำหนดของแต่ละคน
Subin Sebastian

@HexAndBugs คุณสามารถยืนยันได้ว่า Fast Boot เป็นรูปแบบการไฮเบอร์เนตที่สถานะของระบบถูกบันทึกไว้ในระบบไฟล์หรือไม่? ฉันต้องการที่จะสามารถรีเซ็ตสัญญาณเตือนที่ใช้สำหรับการแจ้งเตือนในอนาคตหลังจาก 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.3HTC Incredible S

หวังว่ามันจะช่วย


สาเหตุที่เป็นไปได้อย่างแน่นอนของปัญหา สังเกตได้จาก HTC Desire C ที่ใช้ Android 4.0.3
Zelimir


7

หลังจากลองใช้คำตอบและลูกเล่นทั้งหมดที่กล่าวถึงในที่สุดฉันก็พบว่าทำไมรหัสไม่ทำงานในโทรศัพท์ของฉัน โทรศัพท์ Android บางรุ่นเช่น "Huawei Honor 3C Android 4.2.2 " มีเมนูStatup Managerในการตั้งค่าและต้องตรวจสอบแอปของคุณในรายการ :)


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-clause "android.intent.action.BOOT_COMPLETED".equals(intent.getAction()แล้วเนื่องจากผู้รับอาจได้รับความตั้งใจนั้นแล้วหรือยัง?


ลองสิ่งนี้และมันใช้งานไม่ได้ btw ฉันลืมที่จะพูดถึงฉันยังมี <การใช้สิทธิ์ Android: name = "android.permission.RECEIVE_BOOT_COMPLETED" />
อเล็กซ์

2
ในกรณี: เพิ่ม android.intent.category.HOME ไปยังแท็กใด ๆ ใน AndroidManifest จะทำให้ Samsung Galaxy Tab เรียกใช้แอปในโหมดความเข้ากันได้แม้จะใช้แฮ็คเพื่อปิดโหมดความเข้ากันได้ ไม่แน่ใจว่านี่เป็นแท็บอื่นหรือไม่ ฉันไม่แนะนำให้ตั้งค่าหมวดหมู่หน้าแรกเลย มันไม่จำเป็น
moonlightcheese


3

ก่อนที่จะติดตั้งที่จัดเก็บข้อมูลภายนอก BOOT_COMPLETE จะถูกส่งคำสั่งถ้าแอปของคุณติดตั้งในที่จัดเก็บข้อมูลภายนอกจะไม่ได้รับข้อความออกอากาศของ 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 permssion ใน mainfest ของคุณ:

<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

ฉันประสบกับปัญหานี้ถ้าฉันปล่อยให้ตัวสร้างว่างในคลาสผู้รับ หลังจากการลบ contsructor ที่ว่างเปล่าบนรีโทรสเมทิสเริ่มทำงานได้ดี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.