सामग्री पर जाएं
सभी पोस्ट

2026 में Android App Links: आपके https:// लिंक अब भी ब्राउज़र में क्यों खुलते हैं

Digital Asset Links वेरिफिकेशन, assetlinks.json में छिपी गड़बड़ियाँ, और वो adb कमांड्स जो बताते हैं कि Android लिंक आपकी ऐप को क्यों नहीं दे रहा।

MFKAPPS 6 मिनट पढ़ना

myapp://item/42 जैसी कस्टम URI स्कीम सेट करना आसान है, और इसे गलत तरीके से बनाना भी उतना ही आसान है: कोई भी ऐप वही स्कीम रजिस्टर कर सकती है, इसलिए OS यह गारंटी नहीं दे सकता कि उसे खोलने वाली ऐप वाकई आपकी है। एक Android App Link — एक असली https://yourdomain.com/... URL जो ब्राउज़र टैब की बजाय सीधे ऐप खोलता है — इसे ठीक करता है, लेकिन तभी जब OS यह वेरिफाई कर सके कि आपकी ऐप वाकई उस डोमेन की मालिक है। ज़्यादातर मामलों में ऐसा लिंक चुपचाप Chrome पर वापस गिर जाता है, और manifest पूरी तरह सही दिखता है। जो हिस्सा गायब होता है वह लगभग हमेशा Digital Asset Links वेरिफिकेशन होता है, intent filter नहीं।

दो चीज़ें जिनका मेल होना ज़रूरी है

App Link तभी अपने-आप वेरिफाई होता है जब दो स्वतंत्र हिस्से मेल खाते हैं: ऐप का intent filter, और खुद डोमेन द्वारा सर्व की जाने वाली एक JSON फ़ाइल। दोनों में से किसी को भी दूसरे के बारे में पता न होना ही मुख्य बात है — यही किसी भी बेतरतीब ऐप को आपके डोमेन पर दावा करने से रोकता है।

intent filter manifest में जाता है:

<activity android:name=".MainActivity" android:exported="true">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https"
              android:host="mfkapps.com"
              android:pathPrefix="/apps" />
    </intent-filter>
</activity>

android:autoVerify="true" वही है जो सिर्फ URL पैटर्न मैच करने के बजाय इंस्टॉल के समय Android को असल में मालिकाना हक जांचने के लिए ट्रिगर करता है। इसे छोड़ दें तो फ़िल्टर लिंक तो मैच करता रहेगा, लेकिन तभी जब यूज़र disambiguation शीट से एक बार साफ़ तौर पर आपकी ऐप चुन ले — यह कभी भी “हमेशा अपने-आप खोलें” स्तर तक नहीं पहुँचता।

डोमेन वाला हिस्सा एक तय, बिना किसी बदलाव की गुंजाइश वाले path पर रखी एक स्टैटिक फ़ाइल है:

https://mfkapps.com/.well-known/assetlinks.json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.mfk.granyn",
    "sha256_cert_fingerprints": [
      "14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A3:88:1E:22:0B:99:19:33:4B:C0:5B:0B:64:0C:1D"
    ]
  }
}]

package_name और sha256_cert_fingerprints दोनों को इंस्टॉल किए गए बिल्कुल उसी बिल्ड से मेल खाना चाहिए। यही fingerprint वाला विवरण है जहाँ लगभग हर टूटा हुआ सेटअप वाकई टूटता है।

Fingerprint का बेमेल जो सब कुछ चुपचाप तोड़ देता है

sha256_cert_fingerprints को यूज़र द्वारा इंस्टॉल किए गए APK के साइनिंग सर्टिफिकेट का SHA-256 चाहिए होता है — और अगर ऐप Play App Signing के ज़रिए डिस्ट्रीब्यूट होती है, तो यह Google की साइनिंग की होती है, आपकी लोकल साइन की गई अपलोड की नहीं। assetlinks.json में गलत fingerprint डालें, और वेरिफिकेशन बिना किसी ऐसी एरर के फेल हो जाता है जो यूज़र को कभी दिखे; लिंक हमेशा के लिए ब्राउज़र में खुलता रहता है, और Logcat में इस फ़ाइल की ओर इशारा करने वाला कुछ नहीं होता।

सही fingerprint अपने लोकल keystore से नहीं, Play Console से लें:

Play Console → Setup → App integrity → App signing key certificate → SHA-256

डेवलपमेंट के दौरान debug बिल्ड के लिए, debug keystore का fingerprint इस्तेमाल करें, और अगर आप चाहते हैं कि debug और release दोनों एक ही assetlinks.json के खिलाफ वेरिफाई हों तो दोनों को array में डालें:

keytool -list -v -keystore ~/.android/debug.keystore \
  -alias androiddebugkey -storepass android -keypass android

sha256_cert_fingerprints एक array स्वीकार करता है, तो दोनों fingerprints साथ-साथ रह सकते हैं — वेरिफिकेशन यह जांचता है कि इंस्टॉल की गई ऐप के सिग्नेचर से कोई भी एंट्री मेल खाती है या नहीं।

यह जांचना कि यह वाकई काम कर गया

Android इंस्टॉल के समय वेरिफिकेशन चेक चलाता है और नतीजे को कैश कर लेता है, इसलिए असली स्थिति देखने का सबसे तेज़ तरीका व्यवहार से अंदाज़ा लगाने के बजाय सीधे OS से पूछना है:

adb shell pm get-app-links com.mfk.granyn

काम कर रहा सेटअप डोमेन को verified बताकर रिपोर्ट करता है:

com.mfk.granyn:
  ID: d3a1f0b2-...
  Signatures: [14:6D:E9:...]
  Domain verification state:
    mfkapps.com: verified

