Android 应用进程保活方案实战

  1. 前台服务:将应用运行的服务设置为前台服务,让用户知道应用正在后台运行,系统会给予一定的优先级,减少被系统杀掉的概率。但是需要注意,使用前台服务保活不能大量占用用户的通知栏,否则用户可能会感到烦躁而卸载应用。

  2. JobScheduler:Android 5.0 开始引入的一种调度任务的方式,可以灵活地安排应用的任务执行时间,提高任务执行的效率和稳定性。

  3. AlarmManager:可以在后台定时启动应用的服务或广播,保证应用在后台不会被系统杀掉。但同时也需要注意避免过度使用 AlarmManager,减少应用在后台的功耗和资源占用。

  4. 双进程守护:通过开启两个进程来使应用在系统中运行两条不同的进程,相互守护,保证一旦有一条进程被系统销毁,则另一条进程会重新唤醒应用。但是双进程守护会造成应用的内存占用较高,并且一些手机厂商可能会禁用该功能。

  5. 保活框架:市面上有一些第三方保活框架,可以通过一些技术手段来维持应用的活跃性,如 CPU 占用、唤醒锁等。但需要注意这些框架可能会带来额外的资源消耗和电量消耗。

以上是 Android 应用进程保活的主要方案。当然,不同应用的保活策略可能因应用特性和开发需要而有所不同。

一、前台服务

1.在 AndroidManifest.xml 文件中添加访问网络状态和前台服务的权限:

复制<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

2.创建一个后台服务,让 Service 继承 Service 类,实现其 onBind() 方法和 onStartCommand() 方法,保持服务在前台运行,并在服务被销毁时再次启动:

复制public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Notification notification = new NotificationCompat.Builder(this, "CHANNEL_ID")
                .setContentTitle("App is running in background")
                .setContentText("Tap to open")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(PendingIntent.getActivity(this, 0, intent, 0))
                .build();

        startForeground(1, notification);

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show();

        Intent intent = new Intent(getApplicationContext(), MyService.class);
        startService(intent);
    }
}

3.在 MainActivity 类中启动服务:

扫描二维码关注公众号,回复: 16097464 查看本文章
复制public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(getApplicationContext(), MyService.class);
        startService(intent);
    }
}

在前台服务中的通知栏中使用了一个 PendingIntent 来启动 MainActivity,使得用户可以在单击通知栏时打开应用。在服务被销毁时,通过启动另一个 Intent 对象的方式重新启动服务,从而实现了保活的功能。需要注意的是,在程序退出后服务仍会继续运行,需要通过调用 stopService() 方法或者调用 stopForeground() 方法来停止服务,不然可能会一直在后台运行造成系统负担增大。

二、双进程守护

  • 1.创建一个守护服务类 DaemonService:

    复制public class DaemonService extends Service {
        private final static String TAG = DaemonService.class.getSimpleName();
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.i(TAG, "onCreate: DaemonService created.");
        }
    
        @Override
        public void onTaskRemoved(Intent rootIntent) {
            super.onTaskRemoved(rootIntent);
    
            Log.i(TAG, "onTaskRemoved: App is killed.");
    
            // 在应用被杀死前,启动 ProtectService 来尝试拉活
            Intent intent = new Intent(getApplicationContext(), ProtectService.class);
            startService(intent);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

    2.创建一个拉活服务类 ProtectService:

    复制public class ProtectService extends Service {
        private final static String TAG = ProtectService.class.getSimpleName();
        private final static int NOTIFY_ID = 1;
        private final static String CHANNEL_NAME = "keep_alive";
        private final static String CHANNEL_DESCRIPTION = "keep_alive";
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.i(TAG, "onCreate: ProtectService created.");
    
            startForeground(NOTIFY_ID, getNotification());
    
            startService(new Intent(getApplicationContext(), DaemonService.class));
        }
    
        private Notification getNotification() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
                NotificationChannel channel = new NotificationChannel(CHANNEL_NAME, CHANNEL_DESCRIPTION, NotificationManager.IMPORTANCE_HIGH);
                notificationManager.createNotificationChannel(channel);
    
                Notification.Builder builder = new Notification.Builder(this, CHANNEL_NAME);
                builder.setSmallIcon(R.mipmap.ic_launcher);
                builder.setContentTitle(getString(R.string.app_name));
                builder.setContentText(getString(R.string.text_keep_alive));
    
                return builder.build();
            } else {
                NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
                builder.setSmallIcon(R.mipmap.ic_launcher);
                builder.setContentTitle(getString(R.string.app_name));
                builder.setContentText(getString(R.string.text_keep_alive));
    
                return builder.build();
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

    3.在 MainActivity 中启动守护服务和拉活服务:

    复制public class MainActivity extends AppCompatActivity {
        private final static String TAG = MainActivity.class.getSimpleName();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.i(TAG, "onCreate: MainActivity created.");
    
            startService(new Intent(getApplicationContext(), DaemonService.class));
            startService(new Intent(getApplicationContext(), ProtectService.class));
        }
    }
    

    若应用被系统杀死,实时捕捉到,并且尝试调用 ProtectService 来唤醒应用,让它重新处于前台运行的状态,保证在后台时极少被杀死的情况。同时,由于开启了前台服务,又频繁切换前台后台可能会导致用户的通知栏被大量的“常驻通知”,需要注意这一点。

  • 对上述功能增加手机开机启动功能
  • 好的,以下是在上述方案基础上增加手机开机启动功能的完整代码示例:

    1.创建一个 BroadcastReceiver 类,用于监听手机开机广播,创建一个 Intent 对象用于启动守护服务和拉活服务:

    复制public class BootReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
                Intent service = new Intent(context, DaemonService.class);
                context.startService(service);
    
                Intent protect = new Intent(context, ProtectService.class);
                context.startService(protect);
            }
        }
    }
    

    2.在 AndroidManifest.xml 文件中注册权限和 BroadcastReceiver:

    复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    
    <receiver
        android:name=".BootReceiver"
        android:enabled="true"
        android:exported="true"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    

    3.在 MainActivity 类中检查守护服务和拉活服务是否在运行,如果没有则手动启动:

    复制public class MainActivity extends AppCompatActivity {
        private final static String TAG = MainActivity.class.getSimpleName();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.i(TAG, "onCreate: MainActivity created.");
    
            if (!isServiceRunning(this, DaemonService.class.getName())) {
                startService(new Intent(getApplicationContext(), DaemonService.class));
            }
    
            if (!isServiceRunning(this, ProtectService.class.getName())) {
                startService(new Intent(getApplicationContext(), ProtectService.class));
            }
        }
    
        private boolean isServiceRunning(Context context, String serviceName) {
            ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.RunningServiceInfo> list = am.getRunningServices(Integer.MAX_VALUE);
    
            for (ActivityManager.RunningServiceInfo info : list) {
                if (serviceName.equals(info.service.getClassName())) {
                    return true;
                }
            }
    
            return false;
        }
    }
    

    以上就是增加手机开机启动功能的完整代码示例,可以在设备重启后自动启动服务,并保持应用在后台的运行状态。

三、JobScheduler

1.创建一个 JobService 类,并实现其 onStartJob() 和 onStopJob() 方法:

复制public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        Log.i(TAG, "onStartJob");

        // 在此添加需要执行的任务
        // ...

        jobFinished(params, false);

        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return true;
    }
}

2.在 AndroidManifest.xml 文件中注册 JobService 和必要的权限:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application>
    ...

    <service
        android:name=".MyJobService"
        android:permission="android.permission.BIND_JOB_SERVICE" />

    ...
</application>

3.在应用启动时调起对应的 JobScheduler,实现保活:

复制public class MainActivity extends AppCompatActivity {
    private static final int JOB_ID = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);

        JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, new ComponentName(getPackageName(), MyJobService.class.getName()));
        builder.setPeriodic(10000);
        builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);

        if (scheduler.schedule(builder.build()) <= 0) {
            Log.e(TAG, "onCreate: JobScheduler failed.");
        }
    }
}

这里我们设置保活时间为10秒,设置网络请求不区分Wifi或移动网络。在应用被回收后,JobScheduler 会重新启动应用并调起 MyJobService 类的 onStartJob() 方法,在该方法中添加需要执行的任务,完成应用的保活。

需要注意的是,JobScheduler 并不是100%保证能够精确按照设定的时间执行任务,系统可能会因为一些原因推迟任务的执行时间,而且不同版本的Android可能会有不同支持程度。

如果任务要求立即执行,可以使用 startService() 方法或者 ForegroundService 实现,同时结合 JobScheduler 使用以保证在后台时不会被杀掉。

四、AlarmManager

1.创建一个常驻进程 Service,实现其 onBind()、onStartCommand() 和 onDestroy() 方法:

复制public class KeepAliveService extends Service {
    private static final int NOTIFY_ID = 1001;
    private static final String CHANNEL_ID = "MY_CHANNEL_ID";
    private static final String CHANNEL_NAME = "MY_CHANNEL_NAME";

    private PendingIntent pendingIntent;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");

        Intent notificationIntent = new Intent(this, MainActivity.class);
        pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);

            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);

            notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        } else {
            notification = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setPriority(NotificationCompat.PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        }

        startForeground(NOTIFY_ID, notification);

        // 定时发送广播
        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent alarmIntent = new Intent(getApplicationContext(), KeepAliveReceiver.class);
        pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 30000, pendingIntent);

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy");

        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        am.cancel(pendingIntent);

        stopForeground(true);
    }
}

2.创建一个广播监听器 KeepAliveReceiver,用来接收定时广播并重新启动常驻服务:

复制public class KeepAliveReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent service = new Intent(context, KeepAliveService.class);
        context.startService(service);
    }
}

3.在 AndroidManifest.xml 中注册 BroadcastReceiver 和相应的权限:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<receiver
    android:name=".KeepAliveReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="myAction" />
    </intent-filter>
</receiver>

<service
    android:name=".KeepAliveService"
    android:exported="false" />

可以看到这里注册了一个 BroadcastReceiver 来监听 app 的定时任务,同时也添加了 BOOTCOMPLETED 权限和注册了 BOOTCOMPLETED 广播监听器,来接收设备启动完成的广播。

4.在 MainActivity 的 onCreate() 方法中启动常驻服务:

复制public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent service = new Intent(getApplicationContext(), KeepAliveService.class);
        startService(service);
    }
}

最后在 MainActivity 的 onCreate() 方法中启动常驻服务即可完成 Android 应用的进程保活功能。

五、保活框架

当应用进入后台或者长时间未操作时,Android 系统的进程管理机制会将其进程杀掉,从而避免因应用长时间占用资源导致系统运行不稳定或者其他应用运行出现问题。但是某些的应用,比如推送、IM 类应用,需要在后台一直保持连接,这就需要让应用进程长期存活。

为了解决这个问题,开源社区中出现了一些保活框架,它们的主要功能是通过不同的方式让应用进程保持存活状态,保证应用可以在后台进行连接等任务。以下是一些知名的保活框架:

  1. Daemon

Daemon 是 Android 平台上一个进程守护框架,其包含 app 守护、进程保活、服务保活等多个子模块。Daemon 针对不同的应用场景提供了不同的保活方法,包括 Service 方式、 Alarm 机制、JobScheduler 等,其能够在不同的 Android 版本中支持不同的保活方式。

GitHub: https://github.com/Leaking/daemon

  1. Xposed

Xposed 是一个用来定制和修改 APK 的工具,它允许用户在不修改 APK 文件的情况下更改应用的行为和外观,也可以用来实现应用保活。Xposed 使用应用内的模块来实现保活功能,但需要 root 权限。

GitHub: https://github.com/rovo89/Xposed

  1. Android-Job

Android-Job 是 Android 系统上作业调度框架,是一个基于 JobScheduler API 的库。Android-Job 允许您创建并执行非常容易使用的作业,此库可以非常方便地创建短暂的异步任务或长时间运行的操作。

GitHub: https://github.com/Evernote/android-job

  1. JobSchedulerCompat

JobSchedulerCompat 利用 JobScheduler API 在 Android 5.0 以下版本中实现了 JobScheduler 的所有功能。JobSchedulerCompat 在实现 JobScheduler 的同时可以支持保活等场景的使用。

GitHub: https://github.com/evant/JobSchedulerCompat

  1. WorkManager

WorkManager 是 Google 推出的一款用于管理后台调度任务的库,可以兼容 Api Level 14+ 的设备。WorkManager 是Android Jetpack 的一部分,结合 WorkManager 可以轻松实现工作调度和长期运行的任务.

GitHub: https://github.com/android/architecture-components-samples/tree/master/WorkManagerSample

