概述
前几天产品提了一个需求,想在后台的时候启动我们 APP 的一个 Activity,随着 Android 版本的更新,以及各家 ROM 厂商的无限改造,这种影响用户体验的功能许多都受到了限制,没办法,虽然是比较流氓的功能,但拿人钱财替人消灾,于是开启了哼哧哼哧的调研之路。
原生Android ROM
首先从 Android 的原生 ROM 开始,根据官方的介绍,后台启动 Activity 的限制是从 Android 10(API 29) 才开始的,在此之前原生 ROM 是没有这个限制的,于是我分别启动了一个 Android 9(API 28) 和 10(API 29) 版本的模拟器,发现在 API 28 上可以直接从后台启动 Activity,而在 API 29 上则受到了限制无法直接启动。参照官方 从后台启动 Activity 的限制 的说明,给出了一些不受限制的例外情况,此外官方的推荐是对于后台启动的需求,先向用户展示一个 Notification 而不是直接启动 Activity,然后在用户点击 Notification 后才处理对应的逻辑。还可以在设置 Notification 时通过 setFullScreenIntent 添加一个全屏 Intent 对象,该方法经过测试,可以在 Android 10 的模拟器上从后台启动一个 Activity 界面(需要 android.permission.USE_FULL_SCREEN_INTENT 权限)。代码如下:
object NotificationUtils {
private const val ID = "channel_1"
private const val NAME = "notification"
private var manager: NotificationManager? = null
private fun getNotificationManagerManager(context: Context): NotificationManager? {
if (manager == null) {
manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
}
return manager
}
fun sendNotificationFullScreen(context: Context, title: String?, content: String?) {
if (Build.VERSION.SDK_INT >= 26) {
clearAllNotification(context)
val channel = NotificationChannel(ID, NAME, NotificationManager.IMPORTANCE_HIGH)
channel.setSound(null, null)
getNotificationManagerManager(context)?.createNotificationChannel(channel)
val notification = getChannelNotificationQ(context, title, content)
getNotificationManagerManager(context)?.notify(1, notification)
}
}
private fun clearAllNotification(context: Context) {
getNotificationManagerManager(context)?.cancelAll()
}
private fun getChannelNotificationQ(context: Context, title: String?, content: String?): Notification {
val fullScreenPendingIntent = PendingIntent.getActivity(
context,
0,
DemoActivity.genIntent(context),
PendingIntent.FLAG_UPDATE_CURRENT
)
val notificationBuilder = NotificationCompat.Builder(context, ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(content)
.setSound(null)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(Notification.CATEGORY_CALL)
.setOngoing(true)
.s