Рецепт синтетического стека BackStack для ссылок на контент
В этом рецепте показано, как применять принципы навигации в контексте ссылок на контент, управляя синтетическим стеком возврата и стеками задач.
Структура рецепта
Этот рецепт имитирует реальную ситуацию, в которой приложение А ссылается на контент в приложении Б.
Приложение А имитируется модулем syntheticbackstack, который содержит SyntheticBackStackDeepLinkActivity, позволяющий создать намерение для ссылки на контент и запустить его в существующей или новой задаче.
Приложение Б имитируется модулем syntheticbackstackapp, который содержит SyntheticBackStackAppActivity, на который вы ссылаетесь. В этом модуле рассказывается, как создать искусственный стек возврата и правильно управлять стеком задач, чтобы поддерживать кнопки "Назад" и "Вверх".
Как использовать
Убедитесь, что на эмуляторе или подключенном устройстве установлены как основной пакет app, так и пакет syntheticbackstackapp. Убедитесь, что установленное приложение syntheticbackstackapp поддерживает ссылку "www.nav3deeplink.com".
На целевой странице рецепта выберите фильтры и нажмите кнопку для создания прямой ссылки. Вы перейдете к Activity syntheticbackstackapp.
Принцип работы
Рецепт соответствует правилам в отношении ссылок на контент, которые кратко изложены здесь.
Чтобы посмотреть поведение Existing Task:
- Открыть ссылку на контент, используя текущую задачу
- На устройстве проведите вверх, чтобы посмотреть все недавно использованные приложения.
- Обратите внимание, что новое действие открывается в приложении Nav3Recipes.
- Нажмите кнопку "Назад", чтобы вернуться к исходному действию.
- Повторите шаг 1.
- Нажмите кнопку "Вверх", чтобы перейти на родительский экран.
- На устройстве проведите вверх, чтобы посмотреть все недавно использованные приложения.
- Обратите внимание, что новое действие теперь открывается в приложении Nav3SyntheticBackStack.
Чтобы посмотреть поведение New Task:
- Открыть ссылку на контент с помощью новой задачи
- Проведите по экрану устройства вверх, чтобы посмотреть все недавние приложения.
- Обратите внимание, что новое действие открывается в приложении Nav3SyntheticBackStack.
- Нажмите кнопку "Вверх" или "Назад", чтобы перейти на родительский экран.
Основная реализация
Основные вспомогательные функции для navigateUp и создания синтетического стека возврата можно найти здесь.
Читать дальше
Подробную информацию о принципах работы ссылок на контент и о том, как применять их в Navigation 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), )