Android 12 Notification trampoline restrictions下SDK通知点击重复启动应用的问题咨询
Hey there! I’ve wrestled with exactly these Android 12 notification restrictions before, so let’s walk through each of your questions with practical, actionable solutions:
1. How to check if the app is alive and in foreground/background?
The most reliable way is to use ActivityLifecycleCallbacks to track your app’s state. Here’s how to set it up:
Create a custom lifecycle handler class:
class AppLifecycleHandler : Application.ActivityLifecycleCallbacks { private var foregroundActivities = 0 private var isChangingConfiguration = false var isAppInForeground: Boolean = false private set override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} override fun onActivityStarted(activity: Activity) { foregroundActivities++ if (foregroundActivities == 1 && !isChangingConfiguration) { isAppInForeground = true } } override fun onActivityResumed(activity: Activity) {} override fun onActivityPaused(activity: Activity) {} override fun onActivityStopped(activity: Activity) { foregroundActivities-- isChangingConfiguration = activity.isChangingConfigurations if (foregroundActivities == 0 && !isChangingConfiguration) { isAppInForeground = false } } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {} override fun onActivityDestroyed(activity: Activity) {} }Register it in your Application class:
class MyApp : Application() { val appLifecycleHandler = AppLifecycleHandler() override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(appLifecycleHandler) } }
Then you can call (application as MyApp).appLifecycleHandler.isAppInForeground to check the state. For checking if the app is alive (even in background), this handler covers most use cases – if you need to verify the process is running, you can use ActivityManager.getRunningAppProcesses() as a fallback.
2. How to get the current top Activity in the stack?
Before Android 11, ActivityManager.getRunningTasks() worked, but it’s deprecated now. Instead, maintain your own activity stack using the same lifecycle handler:
- Update the
AppLifecycleHandlerto track the top activity:private val activityStack = mutableListOf<Activity>() var topActivity: Activity? = null private set override fun onActivityStarted(activity: Activity) { // ... existing foreground tracking code activityStack.remove(activity) activityStack.add(activity) topActivity = activityStack.lastOrNull() } override fun onActivityStopped(activity: Activity) { // ... existing foreground tracking code if (!activity.isChangingConfigurations) { activityStack.remove(activity) topActivity = activityStack.lastOrNull() } }
Now appLifecycleHandler.topActivity gives you the current top activity. Just handle null cases (when the app is in background with no active activities).
3. Solutions for the "app restarts on every notification click" issue
This is a super common pain point with Android 12’s trampoline restrictions. Here’s the fix I’ve implemented successfully:
Step 1: Configure MainActivity’s launch mode
In your AndroidManifest.xml, set launchMode="singleTop" for MainActivity:
<activity android:name=".MainActivity" android:launchMode="singleTop"> <!-- ... other attributes --> </activity>
This ensures that if MainActivity is already at the stack top, it won’t restart – instead, onNewIntent() will be called.
Step 2: Build the PendingIntent conditionally
When creating the notification’s PendingIntent, check if the app is in foreground. If it is, directly launch your WebView activity (or pass data to the top activity). If not, launch MainActivity with the necessary data:
val pendingIntent = if (appLifecycleHandler.isAppInForeground) { // Launch WebView activity directly if app is foreground Intent(this, WebViewActivity::class.java).apply { putExtra("NOTIFICATION_URL", yourTargetUrl) }.let { intent -> PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) } } else { // Launch MainActivity with data to trigger WebView later Intent(this, MainActivity::class.java).apply { putExtra("LAUNCH_WEBVIEW", true) putExtra("NOTIFICATION_URL", yourTargetUrl) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) }.let { intent -> PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) } }
Step 3: Handle the intent in MainActivity’s onNewIntent()
Add this to MainActivity to avoid restarting and process the notification data:
override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) intent?.let { if (it.getBooleanExtra("LAUNCH_WEBVIEW", false)) { val targetUrl = it.getStringExtra("NOTIFICATION_URL") targetUrl?.let { url -> // Launch WebView activity or update UI directly startActivity(Intent(this, WebViewActivity::class.java).apply { putExtra("NOTIFICATION_URL", url) }) } } } }
Key Notes:
- Always use
FLAG_IMMUTABLEfor PendingIntents on Android 12+ – mutable ones can trigger trampoline restrictions. - If your WebView is part of MainActivity (not a separate activity), skip launching a new activity and just update the UI in
onNewIntent().
I’ve seen dozens of devs hit this exact issue after Android 12 rolled out, and this approach works consistently across devices.
内容的提问来源于stack exchange,提问作者jerald jacob

