Risal Fajar Amiyardi
Risal Fajar Amiyardi

Reputation: 1021

Jetpack Compose Navigation Deep Link causes duplicate activity

I'm trying to show a notification that when clicked will open ChatScreen. It does open ChatScreen but started as a different activity, so there's 2 MainActivity in the back stack.

I use Compose Destinations, a wrapper library for Compose Navigations.

I have tried singleTop, singleTask, singleInstance launch mode, nothing works.

ChatScreen:

@Destination(deepLinks = [DeepLink(uriPattern = "https://mantools/chats")])
@Composable
fun ChatScreen(
    navigator: DestinationsNavigator,
    viewModel: ChatViewModel = hiltViewModel()
) {
  //contents
}

Manifest

<application
        android:name=".MainApplication"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.Mantools"
        android:hardwareAccelerated="true"
        android:usesCleartextTraffic="${usesCleartextTraffic}"
        tools:targetApi="31">
        <activity
            android:name=".features.MainActivity"
            android:launchMode="singleInstance"
            android:exported="true"
            android:theme="@style/Theme.Mantools.Splash">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <data android:scheme="https" android:host="mantools"/>
            </intent-filter>
        </activity>
</application>

Notification

private fun showChatNotification(message: RemoteMessage) {
        val data = message.data
        showNotification(
            data["title"] ?: "",
            data["text"] ?: "",
            TAG_CHAT,
            Intent(Intent.ACTION_MAIN, "https://mantools/chats".toUri(), this.applicationContext, MainActivity::class.java)
        )
    }


    fun showNotification(
        title: String,
        message: String,
        tag: String,
        intent: Intent
    ) {
        val pendingIntent = getPendingIntent(intent)
        val builder = NotificationCompat.Builder(context, GENERAL_CHANNEL_ID)
            .setLargeIcon(context.getDrawable(R.mipmap.ic_launcher)?.toBitmap())
            .setSmallIcon(R.drawable.app_logo)
            .setColor(ContextCompat.getColor(context, R.color.primary))
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_MAX)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent)
        notificationManager.notify(tag, System.currentTimeMillis().toInt(), builder.build())
    }
    
    private fun getPendingIntent(intent: Intent) = TaskStackBuilder.create(context).run {
        addNextIntentWithParentStack(intent)
        getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
    }

Upvotes: 5

Views: 1067

Answers (1)

lza
lza

Reputation: 11

maybe this is not an issue, but an feature!

try to look at this code in NavController#handleDeepLink:

    @MainThread
    @Suppress("DEPRECATION")
    public open fun handleDeepLink(intent: Intent?): Boolean {
        // ... code above
        val flags = intent.flags
        if (
            flags and Intent.FLAG_ACTIVITY_NEW_TASK != 0 &&
                flags and Intent.FLAG_ACTIVITY_CLEAR_TASK == 0
        ) {
            // this is the true reason why it open two activities,
            // something need to aware is navigation itself called finish after launch another activity.
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
            val taskStackBuilder =
                TaskStackBuilder.create(context).addNextIntentWithParentStack(intent)
            taskStackBuilder.startActivities()
            activity?.let { activity ->
                activity.finish()
                // Disable second animation in case where the Activity is created twice.
                activity.overridePendingTransition(0, 0)
            }
            return true
        }
        // ... code below
    }

at the time i reply, the version of navigation-compose i used is 2.8.4

Upvotes: 1

Related Questions