สร้าง Deep Link สำหรับปลายทาง

ใน Android Deep Link คือลิงก์ที่จะนำคุณไปยังปลายทางที่เฉพาะเจาะจงภายในแอปโดยตรง

คุณรองรับ Deep Link ได้ 2 ประเภทในแอป ได้แก่ Explicit และ Implicit วิธีติดตั้งใช้งาน Deep Link จะแตกต่างกันไปตามประเภทกราฟ ที่แอปใช้ ซึ่งอาจเป็น XML or programmatic

สร้าง Explicit Deep Link

Explicit Deep Link คือ Deep Link อินสแตนซ์เดียวที่ใช้ PendingIntentเพื่อนำผู้ใช้ไปยังตำแหน่งที่เฉพาะเจาะจงภายในแอป คุณอาจแสดง Explicit Deep Link เป็นส่วนหนึ่งของการแจ้งเตือนหรือวิดเจ็ตของแอป เป็นต้น

เมื่อผู้ใช้เปิดแอปผ่าน Explicit Deep Link ระบบจะล้าง Task Back Stack และแทนที่ด้วยปลายทางของ Deep Link เมื่อ ซ้อนกราฟ, ระบบจะเพิ่มปลายทางเริ่มต้นจากแต่ละระดับการซ้อน ซึ่งก็คือปลายทางเริ่มต้น จากองค์ประกอบ <navigation> แต่ละรายการในลำดับชั้นลงในสแต็กด้วย ซึ่งหมายความว่าเมื่อผู้ใช้กดปุ่มย้อนกลับจากปลายทางของ Deep Link ผู้ใช้จะย้อนกลับขึ้นไปตาม Navigation Stack เช่นเดียวกับที่เข้าแอปจากจุดเริ่มต้น

กราฟแบบเป็นโปรแกรม

หากคุณกำหนดกราฟการนำทางแบบเป็นโปรแกรม (ตามที่พบได้ทั่วไปใน Navigation Compose หรือ Kotlin DSL) เราขอแนะนำให้ใช้ TaskStackBuilder เพื่อสร้าง PendingIntent ของ Deep Link

val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
    Intent.ACTION_VIEW,
    "https://www.example.com/profile/$id".toUri(),
    context,
    MyActivity::class.java
)

val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
    addNextIntentWithParentStack(deepLinkIntent)
    getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}

กราฟ XML

คุณสามารถใช้ NavDeepLinkBuilder คลาสเพื่อสร้าง PendingIntent, ดังที่แสดงในตัวอย่างด้านล่าง โปรดทราบว่าหากบริบทที่ระบุไม่ใช่ Activity คอนสตรักเตอร์จะใช้ PackageManager.getLaunchIntentForPackage() เป็นกิจกรรมเริ่มต้นที่จะเปิด หากมี

Kotlin

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.android)
    .setArguments(args)
    .createPendingIntent()

Java

PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.android)
    .setArguments(args)
    .createPendingIntent();

โดยค่าเริ่มต้น NavDeepLinkBuilder จะเปิด Explicit Deep Link ใน Activity เริ่มต้นที่ประกาศไว้ในไฟล์ Manifest ของแอป หาก NavHost อยู่ในกิจกรรมอื่น คุณต้องระบุชื่อคอมโพเนนต์เมื่อสร้างตัวสร้าง Deep Link ดังนี้

Kotlin

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.android)
    .setArguments(args)
    .setComponentName(DestinationActivity::class.java)
    .createPendingIntent()

Java

PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
        .setGraph(R.navigation.nav_graph)
        .setDestination(R.id.android)
        .setArguments(args)
        .setComponentName(DestinationActivity.class)
        .createPendingIntent();

หากคุณมี ComponentName, คุณสามารถส่งผ่านไปยังตัวสร้างได้โดยตรง ดังนี้

Kotlin

val componentName = ...

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.nav_graph)
    .setDestination(R.id.android)
    .setArguments(args)
    .setComponentName(componentName)
    .createPendingIntent()

