本文针对国内手机厂商对于后台应用无法保活的限制下,用户还希望你的应用能在后台保持运行。 ps:如果用户不给权限,除非加入系统白名单,否则你的应用会死的一干二净。 第一步:利用Service类onStartCommand()方法返回值-
- public class YourService extends Service {
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- //这里默认返回就START_STICKY,当然也可以根据需求返回其他的值
- return super.onStartCommand(intent, flags, startId);
- // return START_STICKY 或 START_REDELIVER_INTENT
- }
- }
复制代码
这种方式算是中规中矩了,也不违反官方的编程规范。但是如果用户频繁的杀死你的应用,或者在设置中手动强制停止你的Service,那么重新启动的时机就不好说了,有可能一直启动不起来了。 第二步:捕获系统通知利用接收一些频繁产生通知,让自己应用重新启动。例如 网络变化、屏幕解锁、充电、停止充电、新图片、新视频等。现在大部分第三方推送都会用这种通知的监听。 目前这种方式有两个弊端: 从7.0系统开始,针对全局应用的通知增加了限制,例如非前台应用无法接收到网络变化、新图片、新视频的通知。个人在测试时(8.1系统),如果应用被杀死后,什么通知也唤醒不了应用。
国内系统的手机管理工具内,有自启动限制功能,这也会导致应用无法重启。 第三步:请求自启动权限 + JobService如果系统限制你的应用自启动,那么乖乖的请求用户去把自启动权限打开吧,否则永远没戏。
经过在oppo的机器上测试,就算是允许了应用自启动,我们应用也不会立即重新启动,这个启动时机无法确定。
为了尽快让自己应用启动起来,可以添加JobService周期任务,在最短周期内唤醒自己的应用。其中,小米推送就是利用了JobService这种机制。当然,只能在5.0以上的系统使用。 - //定义一个Service,继承JobService
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- public class KeepAliveJobService extends JobService {
- @Override
- public boolean onStartJob(JobParameters params) {
- Timber.d("----onStartJob-----");
- return true;
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- Timber.d("----onStopJob-----");
- return true;
- }
- }
-
- //不要忘了在清单文件中声明
- <service
- android:name=".service.KeepAliveJobService"
- android:enabled="true"
- android:exported="true"
- android:permission="android.permission.BIND_JOB_SERVICE" />
-
- //最后在应用启动时,开启这个Service
- private void startKeepAliveJobService(Context context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- JobInfo.Builder builder = new JobInfo.Builder(245, new ComponentName(context, KeepAliveJobService.class));
- builder.setPeriodic(6 * 60 * 1000);
- //Android 7.0+ 增加了一项针对 JobScheduler 的新限制,最小间隔只能是下面设定的数字
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- builder.setPeriodic(JobInfo.getMinPeriodMillis(), JobInfo.getMinFlexMillis());
- }
- builder.setPersisted(true);
- JobScheduler scheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);
- if (scheduler != null) {
- scheduler.schedule(builder.build());
- }
- }
- }
复制代码 第四步:利用通知监听服务经过上面三步,基本上能在拥有自启动权限的情况下,能不定时机的唤醒自己的应用了。大家别忘了,国内厂商系统除了自启动权限,还有什么后台限制运行、锁屏清除应用等牛逼限制。能让用户一并把这些限制给我们的App放开肯定是最好的,不过经过实践发现,有些设置入口很深,一般用户根本找不到,我们的App也无法直接跳转这些设置页面。 咳咳,那么有没有一种权限,比较好设置,允许后不管怎么清除应用,都可以马上重新启动呢? 那就是通知监听服务(NotificationListenerService),读者可以在手机开发者模式中,查看正在运行服务中,有一些服务有一个“通知侦听器”的设置,而这些服务是怎么杀都杀不死的,例如某某0手机助手。它就是开启了通知监听服务,并获取到了权限,大家可以自行尝试。下面是使用方法(4.4系统以上适用): - //新建NotificationListenerService子类
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- public class MyNotificationListenerService extends NotificationListenerService {
-
- private static final String TAG = "MyNotificationListenerS";
-
- @Override
- public void onNotificationPosted(StatusBarNotification sbn) {
- super.onNotificationPosted(sbn);
- Log.i(TAG, "onNotificationPosted: " + sbn.toString());
- }
-
- @Override
- public void onNotificationRemoved(StatusBarNotification sbn) {
- super.onNotificationRemoved(sbn);
- Log.i(TAG, "onNotificationRemoved: " + sbn.toString());
- }
-
- @Override
- public void onListenerConnected() {
- super.onListenerConnected();
- Log.i(TAG, "onListenerConnected: ");
- }
-
- @Override
- public void onListenerDisconnected() {
- super.onListenerDisconnected();
- Log.i(TAG, "onListenerDisconnected: ");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "onDestroy: ");
- }
- }
-
- //在清单文件中声明
- <service android:name=".feature.notification.MyNotificationListenerService"
- android:label="@string/app_name"
- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
- >
-
- <intent-filter>
- <action android:name="android.service.notification.NotificationListenerService" />
- </intent-filter>
-
- </service>
-
- //开启服务
-
- Intent intent = new Intent(getBaseContext(), MyNotificationListenerService.class);
- startService(intent);
-
- //检查是否有该权限
- Set<String> pckNames = NotificationManagerCompat.getEnabledListenerPackages(getApplicationContext());
- if (pckNames != null && pckNames.contains(getPackageName())) {
- Toaster.showLongToast(getApplicationContext(), "有权限");
- } else {
- Toaster.showLongToast(getApplicationContext(), "无权限");
- }
-
- //跳转设置页
- String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
-
- startActivity(new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS));
复制代码感觉有点流氓,不过是必须在用户允许的情况才能使用,且用且珍惜。 补充:通知监听服务在oppo和vivo设备上能立即被重新启动。在小米设备不是很及时。
|