Công thức về ngăn xếp lui tổng hợp cho đường liên kết sâu

Công thức này minh hoạ cách áp dụng các nguyên tắc điều hướng trong bối cảnh đường liên kết sâu bằng cách quản lý một backStack giả tạo và ngăn xếp Tác vụ.

Cấu trúc công thức

Công thức này mô phỏng một tình huống thực tế trong đó "Ứng dụng A" liên kết sâu vào "Ứng dụng B".

"Ứng dụng A" được mô phỏng bằng mô-đun syntheticbackstack, chứa SyntheticBackStackDeepLinkActivity cho phép bạn tạo một ý định liên kết sâu và kích hoạt ý định đó trong Task hiện có hoặc trong một Task mới.

"Ứng dụng B" được mô phỏng bằng mô-đun syntheticbackstackapp, chứa SyntheticBackStackAppActivity mà bạn liên kết sâu vào. Học phần đó cho bạn biết cách tạo một backStack giả và cách quản lý ngăn xếp Tác vụ đúng cách để hỗ trợ cả nút Quay lại và Lên.

Cách sử dụng

Đảm bảo cả appsyntheticbackstackapp chính đều được cài đặt trên trình mô phỏng hoặc thiết bị thông minh. Đảm bảo rằng syntheticbackstackapp đã cài đặt hỗ trợ đường liên kết "www.nav3deeplink.com".

Trên trang đích của công thức, hãy chọn bộ lọc rồi nhấp vào nút để liên kết sâu. Thao tác này sẽ đưa bạn đến Hoạt động của syntheticbackstackapp.

Cách thức hoạt động

Công thức tuân thủ nguyên tắc về đường liên kết sâu được tóm tắt tại đây.

Để xem hành vi của Existing Task:

  1. Mở đường liên kết sâu bằng cách sử dụng tác vụ hiện tại
  2. Trên thiết bị, hãy vuốt lên để xem tất cả các ứng dụng gần đây
  3. Lưu ý rằng Hoạt động mới sẽ mở trong ứng dụng Nav3Recipes
  4. Nhấp vào nút quay lại để quay lại Hoạt động ban đầu
  5. Lặp lại bước 1
  6. Nhấp vào nút lên để chuyển đến màn hình chính
  7. Trên thiết bị, hãy vuốt lên để xem tất cả các ứng dụng gần đây
  8. Xin lưu ý rằng Hoạt động mới hiện đã được mở trong ứng dụng Nav3SyntheticBackStack

Để xem hành vi của New Task:

  1. Mở đường liên kết sâu bằng tác vụ mới
  2. Trên thiết bị, hãy vuốt lên để xem tất cả các ứng dụng gần đây
  3. Lưu ý rằng Hoạt động mới được mở trong ứng dụng Nav3SyntheticBackStack
  4. Nhấp vào nút Lên hoặc nút Quay lại để chuyển đến màn hình chính

Triển khai cốt lõi

Bạn có thể tìm thấy các hàm trợ giúp cốt lõi cho navigateUp và xây dựng backStack giả tạo tại đây

Đọc thêm

Hãy xem hướng dẫn về đường liên kết sâu để biết hướng dẫn toàn diện về các nguyên tắc liên kết sâu và cách áp dụng các nguyên tắc này trong 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),
)