Java

ComponentName componentName = ...;

PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
        .setGraph(R.navigation.nav_graph)
        .setDestination(R.id.android)
        .setArguments(args)
        .setComponentName(componentName)
        .createPendingIntent();

หากคุณมี NavController อยู่แล้ว คุณยังสร้าง Deep Link ได้โดยใช้ NavController.createDeepLink()

สร้าง Implicit Deep Link

Implicit Deep Link หมายถึง ปลายทางที่เฉพาะเจาะจงในแอป เมื่อมีการเรียกใช้ Deep Link เช่น เมื่อผู้ใช้คลิกลิงก์ Android จะเปิดแอปของคุณไปยังปลายทางที่เกี่ยวข้องได้

ระบบจะจับคู่ Deep Link ตาม URI, การดำเนินการของ Intent และประเภท MIME คุณระบุประเภทการจับคู่หลายรายการสำหรับ Deep Link รายการเดียวได้ แต่โปรดทราบว่าระบบจะจัดลำดับความสำคัญของการจับคู่อาร์กิวเมนต์ URI ก่อน ตามด้วยการดำเนินการ แล้วจึงเป็นประเภท MIME

กราฟแบบเป็นโปรแกรม

หากคุณกำหนดกราฟการนำทางแบบเป็นโปรแกรม (โดยใช้ Navigation Compose หรือ Kotlin DSL) คุณจะกำหนด Deep Link ในโค้ด

Compose

ใน Navigation Compose คุณสามารถกำหนด Deep Link เป็นส่วนหนึ่งของตัวสร้างปลายทาง composable() โดยใช้พารามิเตอร์ deepLinks ซึ่งจะยอมรับรายการออบเจ็กต์ NavDeepLink ที่คุณสร้างได้โดยใช้ฟังก์ชัน navDeepLink() ดังนี้

@Serializable
data class Profile(val id: String)

val uri = "https://www.example.com"

composable<Profile>(
  deepLinks = listOf(
    navDeepLink<Profile>(basePath = "$uri/profile")
  )
) { backStackEntry ->
  val profile: Profile = backStackEntry.toRoute()
  ProfileScreen(id = profile.id)
}

Kotlin DSL

เมื่อใช้ Kotlin DSL คุณสามารถกำหนด Deep Link ได้โดยใช้ฟังก์ชันตัวสร้าง deepLink() ภายในบล็อกปลายทาง ดังนี้

@Serializable
data class Profile(val id: String)

val uri = "https://www.example.com"

fragment<ProfileFragment, Profile> {
    deepLink<Profile>(basePath = "$uri/profile")
}

เพิ่มตัวกรอง Intent สำหรับกราฟแบบเป็นโปรแกรม

เนื่องจากระบบจะสร้างกราฟการนำทางแบบเป็นโปรแกรมในรันไทม์ คอมโพเนนต์การนำทาง จึงไม่สามารถสร้างองค์ประกอบ <intent-filter> ที่ตรงกัน ใน AndroidManifest.xml โดยอัตโนมัติ คุณต้องเพิ่มองค์ประกอบที่เหมาะสมด้วยตนเอง <intent-filter>

หากต้องการเปิดใช้ Deep Link ในตัวอย่างก่อนหน้า ให้เพิ่มโค้ดต่อไปนี้ภายในองค์ประกอบที่เกี่ยวข้อง <activity> ในไฟล์ Manifest

<activity …>
  <intent-filter>
    ...
    <data android:scheme="https" android:host="www.example.com" />
  </intent-filter>
</activity>

กราฟ XML

หากต้องการสร้าง Implicit Deep Link ในกราฟที่อิงตาม XML คุณสามารถกำหนดองค์ประกอบ <deepLink> ใน XML ได้โดยตรง หรือใช้เครื่องมือแก้ไขการนำทาง

ตัวอย่าง Deep Link ที่มี URI, การดำเนินการ และประเภท MIME

