Starting Kivy service on bootup (Android)
Question:
I’m trying to start my kivy app’s service on bootup.
I’m sure that my service is ok because it works when I start my app. But on bootup I have a problem.
I’ve read this article and tried to make it:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import org.kivy.android.PythonActivity;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent ix = new Intent(context, PythonActivity.class);
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(ix);
}
}
It works but starts the app but not the service. So I’ve studied some questions on StackOverflow and changed my code for this:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import net.saband.myapp.ServiceMyservice;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent ix = new Intent(context, ServiceMyservice.class);
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(ix);
}
}
… and got an error:
10-21 19:16:44.784 1513 1569 I ActivityManager: Start proc 6334:net.saband.myapp:service_myservice/u0a116 for service net.saband.myapp/.ServiceMyservice
10-21 19:16:44.786 6334 6334 I art : Late-enabling -Xcheck:jni
10-21 19:16:44.885 6334 6334 D AndroidRuntime: Shutting down VM
10-21 19:16:44.888 6334 6334 E AndroidRuntime: FATAL EXCEPTION: main
10-21 19:16:44.888 6334 6334 E AndroidRuntime: Process: net.saband.myapp:service_myservice, PID: 6334
10-21 19:16:44.888 6334 6334 E AndroidRuntime: Theme: themes:{}
10-21 19:16:44.888 6334 6334 E AndroidRuntime: java.lang.RuntimeException: Unable to start service net.saband.myapp.ServiceMyservice@8c96929 with Intent { cmp=net.saband.myapp/.ServiceMyservice }: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
Can you please explain me what’s wrong and what should I do to start the service? Thanks!
UPDATED
By request of @Juggernaut I add my service code:
from time import sleep
if __name__ == '__main__':
while True:
print "myapp service"
sleep(5)
It works when I run app because app calls the service:
def __start_service(self):
if platform == 'android':
service = autoclass('net.saband.myapp.ServiceMyservice')
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
argument = ''
service.start(mActivity, argument)
UPDATED (AndroidManifest)
Here is some strings from my AndroidManifest.xml.
-
I have the RECEIVE_BOOT_COMPLETED permission:
<uses-permission android_name="android.permission.RECEIVE_BOOT_COMPLETED" />
-
I have the receiver:
<receiver android_name=".MyBroadcastReceiver" android_enabled="true">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
-
I have the service registered:
<service android_name="net.saband.myapp.ServiceMyservice"
android_process=":service_myservice" />
By advice of @mariachi I’ve tried to change android:enabled="true" to android_enabled="false"
in the receiver and add android:exported="false"
to the service. In this case when the device starts happens nothing: no errors, no service.
Answers:
It seems that Service or Activity that you try to start is not initialized.
You didn’t paste your AndroidManifest, so I’ll write what it’s supposed to have.
The first thing is that you should have permission added to run on boot:
<uses-permission android_name="android.permission.RECEIVE_BOOT_COMPLETED"/>
The second thing is that you should define your receiver in Manifest:
<receiver android_name=".MyBroadcastReceiver"
android_enabled="false">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
The third thing is that you should define your service or activity you try to start, e.g:
<activity android_name=".PythonActivity" />
<service android_name=".ServiceMyservice" android_exported="false"/>
OMG! I’ve found the solution by solving my another issue with kivy service. It’s enough just add some extras. Here is work code:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import net.saband.myapp.ServiceMyservice;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String package_root = context.getFilesDir().getAbsolutePath();
String app_root = package_root + "/app";
Intent ix = new Intent(context, ServiceMyservice.class);
ix.putExtra("androidPrivate", package_root);
ix.putExtra("androidArgument", app_root);
ix.putExtra("serviceEntrypoint", "./service/main.py");
ix.putExtra("pythonName", "myservice");
ix.putExtra("pythonHome", app_root);
ix.putExtra("pythonPath", package_root);
ix.putExtra("pythonServiceArgument", app_root+":"+app_root+"/lib");
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(ix);
}
}
Where Manifest file in kivy project or how you can added this rule in buildozer.spec?:
<receiver android_name=".MyBroadcastReceiver"
android_enabled="false">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
I’m trying to start my kivy app’s service on bootup.
I’m sure that my service is ok because it works when I start my app. But on bootup I have a problem.
I’ve read this article and tried to make it:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import org.kivy.android.PythonActivity;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent ix = new Intent(context, PythonActivity.class);
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(ix);
}
}
It works but starts the app but not the service. So I’ve studied some questions on StackOverflow and changed my code for this:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import net.saband.myapp.ServiceMyservice;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent ix = new Intent(context, ServiceMyservice.class);
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(ix);
}
}
… and got an error:
10-21 19:16:44.784 1513 1569 I ActivityManager: Start proc 6334:net.saband.myapp:service_myservice/u0a116 for service net.saband.myapp/.ServiceMyservice
10-21 19:16:44.786 6334 6334 I art : Late-enabling -Xcheck:jni
10-21 19:16:44.885 6334 6334 D AndroidRuntime: Shutting down VM
10-21 19:16:44.888 6334 6334 E AndroidRuntime: FATAL EXCEPTION: main
10-21 19:16:44.888 6334 6334 E AndroidRuntime: Process: net.saband.myapp:service_myservice, PID: 6334
10-21 19:16:44.888 6334 6334 E AndroidRuntime: Theme: themes:{}
10-21 19:16:44.888 6334 6334 E AndroidRuntime: java.lang.RuntimeException: Unable to start service net.saband.myapp.ServiceMyservice@8c96929 with Intent { cmp=net.saband.myapp/.ServiceMyservice }: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
Can you please explain me what’s wrong and what should I do to start the service? Thanks!
UPDATED
By request of @Juggernaut I add my service code:
from time import sleep
if __name__ == '__main__':
while True:
print "myapp service"
sleep(5)
It works when I run app because app calls the service:
def __start_service(self):
if platform == 'android':
service = autoclass('net.saband.myapp.ServiceMyservice')
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
argument = ''
service.start(mActivity, argument)
UPDATED (AndroidManifest)
Here is some strings from my AndroidManifest.xml.
-
I have the RECEIVE_BOOT_COMPLETED permission:
<uses-permission android_name="android.permission.RECEIVE_BOOT_COMPLETED" />
-
I have the receiver:
<receiver android_name=".MyBroadcastReceiver" android_enabled="true">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver> -
I have the service registered:
<service android_name="net.saband.myapp.ServiceMyservice"
android_process=":service_myservice" />
By advice of @mariachi I’ve tried to change android:enabled="true" to android_enabled="false"
in the receiver and add android:exported="false"
to the service. In this case when the device starts happens nothing: no errors, no service.
It seems that Service or Activity that you try to start is not initialized.
You didn’t paste your AndroidManifest, so I’ll write what it’s supposed to have.
The first thing is that you should have permission added to run on boot:
<uses-permission android_name="android.permission.RECEIVE_BOOT_COMPLETED"/>
The second thing is that you should define your receiver in Manifest:
<receiver android_name=".MyBroadcastReceiver"
android_enabled="false">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
The third thing is that you should define your service or activity you try to start, e.g:
<activity android_name=".PythonActivity" />
<service android_name=".ServiceMyservice" android_exported="false"/>
OMG! I’ve found the solution by solving my another issue with kivy service. It’s enough just add some extras. Here is work code:
package net.saband.myapp;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import net.saband.myapp.ServiceMyservice;
public class MyBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String package_root = context.getFilesDir().getAbsolutePath();
String app_root = package_root + "/app";
Intent ix = new Intent(context, ServiceMyservice.class);
ix.putExtra("androidPrivate", package_root);
ix.putExtra("androidArgument", app_root);
ix.putExtra("serviceEntrypoint", "./service/main.py");
ix.putExtra("pythonName", "myservice");
ix.putExtra("pythonHome", app_root);
ix.putExtra("pythonPath", package_root);
ix.putExtra("pythonServiceArgument", app_root+":"+app_root+"/lib");
ix.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(ix);
}
}
Where Manifest file in kivy project or how you can added this rule in buildozer.spec?:
<receiver android_name=".MyBroadcastReceiver"
android_enabled="false">
<intent-filter>
<action android_name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>