Kivy闹钟应用打包APK后无法后台运行的问题排查与配置咨询
解决Kivy闹钟应用后台持续运行问题
核心问题诊断
你的代码直接在主App中启动AndroidService,但Kivy的Clock调度依赖UI线程,应用退到后台后,Android系统会优先挂起非前台的UI进程,导致定时任务失效。同时,当前的Service未以前台服务运行(Android 8.0+对后台服务有严格限制),也没把闹钟逻辑放到独立的Service进程中,这是后台保活失败的关键。
代码修正方案
1. 拆分独立的Service脚本
创建service.py文件,把闹钟定时、响铃逻辑移到Service内部,使用Android原生AlarmManager实现精准定时(比Kivy Clock更可靠),同时将Service设为前台服务:
from android import AndroidService, mActivity from android.permissions import request_permissions, Permission from jnius import autoclass, cast from kivy.core.audio import SoundLoader import time # 请求必要权限 request_permissions([Permission.FOREGROUND_SERVICE, Permission.WAKE_LOCK]) AlarmManager = autoclass('android.app.AlarmManager') PendingIntent = autoclass('android.app.PendingIntent') Intent = autoclass('android.content.Intent') Context = autoclass('android.content.Context') NotificationManager = autoclass('android.app.NotificationManager') NotificationChannel = autoclass('android.app.NotificationChannel') Notification = autoclass('android.app.Notification') System = autoclass('java.lang.System') class AlarmService(AndroidService): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.alarm_sound = SoundLoader.load('alarm.mp3') self.channel_id = "alchemy_alarm_channel" self.create_notification_channel() def create_notification_channel(self): # 创建通知渠道(Android 8.0+必需) channel = NotificationChannel( self.channel_id, "Alarm Notifications", NotificationManager.IMPORTANCE_HIGH ) channel.setDescription("Alchemy Alarm Service Notifications") notification_manager = mActivity.getSystemService(Context.NOTIFICATION_SERVICE) notification_manager.createNotificationChannel(channel) def on_start(self, intent, start_id): # 构建前台通知,让Service保持运行 notification = Notification.Builder(mActivity, self.channel_id) \ .setContentTitle("Alchemy Alarm") \ .setContentText("Alarm service running in background") \ .setSmallIcon(autoclass('android.R')..drawable.ic_dialog_alert) \ .build() # 启动为前台服务 self.startForeground(1, notification) # 设置闹钟定时:6秒后第一次响铃,之后每15秒一次,共7次 alarm_manager = cast(AlarmManager, mActivity.getSystemService(Context.ALARM_SERVICE)) intent = Intent(mActivity, self.__class__) intent.setAction("RING_ALARM") for i in range(7): trigger_time = System.currentTimeMillis() + (6 + i * 15) * 1000 pending_intent = PendingIntent.getService(mActivity, i, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE) alarm_manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, trigger_time, pending_intent) return super().on_start(intent, start_id) def on_handle_intent(self, intent): # 处理闹钟触发事件 if intent.getAction() == "RING_ALARM": self.ring_alarm() def ring_alarm(self): if self.alarm_sound: self.alarm_sound.play() # 可在此添加UI更新逻辑(若需同步显示) def on_destroy(self): # 停止前台服务 self.stopForeground(True) super().on_destroy() if __name__ == '__main__': service = AlarmService('Alchemy Alarm Service', 'Running') service.start()
2. 修改主App代码
主App仅负责启动Service,不再处理定时逻辑:
import kivy from kivy.app import App from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout from android import AndroidService class AlchemyApp(App): def build(self): self.layout = BoxLayout(orientation='vertical') self.label = Label(text='Alchemy', font_size=50, color=(0.8, 0.4, 0.1, 1)) self.layout.add_widget(self.label) self.start_button = Button(text='Start', font_size=30, background_color=(0.8, 0.8, 0.1, 1)) self.start_button.bind(on_press=self.start_alarm_service) self.layout.add_widget(self.start_button) return self.layout def start_alarm_service(self, instance): self.start_button.disabled = True # 启动后台Service service = AndroidService('Alchemy Alarm Service', 'running') service.start('service started') # 可根据需求设置按钮重新启用逻辑,或让Service结束后通知App if __name__ == '__main__': AlchemyApp().run()
Buildozer.spec 配置调整
修改你的buildozer.spec文件,添加以下关键配置:
# 权限配置 android.permissions = FOREGROUND_SERVICE, WAKE_LOCK, RECEIVE_BOOT_COMPLETED # 指定Service入口脚本 android.service = service.py # 添加依赖 requirements = python3,kivy,pyjnius,android # 目标SDK版本(建议适配最新版本) android.api = 33 # 最小SDK版本(适配Android 8.0+) android.minapi = 26 # 允许后台运行模式 android.background_mode = service # 启用AndroidX(适配新特性) android.use_androidx = True
关键注意事项
- 前台服务必要性:Android 8.0+不允许后台服务长时间运行,必须通过前台通知让系统识别服务在运行,避免被回收。
- AlarmManager使用:
setExactAndAllowWhileIdle可保证设备休眠时也能触发闹钟,是闹钟类应用的可靠选择。 - 权限申请:必须申请
FOREGROUND_SERVICE和WAKE_LOCK权限,否则服务无法启动或唤醒设备。
内容的提问来源于stack exchange,提问作者alex1888
相关产品推荐
相关产品推荐