<fragment android:id="@+id/a"
          android:name="com.example.myapplication.FragmentA"
          tools:layout="@layout/a">
        <deepLink app:uri="www.example.com"
                app:action="android.intent.action.MY_ACTION"
                app:mimeType="type/subtype"/>
</fragment>

นอกจากนี้ คุณยังใช้เครื่องมือแก้ไขการนำทางเพื่อสร้าง Implicit Deep Link ไปยังปลายทางได้ดังนี้

  1. ในแท็บดีไซน์ ของเครื่องมือแก้ไขการนำทาง ให้เลือกปลายทางสำหรับ Deep Link
  2. คลิก + ในส่วน Deep Link ของแผงแอตทริบิวต์
  3. ในกล่องโต้ตอบเพิ่ม Deep Link ที่ปรากฏขึ้น ให้ป้อนข้อมูลสำหรับ Deep Link

    ข้อควรทราบ

    • ระบบจะถือว่า URI ที่ไม่มีรูปแบบเป็น http หรือ https เช่น www.google.com จะตรงกับทั้ง http://www.google.com และ https://www.google.com
    • ตัวยึดตำแหน่งพารามิเตอร์เส้นทางในรูปแบบ {placeholder_name} จะตรงกับอักขระอย่างน้อย 1 ตัว เช่น http://www.example.com/users/{id} จะตรงกับ http://www.example.com/users/4 คอมโพเนนต์การนำทางจะพยายาม แยกวิเคราะห์ค่าตัวยึดตำแหน่งเป็นประเภทที่เหมาะสมโดยการจับคู่ชื่อตัวยึดตำแหน่งกับ อาร์กิวเมนต์ที่กำหนดไว้สำหรับ ปลายทางของ Deep Link หากไม่มีการกำหนดอาร์กิวเมนต์ที่มีชื่อเดียวกัน ระบบจะใช้ประเภท String เริ่มต้นสำหรับค่าอาร์กิวเมนต์ คุณสามารถใช้ไวลด์การ์ด .* เพื่อจับคู่อักขระตั้งแต่ 0 ตัวขึ้นไป
    • คุณสามารถใช้ตัวยึดตำแหน่งพารามิเตอร์การค้นหาแทนหรือร่วมกับพารามิเตอร์เส้นทางได้ เช่น http://www.example.com/users/{id}?myarg={myarg} จะตรงกับ http://www.example.com/users/4?myarg=28
    • ตัวยึดตำแหน่งพารามิเตอร์การค้นหาสำหรับตัวแปรที่กำหนดด้วยค่าเริ่มต้นหรือค่าที่อนุญาตให้เป็น Null ไม่จำเป็นต้องตรงกัน เช่น http://www.example.com/users/{id}?arg1={arg1}&arg2={arg2} จะตรงกับ http://www.example.com/users/4?arg2=28 หรือ http://www.example.com/users/4?arg1=7 แต่จะไม่เป็นเช่นนั้นกับพารามิเตอร์เส้นทาง เช่น http://www.example.com/users?arg1=7&arg2=28 จะไม่ตรงกับรูปแบบด้านบนเนื่องจากไม่มีการระบุพารามิเตอร์เส้นทางที่จำเป็น
    • พารามิเตอร์การค้นหาที่ไม่เกี่ยวข้องจะไม่ส่งผลต่อการจับคู่ URI ของ Deep Link เช่น http://www.example.com/users/{id} จะตรงกับ http://www.example.com/users/4?extraneousParam=7 แม้ว่าจะไม่ได้กำหนด extraneousParam ไว้ในรูปแบบ URI ก็ตาม
  4. (ไม่บังคับ) เลือกยืนยันอัตโนมัติ เพื่อกำหนดให้ Google ยืนยันว่าคุณเป็นเจ้าของ URI ดูข้อมูลเพิ่มเติมได้ที่ ยืนยัน Android App Link

  5. คลิกเพิ่ม ไอคอนลิงก์ จะปรากฏขึ้นเหนือปลายทางที่เลือกเพื่อระบุว่าปลายทางนั้นมี Deep Link

  6. คลิกแท็บโค้ด เพื่อเปลี่ยนเป็นมุมมอง XML ระบบได้เพิ่มองค์ประกอบ <deepLink> แบบซ้อนลงในปลายทางแล้ว ดังนี้

    <deepLink app:uri="https://www.google.com" />
    

