Android. Starting Kivy App and Service on bootup. API 35

от автора

Это мини статья является дополнением к статье 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 

Спасибо за внимание.

Ссылки


ссылка на оригинал статьи https://habr.com/ru/articles/940534/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *