डेस्टिनेशन के लिए डीप लिंक बनाना

Android में, डीप लिंक एक ऐसा लिंक होता है जो आपको सीधे किसी ऐप्लिकेशन के किसी खास डेस्टिनेशन पर ले जाता है.

अपने ऐप्लिकेशन में दो तरह के डीप लिंक इस्तेमाल किए जा सकते हैं: एक्सप्लिसिट और इंप्लिसिट. डीप लिंक लागू करने का तरीका इस बात पर निर्भर करता है कि आपका ऐप्लिकेशन किस तरह का ग्राफ़—XML or programmatic—इस्तेमाल करता है.

एक्सप्लिसिट डीप लिंक बनाना

एक्सप्लिसिट डीप लिंक, डीप लिंक का एक ऐसा इंस्टेंस होता है जो PendingIntent का इस्तेमाल करके, उपयोगकर्ताओं को आपके ऐप्लिकेशन के किसी खास हिस्से पर ले जाता है. उदाहरण के लिए, सूचना या ऐप्लिकेशन विजेट के हिस्से के तौर पर, एक्सप्लिसिट डीप लिंक दिखाया जा सकता है.

जब कोई उपयोगकर्ता एक्सप्लिसिट डीप लिंक के ज़रिए आपका ऐप्लिकेशन खोलता है, तो टास्क बैक स्टैक मिट जाता है और उसकी जगह डीप लिंक डेस्टिनेशन ले लेता है. नेस्टिंग ग्राफ़ करते समय, नेस्टिंग के हर लेवल का शुरुआती डेस्टिनेशन भी स्टैक में जोड़ा जाता है. इसका मतलब है कि क्रम में मौजूद हर <navigation> एलिमेंट का शुरुआती डेस्टिनेशन भी स्टैक में जोड़ा जाता है. इसका मतलब है कि जब कोई उपयोगकर्ता डीप लिंक डेस्टिनेशन से 'वापस जाएं' बटन दबाता है, तो वह नेविगेशन स्टैक में वापस चला जाता है. ऐसा तब होता है, जब वह आपके ऐप्लिकेशन में एंट्री पॉइंट से प्रवेश करता है.

प्रोग्रामैटिक ग्राफ़

अगर आपका नेविगेशन ग्राफ़, प्रोग्राम के हिसाब से तय किया गया है (जैसा कि आम तौर पर Navigation Compose या Kotlin DSL में होता है), तो हमारा सुझाव है कि डीप लिंक PendingIntent बनाने के लिए, TaskStackBuilder का इस्तेमाल करें.

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)
}

एक्सएमएल ग्राफ़

PendingIntent बनाने के लिए, NavDeepLinkBuilder क्लास का इस्तेमाल किया जा सकता है. इसके बारे में यहां दिए गए उदाहरण में बताया गया है. ध्यान दें कि अगर दिया गया कॉन्टेक्स्ट 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 आपके साफ़ तौर पर बताए गए डीप लिंक को, ऐप्लिकेशन लॉन्च करने के डिफ़ॉल्ट Activity में लॉन्च करता है. यह डिफ़ॉल्ट लॉन्च, आपके ऐप्लिकेशन के मेनिफ़ेस्ट में बताया गया होता है. अगर आपका NavHost किसी दूसरी गतिविधि में है, तो डीप लिंक बिल्डर बनाते समय आपको उसके कॉम्पोनेंट का नाम बताना होगा:

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 है, तो NavController.createDeepLink() का इस्तेमाल करके भी डीप लिंक बनाया जा सकता है.

इंप्लिसिट डीप लिंक बनाना

इंप्लिसिट डीप लिंक का मतलब, ऐप्लिकेशन में मौजूद किसी खास डेस्टिनेशन से है. जब डीप लिंक को चालू किया जाता है, तब Android आपके ऐप्लिकेशन को उस डेस्टिनेशन पर खोल सकता है. उदाहरण के लिए, जब कोई उपयोगकर्ता किसी लिंक पर क्लिक करता है.

डीप लिंक को यूआरआई, इंटेंट ऐक्शन, और MIME टाइप के हिसाब से मैच किया जा सकता है. एक डीप लिंक के लिए, कई मैच टाइप तय किए जा सकते हैं. हालांकि, ध्यान दें कि यूआरआई आर्ग्युमेंट मैचिंग को सबसे पहले प्राथमिकता दी जाती है. इसके बाद, कार्रवाई और फिर MIME टाइप को प्राथमिकता दी जाती है.

प्रोग्रामैटिक ग्राफ़

अगर आपने नेविगेशन ग्राफ़ को प्रोग्राम के हिसाब से तय किया है (Navigation Compose या Kotlin DSL का इस्तेमाल करके), तो आपको कोड में डीप लिंक तय करने होंगे.

लिखें

Navigation Compose में, deepLinks पैरामीटर का इस्तेमाल करके, डीप लिंक को composable() डेस्टिनेशन बिल्डर के हिस्से के तौर पर तय किया जा सकता है. यह 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 का इस्तेमाल करते समय, डेस्टिनेशन ब्लॉक में deepLink() बिल्डर फ़ंक्शन का इस्तेमाल करके डीप लिंक तय किए जा सकते हैं:

@Serializable
data class Profile(val id: String)

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

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

प्रोग्राम के हिसाब से बनाए गए ग्राफ़ के लिए इंटेंट फ़िल्टर जोड़ना

प्रोग्राम के चलने के दौरान नेविगेशन ग्राफ़ बनाए जाते हैं. इसलिए, नेविगेशन कॉम्पोनेंट, आपके AndroidManifest.xml में मैच करने वाले <intent-filter> एलिमेंट अपने-आप जनरेट नहीं कर सकता. इसके बजाय, आपको सही <intent-filter> एलिमेंट मैन्युअल तरीके से जोड़ने होंगे.

ऊपर दिए गए उदाहरणों में डीप लिंक चालू करने के लिए, अपने मेनिफ़ेस्ट में मौजूद <activity> एलिमेंट में यह कोड जोड़ें:

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

एक्सएमएल ग्राफ़

एक्सएमएल पर आधारित ग्राफ़ में इंप्लिसिट डीप लिंक बनाने के लिए, <deepLink> एलिमेंट को सीधे एक्सएमएल में तय किया जा सकता है. इसके अलावा, नेविगेशन एडिटर का इस्तेमाल भी किया जा सकता है.

यहां एक डीप लिंक का उदाहरण दिया गया है, जिसमें यूआरआई, कार्रवाई, और 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>

किसी डेस्टिनेशन के लिए इंप्लिसिट डीप लिंक बनाने के लिए, नेविगेशन एडिटर का इस्तेमाल भी किया जा सकता है. इसके लिए, यह तरीका अपनाएं:

  1. नेविगेशन एडिटर के डिज़ाइन टैब में जाकर, डीप लिंक का डेस्टिनेशन चुनें.
  2. एट्रिब्यूट पैनल के डीप लिंक सेक्शन में, + पर क्लिक करें.
  3. दिखने वाले डीप लिंक जोड़ें डायलॉग में, अपने डीप लिंक की जानकारी डालें.

    यहां दी गई बातों का ध्यान रखें:

    • बिना स्कीम वाले यूआरआई को http या https माना जाता है. उदाहरण के लिए, www.google.com, http://www.google.com और https://www.google.com, दोनों से मेल खाता है.
    • {placeholder_name} के फ़ॉर्म में मौजूद पाथ पैरामीटर प्लेसहोल्डर, एक या उससे ज़्यादा वर्णों से मेल खाते हैं. उदाहरण के लिए, http://www.example.com/users/{id}, http://www.example.com/users/4 से मेल खाता है. नेविगेशन कॉम्पोनेंट, प्लेसहोल्डर वैल्यू को सही टाइप में पार्स करने की कोशिश करता है. इसके लिए, वह प्लेसहोल्डर के नामों को डीप लिंक डेस्टिनेशन के लिए तय किए गए आर्ग्युमेंट से मैच करता है. अगर एक ही नाम का कोई आर्ग्युमेंट तय नहीं किया गया है, तो आर्ग्युमेंट की वैल्यू के लिए डिफ़ॉल्ट String टाइप का इस्तेमाल किया जाता है. शून्य या उससे ज़्यादा वर्णों से मिलान करने के लिए, .* वाइल्डकार्ड का इस्तेमाल किया जा सकता है.
    • क्वेरी पैरामीटर प्लेसहोल्डर का इस्तेमाल, पाथ पैरामीटर के साथ या उनके बजाय किया जा सकता है. उदाहरण के लिए, http://www.example.com/users/{id}?myarg={myarg} से http://www.example.com/users/4?myarg=28 मैच होता है.
    • डिफ़ॉल्ट या शून्य के तौर पर तय की गई वैल्यू वाले वैरिएबल के लिए, क्वेरी पैरामीटर प्लेसहोल्डर का मेल खाना ज़रूरी नहीं है. उदाहरण के लिए, 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 ऊपर दिए गए पैटर्न से मेल नहीं खाता, क्योंकि ज़रूरी पाथ पैरामीटर नहीं दिया गया है.
    • अतिरिक्त क्वेरी पैरामीटर से, डीप लिंक यूआरआई मैचिंग पर कोई असर नहीं पड़ता. उदाहरण के लिए, http://www.example.com/users/{id}, http://www.example.com/users/4?extraneousParam=7 से मेल खाता है. भले ही, extraneousParam को यूआरआई पैटर्न में तय न किया गया हो.
  4. (ज़रूरी नहीं) अपने-आप पुष्टि करें पर सही का निशान लगाएं, ताकि Google यह पुष्टि कर सके कि आपके पास यूआरआई का मालिकाना हक है. ज़्यादा जानकारी के लिए, Android ऐप्लिकेशन के लिंक की पुष्टि करना लेख पढ़ें.

  5. जोड़ें पर क्लिक करें. चुने गए डेस्टिनेशन के ऊपर एक लिंक आइकॉन दिखता है. इससे पता चलता है कि डेस्टिनेशन में डीप लिंक है.

  6. एक्सएमएल व्यू पर टॉगल करने के लिए, कोड टैब पर क्लिक करें. डेस्टिनेशन में एक नेस्ट किया गया <deepLink> एलिमेंट जोड़ा गया है:

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

