尝试在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" />

广播接收器

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:permission =“ android.permission.RECEIVE_BOOT_COMPLETED”
Alex

您是否在<action android:name =“ android.intent.action._BOOT_COMPLETED” />
OneWorld中

导出必须为真,这样系统才能调用接收器,不是吗?还是默认情况下是真的?
Eugen Pechanec

Answers:


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:enabledexported等等,属性: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
看起来不错 我将以此为基础,谢谢:)。没有可勾选的标记,可疑的投票或可悲的回应:(。任何人都可以验证吗?
Nanne 2011年

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” .equals(intent.getAction())){Intent serviceIntent = new Intent(context,Service_Location.class); // i.putExtra(“ KEY1”,“服务要使用的值”); context.startService(serviceIntent); }
Gunnar Bernstein 2013年

2
您应该扩展developer.android.com/reference/android/support/v4/content/…。它是实现BroadcastReceiver的通用模式的助手,该模式接收设备唤醒事件,然后将工作传递给Service,同时确保设备在过渡期间不会重新进入睡眠状态。此类负责为您创建和管理部分唤醒锁。您必须请求WAKE_LOCK权限才能使用它。
达米安

84

作为附加信息:BOOT_COMPLETE 挂载外部存储之前被发送到应用程序。因此,如果将应用程序安装到外部存储,它将不会收到BOOT_COMPLETE广播消息。

更多细节在这里在部分广播接收机监听“启动完成”


为避免上述问题,开发人员可以在应用清单中设置“ 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,如果设备未捕获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

如何获取设备ID?获取具有ID的已连接设备的列表:

adb devices

默认情况下,您可以在ADT中找到adb

adt-installation-dir/sdk/platform-tools

请享用!)


您的第一段是大写。我无法使其在调试器中运行。
estornes '16

34

随着

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

也用

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

HTC设备似乎没有赶上BOOT_COMPLETED


是否需要为HTC设备添加类似的权限?
南达

2
在某些情况下这可能很有用,但我了解HTC快速启动是一种休眠形式,系统状态保存到文件系统中,并且android.intent.action.QUICKBOOT_POWERON仅在从快速启动还原时才发送。这意味着从快速启动中恢复后,由于保留了警报,因此无需执行诸如重置警报之类的操作。因此,只有<action android:name="android.intent.action.QUICKBOOT_POWERON" />在用户认为设备已启动时要执行某些操作时才需要使用。
HexAndBugs 2015年

2
从应用程序开发人员的角度来看,如果该行为仅存在于HTC设备上,则不应使用此功能。因为按照文档说明,BOOT_COMPLETED总是在设备打开时发送。其他一些制造商可能会想出另一种快速启动的方法,而最终我们会将代码与每个人的规范搞混。
Subin Sebastian 2015年

@HexAndBugs您是否能够确认快速启动是一种将系统状态保存到文件系统的休眠方式?如果系统状态未保存,我希望能够在快速启动后重设用于将来通知的警报...请注意。
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

希望能帮助到你。


绝对可能是问题的原因。在运行Android 4.0.3的HTC Desire C上也可以观察到。
Zelimir


7

在尝试了所有提到的答案和技巧后,我终于找到了为什么该代码无法在手机中运行的原因。某些Android手机(例如“ Huawei Honor 3C Android 4.2.2 ”)在其设置中具有Statup Manager菜单,必须在列表中检查您的应用。:)


5

我还有一个<category>-tag,不知道这有什么区别。

<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子句"android.intent.action.BOOT_COMPLETED".equals(intent.getAction(),因为接收者可能无论如何都只能接收到该意图?


尝试了一下,但没有成功,我忘了提一下,我也有<uses-permission android:name =“ android.permission.RECEIVE_BOOT_COMPLETED” />
Alex

2
以防万一:将android.intent.category.HOME添加到AndroidManifest中的任何标签将导致Samsung Galaxy Tab在兼容模式下运行该应用程序,即使在使用黑客关闭兼容模式后也是如此。不知道其他选项卡是否相同。我建议根本不要设置HOME类别。没必要
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权限添加到您的mainfest中:

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

小问题,我有一个疑问。如果我的服务Service而不是IntentService,则我不能使用这种方式,因为onHandleIntend方法不能在简单Service中覆盖
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

如果我将空的构造函数留在接收器类中,则会遇到此问题。卸下空的容器后,onRreceive方法开始正常运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.