Android webview में डीप लिंकिंग और कस्टम स्कीम को कैसे हैंडल करें? Android WebView में डीप लिंक हैंडल करने के लिए WebViewClient को एक्सटेंड करना, shouldOverrideUrlLoading को ओवरराइड करके isForMainFrame की जांच करना, कस्टम स्कीम को अनुमति-सूची (allowlist) के विरुद्ध सत्यापित करना और अनधिकृत स्कीम को WebView लोडिंग पाइपलाइन में रहने से रोकने के लिए अधिकृत बाहरी इंटेंट को सुरक्षित रूप से लॉन्च करना आवश्यक है।
Android WebView डीप लिंक इंटरसेप्शन एक कस्टम WebViewClient के भीतर नेविगेशन कॉलबैक को ओवरराइड करने की प्रोग्रामेटिक प्रक्रिया है, ताकि HTTP-मुक्त प्रोटोकॉल जैसे कस्टम URI स्कीम और Chrome Intent URIs को कैप्चर किया जा सके। अनुरोध मेटाडेटा का मूल्यांकन करके और डेस्टिनेशन पेलोड को सत्यापित करके, होस्ट एप्लिकेशन मूल (native) Intent लॉन्च निष्पादित करता है और अनहैंडल्ड प्रोटोकॉल क्रैश को रोकता है।
| शब्द | परिभाषा | संबंधित एंटिटी | सर्च इंटेंट भूमिका |
|---|---|---|---|
| WebView | एक एम्बेडेड क्रोमियम-आधारित व्यू कंपोनेंट जो Android ऐप्स के अंदर वेब कंटेंट रेंडर करता है। | Android SDK | सूचनात्मक / वाणिज्यिक |
| Custom URL Scheme | एक प्रोप्राइटरी URI प्रोटोकॉल जो वेब लिंक को नेटिव एप्लिकेशन को टारगेट करने की अनुमति देता है। | डीप लिंक राउटिंग | तकनीकी / सूचनात्मक |
| Web to App | उपयोगकर्ताओं को वेब पेजों से नेटिव एप्लिकेशन इंटरफेस में स्थानांतरित करने की प्रक्रिया। | मोबाइल डीप लिंकिंग | सूचनात्मक |

Android WebViews net ERR UNKNOWN URL SCHEME त्रुटियां क्यों देते हैं
क्रोमियम प्रोटोकॉल सीमाएं: WebView केवल मानक वेब स्कीम को ही क्यों पहचानते हैं
Android WebView कंपोनेंट एक क्रोमियम रेंडरिंग इंजन द्वारा संचालित होता है जिसे मुख्य रूप से मानक वेब-संसाधन प्रोटोकॉल: http://, https://, file://, data://, about:, और javascript: को पार्स और प्रदर्शित करने के लिए कॉन्फ़िगर किया गया है।
डिफ़ॉल्ट रूप से, जब कोई कस्टम WebViewClient असाइन नहीं किया जाता है, तो Android फ्रेमवर्क अनहैंडल्ड URL को सिस्टम के एक्टिविटी मैनेजर को सौंप देता है। हालाँकि, एक बार जब एप्लिकेशन एक कस्टम WebViewClient प्रदान करता है, तो गैर-HTTP(S) स्कीम (जैसे myapp://product/detail/1024, alipay://, या whatsapp://) सीधे क्लाइंट के नेविगेशन कॉलबैक में रूट हो जाते हैं। यदि होस्ट एप्लिकेशन किसी कस्टम स्कीम को इंटरसेप्ट करने के बजाय WebView लोडिंग पाइपलाइन में रहने देता है, तो क्रोमियम इंजन कस्टम स्कीम को सामान्य वेब संसाधन के रूप में हल करने का प्रयास करता है। चूंकि गैर-मानक प्रोटोकॉल को DNS या वेब सर्वर ट्रांसपोर्ट लेयर्स के विरुद्ध हल नहीं किया जा सकता है, इसलिए इंजन एक लो-लेवल नेविगेशन विफलता प्रदर्शित करता है।
net::ERR_UNKNOWN_URL_SCHEME का क्रैश एनाटॉमी: यूजर टैप से वेब संसाधन लोड विफलता तक
यूज़र इंटरेक्शन से एरर पेज तक का संक्रमण एक त्वरित, दृढ़ अनुक्रम में होता है:
- यूज़र ट्रिगर: एक उपयोगकर्ता एम्बेडेड H5 लैंडिंग पेज के अंदर कॉल-टू-एक्शन बटन या हाइपरलिंक पर टैप करता है।
- नेविगेशन अनुरोध: वेब इंजन टारगेट URI स्ट्रिंग (जैसे
myapp://promo/summer) युक्त नेविगेशन अनुरोध बनाता है। - पाइपलाइन मूल्यांकन: यदि
shouldOverrideUrlLoading()का मानfalseहै या वह गैर-HTTP(S) URI को इंटरसेप्ट करने में विफल रहता है, तो क्रोमियम इंजन URL को मानक वेब संसाधन लोड के रूप में मानता है। - एरर डिस्पैच: प्रोटोकॉल के लिए कोई आंतरिक हैंडलर न मिलने पर, इंजन
onReceivedError()को ट्रिगर करता है और वेब व्यू के कंटेंट को डिफ़ॉल्ट क्रोमियम एरर टेम्पलेट से बदल देता है:net::ERR_UNKNOWN_URL_SCHEME।
यह एरर पेज उपयोगकर्ता यात्रा को रोक देता है, कन्वर्जन ट्रैकिंग को रोकता है, और होस्ट एप्लिकेशन की स्थिरता को कम करता है।
टारगेट एप्लिकेशन की अनुपस्थिति में unhandled ActivityNotFoundException क्रैश का जोखिम
जब डेवलपर्स पहली बार net::ERR_UNKNOWN_URL_SCHEME को हल करने का प्रयास करते हैं, तो एक सामान्य गलती URI स्ट्रिंग को पार्स करना और बिना पर्याप्त अपवाद हैंडलिंग के context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) को कॉल करना है।
यदि उपयोगकर्ता के डिवाइस पर टारगेट एप्लिकेशन इंस्टॉल नहीं है, तो Android ऑपरेटिंग सिस्टम Intent को हल करने के लिए योग्य Activity नहीं ढूंढ पाता है। मानक Android निष्पादन में, बिना मैचिंग हैंडलर के startActivity() को कॉल करने से एक अनहैंडल्ड android.content.ActivityNotFoundException उत्पन्न होता है। यदि इस अपवाद को संरचित try-catch ब्लॉक के भीतर पकड़ा नहीं जाता है, तो संपूर्ण होस्ट एप्लिकेशन प्रक्रिया अचानक समाप्त हो जाती है, जिसके परिणामस्वरूप एक घातक क्रैश होता है।
shouldOverrideUrlLoading डीप लिंक प्रोटोकॉल को कैसे इंटरसेप्ट करता है
API विकास: API 24+ WebResourceRequest ओवरलोड की लेगेसी स्ट्रिंग कॉलबैक के साथ तुलना
Android का WebViewClient होस्ट एप्लिकेशन को नेविगेशन अनुरोधों को वेब इंजन द्वारा निष्पादित करने से पहले निरीक्षण और इंटरसेप्ट करने की अनुमति देने के लिए shouldOverrideUrlLoading कॉलबैक प्रदान करता है। इस पद्धति के हस्ताक्षर और क्षमताएं Android API स्तरों में विकसित हुई हैं:
- API 24+ (Android 7.0 और उच्चतर):
shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Booleanको ओवरराइड करता है।WebResourceRequestइंटरफेस समृद्ध प्रासंगिक मेटाडेटा प्रदान करता है, जिसमें टारगेट URL (request.url), HTTP अनुरोध विधि (request.method), अनुरोध हेडर, और महत्वपूर्ण फ्रेम-पदानुक्रम फ्लैग (request.isForMainFrame,request.hasGesture()) शामिल हैं। - लेगेसी ओवरलोड (API 24 मेंDeprecated):
shouldOverrideUrlLoading(view: WebView?, url: String?): Booleanको ओवरराइड करता है। यह लेगेसी कॉलबैक केवल कच्ची URL स्ट्रिंग प्राप्त करता है, जिसमें अनुरोध करने वाले फ्रेम या यूज़र इंटरेक्शन स्थिति के बारे में कोई मेटाडेटा नहीं होता है।
WebViewClient shouldOverrideUrlLoading पर Android डेवलपर्स संदर्भ के अनुसार, आधुनिक एप्लिकेशन को WebResourceRequest ओवरलोड को लागू करना चाहिए। लेगेसी Android संस्करणों का समर्थन करते समय, सुरक्षा बायपास को रोकने के लिएDeprecated स्ट्रिंग कॉलबैक को रूढ़िवादी रूप से कॉन्फ़िगर किया जाना चाहिए।
request.isForMainFrame की सुरक्षा गंभीरता: सबफ्रेम और Iframe हाइजैकिंग को रोकना

WebResourceRequest पर Android डेवलपर्स गाइड के अनुसार, shouldOverrideUrlLoading कॉलबैक को सबफ्रेम, iframe और बैकग्राउंड संसाधन रीडायरेक्ट के साथ-साथ टॉप-लेवल डॉक्यूमेंट नेविगेशन के लिए ट्रिगर किया जा सकता है।
एप्लिकेशन सुरक्षा के लिए request.isForMainFrame को लागू करना आवश्यक है:
- फ्रेम बाउंड्री अलगाव:
request.isForMainFrameकी जांच यह सुनिश्चित करती है कि सबफ्रेम और iframe बाहरी एप्लिकेशन लॉन्च या कस्टम स्कीम इंटेंट को ट्रिगर न कर सकें। यदि कोई सबफ्रेम नेविगेशन का प्रयास करता है, तो मानक HTTP(S) लोड को इन-फ्रेम रेंडरिंग जारी रखने के लिएfalseवापस करना चाहिए, जबकि गैर-HTTP(S) स्कीम को त्रुटियां उत्पन्न किए बिना निष्पादन को दबाने के लिएtrueवापस करना चाहिए। - यूज़र जेस्चर अंतर: जबकि
isForMainFrameयह पुष्टि करता है कि अनुरोध प्राथमिक डॉक्यूमेंट पर लागू होता है, यह यूज़र सक्रियण को साबित नहीं करता है। यदि आपके आर्किटेक्चर को यूज़र-जेस्चर सत्यापन की आवश्यकता है, तोrequest.hasGesture()का मूल्यांकन करें या एप्लिकेशन-स्तर पर पुष्टिकरण मॉडल लागू करें, यह ध्यान में रखते हुए कि Android दस्तावेज़ीकरण कुछ वैध यूज़र फ्लो पर प्रकाश डालता है जहांhasGesture()गलत (false) वापस कर सकता है।
सामान्य वेब नेविगेशन को डीप लिंक हैंडऑफ़ से अलग करना: false बनाम true कब वापस करें
shouldOverrideUrlLoading का बूलियन रिटर्न मान WebView के रेंडरिंग लाइफसाइकिल को नियंत्रित करता है:
- return
false: Android फ्रेमवर्क को सूचित करता है कि होस्ट एप्लिकेशन ने URL को हैंडल नहीं किया है।WebViewमानक वेब नेविगेशन जारी रखता है, और URL को अपने आंतरिक क्रोमियम कंटेनर के भीतर लोड करता है। यह रिटर्न मान उन मानकhttp://औरhttps://वेब पेजों के लिए अनिवार्य है जिन्हें एम्बेडेड ब्राउज़र के अंदर प्रदर्शित होना चाहिए। - return
true: फ्रेमवर्क को सूचित करता है कि होस्ट एप्लिकेशन ने URL को इंटरसेप्ट और हैंडल कर लिया है।WebViewतुरंत अपनी आंतरिक लोडिंग प्रक्रिया को रद्द कर देता है। बाहरीIntentलॉन्च करते समय, नेटिव एक्टिविटी में रूट करते समय, या अनधिकृत स्कीम को दबाते समय यह रिटर्न मान अनिवार्य है।
एम्बेडेड कंटेनर के भीतर होस्ट ऐप सत्यापित ऐप लिंक को हैंडल करना
जब WebView के अंदर का लिंक होस्ट एप्लिकेशन के अपने सत्यापित HTTPS डोमेन (जैसे https://app.example.com/product/1024) की ओर इशारा करता है, तो डिफ़ॉल्ट नेविगेशन को निष्पादित करने से WebView प्रोडक्ट पेज का वेब संस्करण लोड हो जाता है।
नेटिव अनुभव प्रदान करने के लिए, WebViewClient को आने वाले HTTPS URL का निरीक्षण करना चाहिए। यदि होस्ट एप्लिकेशन के संबंधित डोमेन से मेल खाता है, तो क्लाइंट अनुरोध को इंटरसेप्ट करता है, पाथ और क्वेरी पैरामीटर्स को आंतरिक रूट वैलिडेटर (AppLinkRouteValidator) के विरुद्ध सत्यापित करता है, और डेटा को सीधे नेटिव राउटर (internalRouter(validatedRoute)) को भेज देता है, और अनावश्यक वेब रेंडरिंग को रद्द करने के लिए true वापस करता है।
कस्टम स्कीम और Intent URIs के लिए सुरक्षित Intent हैंडलर बनाना
Chrome Intent URI सिंटैक्स का विश्लेषण: स्कीम्स, पैकेज, और S.browser_fallback_url
Android पर, वेब पेज अक्सर नेटिव डीप लिंक को इन-बिल्ट ब्राउज़र फॉलबैक तंत्र के साथ संरचित करने के लिए Chrome Intent URIs का उपयोग करते हैं। एक Intent URI intent:// स्कीम का उपयोग करता है और राउटिंग पैरामीटर्स, पैकेज टारगेट्स, और फॉलबैक URL को एक सीरियलाइज्ड स्ट्रिंग में एनकोड करता है:
intent://product/detail/1024#Intent;scheme=myapp;package=com.example.app;S.browser_fallback_url=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.example.app;end
Android Intent URIs पर Chrome फॉर डेवलपर्स गाइड में प्रलेखित के अनुसार, URI अलग-अलग घटकों में विभाजित होता है:
- होस्ट और पाथ (
product/detail/1024): आंतरिक एप्लिकेशन गंतव्य को परिभाषित करता है। scheme=myapp: अंतर्निहित कस्टम प्रोटोकॉल निर्दिष्ट करता है।package=com.example.app: इंटेंट रिज़ॉल्यूशन को विशेष रूप से निर्दिष्ट Android पैकेज तक सीमित करता है।S.browser_fallback_url=...: एक वैकल्पिक स्ट्रिंग एक्स्ट्रा जो टारगेट एप्लिकेशन इंस्टॉल न होने पर लोड करने के लिए एक स्पष्ट वेब या स्टोर URL को परिभाषित करता है।
कच्चे पार्स किए गए Intent को निष्पादित करने का खतरा: Intent इंजेक्शन कमजोरियों को कम करना
एक सामान्य कार्यान्वयन एंटी-पैटर्न Intent.parseUri(url, Intent.URI_INTENT_SCHEME) के साथ आने वाले URI को पार्स करना और परिणामी Intent को सीधे context.startActivity(intent) में पास करना है।
असुरक्षित डीप लिंक पर OWASP मोबाइल एप्लिकेशन सुरक्षा परीक्षण गाइड मार्गदर्शन के अनुसार, कच्चे पार्स किए गए इंटेंट को निष्पादित करना एप्लिकेशन को इंटेंट इंजेक्शन हमलों के संपर्क में लाता है। वेब पेज को नियंत्रित करने वाला एक हमलावर दुर्भावनापूर्ण स्पष्ट घटक टारगेट्स (component=com.example.app/.InternalAdminActivity), संवेदनशील कार्यों, या विशेषाधिकार प्राप्त इंटेंट एक्स्ट्रा (S.is_admin=true) युक्त एक Intent URI बना सकता है। WebView इन मापदंडों को डीसीरियलाइज करेगा और प्रमाणीकरण बाधाओं को दरकिनार करते हुए, अनएक्स्पोर्टेड या आंतरिक गतिविधियों को लॉन्च करेगा।

सुरक्षित Intent पुनर्निर्माण: घटकों को हटाना और ACTION_VIEW तक सीमित करना
Intent इंजेक्शन कमजोरियों को खत्म करने के लिए, होस्ट एप्लिकेशन को कभी भी सीधे कच्चे डीसीरियलाइज्ड Intent को लॉन्च नहीं करना चाहिए। इसके बजाय, WebViewClient को URI को पार्स करना चाहिए, केवल सत्यापित डेटा पेलोड निकालना चाहिए, और एक स्वच्छ, समर्पित Intent का पुनर्निर्माण करना चाहिए:
- डेटा निकालें: URI को पार्स करें और सत्यापित टारगेट पैकेज और डेटा URI निकालें।
- पैकेज सत्यापित करें: यह सुनिश्चित करें कि घोषित पैकेज अधिकृत पार्टनर या आंतरिक पैकेज की स्पष्ट अनुमति-सूची से मेल खाता है।
- पुनर्निर्माण: एक नया
Intent(Intent.ACTION_VIEW, validatedDataUri)इंस्टेंट करें। - आइसोलेट: यह सुनिश्चित करने के लिए
intent.addCategory(Intent.CATEGORY_BROWSABLE)लागू करें कि केवल ब्राउज़ करने योग्य गतिविधियां अनुरोध को हल कर सकें, स्पष्ट फ्लैग (FLAG_ACTIVITY_NEW_TASK) सेट करें, और सुनिश्चित करें किintent.componentऔरintent.selectorशून्य रहें।
सख्त स्कीम, होस्ट, पाथ, और क्वेरी पैरामीटर अनुमति-सूची लागू करना
कस्टम स्कीम (myapp://) और पुनर्निर्मित Intent URIs दोनों को निष्पादन से पहले एक सख्त वैलिडेटर से गुजरना होगा।
यह संदर्भ कार्यान्वयन विशेष रूप से होस्ट एप्लिकेशन की अपनी myapp:// स्कीम को हैंडल करता है, जो इंटेंट निष्पादन को स्पष्ट रूप से com.example.app तक सीमित करता है। मल्टी-ऐप पार्टनर इकोसिस्टम के लिए, डेवलपर्स को एक सख्त स्कीम-टू-पैकेज मैपिंग बनाए रखनी चाहिए या सत्यापित HTTPS App Links को प्राथमिकता देनी चाहिए।
वैलिडेटर जाँचता है:
- स्कीम: अधिकृत कस्टम स्कीम (
myapp) से मेल खाता है। - होस्ट: पूर्वनिर्धारित राउटिंग श्रेणियों (
open,product,event) से मेल खाता है। - पाथ प्रीफिक्स: अपेक्षित रूट संरचनाओं (
/detail/,/view/,/main/) के अनुरूप है। - क्वेरी पैरामीटर्स: अनुमति-सूचीबद्ध क्वेरी कुंजियों (
target,id,promo,utm_source) को लागू करता है और यह सत्यापित करता है कि पैरामीटर मान लंबाई सीमा (जैसे 128 वर्ण) और अल्फ़ान्यूमेरिक वर्ण सेटों का अनुपालन करते हैं।
[User Taps Link Inside Android WebView]
│
▼
[WebViewClient.shouldOverrideUrlLoading]
│
┌─────────────┴─────────────┐
▼ ▼
[!request.isForMainFrame] [request.isForMainFrame]
│ │
▼ ▼
[Check Subframe Scheme] [Inspect URL Scheme]
├─ HTTP(S) -> return false │
└─ Non-Web -> return true ┌────┴───────────────────────────┐
(Suppress Error) ▼ ▼
[HTTP / HTTPS] [Non-HTTP(S) Scheme]
│ │
▼ ▼
[Check Host Domain] [CustomSchemeValidator]
├─ Internal App Link ├─ Valid -> Launch Pinned Intent
│ -> Internal Router └─ Intent -> Reconstruct & Fallback
└─ External Web
-> Return false
Android 11 पैकेज दृश्यता और ऐप स्टोर फॉलबैक को कैसे हैंडल करें

Android 11 पैकेज दृश्यता परिवर्तन: प्रीफाइट क्वेरी के लिए घोषणा की आवश्यकता क्यों है
Android 11 (API लेवल 30) से शुरू करते हुए, Google ने उपयोगकर्ता गोपनीयता बढ़ाने के लिए पैकेज दृश्यता फ़िल्टरिंग शुरू की। इस ढांचे के तहत, अन्य इंस्टॉल किए गए एप्लिकेशन का एप्लिकेशन का दृश्य डिफ़ॉल्ट रूप से प्रतिबंधित है।
इंटेंट लॉन्चिंग और इंटेंट क्वेरीइंग के बीच अंतर समझना महत्वपूर्ण है:
- डायरेक्ट इंटेंट लॉन्चिंग:
context.startActivity(intent)के मानक कॉल्स के लिए पैकेज दृश्यता घोषणाओं की आवश्यकता नहीं होती है। यदि टारगेट एप्लिकेशन इंस्टॉल है, तो ऑपरेटिंग सिस्टम इसे सफलतापूर्वक रूट और लॉन्च करता है, चाहे वह पैकेज क्वेरीज़ के लिए दृश्यमान हो या नहीं। - प्रीफाइट इंटेंट क्वेरीज़: यदि आपका
WebViewClientआर्किटेक्चर प्रीफाइट निरीक्षण करता है—जैसे लॉन्च करने से पहले एप्लिकेशन की उपस्थिति की जांच करने के लिएpackageManager.resolveActivity(intent, 0)याpackageManager.queryIntentActivities(intent, 0)को कॉल करना—तो क्वेरीnullया एक खाली सूची वापस करती है जब तक कि टारगेट पैकेज या स्कीमAndroidManifest.xmlमें घोषित न हो।
AndroidManifest.xml में कस्टम स्कीम और पैकेज टारगेट्स के लिए <queries> तत्वों की घोषणा
Android 11 में पैकेज दृश्यता पर Android डेवलपर्स गाइड के अनुसार, जो एप्लिकेशन इंटेंट निष्पादन से पहले प्रीफाइट जांच करते हैं, उन्हें मैनिफेस्ट में अपने टारगेट पैकेज या इंटेंट हस्ताक्षरों की घोषणा करनी चाहिए:
<manifest package="com.example.app">
<!-- स्पष्ट पैकेज खोज के लिए वैकल्पिक प्रीफाइट क्वेरी घोषणाएं -->
<queries>
<package android:name="com.example.partner" />
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="myapp" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="app.example.com" />
</intent>
</queries>
</manifest>
यदि आपका आर्किटेक्चर मानक लॉन्च पैटर्न पसंद करता है, तो try-catch ब्लॉक के भीतर startActivity() को निष्पादित करना जो ActivityNotFoundException को पकड़ता है, एक लचीला, क्वेरी-स्वतंत्र कार्यान्वयन प्रदान करता है।
फॉलबैक चेन लागू करना: टारगेट एप्लिकेशन अनुपस्थित होने पर ग्रेसफुल स्टोर राउटिंग
जब किसी इंटरसेप्ट की गई कस्टम स्कीम या Intent URI को लॉन्च नहीं किया जा सकता क्योंकि उपयोगकर्ता के डिवाइस पर टारगेट एप्लिकेशन इंस्टॉल नहीं है, तो WebViewClient को एक स्पष्ट फॉलबैक चेन निष्पादित करनी चाहिए:
- फॉलबैक URL निकालें और बाइंड करें:
intent://URIs के लिए,S.browser_fallback_urlस्ट्रिंग पैरामीटर निकालें और सत्यापित करें कि यह एक अधिकृत गंतव्य की ओर इशारा करता है। Google Play URL के लिए, सत्यापित करें किidपैरामीटर टारगेट पैकेज नाम (id=targetPackage) से पूरी तरह मेल खाता है ताकि ओपन-रीडायरेक्ट कारनामों को रोका जा सके। - मार्केट URI जनरेशन: यदि कोई फॉलबैक URL मौजूद नहीं है, तो एक मार्केट इंटेंट बनाएं:
market://details?id=com.example.app। - वेब प्ले स्टोर फॉलबैक: यदि Google Play अक्षम है या अनुपस्थित है, तो मार्केट इंटेंट पर
ActivityNotFoundExceptionको पकड़ें औरhttps://play.google.com/store/apps/details?id=com.example.appलोड करें।
OpoInstall के साथ फॉलबैक रीडायरेक्ट्स पर प्रासंगिक पैरामीटर्स बाइंड करना
जब अनइंस्टॉल किए गए उपयोगकर्ताओं को Google Play पर रूट किया जाता है, तो स्टेटिक स्टोर लिंक डायनामिक पैरामीटर्स को छोड़ देते हैं। OpoInstall, एक मोबाइल एट्रिब्यूशन और डीप लिंकिंग प्लेटफॉर्म, स्टोर रीडायरेक्ट से पहले एट्रिब्यूशन बैकएंड पर रेफरल टोकन और कैंपेन संदर्भ को कैप्चर करके इस अंतर को पाटता है। प्रोडक्शन में तैनात OpoInstall Android SDK संस्करण के विरुद्ध डेफ़र्ड-पैरामीटर पुनर्प्राप्ति व्यवहार और आरंभीकरण APIs को सत्यापित करें।
बाद के इंस्टॉलेशन और शुरुआती ऐप लॉन्च पर, OpoInstall Android SDK कैश किए गए पैरामीटर्स को पुनर्प्राप्त करता है, जिससे होस्ट ऐप को उपयोगकर्ता के टारगेट दृश्य को पुनर्स्थापित करने में मदद मिलती है। इंस्टॉल-पश्चात डेफ़र्ड पैरामीटर्स प्राप्त करने के निर्देशों के लिए SDK एकीकरण दस्तावेज़ीकरण की समीक्षा करें।
सुरक्षित स्कीम इंटरसेप्शन के लिए प्रोडक्शन WebViewClient कार्यान्वयन
Kotlin में कस्टम WebViewClient आर्किटेक्चर तैयार करना
एक प्रोडक्शन WebViewClient फ्रेम सत्यापन, स्कीम अनुमति-सूची, इंटेंट पुनर्निर्माण, फॉलबैक निष्कर्षण, और आंतरिक राउटिंग का समन्वय करता है। कार्यान्वयन नेविगेशन कॉलबैक को साफ और रखरखाव योग्य रखने के लिए समर्पित वैलिडेटर ऑब्जेक्ट्स (AppLinkRouteValidator और CustomSchemeValidator) के भीतर सत्यापन नियमों को समाहित करता है।
AppLinkRouteValidator और CustomSchemeValidator मॉडल लागू करना
वैलिडेटर ऑब्जेक्ट्स सख्त फेल-क्लोज सुरक्षा लागू करते हैं:
AppLinkRouteValidatorआंतरिक HTTPS डोमेन, अनुमत पाथ प्रीफिक्स, और अधिकृत क्वेरी कुंजियों (target,id,promo,utm_source) को सत्यापित करता है, और एक संरचितValidatedAppRouteडेटा क्लास लौटाता है।CustomSchemeValidatorअधिकृत कस्टम स्कीम (myapp) की जांच करता है, अनुमत होस्ट (open,product,event) को सत्यापित करता है, पाथ प्रीफिक्स लागू करता है, और क्वेरी पैरामीटर मानों को अल्फ़ान्यूमेरिक वर्ण सेट और लंबाई बाधाओं (≤ 128 वर्ण) के विरुद्ध सैनिटाइज़ करता है।
नीचे दिया गया कोड कार्यान्वयन यह प्रदर्शित करता है कि वैकल्पिक AndroidManifest.xml पैकेज दृश्यता घोषणाओं को कैसे कॉन्फ़िगर किया जाए और स्वचालित फॉलबैक हैंडलिंग के साथ Kotlin में एक थ्रेड-सुरक्षित, सुरक्षित CustomWebViewClient कैसे लागू किया जाए। प्रमाणित SDK बाइनरी और एकीकरण रैपर OpoInstall SDK डाउनलोड सेंटर से प्राप्त किए जा सकते हैं।
<!-- AndroidManifest.xml: प्रीफाइट इंटेंट क्वेरी के लिए वैकल्पिक पैकेज दृश्यता घोषणाएं (Android 11+) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<!-- यदि प्रीफाइट resolveActivity क्वेरी का उपयोग कर रहे हैं तो बाहरी पैकेज और कस्टम स्कीम घोषित करें -->
<queries>
<!-- विशिष्ट पार्टनर या टारगेट पैकेज के लिए प्रीफाइट खोज को अधिकृत करें -->
<package android:name="com.example.partner" />
<!-- कस्टम डीप लिंकिंग स्कीम के प्रीफाइट रिज़ॉल्यूशन को अधिकृत करें -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="myapp" />
</intent>
<!-- सत्यापित HTTPS App Link डोमेन के प्रीफाइट रिज़ॉल्यूशन को अधिकृत करें -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="app.example.com" />
</intent>
</queries>
<application
android:allowBackup="true"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<!-- एप्लिकेशन घटक -->
</application>
</manifest>
// Android: फ्रेम बाउंड्री सुरक्षा, अनुमति-सूची सत्यापन, और फॉलबैक राउटिंग के साथ कस्टम WebViewClient
// संदर्भ एकीकरण उदाहरण; तैनात Android आर्किटेक्चर के विरुद्ध पद्धति हस्ताक्षरों को सत्यापित करें।
package com.example.app.webview
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
data class ValidatedAppRoute(val path: String, val queryParams: Map<String, String>)
object AppLinkRouteValidator {
private val allowedPrefixes = setOf("/open/", "/product/", "/promo/")
private val allowedQueryKeys = setOf("target", "id", "promo", "utm_source")
fun validate(uri: Uri): ValidatedAppRoute? {
val path = uri.path ?: ""
if (allowedPrefixes.none { path.startsWith(it) }) {
return null
}
val sanitizedParams = mutableMapOf<String, String>()
for (name in uri.queryParameterNames) {
// सख्त सुरक्षा रुख: यदि अज्ञात क्वेरी कुंजियाँ मौजूद हैं तो अनुरोध को अस्वीकार करें
if (name !in allowedQueryKeys) {
return null
}
val value = uri.getQueryParameter(name) ?: ""
if (value.length <= 64 && value.matches(Regex("^[A-Za-z0-9_-]+$"))) {
sanitizedParams[name] = value
} else {
return null
}
}
return ValidatedAppRoute(path, sanitizedParams)
}
}
object CustomSchemeValidator {
private val allowedSchemes = setOf("myapp")
private val allowedHosts = setOf("open", "product", "event")
private val allowedPathPrefixes = setOf("/detail/", "/view/", "/main/")
private val allowedQueryKeys = setOf("target", "id", "promo", "utm_source")
fun validate(uri: Uri): Uri? {
val scheme = uri.scheme?.lowercase() ?: return null
val host = uri.host?.lowercase() ?: return null
val path = uri.path ?: ""
if (!allowedSchemes.contains(scheme) || !allowedHosts.contains(host)) {
return null
}
if (allowedPathPrefixes.none { path.startsWith(it) }) {
return null
}
for (name in uri.queryParameterNames) {
if (name !in allowedQueryKeys) return null
val value = uri.getQueryParameter(name) ?: ""
if (value.length > 128 || !value.matches(Regex("^[A-Za-z0-9_-]+$"))) {
return null
}
}
return uri
}
}
class CustomWebViewClient(
private val context: Context,
private val internalRouter: (ValidatedAppRoute) -> Unit
) : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
request ?: return false
// सुरक्षा आवश्यकता: केवल मेन फ्रेम नेविगेशन तक बाहरी ऐप राउटिंग को सीमित करें
if (!request.isForMainFrame) {
val scheme = request.url.scheme?.lowercase()
// मानक HTTP(S) सबफ्रेम लोडिंग की अनुमति दें, लेकिन iframe हाइजैकिंग और त्रुटियों को रोकने के लिए गैर-वेब स्कीम को दबाएं
return if (scheme == "http" || scheme == "https") {
false
} else {
Log.w("WebViewClient", "सबफ्रेम/iframe में गैर-वेब स्कीम को दबाया गया: $scheme")
true // बाहरी इंटेंट लॉन्च किए या क्रोमियम त्रुटि प्रदर्शित किए बिना उपभोग/रद्द करें
}
}
val url = request.url.toString()
return handleUrlNavigation(view, url)
}
@Deprecated("Java मेंDeprecated")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
if (url == null) return false
val uri = Uri.parse(url)
val scheme = uri.scheme?.lowercase()
// लेगेसी कॉलबैक में विश्वसनीय isForMainFrame मेटाडेटा की कमी होती है; बाहरी स्कीम को रूट न करें
return if (scheme == "http" || scheme == "https") {
false // मानक वेब कंटेंट लोड करने की अनुमति दें
} else {
Log.w("WebViewClient", "लेगेसी कॉलबैक पर बाहरी स्कीम को ब्लॉक किया गया: $scheme")
true // बाहरी इंटेंट लॉन्च किए बिना अनहैंडल्ड स्कीम त्रुटियों को दबाएं
}
}
private fun handleUrlNavigation(view: WebView?, url: String): Boolean {
val uri = Uri.parse(url)
val scheme = uri.scheme?.lowercase() ?: return false
// 1. HTTP / HTTPS और आंतरिक ऐप लिंक को हैंडल करें
if (scheme == "http" || scheme == "https") {
// जांचें कि क्या URL होस्ट ऐप के अपने ऐप लिंक डोमेन से मेल खाता है
if (scheme == "https" && uri.host?.lowercase() == "app.example.com") {
val validatedRoute = AppLinkRouteValidator.validate(uri)
if (validatedRoute != null) {
Log.i("WebViewClient", "सत्यापित आंतरिक HTTPS रूट। आंतरिक राउटर को डिस्पैच कर रहे हैं।")
internalRouter(validatedRoute)
} else {
Log.w("WebViewClient", "विकृत या अनधिकृत आंतरिक ऐप लिंक अस्वीकृत: $uri")
}
return true // आंतरिक रूप से हैंडल किया गया; वेबव्यू लोडिंग रद्द करें
}
return false // वेबव्यू को मानक वेब कंटेंट को नेटिव रूप से लोड करने दें
}
// 2. हाइजैकिंग को रोकने के लिए सख्त अनुमति-सूची और पैकेज पिनिंग के साथ कस्टम स्कीम को सत्यापित करें
val validatedUri = CustomSchemeValidator.validate(uri)
if (validatedUri != null) {
val pinnedIntent = Intent(Intent.ACTION_VIEW, validatedUri).apply {
`package` = "com.example.app" // स्पष्ट रूप से होस्ट ऐप पैकेज पिन करें
addCategory(Intent.CATEGORY_BROWSABLE)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
return launchSafeIntent(pinnedIntent, fallbackAction = {
handleStoreFallback(view, "com.example.app")
})
}
// 3. सुरक्षित पुनर्निर्माण और फॉलबैक निष्कर्षण के साथ Chrome Intent URIs को हैंडल करें
if (scheme == "intent") {
return try {
val parsed = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
val targetPackage = parsed.`package`
val allowedPackages = setOf("com.example.app", "com.example.partner")
val fallbackUrl = parsed.getStringExtra("browser_fallback_url")
if (targetPackage != null && allowedPackages.contains(targetPackage)) {
val rawDataUri = parsed.data
if (rawDataUri != null) {
val validatedDataUri = CustomSchemeValidator.validate(rawDataUri)
if (validatedDataUri != null) {
// कच्चे पार्स किए गए ऑब्जेक्ट को निष्पादित करने के बजाय एक स्वच्छ, समर्पित ACTION_VIEW इंटेंट को पुनर्निर्मित करें
val safeIntent = Intent(Intent.ACTION_VIEW, validatedDataUri).apply {
`package` = targetPackage
addCategory(Intent.CATEGORY_BROWSABLE)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
launchSafeIntent(safeIntent, fallbackAction = {
handleIntentFallback(view, fallbackUrl, targetPackage)
})
} else {
Log.w("WebViewClient", "अमान्य डेटा URI के साथ इंटेंट अस्वीकृत: $rawDataUri")
true
}
} else {
Log.w("WebViewClient", "डेटा URI पेलोड की कमी वाला इंटेंट अस्वीकृत")
true
}
} else {
Log.w("WebViewClient", "अविज्ञापित पैकेज को लक्षित करने वाला इंटेंट अस्वीकृत: $targetPackage")
true // अविज्ञापित पैकेज इंटेंट रद्द करें
}
} catch (e: Exception) {
Log.e("WebViewClient", "इंटेंट URI पार्स करने में विफल: $url", e)
true // अनहैंडल्ड स्कीम त्रुटियों को दबाएं
}
}
// net::ERR_UNKNOWN_URL_SCHEME त्रुटियों से बचने के लिए अज्ञात स्कीम को अस्वीकार करें
Log.w("WebViewClient", "अविज्ञापित स्कीम नेविगेशन ब्लॉक किया गया: $scheme")
return true
}
private fun launchSafeIntent(intent: Intent, fallbackAction: () -> Unit): Boolean {
return try {
context.startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
Log.w("WebViewClient", "टारगेट एप्लिकेशन इंस्टॉल नहीं है: ${intent.data}. फॉलबैक ट्रिगर कर रहे हैं।")
fallbackAction()
true
} catch (e: SecurityException) {
Log.e("WebViewClient", "इंटेंट लॉन्च करते समय सुरक्षा अपवाद: ${intent.data}", e)
true
}
}
private fun handleIntentFallback(view: WebView?, fallbackUrl: String?, targetPackage: String) {
if (!fallbackUrl.isNullOrBlank() && isAuthorizedFallbackUrl(fallbackUrl, targetPackage)) {
Log.i("WebViewClient", "अधिकृत ब्राउज़र फॉलबैक URL पर रूट कर रहे हैं: $fallbackUrl")
view?.loadUrl(fallbackUrl)
} else {
handleStoreFallback(view, targetPackage)
}
}
private fun handleStoreFallback(view: WebView?, packageName: String) {
val marketUri = Uri.parse("market://details?id=$packageName")
val marketIntent = Intent(Intent.ACTION_VIEW, marketUri).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
try {
context.startActivity(marketIntent)
} catch (e: ActivityNotFoundException) {
val webStoreUrl = "https://play.google.com/store/apps/details?id=$packageName"
Log.i("WebViewClient", "प्ले स्टोर ऐप अनुपस्थित है। वेब स्टोर URL लोड कर रहे हैं: $webStoreUrl")
view?.loadUrl(webStoreUrl)
}
}
private fun isAuthorizedFallbackUrl(url: String, targetPackage: String): Boolean {
val uri = Uri.parse(url)
val scheme = uri.scheme?.lowercase()
val host = uri.host?.lowercase()
if (scheme != "https" || host == null) return false
return when (host) {
"play.google.com" -> {
// Google Play फॉलबैक URL को विशेष रूप से टारगेट पैकेज की ओर इंगित करने के लिए लागू करें
uri.path == "/store/apps/details" && uri.getQueryParameter("id") == targetPackage
}
"app.example.com", "www.example.com" -> {
// स्वामित्व वाले डोमेन फॉलबैक रूट को सत्यापित करें
AppLinkRouteValidator.validate(uri) != null
}
else -> false
}
}
}
थ्रेड-सुरक्षित निष्पादन: आंतरिक रूट डिस्पैच करना और लाइफसाइकिल स्थिति प्रबंधित करना
जब AppLinkRouteValidator एक वैध आंतरिक रूट की पुष्टि करता है, तो UI ट्रांज़िशन को Android के मुख्य UI थ्रेड पर निष्पादित होना चाहिए। यदि internalRouter फ्रैगमेंट, एक्टिविटी ट्रांज़िशन, या Compose नेविगेशन को ट्रिगर करता है, तो थ्रेडिंग क्रैश को रोकने के लिए डिस्पैच कॉल को runOnUiThread या मुख्य-थ्रेड लाइफसाइकिल को-रूटीन के भीतर लपेटें।
Android WebView रीडायरेक्ट त्रुटियां और नैदानिक समाधान मैट्रिक्स
व्यापक Android WebView डीप लिंकिंग ट्रबलशूटिंग गाइड
नीचे दिया गया मैट्रिक्स Android WebViews में कस्टम स्कीम को हैंडल करते समय सामने आने वाले सामान्य त्रुटि हस्ताक्षरों का विवरण देता है, साथ ही प्राथमिक मूल कारणों और इंजीनियरिंग सुधारों के साथ:
| त्रुटि हस्ताक्षर / लक्षण | प्राथमिक मूल कारण | प्रभावित API स्तर | नैदानिक चेकपॉइंट | अनुशंसित समाधान |
|---|---|---|---|---|
net::ERR_UNKNOWN_URL_SCHEME |
वेबव्यू लोडर में गैर-वेब स्कीम अनहैंडल्ड है | सभी API स्तर | shouldOverrideUrlLoading गायब है या false लौटाता है |
डेलिगेट को ओवरराइड करें, स्कीम को इंटरसेप्ट करें, true लौटाएं |
ActivityNotFoundException |
डिवाइस पर टारगेट ऐप अनुपस्थित है | सभी API स्तर | अनहैंडल्ड context.startActivity() |
अपवाद को पकड़ें और S.browser_fallback_url या प्ले स्टोर रूट निष्पादित करें |
| Iframe इंटेंट हाइजैकिंग | सबफ्रेम बाहरी इंटेंट को ट्रिगर कर रहा है | API 24+ | request.isForMainFrame अनियंत्रित है |
if (!request.isForMainFrame) के साथ सुरक्षित करें और गैर-वेब स्कीम को दबाएं |
| प्रीफाइट क्वेरी Null लौटाती है | Android 11+ पैकेज दृश्यता फ़िल्टर | API 30+ (Android 11+) | मैनिफेस्ट घोषणा के बिना resolveActivity को कॉल करना |
मैनिफेस्ट में <queries> घोषित करें या सीधे startActivity try-catch का उपयोग करें |
| आंतरिक ऐप लिंक रीलोड लूप | होस्ट ऐप लिंक WebView पर रीडायरेक्ट हो गया | सभी API स्तर | डेलिगेट में होस्ट डोमेन अनहैंडल्ड है | स्वयं के डोमेन को इंटरसेप्ट करें, रूट सत्यापित करें, नेटिव राउटर पर भेजें |
अक्सर पूछे जाने वाले प्रश्न (FAQ)
कस्टम URL स्कीम खोलते समय मेरा Android WebView क्रैश क्यों हो जाता है?
मैं बिना सुरक्षा कमजोरियों के WebView में intent:// URL को सुरक्षित रूप से कैसे हैंडल करूं?
Android 11 पैकेज दृश्यता WebViews में डीप लिंक इंटरसेप्शन को कैसे प्रभावित करती है?
सारांश और निर्णय ढांचा
Android WebViews के भीतर डीप लिंकिंग और कस्टम स्कीम को हैंडल करने के लिए वेब रेंडरिंग सैंडबॉक्स और नेटिव ऑपरेटिंग सिस्टम इंटेंट राउटिंग के बीच की खाई को पाटने की आवश्यकता होती है। डिफ़ॉल्ट WebView व्यवहार पर निर्भर रहने से अनहैंडल्ड प्रोटोकॉल त्रुटियां, खराब उपयोगकर्ता अनुभव, और संभावित सुरक्षा कमजोरियां पैदा होती हैं।
एक मजबूत WebViewClient को लागू करके जो फ्रेम बाउंड्री को सत्यापित करता है, स्पष्ट अनुमति-सूचियों के विरुद्ध कस्टम स्कीम को सत्यापित करता है, सुरक्षित ACTION_VIEW इंटेंट को पुनर्निर्मित करता है, और ग्रेसफुल स्टोर फॉलबैक को हैंडल करता है, इंजीनियरिंग टीमें WebView स्कीम-हैंडलिंग विफलताओं को कम करती हैं और अधिक लचीली नेविगेशन का समर्थन करती हैं। विश्वसनीय क्लाइंट-साइड राउटिंग को व्यापक मोबाइल एट्रिब्यूशन फ्रेमवर्क के साथ एकीकृत करने से एट्रिब्यूशन फ्लो के दौरान राउटिंग घर्षण कम होता है और अधिक सुसंगत उपयोगकर्ता यात्राओं का समर्थन मिलता है।
नेटिव Android डीप लिंकिंग और पैरामीटर राउटिंग आर्किटेक्चर का पता लगाने के लिए, SDK एकीकरण दस्तावेज़ीकरण देखें, OpoInstall SDK डाउनलोड सेंटर से क्लाइंट लाइब्रेरी डाउनलोड करें, मोबाइल एट्रिब्यूशन कार्यान्वयन संदर्भ देखें, या OpoInstall डेवलपर कंसोल पर अपना एप्लिकेशन पंजीकृत करें।
संबंधित सामग्रियां
- अवधारणाएं: Android WebView नेविगेशन, कस्टम URL स्कीम इंटरसेप्शन, इंटेंट URI पुनर्निर्माण, पैकेज दृश्यता
- तकनीकें: Android WebViewClient, क्रोमियम वेबइंजन, Android डीबग ब्रिज, OpoInstall Android SDK
- मानक: IETF RFC 3986 यूनिफ़ॉर्म रिसोर्स आइडेंटिफ़ायर, Android इंटेंट विनिर्देश, OWASP मोबाइल एप्लिकेशन सुरक्षा परीक्षण गाइड (MASTG)
- APIs: Android
shouldOverrideUrlLoading,WebResourceRequest.isForMainFrame,Intent.parseUri,PackageManager.queryIntentActivities - आधिकारिक दस्तावेज़ीकरण और संदर्भ:
Share this article