หากต้องการเปิดใช้ Implicit Deep Link สำหรับกราฟที่อิงตาม XML คุณต้องเพิ่มโค้ดลงในไฟล์ manifest.xml ของแอปด้วย เพิ่มองค์ประกอบ <nav-graph> รายการเดียวลงในกิจกรรมที่ชี้ไปยังกราฟการนำทางที่มีอยู่ ดังที่แสดง ในตัวอย่างต่อไปนี้

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application ... >

        <activity name=".MainActivity" ...>
            ...

            <nav-graph android:value="@navigation/nav_graph" />

            ...

        </activity>
    </application>
</manifest>

เมื่อสร้างโปรเจ็กต์ คอมโพเนนต์การนำทางจะแทนที่องค์ประกอบ <nav-graph> ด้วยองค์ประกอบ <intent-filter> ที่สร้างขึ้นเพื่อให้ตรงกับ Deep Link ทั้งหมด ในกราฟการนำทาง

Implicit Deep Link และ Back Stack

เมื่อทริกเกอร์ Implicit Deep Link สถานะของ Back Stack จะขึ้นอยู่กับ ว่ามีการเปิดใช้ Intent โดยนัยด้วย Intent.FLAG_ACTIVITY_NEW_TASK แฟล็กหรือไม่

  • หากมีการตั้งค่าแฟล็ก ระบบจะล้าง Task Back Stack และแทนที่ด้วยปลายทางของ Deep Link เช่นเดียวกับ Explicit Deep Link เมื่อ ซ้อนกราฟ ระบบจะเพิ่มปลายทางเริ่มต้นจากแต่ละระดับการซ้อน ซึ่งก็คือปลายทางเริ่มต้นจากองค์ประกอบ <navigation> แต่ละรายการในลำดับชั้นลงใน สแต็กด้วย ซึ่งหมายความว่าเมื่อผู้ใช้กดปุ่มย้อนกลับจากปลายทางของ Deep Link ผู้ใช้จะย้อนกลับขึ้นไปตาม Navigation Stack เช่นเดียวกับที่เข้าแอปจากจุดเริ่มต้น
  • หากไม่ได้ตั้งค่าแฟล็ก คุณจะยังคงอยู่ใน Task Stack ของแอปก่อนหน้าซึ่งมีการทริกเกอร์ Implicit Deep Link ในกรณีนี้ ปุ่มย้อนกลับจะนำคุณกลับไปยังแอปก่อนหน้า ส่วนปุ่มขึ้นจะเริ่ม Task ของแอปในปลายทางระดับบนสุดในลำดับชั้นภายในกราฟการนำทาง

จัดการ Deep Link

เราขอแนะนำอย่างยิ่งให้ใช้ค่าเริ่มต้น launchMode ของ standard เสมอเมื่อใช้การนำทาง เมื่อใช้โหมดเปิดใช้งาน standard การนำทาง จะจัดการ Deep Link โดยอัตโนมัติด้วยการเรียกใช้ handleDeepLink() เพื่อประมวลผล Explicit หรือ Implicit Deep Link ภายใน Intent อย่างไรก็ตาม การดำเนินการนี้จะไม่เกิดขึ้นโดยอัตโนมัติหากมีการนำ Activity กลับมาใช้ซ้ำเมื่อใช้ launchMode อื่น เช่น singleTop ในกรณีนี้ คุณต้องเรียกใช้ handleDeepLink() ใน onNewIntent() ด้วยตนเอง ดังที่แสดงในตัวอย่างต่อไปนี้

Kotlin

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    navController.handleDeepLink(intent)
}

Java

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    navController.handleDeepLink(intent);
}