Это мини статья является дополнением к статье Android. Starting Kivy App and Service on bootup, в которой запускал сервисом kivy приложение на API 22 Android 5. Теперь будем запускать на последних версиях Android. C API 26 Android 8 и по текущий API 35 Android 15 который есть у меня, постигли изменения, которые необходимо внести для автостарта сервиса. Проверял работу на API 22...35, телефоны: Highscreen power five, Nokia 8, Xiaomi Redmi Note 14.
C Android 8 претерпело изменение в запуске сервиса:
public void service_start(Context context, Intent intent) {
String package_root = context.getFilesDir().getAbsolutePath();
String app_root = package_root + "/app";
Intent ix = new Intent(context, ServiceTest.class);
ix.putExtra("androidPrivate", package_root);
ix.putExtra("androidArgument", app_root);
ix.putExtra("serviceEntrypoint", "service.py");
ix.putExtra("pythonName", "test");
ix.putExtra("pythonHome", app_root);
ix.putExtra("pythonPath", package_root);
ix.putExtra("serviceStartAsForeground", "true");
ix.putExtra("serviceTitle", "ServiceTest");
ix.putExtra("serviceDescription", "ServiceTest");
ix.putExtra("pythonServiceArgument", app_root + ":" + app_root + "/lib");
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(ix);
} else {
context.startService(ix);
}
}
Теперь он запускается методом startForegroundService.
Начиная с Android 14 действует ограничение на запуск служб из приёмника BOOT_COMPLETED. Поэтому придется править AndroidManifest.xml, в kivy они задаются файлами шаблонами AndroidManifest.tmpl.xml. Нас будет интересовать два таких файла. Изменением оба, т.к. они идентичны и один из них берется как основа другого.
./kivy_service_test/.buildozer/android/platform/python-for-android/pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml
./kivy_service_test/.buildozer/android/platform/build-arm64-v8a/dists/kivy_service_test/templates/AndroidManifest.tmpl.xml
Здесь мы идем по неправильному пути исходной статьи, так как он самый простой.
Во всех секциях service дописываем android:foregroundServiceType, т.к. теперь требуется указать тип сервиса. Не особо углублялся в эти типы, выбрал первый подходящий который решал мою задачу: location. Он разрешает запуск при сигнале BOOT_COMPLETED. Заодно прописываю android:exported, он вроде как запрещает запускать сервис из другого приложения.
{% if service or args.launcher %}
<service android:name="{{ args.service_class_name }}"
android:process=":pythonservice"
android:foregroundServiceType="location"
android:exported="false"/>
{% endif %}
{% for name in service_names %}
<service android:name="{{ args.package }}.Service{{ name|capitalize }}"
android:process=":service_{{ name }}"
android:foregroundServiceType="location"
android:exported="false" />
{% endfor %}
{% for name in native_services %}
<service android:name="{{ name }}"
android:foregroundServiceType="location"
android:exported="false" />
{% endfor %}
{% if args.billing_pubkey %}
<service android:name="org.kivy.android.billing.BillingReceiver"
android:process=":pythonbilling"
android:foregroundServiceType="location"
android:exported="false"/>
После открытия тега application дописываем внутри него:
receiver android:name=".MyBroadcastReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="service_start" />
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.DELETE" />
</intent-filter>
</receiver>
service_start мой сигнал для запуска сервиса при старте приложения, если сервис уже запущен то ни чего не произойдет.
В каждом новом проекте, эти действия придется производить руками. И возможно после команды очистки, придется заново прописывать тип сервиса.
Так же переделал запуск сервиса на старте приложения через свой сигнал:
def service_send_start(*args):
"""
Отправка сообщения MyBroadcastReceiver. В recivers.xml нужно прописать разрешение.
"""
intent = Intent('service_start')
intent.setPackage(Context.getPackageName())
Context.sendBroadcast(intent)
В buildozer.spec добавляем разрешение FOREGROUND_SERVICE_LOCATION
android.permissions = FOREGROUND_SERVICE,
RECEIVE_BOOT_COMPLETED,
QUICKBOOT_POWERON,
ACCESS_COARSE_LOCATION,
ACCESS_FINE_LOCATION,
READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE,
FOREGROUND_SERVICE_LOCATION
Список всех разрешений который мне в итоге потребовался.
Подключаем телефон к ПК. Собираем проект и устанавливаем на телефон:
buildozer android debug && adb install -r -d `ls ./bin/kivy_service_*.apk | tail -1`
Запускам:


Отладка
Ждем печати python service running..... com.heattheatr.kivy_service_test
adb logcat | egrep "python |Test "
Результат работы:
08-25 14:54:14.652 21092 21112 I Test : Android kivy bootstrap done. __name__ is __main__
08-25 14:54:14.652 21092 21112 I python : AND: Ran string
08-25 14:54:14.652 21092 21112 I python : Run user program, change dir and execute entrypoint
08-25 14:54:14.791 21092 21112 I Test : [INFO ] [Logger ] Record log in /data/user/0/com.heattheatr.kivy_service_test/files/app/.kivy/logs/kivy_25-08-25_1.txt
08-25 14:54:14.791 21092 21112 I Test : [INFO ] [Kivy ] v2.3.1
08-25 14:54:14.791 21092 21112 I Test : [INFO ] [Kivy ] Installed at "/data/user/0/com.heattheatr.kivy_service_test/files/app/_python_bundle/site-packages/kivy/__init__.pyc"
08-25 14:54:14.792 21092 21112 I Test : [INFO ] [Python ] v3.11.5 (main, Aug 18 2025, 22:24:06) [Clang 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0
08-25 14:54:14.792 21092 21112 I Test : [INFO ] [Python ] Interpreter at ""
08-25 14:54:14.792 21092 21112 I Test : [INFO ] [Logger ] Purge log fired. Processing...
08-25 14:54:14.792 21092 21112 I Test : [INFO ] [Logger ] Purge finished!
08-25 14:54:15.473 21092 21112 I Test : python service running..... com.heattheatr.kivy_service_test 21092
08-25 14:54:25.474 21092 21112 I Test : python service running..... com.heattheatr.kivy_service_test 21092
08-25 14:54:35.474 21092 21112 I Test : python service running..... com.heattheatr.kivy_service_test 21092
08-25 14:54:45.475 21092 21112 I Test : python service running..... com.heattheatr.kivy_service_test 21092
Перезагружаем телефон, смотрим adb:
08-25 15:17:33.023 12012 12012 I System.out: python Context: android.app.ReceiverRestrictedContext@2829109, Intent: android.intent.action.BOOT_COMPLETED
08-25 15:17:33.023 12012 12012 I System.out: python Build.VERSION.SDK_INT 35
08-25 15:17:33.047 1737 1755 I ActivityManager: Background started FGS: Allowed [callingPackage: com.heattheatr.kivy_service_test; callingUid: 10350; uidState: RCVR; uidBFSL: n/a; intent: Intent { flg=0x10000000 cmp=com.heattheatr.kivy_service_test/.ServiceTest (has extras) }; code:BOOT_COMPLETED; tempAllowListReason:<ad20de6 android.intent.action.BOOT_COMPLETED/u0,reasonCode:BOOT_COMPLETED,duration:20000,callingUid:1000>; targetSdkVersion:31; callerTargetSdkVersion:31; startForegroundCount:0; bindFromPackage:null: isBindService:false]
08-25 15:17:33.333 12281 12281 D ActivityThread: setEmbeddedParam packageName=com.heattheatr.kivy_service_test processName=com.heattheatr.kivy_service_test:service_Test isEmbedded=false isIsolated=false
08-25 15:17:34.028 12281 12435 I python : Initializing Python for Android
08-25 15:17:34.028 12281 12435 I python : Setting additional env vars from p4a_env_vars.txt
08-25 15:17:34.029 12281 12435 I python : Changing directory to the one provided by ANDROID_ARGUMENT
08-25 15:17:34.029 12281 12435 I python : /data/user/0/com.heattheatr.kivy_service_test/files/app
08-25 15:17:34.031 12281 12435 I python : Preparing to initialize python
08-25 15:17:34.032 12281 12435 I python : _python_bundle dir exists
08-25 15:17:34.032 12281 12435 I python : calculated paths to be...
08-25 15:17:34.032 12281 12435 I python : /data/user/0/com.heattheatr.kivy_service_test/files/app/_python_bundle/stdlib.zip:/data/user/0/com.heattheatr.kivy_service_test/files/app/_python_bundle/modules
08-25 15:17:34.032 12281 12435 I python : set wchar paths...
08-25 15:17:34.077 12281 12435 I python : Initialized python
08-25 15:17:34.077 12281 12435 I python : AND: Init threads
08-25 15:17:34.078 12281 12435 I test : testing python print redirection
08-25 15:17:34.079 12281 12435 I python : AND: Ran string
08-25 15:17:34.079 12281 12435 I python : Run user program, change dir and execute entrypoint
08-25 15:17:35.399 12281 12435 I test : python service running..... com.heattheatr.kivy_service_test 12281
08-25 15:17:36.659 12885 12971 I python : Initializing Python for Android
08-25 15:17:36.659 12885 12971 I python : Setting additional env vars from p4a_env_vars.txt
08-25 15:17:36.661 12885 12971 I python : Changing directory to the one provided by ANDROID_ARGUMENT
08-25 15:17:36.661 12885 12971 I python : /data/user/0/com.intercom.intercom/files/app
08-25 15:17:36.662 12885 12971 I python : Preparing to initialize python
08-25 15:17:36.663 12885 12971 I python : _python_bundle dir exists
08-25 15:17:36.663 12885 12971 I python : calculated paths to be...
08-25 15:17:36.663 12885 12971 I python : /data/user/0/com.intercom.intercom/files/app/_python_bundle/stdlib.zip:/data/user/0/com.intercom.intercom/files/app/_python_bundle/modules
08-25 15:17:36.663 12885 12971 I python : set wchar paths...
08-25 15:17:36.826 12885 12971 I python : Initialized python
08-25 15:17:36.826 12885 12971 I python : AND: Init threads
08-25 15:17:36.826 12885 12971 I intercom: testing python print redirection
08-25 15:17:36.827 12885 12971 I python : AND: Ran string
08-25 15:17:36.827 12885 12971 I python : Run user program, change dir and execute entrypoint
08-25 15:17:45.400 12281 12435 I test : python service running..... com.heattheatr.kivy_service_test 12281
08-25 15:17:55.408 12281 12435 I test : python service running..... com.heattheatr.kivy_service_test 12281
08-25 15:18:05.408 12281 12435 I test : python service running..... com.heattheatr.kivy_service_test 12281
Спасибо за внимание.