El servicio Kivy se detiene cuando la aplicación está cerrada

Estoy empezando un servicio desde mi aplicación Kivy:

service = autoclass('net.saband.myapp.ServiceMyservice') mActivity = autoclass('org.kivy.android.PythonActivity').mActivity service.start(mActivity, '') 

Funciona. Y si cierro mi aplicación con el botón Atrás, mi servicio todavía funciona. Pero si cierro mi aplicación al deslizarla de la lista de aplicaciones recientes, el servicio muere.

Encontré este problema y traté de usar startForeground guiado por este artículo . Funciona, pero la notificación no es removible, por lo que esta solución no me conviene.

He leído esta pregunta y parece que podría ayudarme a usar START_STICKY … pero es un servicio kivy, ¿cómo puedo implementarlo? He intentado editar Service.tmpl.java en mis plantillas de python-for-android y cambiar esto:

 public class Service{{ name|capitalize }} extends PythonService { {% if sticky %} @Override public int startType() { return START_STICKY; } {% endif %} ... 

a esto:

 public class Service{{ name|capitalize }} extends PythonService { @Override public int startType() { return START_STICKY; } 

(Sí, entiendo que {% if sticky %} significa que puedo configurarlo en algún lugar, pero en los documentos oficiales no hay nada al respecto).

Pero nada cambió, el servicio sigue muriendo. Según los registros está progtwigdo el reinicio:

 11-17 22:52:07.140 1496 1511 I ActivityManager: Killing 29431:net.saband.myapp/u0a122 (adj 9): remove task 11-17 22:52:07.219 1496 3404 I WindowState: WIN DEATH: Window{3c605b3 u0 net.saband.myapp/org.kivy.android.PythonActivity} 11-17 22:52:07.220 1496 3404 W WindowManager: Force-removing child win Window{5ed4ff u0 SurfaceView} from container Window{3c605b3 u0 net.saband.myapp/org.kivy.android.PythonActivity} 11-17 22:52:07.225 1496 2871 W WindowManager: Failed looking up window 11-17 22:52:07.225 1496 2871 W WindowManager: java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@c7f2770 does not exist 11-17 22:52:07.225 1496 2871 W WindowManager: at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8821) 11-17 22:52:07.225 1496 2871 W WindowManager: at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8812) 11-17 22:52:07.225 1496 2871 W WindowManager: at com.android.server.wm.WindowState$DeathRecipient.binderDied(WindowState.java:1212) 11-17 22:52:07.225 1496 2871 W WindowManager: at android.os.BinderProxy.sendDeathNotice(Binder.java:558) 11-17 22:52:07.225 1496 2871 I WindowState: WIN DEATH: null 11-17 22:52:07.247 1496 3311 D ActivityManager: cleanUpApplicationRecord -- 29431 11-17 22:52:07.250 1496 3538 I ActivityManager: Killing 29366:net.saband.myapp:service_myservice/u0a122 (adj 8): remove task 11-17 22:52:07.304 1496 3557 D ActivityManager: cleanUpApplicationRecord -- 29366 11-17 22:52:07.305 1496 3557 W ActivityManager: Scheduling restart of crashed service net.saband.myapp/.ServiceMyservice in 1000ms 

Pero nada pasa.

Necesito que el servicio continúe funcionando incluso cuando la aplicación está cerrada al deslizarla de la lista de aplicaciones recientes. Y necesito notificaciones removibles. Eso es todo. Muchas aplicaciones pueden hacerlo. Pero, ¿hay alguna manera de hacerlo con Kivy y python-for-Android?

Gracias.

Lo hice. Pero esto requería cambiar el código java y la solución está codificada. Es extraño y desagradable que los desarrolladores de python para Android no hayan previsto esto.

Bueno, la solución.

Abra el archivo .buildozer/android/platform/build/dists/myapp/src/org/kivy/android/PythonService.java . En la función startType() cambie START_NOT_STICKY a START_STICKY :

 public int startType() { return START_STICKY; } 

Ahora se reiniciará el servicio. Pero esto no es suficiente porque después de reiniciar en la función onStartCommand(Intent intent, int flags, int startId) intención será nula, por lo que obtendremos un error:

 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Bundle android.content.Intent.getExtras()' on a null object reference 

Entonces necesitamos agregar la sentencia if en esta función:

 @Override public int onStartCommand(Intent intent, int flags, int startId) { if (pythonThread != null) { Log.v("python service", "service exists, do not start again"); return START_NOT_STICKY; } if (intent != null) { startIntent = intent; Bundle extras = intent.getExtras(); androidPrivate = extras.getString("androidPrivate"); androidArgument = extras.getString("androidArgument"); serviceEntrypoint = extras.getString("serviceEntrypoint"); pythonName = extras.getString("pythonName"); pythonHome = extras.getString("pythonHome"); pythonPath = extras.getString("pythonPath"); pythonServiceArgument = extras.getString("pythonServiceArgument"); pythonThread = new Thread(this); pythonThread.start(); if (canDisplayNotification()) { doStartForeground(extras); } } else { pythonThread = new Thread(this); pythonThread.start(); } return startType(); } 

Pero esto no es suficiente porque ahora tenemos otro error en la nativeStart función nativeStart porque no hay extras:

 F DEBUG : Abort message: 'art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: GetStringUTFChars received NULL jstring' 

Así que agregué la verificación nula y algunos valores predeterminados (2 de ellos están codificados) a la función run() :

 @Override public void run(){ String package_root = getFilesDir().getAbsolutePath(); String app_root = package_root + "/app"; File app_root_file = new File(app_root); PythonUtil.loadLibraries(app_root_file); this.mService = this; if (androidPrivate == null) { androidPrivate = package_root; } if (androidArgument == null) { androidArgument = app_root; } if (serviceEntrypoint == null) { serviceEntrypoint = "./service/main.py"; // hardcoded } if (pythonName == null) { pythonName = "myservice"; // hardcoded } if (pythonHome == null) { pythonHome = app_root; } if (pythonPath == null) { pythonPath = package_root; } if (pythonServiceArgument == null) { pythonServiceArgument = app_root+":"+app_root+"/lib"; } nativeStart( androidPrivate, androidArgument, serviceEntrypoint, pythonName, pythonHome, pythonPath, pythonServiceArgument); stopSelf(); } 

Ahora funciona.