Đang cố gắng bắt đầu một dịch vụ khi khởi động trên Android


332

Tôi đã cố gắng bắt đầu một dịch vụ khi một thiết bị khởi động trên Android, nhưng tôi không thể làm cho nó hoạt động. Tôi đã xem một số liên kết trực tuyến nhưng không có mã nào hoạt động. Có phải tôi đang quên một cái gì đó?

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

Phát sóng thu

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
Tôi không biết những gì tôi đã làm nhưng tôi nghĩ nó hoạt động ngay bây giờ, nó có thể là android: allow = "ERIC.RECEIVE_BOOT_COMPLETED" cho người nhận
Alex

bạn đã kiểm tra thêm "_" trong <action android: name = "android.intent.action._BOOT_COMPLETED" />
OneWorld

Xuất khẩu phải đúng để hệ thống có thể gọi máy thu, không? Hoặc nó là đúng theo mặc định?
Eugen Pechanec

đối với Oreo, xem tại đây: stackoverflow.com/questions/44502229/ Kẻ
Andy Weinstein

Câu trả lời:


601

Các câu trả lời khác có vẻ tốt, nhưng tôi nghĩ tôi sẽ kết thúc mọi thứ thành một câu trả lời hoàn chỉnh.

Bạn cần những điều sau đây trong AndroidManifest.xmltập tin của bạn :

  1. Trong <manifest>phần tử của bạn :

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  2. Trong <application>phần tử của bạn (hãy chắc chắn sử dụng tên lớp [hoặc người thân] đủ điều kiện cho bạn BroadcastReceiver):

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

    (bạn không cần android:enabled, exportedvv, thuộc tính: giá trị mặc định Android là chính xác)

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

Từ câu hỏi ban đầu:

  • Không rõ <receiver>phần tử có trong <application>phần tử không
  • không rõ tên lớp đủ điều kiện (hoặc tương đối) chính xác cho tên BroadcastReceiverđược chỉ định
  • có một lỗi đánh máy trong <intent-filter>

2
Nhìn có vẻ tốt. Tôi sẽ sử dụng nó như là một cơ sở, cảm ơn :). Không có dấu kiểm hoặc upvote hoặc phản hồi đáng buồn :(. Có ai xác minh điều này không?
Nanne

51
Chỉ là phần bổ sung: đảm bảo ứng dụng của bạn được cài đặt trong bộ nhớ trong <manifest xmlns: android = "..." pack = "..." android: installLocation = "InternalOnly">
Bao Le

2
Trong Android Jellybean 4.2.2 trong thẻ <receive> tôi đã phải sử dụng tên tương đối của lớp thay vì tên đủ điều kiện cho dịch vụ để bắt đầu, như đã lưu ý trong stackoverflow.com/questions/16671619/ế
Piovezan

6
Nếu người nhận được sử dụng cho các nội dung khác nhau: <br> if ("android.intent.action.BOOT_COMPLETED" .equals (aim.getAction ())) {Intent serviceIntent = new Intent (bối cảnh, Service_Location. Class); // i.putExtra ("KEY1", "Giá trị được sử dụng bởi dịch vụ"); bối cảnh.startService (serviceIntent); }
Gunnar Bernstein

2
Thay vào đó, bạn nên mở rộng developer.android.com/reference/android/support/v4/content/ vào. Đây là Trình trợ giúp cho mô hình chung của việc triển khai BroadcastReceiver nhận sự kiện đánh thức thiết bị và sau đó chuyển công việc sang Dịch vụ, đồng thời đảm bảo rằng thiết bị không quay trở lại trạng thái ngủ trong quá trình chuyển đổi. Lớp này đảm nhiệm việc tạo và quản lý khóa đánh thức một phần cho bạn; bạn phải yêu cầu quyền WAKE_LOCK để sử dụng nó.
Damian

84

Như một thông tin bổ sung: BOOT_COMPLETE được gửi đến các ứng dụng trước khi bộ nhớ ngoài được gắn kết. Vì vậy, nếu ứng dụng được cài đặt vào bộ nhớ ngoài, nó sẽ không nhận được tin nhắn quảng bá BOOT_COMPLETE.

Thêm chi tiết tại đây trong phần Bộ thu phát đang nghe "đã hoàn thành khởi động"


Để ngăn chặn vấn đề trên, nhà phát triển có thể đặt "android: installLocation =" InternalOnly "trong bảng kê khai cho một ứng dụng. Đó có phải là một ý tưởng tồi không? , bằng cách sử dụng bộ nhớ trong thay vì bộ nhớ ngoài, thì có vẻ như bổ sung "InternalOnly" vào bảng kê khai sẽ ổn. Tôi sẽ đánh giá cao bất kỳ suy nghĩ hoặc ý tưởng nào bạn có về điều này.
AJW

69

Cách khởi động dịch vụ khi khởi động thiết bị (ứng dụng tự động chạy, v.v.)

Lần đầu tiên: kể từ phiên bản Android 3.1+, bạn không nhận được BOOT_COMPLETE nếu người dùng không bao giờ khởi động ứng dụng của bạn ít nhất một lần hoặc người dùng "buộc đóng" ứng dụng. Điều này đã được thực hiện để ngăn chặn phần mềm độc hại tự động đăng ký dịch vụ. Lỗ hổng bảo mật này đã bị đóng trong các phiên bản Android mới hơn.

Giải pháp:

Tạo ứng dụng với hoạt động. Khi người dùng chạy nó một lần, ứng dụng có thể nhận được tin nhắn quảng bá BOOT_COMPLETE.

Đối với lần thứ hai: BOOT_COMPLETE được gửi trước khi bộ nhớ ngoài được gắn kết. Nếu ứng dụng được cài đặt vào bộ nhớ ngoài, nó sẽ không nhận được tin nhắn quảng bá BOOT_COMPLETE.

Trong trường hợp này, có hai giải pháp:

  1. Cài đặt ứng dụng của bạn vào bộ nhớ trong
  2. Cài đặt một ứng dụng nhỏ khác trong bộ nhớ trong. Ứng dụng này nhận BOOT_COMPLETE và chạy ứng dụng thứ hai trên bộ nhớ ngoài.

Nếu ứng dụng của bạn đã được cài đặt trong bộ nhớ trong thì mã bên dưới có thể giúp bạn hiểu cách bắt đầu dịch vụ khi khởi động thiết bị.


Trong Manifest.xml

Quyền:

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

Đăng ký người nhận BOOT_COMPLETED của bạn:

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

Đăng ký dịch vụ của bạn:

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

Trong máy thu 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);

    }

 }

Đối với HTC, bạn cũng có thể cần thêm vào Bản kê khai mã này nếu thiết bị không bắt RECEIVE_BOOT_COMPLETED:

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

Người nhận bây giờ trông như thế này:

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

Làm cách nào để kiểm tra BOOT_COMPLETED mà không cần khởi động lại trình giả lập hoặc thiết bị thực? Dễ thôi. Thử cái này:

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

Làm thế nào để có được id thiết bị? Nhận danh sách các thiết bị được kết nối với id:

adb devices

adb trong ADT theo mặc định bạn có thể tìm thấy trong:

adt-installation-dir/sdk/platform-tools

Thưởng thức! )


Đoạn đầu tiên của bạn là vốn. Tôi không thể làm cho nó chạy trong trình gỡ lỗi của tôi.
estornes

34

Cùng với

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

cũng sử dụng,

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

Các thiết bị HTC dường như không bắt được BOOT_COMPLETED


Cần thêm bất cứ điều gì tương tự về quyền cho các thiết bị HTC?
Nanda

2
Điều này có thể hữu ích trong một số trường hợp, nhưng tôi hiểu HTC Fast Boot là một dạng ngủ đông trong đó trạng thái hệ thống được lưu vào hệ thống tệp và android.intent.action.QUICKBOOT_POWERONchỉ được gửi khi khôi phục từ khởi động nhanh. Điều này có nghĩa là không cần thiết phải thực hiện những việc như đặt lại báo thức khi khôi phục từ Fast Boot khi chúng được bảo tồn. Do đó, chỉ cần sử dụng <action android:name="android.intent.action.QUICKBOOT_POWERON" />nếu bạn muốn làm gì đó khi người dùng nghĩ rằng thiết bị đã khởi động.
HexAndBugs 14/07/2015

2
Từ quan điểm của một nhà phát triển ứng dụng, chúng ta không bao giờ nên sử dụng điều này, nếu hành vi chỉ tồn tại trên các thiết bị HTC. Bởi vì, theo BOOT_COMPLETED, theo tài liệu, sẽ luôn được gửi khi thiết bị BẬT. Một số nhà sản xuất khác có thể đưa ra một phương pháp khởi động nhanh khác và cuối cùng chúng tôi sẽ làm rối mã của chúng tôi với thông số kỹ thuật của mỗi người.
Subin Sebastian

@HexAndBugs Bạn có thể xác nhận rằng Fast Boot là một dạng ngủ đông trong đó trạng thái hệ thống được lưu vào hệ thống tập tin không? Tôi muốn có thể đặt lại các báo thức được sử dụng cho Thông báo trong tương lai sau khi Khởi động nhanh nếu trạng thái hệ thống không được lưu ... vui lòng tư vấn.
AJW

20

lưu ý rằng ở đầu câu hỏi, có một lỗi đánh máy:

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

thay vì :

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

một "_" nhỏ và tất cả những rắc rối này :)


13

Tôi phát hiện ra rằng có thể là do Fast Boottùy chọn trong Settings>Power

Khi tôi tắt tùy chọn này, ứng dụng của tôi nhận được một chương trình phát sóng này nhưng không thì khác.

Nhân tiện, tôi có Android 2.3.3trên HTC Incredible S.

Hy vọng nó giúp.


Chắc chắn có thể nguyên nhân của vấn đề. Quan sát cũng trên HTC Desire C chạy Android 4.0.3.
Zelimir


7

Sau khi thử tất cả các câu trả lời và thủ thuật được đề cập, cuối cùng tôi cũng tìm thấy lý do tại sao mã không hoạt động trong điện thoại của mình. Một số điện thoại Android như "Huawei Honor 3C Android 4.2.2 " có menu Trình quản lý Statup trong cài đặt của chúng và ứng dụng của bạn phải được kiểm tra trong danh sách. :)


5

Tôi có một <category>-tag bổ sung , không biết điều đó có khác biệt gì không.

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

Bạn đã thử sử dụng mệnh đề if "android.intent.action.BOOT_COMPLETED".equals(intent.getAction(), vì người nhận có thể chỉ nhận được ý định đó chứ?


đã thử điều này và nó không hoạt động nhưng tôi đã quên đề cập đến tôi cũng có <sử dụng cho phép android: name = "ERIC.RECEIVE_BOOT_COMPLETED" />
Alex

2
chỉ trong trường hợp: thêm android.intent.c Category.HOME vào bất kỳ thẻ nào trong AndroidManifest sẽ khiến Samsung Galaxy Tab chạy ứng dụng ở chế độ tương thích, ngay cả sau khi sử dụng hack để tắt chế độ tương thích. không chắc chắn nếu điều này là giống nhau cho các tab khác. tôi khuyên bạn không nên thiết lập danh mục HOME. nó không cần thiết
moonlightcheese


3

Trước khi gắn bộ nhớ ngoài BOOT_COMPLETE được gửi thực thi. Nếu ứng dụng của bạn được cài đặt vào bộ nhớ ngoài, nó sẽ không nhận được tin nhắn quảng bá BOOT_COMPLETE. Để ngăn chặn điều này, bạn có thể cài đặt ứng dụng của mình trong bộ nhớ trong. bạn có thể làm điều này chỉ bằng cách thêm dòng này trong menifest.xml

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

Một số thiết bị HTC có thể kích hoạt tính năng "khởi động nhanh" giống như ngủ đông sâu và không phải là khởi động lại thực sự và do đó không nên đưa ra ý định BOOT_COMPLETE. Để khôi phục điều này, bạn có thể thêm bộ lọc ý định này bên trong máy thu của bạn:

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

Như bạn đề xuất, để ngăn chặn sự cố trên, nhà phát triển có thể đặt "android: installLocation =" InternalOnly "trong bảng kê khai cho một ứng dụng. Đó có phải là một ý tưởng tồi không? Đối với một ứng dụng điện thoại thông minh, nếu 99,9% (tôi đoán) của tất cả người dùng cài đặt các ứng dụng bình thường, bằng cách sử dụng lưu trữ nội bộ chứ không phải lưu trữ bên ngoài, sau đó có vẻ như các "internalOnly" Ngoài những biểu hiện sẽ là tốt tôi sẽ đánh giá cao bất kỳ suy nghĩ hay ý tưởng mà bạn có trong này -.. AJW
AJW

3

Đây là những gì tôi đã làm

1. Tôi đã tạo lớp Nhận

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. trong bảng kê khai

<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. và sau TẤT CẢ bạn CẦN "đặt" máy thu trong MainActivity của mình, nó có thể nằm trong 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);
...