अगर यह legacy_failure या none दिखाता है, तो fingerprint या JSON गलत है — assetlinks.json ठीक करें, फिर बिना दोबारा इंस्टॉल किए दोबारा जांच को मजबूर करें:

adb shell pm verify-app-links --re-verify com.mfk.granyn
adb shell pm get-app-links com.mfk.granyn

वेरिफिकेशन पास होने के बाद असली टैप-थ्रू व्यवहार टेस्ट करने के लिए, वैसे ही एक intent चलाएँ जैसे कोई ब्राउज़र या दूसरी ऐप चलाती:

adb shell am start -a android.intent.action.VIEW \
  -d "https://mfkapps.com/apps/granyn"

अगर ऐप बिना किसी chooser शीट के खुल जाती है, तो वेरिफिकेशन काम कर रहा है। अगर एक disambiguation डायलॉग दिखता है, तो वेरिफिकेशन फेल हो गया है और OS इसे एक साधारण, अनवेरिफाइड लिंक मैच की तरह ट्रीट कर रहा है।

लॉन्च के बाद चुपचाप तोड़ने वाली तीन चीज़ें

JSON सही content type के साथ और बिना किसी रीडायरेक्ट के सर्व होनी चाहिए। कोई CDN या reverse proxy जो /.well-known/assetlinks.json को किसी canonical URL पर 301 रीडायरेक्ट करता है, या इसे text/html की तरह सर्व करता है, वेरिफिकेशन फेल कर देता है भले ही ब्राउज़र में यह ठीक दिखे। दोनों को सीधे curl से चेक करें:

curl -sI https://mfkapps.com/.well-known/assetlinks.json | grep -i content-type

ऐप को दोबारा साइन करने से fingerprint बदल जाता है। साइनिंग की को रोटेट करना, लोकल keystore से Play App Signing पर स्विच करना, या नई बिल्ड पाइपलाइन अपनाना — ये सब तब तक हर पहले से वेरिफाई हो चुके लिंक को चुपचाप तोड़ देते हैं जब तक assetlinks.json को नए fingerprint के साथ अपडेट न किया जाए। यह release checklist में एक लाइन के लायक है, क्योंकि इसका फेलियर मोड — लिंक्स का चुपचाप ब्राउज़र फॉलबैक पर गिर जाना — न कोई क्रैश देता है, न कोई एरर रिपोर्ट।

एक ही डोमेन शेयर करने वाली कई ऐप्स को कई स्टेटमेंट्स चाहिए होते हैं। अगर एक ही टीम की एक से ज़्यादा ऐप एक ही host के अंदर अलग-अलग paths पर दावा करती हैं, तो assetlinks.json एक JSON array होता है — हर ऐप के लिए एक object, हर एक का अपना package_name और fingerprint लिस्ट। सिर्फ एक ऐप का स्टेटमेंट रखने वाली फ़ाइल उस डोमेन की बाकी हर ऐप के लिए वेरिफिकेशन को चुपचाप फेल कर देती है।

एक अच्छे टैप से आगे यह क्या देता है

एक बार डोमेन वेरिफाई हो जाए, तो वही intent filter ऐप को हर उस जगह उस डोमेन के डिफ़ॉल्ट हैंडलर की तरह काम करने देता है जहाँ OS कोई URL सौंपता है — एक नोटिफिकेशन एक्शन, एक QR कोड, किसी दूसरी ऐप से शेयर किया गया लिंक, एक Smart Lock क्रेडेंशियल फ्लो। इनमें से किसी को भी अलग वायरिंग नहीं चाहिए; यह वही autoVerify फ़िल्टर और वही assetlinks.json है, जो OS के उसके पीछे के दावे पर वाकई भरोसा करने के बाद और ज़्यादा कर पाता है।

अगर इस सब के बाद भी ऐप का कोई लिंक ब्राउज़र में खुलता है, तो manifest को दोबारा छूने से पहले pm get-app-links जांचें — व्यवहार में, टूटा हुआ आधा हिस्सा लगभग कभी intent filter नहीं होता।

// संबंधित पठन

जर्नल से और भी

MFKAPPS 5 मिनट पढ़ना

Android का In-App Review API: बिना परेशान किए रेटिंग माँगना

Google के In-App Review API की एक व्यावहारिक गाइड — यह असल में कैसे काम करता है, इसे कब ट्रिगर करना चाहिए, और सामान्य 'हमें रेट करें' पॉपअप आपकी Play Store रेटिंग को चुपचाप कैसे नुकसान पहुँचा रहा है।

#android #engineering #kotlin
MFKAPPS 6 मिनट पढ़ना

Android ऐप शॉर्टकट्स और Quick Settings Tiles: बिना ऐप खोले पानी लॉग करना

Android के डायनामिक ShortcutManager API और TileService की एक व्यावहारिक गाइड — कैसे एक-टैप एक्शन को पूरी तरह ऐप को छोड़कर काम करने दें, साथ ही वे गड़बड़ियाँ जो ज़्यादातर इम्प्लीमेंटेशन को फँसा देती हैं।

#android #engineering #kotlin
MFKAPPS 6 मिनट पढ़ना

2026 में Android पर फोरग्राउंड सर्विस टाइप्स: वह चुनना जो आपके फीचर पर सच में लागू हो

Android के फोरग्राउंड सर्विस टाइप प्रतिबंधों की एक व्यावहारिक गाइड — dataSync, mediaPlayback, specialUse, shortService — और बिना मारे या रिजेक्ट हुए सही वाला कैसे चुनें।

#android #engineering #kotlin