딥 링크 합성 백 스택 레시피

이 레시피에서는 합성 백 스택 및 작업 스택을 관리하여 딥 링크의 컨텍스트에서 탐색 원리를 적용하는 방법을 보여줍니다.

레시피 구조

이 레시피는 '앱 A'가 '앱 B'로 딥 링크하는 실제 시나리오를 시뮬레이션합니다.

'앱 A'는 딥 링크 인텐트를 만들고 기존 작업 또는 새 작업에서 트리거할 수 있는 syntheticbackstackSyntheticBackStackDeepLinkActivity 모듈에 의해 시뮬레이션됩니다.

'앱 B'는 딥 링크하는 SyntheticBackStackAppActivity가 포함된 모듈 syntheticbackstackapp에 의해 시뮬레이션됩니다. 이 모듈은 합성 백 스택을 빌드하는 방법과 뒤로 및 위로 버튼을 모두 지원하기 위해 작업 스택을 올바르게 관리하는 방법을 보여줍니다.

사용 방법

기본 appsyntheticbackstackapp이 모두 에뮬레이터 또는 연결된 기기에 설치되어 있는지 확인합니다. 설치된 syntheticbackstackapp"www.nav3deeplink.com" 링크를 지원하는지 확인합니다.

레시피의 방문 페이지에서 필터를 선택하고 버튼을 클릭하여 딥 링크합니다. syntheticbackstackapp의 활동으로 이동해야 합니다.

작동 방식

이 레시피는 여기에 요약된 딥 링크 가이드라인을 따릅니다.

Existing Task의 동작을 보려면 다음 단계를 따르세요.

  1. 현재 작업을 사용하여 딥 링크 열기
  2. 기기에서 위로 스와이프하여 최근 앱을 모두 확인합니다.
  3. 새 활동이 Nav3Recipes 앱 내에서 열립니다.
  4. 뒤로 버튼을 클릭하여 원래 활동으로 돌아갑니다.
  5. 1단계를 반복합니다.
  6. 위로 버튼을 클릭하여 상위 화면으로 이동합니다.
  7. 기기에서 위로 스와이프하여 최근 앱을 모두 확인합니다.
  8. 이제 새 활동이 Nav3SyntheticBackStack 앱 내에서 열립니다.

New Task의 동작을 보려면 다음 단계를 따르세요.

  1. 새 작업을 사용하여 딥 링크 열기
  2. 기기에서 위로 스와이프하여 최근 앱을 모두 확인합니다.
  3. 새 활동이 Nav3SyntheticBackStack 앱 내에서 열립니다.
  4. 위로 또는 뒤로 버튼을 클릭하여 상위 화면으로 이동합니다.

핵심 구현

navigateUp 및 합성 백 스택 빌드를 위한 핵심 도우미 함수는 여기에서 확인할 수 있습니다.

추가 자료

딥 링크 원리 및 탐색 3에서 이를 적용하는 방법에 관한 포괄적인 가이드는 딥 링크 가이드를 참고하세요.

package com.example.nav3recipes.deeplink.handlerequests.syntheticbackstack

import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.core.net.toUri
import androidx.lifecycle.compose.dropUnlessResumed
import com.example.nav3recipes.common.deeplink.EntryScreen
import com.example.nav3recipes.common.deeplink.LIST_FIRST_NAMES
import com.example.nav3recipes.common.deeplink.LIST_LOCATIONS
import com.example.nav3recipes.common.deeplink.MenuDropDown
import com.example.nav3recipes.common.deeplink.PaddedButton
import com.example.nav3recipes.common.deeplink.TextContent
import com.example.nav3recipes.ui.setEdgeToEdgeConfig

internal const val ADVANCED_PATH_BASE = "https://www.nav3deeplink.com"

/**
 * The recipe entry point that allows users to create a deep link and make a request with it.
 *
 * **HOW THIS RECIPE WORKS** This recipe simulates a real-world scenario where "App A" deep links
 * into "App B".
 *
 * "App A" is simulated by this current module `syntheticbackstack`, which
 * contains the [SyntheticBackStackDeepLinkActivity] that allows you to create a deeplink intent and
 * trigger that in either the existing Task, or in a new Task.
 *
 * "App B" is simulated by the module `syntheticbackstackapp`, which contains
 * the SyntheticBackStackAppActivity that you deeplink into. That module shows you how to build a synthetic backStack
 * and how to manage the Task stack properly in order to support both Back and Up buttons.
 *
 * See the [README](README.md) file of current module for more info on advanced deep linking.
 */
class SyntheticBackStackDeepLinkActivity: ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        setEdgeToEdgeConfig()
        super.onCreate(savedInstanceState)

        setContent {
            EntryScreen("Sandbox - Build Your Deeplink Intent") {
                val initFirstName = MENU_OPTIONS_FIRST_NAME.values.first().first()
                val initLocation = MENU_OPTIONS_LOCATION.values.last().first()
                val initTaskStack = MENU_OPTIONS_TASK_STACK.values.first().first()
                var firstName by remember { mutableStateOf(initFirstName) }
                var location by remember { mutableStateOf(initLocation) }
                var taskStack by remember { mutableStateOf(initTaskStack) }

                // select first name
                MenuDropDown(
                    menuOptions = MENU_OPTIONS_FIRST_NAME,
                ) { _, selected ->
                    firstName = selected
                }

                // select first name
                MenuDropDown(
                    menuOptions = MENU_OPTIONS_LOCATION,
                ) { _, selected ->
                    location = selected
                }

                // select current task stack or build new task stack
                MenuDropDown(
                    menuOptions = MENU_OPTIONS_TASK_STACK,
                ) { _, selected ->
                    taskStack = selected
                }

                // build final deeplink URL and Intent
                val finalUrl = "${ADVANCED_PATH_BASE}/user/$firstName/$location"

                // display Intent info
                val flagString = if (taskStack == TAG_NEW_TASK) {
                    "Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK"
                } else "<none>"
                val intentString = """
                    | Final Intent:
                    | data = "$finalUrl"
                    | action = Intent.ACTION_VIEW
                    | flags = $flagString
                """.trimMargin()

                TextContent(intentString)

                // deeplink to target
                PaddedButton("Deeplink Away!", onClick = dropUnlessResumed {
                    val intent = Intent().apply {
                        data = finalUrl.toUri()
                        action = Intent.ACTION_VIEW
                        if (taskStack == TAG_NEW_TASK) {
                            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
                        }
                    }

                    startActivity(intent)
                })
            }
        }
    }
}

private const val TAG_FIRST_NAME = "firstName"
private const val TAG_LOCATION = "location"
private const val TAG_TASK_STACK = "Task stack"
private const val TAG_CURRENT_TASK = "Use Current Task Stack"
private const val TAG_NEW_TASK = "Start New Task Stack"

private val MENU_OPTIONS_FIRST_NAME = mapOf(
    TAG_FIRST_NAME to LIST_FIRST_NAMES
)

private val MENU_OPTIONS_LOCATION = mapOf(
    TAG_LOCATION to LIST_LOCATIONS
)

private val MENU_OPTIONS_TASK_STACK = mapOf(
    TAG_TASK_STACK to listOf(TAG_CURRENT_TASK, TAG_NEW_TASK),
)