एक्सएमएल पर आधारित ग्राफ़ के लिए, इंप्लिसिट डीप लिंकिंग की सुविधा चालू करने के लिए, आपको अपने ऐप्लिकेशन की 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>

प्रोजेक्ट बनाते समय, Navigation कॉम्पोनेंट, जनरेट किए गए <intent-filter> एलिमेंट के साथ <nav-graph> एलिमेंट को बदल देता है, ताकि नेविगेशन ग्राफ़ में मौजूद सभी डीप लिंक से मेल खा सके.

इंप्लिसिट डीप लिंक और बैक स्टैक

इंप्लिसिट डीप लिंक ट्रिगर करते समय, बैक स्टैक की स्थिति इस बात पर निर्भर करती है कि इंप्लिसिट Intent को Intent.FLAG_ACTIVITY_NEW_TASK फ़्लैग के साथ लॉन्च किया गया था या नहीं:

  • अगर फ़्लैग सेट है, तो टास्क के बैक स्टैक को मिटा दिया जाता है और उसे डीप लिंक डेस्टिनेशन से बदल दिया जाता है. एक्सप्लिसिट डीप लिंकिंग की तरह ही, नेस्टिंग ग्राफ़ करते समय, नेस्टिंग के हर लेवल का शुरुआती डेस्टिनेशन भी स्टैक में जोड़ा जाता है. इसका मतलब है कि क्रम में मौजूद हर <navigation> एलिमेंट का शुरुआती डेस्टिनेशन भी स्टैक में जोड़ा जाता है. इसका मतलब है कि जब कोई उपयोगकर्ता डीप लिंक के डेस्टिनेशन से 'वापस जाएं' बटन दबाता है, तो वह नेविगेशन स्टैक पर वापस चला जाता है. ऐसा तब होता है, जब वह आपके ऐप्लिकेशन में एंट्री पॉइंट से प्रवेश करता है.
  • अगर फ़्लैग सेट नहीं किया जाता है, तो आपको पिछले ऐप्लिकेशन के टास्क स्टैक पर ही रखा जाता है. इसी ऐप्लिकेशन में इंप्लिसिट डीप लिंक ट्रिगर किया गया था. इस मामले में, 'वापस जाएं' बटन आपको पिछले ऐप्लिकेशन पर वापस ले जाता है. वहीं, 'ऊपर जाएं' बटन, आपके ऐप्लिकेशन के टास्क को आपके नेविगेशन ग्राफ़ में मौजूद पैरंट डेस्टिनेशन पर शुरू करता है.

डीप लिंक मैनेज करना

हमारा सुझाव है कि नेविगेशन का इस्तेमाल करते समय, हमेशा standard के डिफ़ॉल्ट launchMode का इस्तेमाल करें. standard लॉन्च मोड का इस्तेमाल करने पर, Navigation handleDeepLink() को कॉल करके डीप लिंक को अपने-आप मैनेज करता है. इससे Intent में मौजूद किसी भी साफ़ तौर पर या इंप्लिसिट डीप लिंक को प्रोसेस किया जा सकता है. हालांकि, अगर singleTop जैसे किसी दूसरे launchMode का इस्तेमाल करते समय Activity को फिर से इस्तेमाल किया जाता है, तो ऐसा अपने-आप नहीं होता. ऐसे में, onNewIntent() में handleDeepLink() को मैन्युअल तरीके से कॉल करना ज़रूरी है. जैसा कि यहां दिए गए उदाहरण में दिखाया गया है:

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);
}