以上是一些知名的保活框架,它们都有各自独特的特点和适用场景,可以根据具体的开发需求来选择使用。

六、WorkManager

1.创建一个 WorkManager 的 Worker 类:

复制public class KeepAliveWorker extends Worker {
    private static final String TAG = "KeepAliveWorker";

    public KeepAliveWorker(
            @NonNull Context context,
            @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.i(TAG, "doWork");

        // 在此添加需要执行的任务
        // ...

        return Result.success();
    }
}

2.创建一个定时任务,并调度执行:

复制PeriodicWorkRequest keepAliveWork =
        new PeriodicWorkRequest.Builder(KeepAliveWorker.class, 15, TimeUnit.MINUTES)
                .setConstraints(Constraints.NONE)
                .build();

WorkManager workManager = WorkManager.getInstance(context);
workManager.enqueueUniquePeriodicWork(
        "keep_alive_work",
        ExistingPeriodicWorkPolicy.KEEP,
        keepAliveWork
);

此处我们创建了一个周期性执行的任务,每隔 15 分钟执行一次。通过 WorkManager 调度执行该任务,其中的 WorkPolicy 设置为 ExistingPeriodicWorkPolicy.KEEP 表示如果当前已经有相同名字的任务在执行,则保持不变,不会重新启动。

3.在 AndroidManifest.xml 文件中声明以及申请一些必要的权限:

复制<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application>
    ...

    <receiver
        android:name=".KeepAliveReceiver"
        android:enabled="true"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

    ...
</application>

可以看到,我们在 AndroidManifest.xml 中注册了一个 BroadcastReceiver 来接收 BOOT_COMPLETED 广播,这样当设备启动完成后能够自动重启任务。

4.创建一个 BroadcastReceiver,接收 BOOT_COMPLETED 广播并重新启动任务:

复制public class KeepAliveReceiver extends BroadcastReceiver {
    private static final String TAG = "KeepAliveReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(new Intent(context, KeepAliveService.class));
        } else {
            context.startService(new Intent(context, KeepAliveService.class));
        }
    }
}

5.创建一个常驻服务,确保应用在后台运行的同时能够通过 WorkManager 定时执行任务:

复制public class KeepAliveService extends Service {
    private static final int NOTIFY_ID = 1001;
    private static final String CHANNEL_ID = "MY_CHANNEL_ID";
    private static final String CHANNEL_NAME = "MY_CHANNEL_NAME";

    private PendingIntent pendingIntent;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");

        Intent notificationIntent = new Intent(this, MainActivity.class);
        pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);

            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
 notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        } else {
            notification = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.text_keep_alive))
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(false)
                    .setPriority(NotificationCompat.PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
        }

        startForeground(NOTIFY_ID, notification);

        startWorkManager();

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy");

        stopWorkManager();

        stopForeground(true);

        Intent intent = new Intent(this, KeepAliveReceiver.class);
        intent.setAction("myAction");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000, pendingIntent);
    }

    private void startWorkManager() {
        Log.i(TAG, "startWorkManager");

        PeriodicWorkRequest keepAliveWork =
                new PeriodicWorkRequest.Builder(KeepAliveWorker.class, 15, TimeUnit.MINUTES)
                        .setConstraints(Constraints.NONE)
                        .build();

        WorkManager workManager = WorkManager.getInstance(getApplicationContext());
        workManager.enqueueUniquePeriodicWork(
                "keep_alive_work",
                ExistingPeriodicWorkPolicy.KEEP,
                keepAliveWork
        );
    }

    private void stopWorkManager() {
        Log.i(TAG, "stopWorkManager");

        WorkManager workManager = WorkManager.getInstance(getApplicationContext());
        workManager.cancelUniqueWork("keep_alive_work");
    }
}

我们在 onStartCommand() 方法中启动了一个常驻的前台服务(通过 Notification),同时调用了 startWorkManager() 方法来开启 WorkManager 的定时任务。在 onDestroy() 方法中,我们调用了 stopWorkManager() 来关闭任务,停止 WorkManager 进程运行。

另外值得注意的是,在 onDestroy() 方法中,我们使用 AlarmManager 来启动一个定时广播,其目的是在 WorkManager 定时任务被系统强杀时,能够通过广播重启服务,达到保活效果。

6.最后在 MainActivity 的 onCreate() 方法中启动该 Service:

复制public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent service = new Intent(getApplicationContext(), KeepAliveService.class);
        startService(service);
    }
}

这样就完成了使用 WorkManager 实现 Android 应用进程保活的示例。

七、

  • Daemon实现应用进程保活的接入方案
  • 好的,以下是使用 Daemon 实现 Android 应用进程保活的示例:

    1.在 build.gradle 文件中导入依赖:

    复制repositories {
        maven { url "https://jitpack.io" }
    }
    
    dependencies {
        implementation 'com.github.Leaking:Daemon:2.1.13'
    }
    

    2.创建一个自定义的 Service 继承自 DaemonInnerService。DaemonInnerService 是 Daemon 库中提供的一个基础服务,用于在后台开启常驻进程。

    复制public class MyService extends DaemonInnerService {
        private static final String TAG = "MyService";
    
        // ...
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "onCreate");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(TAG, "onStartCommand");
            startWork();
    
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            Log.i(TAG, "onDestroy");
            stopWork();
        }
    
        // ...
    }
    

    在这里我们创建的 MyService 继承了 DaemonInnerService,覆写了 onStartCommand() 和 onDestroy() 方法。需要注意的是,我们在 onStartCommand() 中调用了 startWork() 方法,这个方法用于启动一些需要保活的任务。同时在 onDestroy() 方法中,我们调用了 stopWork() 方法,用于停止保活任务。

    3.在 AndroidManifest.xml 文件中注册服务:

    复制<service
        android:name=".MyService"
        android:enabled="true"
        android:exported="false" />
    
    <receiver
        android:name=".MyReceiver"
        android:priority="1000"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.USER_PRESENT" />
        </intent-filter>
    </receiver>
    

    在这里我们同时注册了一个广播接收器 MyReceiver,用于接收 BOOTCOMPLETED 和 USERPRESENT 广播,当设备启动完成或解锁时启动服务。

    4.创建一个保活延迟任务类来执行保活相关操作:

    复制public class MyDelayService extends AbsWorkService {
        private static final String TAG = "MyDelayService";
    
        @Override
        public Boolean shouldStopService(Intent intent, int flags, int startId) {
            Log.i(TAG, "shouldStopService");
            return super.shouldStopService(intent, flags, startId);
        }
    
        @Override
        public void startWork(Intent intent, int flags, int startId) {
            Log.i(TAG, "startWork");
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
    _
    
        Intent service = new Intent(getApplicationContext(), MyService.class);
                startService(service);
                startDaemonService(MyDelayService.class);
            }, 10000);
        }
    
        @Override
        public void stopWork(Intent intent, int flags, int startId) {
            Log.i(TAG, "stopWork");
            stopDaemonService(MyDelayService.class);
        }
    
        @NonNull
        @Override
        public Result onRunTask(Intent intent, int flags, int startId) {
            Log.i(TAG, "onRunTask");
    
            return Result.SUCCESS;
        }
    }
    
    在 MyDelayService 中我们定义了一个 startWork() 方法,在该方法中需要手动启动 MyService,并启动 DaemonInnerService 类型为 MyDelayService 的服务。同时需要注意,需要在 10 秒后执行任务,保证能够在服务启动完成后调用 startWork() 方法。
    
    5.创建一个广播接收器 MyReceiver,接收系统广播并重启保活服务:
  • 复制public class MyReceiver extends AbsReceiver {
        private static final String TAG = "MyReceiver";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);
    
            Log.i(TAG, "onReceive");
    
            boolean isScreenOn = isScreenOn(context);
    
            if (isScreenOn) {
                Intent service = new Intent(context, MyService.class);
                context.startService(service);
            }
        }
    }
    

    在 MyReceiver 中我们根据广播的类型判断设备是否解锁,并根据结果重启服务。注意,这里我们需要通过 isScreenOn() 方法来判断设备是否解锁,该方法需要在 AbsReceiver 中进行实现。

    6.最后在 MainActivity 中启动保活服务:

    复制public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Intent service = new Intent(getApplicationContext(), MyService.class);
            startService(service);
        }
    }
    

    以上是使用 Daemon 实现 Android 应用进程保活的示例。通过 Daemon 库,我们可以非常简单地实现应用进程保活功能,支持在不同的场景下保活,并能够通过

猜你喜欢

转载自blog.csdn.net/MYBOYER/article/details/129945121