赞
踩
在小米 Max3 上测试发现了两种方式可以实现从后台启动 Activity 界面,其系统是基于 Android 9 的 MIUI 系统。
方式一:moveTaskToFront
这种方式不算是直接从后台启动 Activity,而是换了一个思路,在后台启动目标 Activity 之前先将应用切换到前台,然后再启动目标 Activity,如果有必要的话,还可以通过 Activity.moveTaskToBack 方法将之前切换到前台的 Activity 重新移入后台,经过测试,在 Android 10 上这个方法已经失效了…但是 10 以下的版本还是可以抢救一下的(需要声明 android.permission.REORDER_TASKS 权限)。
启动目标 Activity 之前先判断一下应用是否在后台,判断方法可以借助 ActivityManager.getRunningAppProcesses 方法或者 Application.ActivityLifecycleCallbacks 来监听前后台,这两种方法网上都有文章讲解,就不赘述了。直接贴出后台切换到前台的代码:
fun moveToFront(context: Context) {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
activityManager?.getRunningTasks(100)?.forEach { taskInfo ->
if (taskInfo.topActivity?.packageName == context.packageName) {
Log.d(“LLL”, “Try to move to front”)
activityManager.moveTaskToFront(taskInfo.id, 0)
return
}
}
}
fun startActivity(activity: Activity, intent: Intent) {
if (!isRunningForeground(activity)) {
Log.d(“LLL”, “Now is in background”)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// TODO 防止 moveToFront 失败,可以多尝试调用几次
moveToFront(activity)
activity.startActivity(intent)
activity.moveTaskToBack(true)
} else {
NotificationUtils.sendNotificationFullScreen(activity, “”, “”)
}
} else {
Log.d(“LLL”, “Now is in foreground”)
activity.startActivity(intent)
}
}
方式二:Hook
由于 MIUI 系统不开源,因此尝试再研究研究 AOSP 源码,死马当活马医看能不能找到什么蛛丝马迹。首先从 Activity.startActivity 方法开始追,如果阅读过 Activity 启动源码流程的话可以知道 Activity.startActivity 或调用到 Instrumentation.execStartActivity 中,然后通过 Binder 调用到 AMS 相关的方法,权限认证就在 AMS 中完成,如果权限不满足自然启动就失败了(Android 10)。
// APP 进程
public ActivityResult execStartActivity(Context who, IBinder contextThread, …) {
// …
// 这里会通过 Binder 调用到 AMS 相关的代码
int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(),
intent, intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null, req
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。