I want to make an Android service that can run independent of the main app. It will be a TCP server to receive messages. The project is created and managed with BeeWare, not with Android Studio. I configured the manifest to run the service in a separeted process and when the service is started, I elevated it to the foreground service. Now, if I go to Task Manager and swipe away my app, the service indeed remains running. But if I press the X button to clear all recent apps, the service is killed too. What do I need to do so that my service remains running under all nomal circumstances ? I have enough RAM and the battery is full, so it shouldn't kill my service. I have Android 13 on Xiaomi Redmi Note 10 Pro.
Note: My question is not a dupplicate of these questions because they are 10 years old, and the things got changed and they work differently:
For reference, this is my manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/formal_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Launcher" >
<!-- https://developer.android.com/guide/topics/resources/runtime-changes#HandlingTheChange -->
<activity
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:name="org.beeware.android.MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="org.beeware.android.MyService"
android:foregroundServiceType="remoteMessaging"
android:exported="false"
android:process=":tcp_service_process"
android:icon="@mipmap/ic_launcher_round">
</service>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
</application>
</manifest>
And this is my service:
package org.beeware.android;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
import android.util.Log;
import com.chaquo.python.PyObject;
import com.chaquo.python.Python;
import com.chaquo.python.android.AndroidPlatform;
import com.example.myapp.R;
public class MyService extends Service {
private static final String ChannelID = "MyServiceChannel";
private String mySrv = "MyService";
private int ONGOING_NOTIFICATION_ID = 1; // This cannot be 0. So 1 is a good candidate.
@Override
public void onCreate() {
Log.d(mySrv, "Service created.");
// Start Python in this process
if (!Python.isStarted()) {
Python.start(new AndroidPlatform(this));
}
// Create notification channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
ChannelID, "My Service Channel", NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) { manager.createNotificationChannel(serviceChannel); }
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(mySrv, "Service started.");
// Put the service in a foreground state
Intent notifIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_IMMUTABLE);
Notification notif = new NotificationCompat.Builder(this, ChannelID)
.setContentTitle("My Service")
.setContentText("Service is running")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentIntent(pendingIntent)
.build();
startForeground(ONGOING_NOTIFICATION_ID, notif);
Log.d(mySrv, "Starting worker thread...");
Python py = Python.getInstance();
PyObject srv_thread = py.getModule("myapp.app");
srv_thread.callAttr("StartServer");
Log.d(mySrv, "Worker thread started.");
Toast.makeText(this, "Service started !", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
@Override
public void onDestroy() {
Log.d(mySrv, "Stopping service thread...");
Python py = Python.getInstance();
PyObject srv_thread = py.getModule("myapp.app");
srv_thread.callAttr("StopServer");
Log.d(mySrv, "Service thread stopped.");
Toast.makeText(this, "Service stopped !", Toast.LENGTH_SHORT).show();
Log.d(mySrv, "Service destroyed.");
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
}
I studied all other questions about this problem and it seems that nothing works anymore, for the devices from our time (the year 2024)... Starting the service as foreground will still close it when you clear all recent apps. I don't like the solution with restart it by an alarm started in onDestroy event either, because it will interrupt my service and it's against common sense to brute force a service to restart... But I find an acceptable workaround: