Android应用保活四步曲

Android应用保活四步曲

本文针对国内手机厂商对于后台应用无法保活的限制下,用户还希望你的应用能在后台保持运行。

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,那么重新启动的时机就不好说了,有可能一直启动不起来了。

第二步:捕获系统通知

利用接收一些频繁产生通知,让自己应用重新启动。例如 网络变化、屏幕解锁、充电、停止充电、新图片、新视频等。现在大部分第三方推送都会用这种通知的监听。

目前这种方式有两个弊端:

  1. 从7.0系统开始,针对全局应用的通知增加了限制,例如非前台应用无法接收到网络变化、新图片、新视频的通知。个人在测试时(8.1系统),如果应用被杀死后,什么通知也唤醒不了应用。
  2. 国内系统的手机管理工具内,有自启动限制功能,这也会导致应用无法重启。

第三步:请求自启动权限 + 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设备上能立即被重新启动。在小米设备不是很及时。

猜你喜欢

转载自blog.csdn.net/joye123/article/details/79644567