cú đánh cuối cùng tôi đã học được từ ApiDemos


2

Nếu bạn đang sử dụng Android Studio và bạn rất thích tự động hoàn thành thì tôi phải thông báo cho bạn, tôi đang sử dụng Android Studio v 1.1.0 và tôi đã sử dụng tự động hoàn thành cho các quyền sau

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

Và Android Studio Tự động hoàn thành RECEIVE_BOOT_COMPLETEDtất cả trong trường hợp thấp hơn receive_boot_completedvà tôi tiếp tục nhổ tóc vì tôi đã đánh dấu vào danh sách kiểm tra những việc cần làm để bắt đầu dịch vụ khi khởi động. Tôi vừa xác nhận lại

Android Studio DOES tự động hoàn thành quyền này trong trường hợp thấp hơn.


2

Như @Damian đã nhận xét, tất cả các câu trả lời trong chủ đề này đang làm sai. Làm theo cách thủ công như thế này sẽ có nguy cơ Dịch vụ của bạn bị dừng ở giữa khi thiết bị chuyển sang chế độ ngủ. Bạn cần phải có được một khóa thức dậy đầu tiên. May mắn thay, thư viện Hỗ trợ cung cấp cho chúng tôi một lớp để làm điều này:

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

sau đó, trong Dịch vụ của bạn, đảm bảo phát hành khóa đánh thức:

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

Đừng quên thêm hoán vị WAKE_LOCK vào mainfest của bạn:

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

Câu hỏi nhỏ tôi có một nghi ngờ. Nếu dịch vụ của tôi là Dịch vụ và không phải IntentService, tôi không thể sử dụng cách này, vì phương thức onHandleIntend không thể được ghi đè trong Dịch vụ đơn giản ?
paolo2988

Tôi đang có cùng một vấn đề. Bạn có giúp đỡ tôi không? Cảm ơn! stackoverflow.com/questions353373525/starting-my-service
Ruchir Baronia

Có thể sử dụng onNewIntent()? Hoặc bạn có thể xem nguồn của IntentService và xem những gì bạn cần làm cho Dịch vụ của mình để làm cho nó phù hợp ...
phreakhead

1

Trên thực tế, tôi đã gặp rắc rối này cách đây không lâu và thực sự rất dễ khắc phục, bạn thực sự không làm gì sai nếu bạn thiết lập "android.intent.action.BOOT_COMPLETED"quyền và bộ lọc ý định.

Hãy chú ý rằng nếu bạn trên Android 4.X, bạn phải chạy trình nghe quảng bá trước khi bắt đầu dịch vụ khi khởi động, điều đó có nghĩa là bạn phải thêm một hoạt động trước, khi bộ thu phát của bạn chạy, ứng dụng của bạn sẽ hoạt động như bạn mong đợi, tuy nhiên, trên Android 4.X, tôi chưa tìm được cách khởi động dịch vụ khi khởi động mà không có bất kỳ hoạt động nào, tôi nghĩ google đã làm điều đó vì lý do bảo mật.


0

Tôi đã đối mặt với vấn đề này nếu tôi để lại hàm tạo trống trong lớp máy thu. Sau khi loại bỏ các contsructor trống, methosive bắt đầu hoạt động tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.