You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Android Oreo中长时间运行后台服务且不被系统杀死?

嘿,这个问题我太有发言权了——自从Android Oreo把后台服务的生存空间砍得七零八落之后,想在后台持续跑个传感器监听确实挺头疼的,尤其是你还不想用前台服务的通知打扰用户。咱们来聊聊几个可行的方案,按靠谱程度排序:

1. 用辅助功能服务(Accessibility Service)——最靠谱的正规方案

辅助功能服务的进程优先级极高,系统几乎不会随便杀它,而且天然支持后台持续运行。你完全可以把传感器监听逻辑放在这里,完美适配你的摇晃开手电筒需求。

不过有个前提:得引导用户手动开启你的应用的辅助功能权限,这是敏感权限,没法自动授予,所以你得在应用里做个友好的引导,告诉用户怎么去系统设置里开启。

具体步骤:

首先在AndroidManifest.xml里声明服务:

<service
    android:name=".ShakeAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

然后在res/xml下创建accessibility_service_config.xml配置文件:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:description="@string/accessibility_service_desc" />

这里的description要写清楚你的服务是干嘛的,比如“监听摇晃动作以控制手电筒”,用户在设置里能看到这个描述。

最后实现服务类:

class ShakeAccessibilityService : AccessibilityService() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private val shakeListener = object : SensorEventListener {
        private var lastShakeTime = 0L
        private val SHAKE_THRESHOLD = 800 // 摇晃阈值,可根据实际调整
        private val SHAKE_INTERVAL = 1000 // 1秒内只响应一次,防止重复触发

        override fun onSensorChanged(event: SensorEvent?) {
            event ?: return
            if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
                val x = event.values[0]
                val y = event.values[1]
                val z = event.values[2]

                // 计算加速度变化
                val acceleration = abs(x + y + z - 9.81) * 1000
                val currentTime = System.currentTimeMillis()
                
                if (acceleration > SHAKE_THRESHOLD && currentTime - lastShakeTime > SHAKE_INTERVAL) {
                    lastShakeTime = currentTime
                    // 触发手电筒开关逻辑
                    toggleFlashlight()
                }
            }
        }

        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
    }

    override fun onServiceConnected() {
        super.onServiceConnected()
        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        accelerometer?.let {
            sensorManager.registerListener(shakeListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onInterrupt() {}

    override fun onDestroy() {
        super.onDestroy()
        sensorManager.unregisterListener(shakeListener)
    }

    private fun toggleFlashlight() {
        // 记得申请CAMERA权限
        val cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
        val cameraId = cameraManager.cameraIdList[0]
        val isFlashOn = cameraManager.getTorchMode(cameraId) == CameraManager.TORCH_MODE_ON
        cameraManager.setTorchMode(cameraId, !isFlashOn)
    }
}
2. 前台服务的“隐形通知”技巧——不推荐,有风险

虽然你说不想用前台服务,但有些厂商允许创建一个几乎看不见的通知来满足前台服务的要求。不过这个方法踩坑点很多:不同厂商系统表现不一,而且Google Play可能判定这是欺骗用户,导致应用被拒。

如果只是自己玩玩或者小众分发,可以试试:

private fun startStealthForegroundService() {
    // 创建一个透明图标,注意要真·透明,不然会显示系统默认图标
    val notification = NotificationCompat.Builder(this, "STEALTH_CHANNEL")
        .setSmallIcon(R.drawable.ic_transparent)
        .setContentTitle("")
        .setContentText("")
        .setPriority(NotificationCompat.PRIORITY_MIN)
        .setVisibility(NotificationCompat.VISIBILITY_SECRET)
        .build()
    startForeground(1, notification)
}

再次强调:这个方法不适合上线的应用,风险很高。

3. 在Application类里注册传感器监听——效果有限

你可以在自定义Application的onCreate()里注册传感器监听器,这样只要应用进程活着就能监听。但问题是,Oreo及以上系统在应用后台时,很容易杀死闲置进程,尤其是内存不足的时候。

可以配合监听屏幕状态来优化,比如屏幕亮时重新注册,屏幕灭时取消监听,能稍微提高存活概率:

class MyApp : Application() {
    private lateinit var sensorManager: SensorManager
    private var accelerometer: Sensor? = null
    private val shakeListener = object : SensorEventListener {
        // 和之前的监听器逻辑一样
    }

    override fun onCreate() {
        super.onCreate()
        sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        registerShakeListener()

        // 监听屏幕状态
        val screenFilter = IntentFilter(Intent.ACTION_SCREEN_ON)
        screenFilter.addAction(Intent.ACTION_SCREEN_OFF)
        registerReceiver(screenReceiver, screenFilter)
    }

    private fun registerShakeListener() {
        accelerometer?.let {
            sensorManager.registerListener(shakeListener, it, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    private fun unregisterShakeListener() {
        sensorManager.unregisterListener(shakeListener)
    }

    private val screenReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                Intent.ACTION_SCREEN_ON -> registerShakeListener()
                Intent.ACTION_SCREEN_OFF -> unregisterShakeListener()
            }
        }
    }
}

这个方案的保活效果最差,只能作为备选。


总的来说,最合规、最稳定的方案就是用辅助功能服务,虽然需要用户手动授权,但这是系统允许的正规路径,不会有被封杀的风险。

内容的提问来源于stack exchange,提问作者Gurleen Sethi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:23:07