JavaScript ब्रिज की मदद से नेटिव एपीआई ऐक्सेस करना

इस पेज पर, नेटिव ब्रिज (इसे JavaScript ब्रिज भी कहा जाता है) बनाने के अलग-अलग तरीकों और सबसे सही तरीकों के बारे में बताया गया है. इससे WebView में मौजूद वेब कॉन्टेंट और होस्ट करने वाले Android ऐप्लिकेशन के बीच कम्यूनिकेशन को आसान बनाया जा सकता है.

इससे वेब डेवलपर, JavaScript का इस्तेमाल करके, नेटिव प्लैटफ़ॉर्म की सुविधाओं को ऐक्सेस कर पाते हैं. जैसे, कैमरा, फ़ाइल सिस्टम या बेहतर हार्डवेयर सेंसर. आम तौर पर, स्टैंडर्ड वेब एपीआई ये सुविधाएं नहीं देते.

इस्तेमाल के उदाहरण

JavaScript ब्रिज लागू करने से, इंटिग्रेशन के अलग-अलग ऐसे परिदृश्य तैयार किए जा सकते हैं जिनमें वेब कॉन्टेंट को Android ऑपरेटिंग सिस्टम का ज़्यादा ऐक्सेस चाहिए. यहां कुछ उदाहरण दिए गए हैं:

  • प्लैटफ़ॉर्म इंटिग्रेशन: वेब पेज से, Android के नेटिव यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को ट्रिगर करना. जैसे, बायोमेट्रिक प्रॉम्प्ट, BottomSheetDialog.
  • परफ़ॉर्मेंस: ज़्यादा कंप्यूटेशनल टास्क को नेटिव Java या Kotlin कोड पर ऑफ़लोड करना.
  • डेटा परसिस्टेंस: स्थानीय तौर पर एन्क्रिप्ट (सुरक्षित) किए गए डेटाबेस या शेयर की गई सेटिंग को ऐक्सेस करना.
  • बड़े पैमाने पर डेटा ट्रांसफ़र करना: मीडिया फ़ाइलें या जटिल डेटा स्ट्रक्चर पास करना ऐप्लिकेशन और वेब रेंडरर के बीच.

कम्यूनिकेशन के तरीके

Android, नेटिव ब्रिज बनाने के लिए, एपीआई की तीन मुख्य जनरेशन उपलब्ध कराता है. ये सभी अब भी उपलब्ध हैं, लेकिन सुरक्षा, इस्तेमाल में आसानी, और परफ़ॉर्मेंस के मामले में इनमें काफ़ी अंतर है.

addWebMessageListener का इस्तेमाल करना (सुझाया गया)

addWebMessageListener , वेब कॉन्टेंट और नेटिव ऐप्लिकेशन कोड के बीच कम्यूनिकेशन के लिए, सबसे नया और सुझाया गया तरीका है. इसमें, मैसेजिंग सिस्टम की सुरक्षा के साथ-साथ JavaScript इंटरफ़ेस के इस्तेमाल में आसानी भी मिलती है.

यह कैसे काम करता है: ऐप्लिकेशन, खास नाम और अनुमति वाले ऑरिजिन के नियमों के सेट के साथ एक लिसनर जोड़ता है. इसके बाद, WebView यह पक्का करता है कि पेज लोड होना शुरू होने के बाद से, JavaScript ऑब्जेक्ट ग्लोबल स्कोप (window.objectName) में मौजूद हो.

शुरुआत: यह पक्का करने के लिए कि WebView, किसी भी स्क्रिप्ट के चलने से पहले JavaScript ऑब्जेक्ट को इंजेक्ट करे, आपको पेज पर नेविगेट करने से पहले addWebMessageListener को कॉल करना होगा. जैसे, WebViewCompat.navigate या loadUrl को कॉल करना.

खास बातें:

  • सुरक्षा और भरोसा: पुराने एपीआई के उलट, इस तरीके के लिए शुरुआत के दौरान, Set<String> का allowedOriginRules ज़रूरी होता है. यह भरोसेमंद कनेक्शन बनाने का मुख्य तरीका है.

    जब कोई भरोसेमंद ऑरिजिन तय किया जाता है, जैसे कि https://example.com, तो WebView इस बात की गारंटी देता है कि वह इंजेक्ट किए गए JavaScript ऑब्जेक्ट को सिर्फ़ उसी ऑरिजिन से लोड किए गए वेब पेजों पर दिखाएगा.

    नेटिव लिसनर कॉलबैक को हर मैसेज के साथ sourceOrigin पैरामीटर मिलता है. अगर आपका ब्रिज, अनुमति वाले एक से ज़्यादा ऑरिजिन के साथ काम करता है, तो इसका इस्तेमाल करके, भेजने वाले के ऑरिजिन की पुष्टि की जा सकती है.

    WebView, प्लैटफ़ॉर्म लेवल पर ऑरिजिन की जांच को सख्ती से लागू करता है. इसलिए, आम तौर पर आपका ऐप्लिकेशन, भरोसेमंद sourceOrigin से मिले मैसेज पर भरोसा कर सकता है. इससे ज़्यादातर स्टैंडर्ड लागू करने के तरीकों में, पेलोड की पुष्टि करने की ज़रूरत नहीं होती.

    • WebView, स्कीम (एचटीटीपी/एचटीटीपीएस), होस्ट, और पोर्ट के हिसाब से नियमों को मैच करता है.
    • WebView, पाथ को अनदेखा करता है. उदाहरण के लिए, https://example.com से https://example.com/login और https://example.com/home को अनुमति मिलती है.
    • WebView, सबडोमेन के लिए वाइल्डकार्ड को होस्ट की शुरुआत तक सीमित रखता है. उदाहरण के लिए, https://*.example.com, https://foo.example.com से मैच करता है, लेकिन https://example.com से नहीं. अगर आपको https://example.com और उसके सबडोमेन, दोनों को मैच करना है, तो आपको अनुमति वाली सूची में हर ऑरिजिन के नियम को अलग से जोड़ना होगा. जैसे, "https://example.com", "https://*.example.com". स्कीम के लिए या डोमेन के बीच में वाइल्डकार्ड का इस्तेमाल नहीं किया जा सकता.

    इससे ब्रिज को पुष्टि किए गए डोमेन तक सीमित रखा जाता है. साथ ही, तीसरे पक्ष के ऐसे कॉन्टेंट या इंजेक्ट किए गए iframe को नेटिव कोड लागू करने से रोका जाता है जिनके पास अनुमति नहीं है.

  • मल्टी-फ़्रेम के लिए सहायता: यह उन सभी फ़्रेम पर काम करता है जो ऑरिजिन के नियमों से मैच करते हैं.

  • थ्रेडिंग: लिसनर कॉलबैक, ऐप्लिकेशन के मुख्य (यूआई) थ्रेड पर चलता है. अगर आपके ब्रिज को जटिल डेटा प्रोसेसिंग, JSON पार्सिंग या डेटाबेस लुकअप को हैंडल करना है, तो आपको उस काम को बैकग्राउंड थ्रेड पर ऑफ़लोड करना होगा. ऐसा करने से, ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) "ऐप्लिकेशन काम नहीं कर रहा है" (एएनआर) वाली गड़बड़ी के साथ फ़्रीज़ नहीं होगा.

  • दोतरफ़ा: जब वेब पेज कोई मैसेज भेजता है, तो ऐप्लिकेशन को JavaScriptReplyProxy मिलता है. इसका इस्तेमाल करके, उस खास फ़्रेम को वापस मैसेज भेजे जा सकते हैं. replyProxy ऑब्जेक्ट को बनाए रखा जा सकता है और इसका इस्तेमाल, पेज को किसी भी समय मैसेज भेजने के लिए किया जा सकता है. ऐसा ज़रूरी नहीं है कि पेज से मिले हर मैसेज का जवाब देने के लिए ही इसका इस्तेमाल किया जाए. अगर ऑरिजिनल फ़्रेम, किसी दूसरे पेज पर नेविगेट करता है या उसे मिटा दिया जाता है, तो प्रॉक्सी पर postMessage() का इस्तेमाल करके भेजे गए मैसेज को अनदेखा कर दिया जाता है.

  • ऐप्लिकेशन-साइड से शुरुआत: हालांकि, वेब पेज को हमेशा ऐप्लिकेशन के साथ कम्यूनिकेशन चैनल शुरू करना चाहिए, लेकिन खास ऐप्लिकेशन, वेब पेज को इस प्रोसेस को शुरू करने के लिए एकतरफ़ा तरीके से प्रॉम्प्ट कर सकता है. खास ऐप्लिकेशन, वेब पेज से addDocumentStartJavaScript() (पेज लोड होने से पहले JavaScript का आकलन करने के लिए) या evaluateJavaScript() (पेज लोड होने के बाद JavaScript का आकलन करने के लिए) का इस्तेमाल करके कम्यूनिकेट कर सकता है.

सीमा: यह एपीआई, डेटा को स्ट्रिंग या byte[] कलेक्शन के तौर पर भेजता है. JSON ऑब्जेक्ट जैसे ज़्यादा जटिल डेटा स्ट्रक्चर के लिए, आपको इसे इनमें से किसी एक फ़ॉर्मैट में सीरियल करना होगा. इसके बाद, डेटा स्ट्रक्चर को फिर से बनाने के लिए, दूसरी तरफ़ डीसीरियल करना होगा.

इस्तेमाल का उदाहरण:

दोतरफ़ा मैसेज एक्सचेंज की पूरी प्रोसेस को समझने के लिए, इवेंट इस क्रम में होते हैं:

  1. शुरुआत (ऐप्लिकेशन): खास ऐप्लिकेशन, लिसनर को addWebMessageListener के साथ रजिस्टर करता है और पेज नेविगेशन शुरू करता है. जैसे, WebViewCompat.navigate या loadUrl का इस्तेमाल करके.
  2. मैसेज भेजना (वेब): कम्यूनिकेशन शुरू करने के लिए, वेब पेज का JavaScript, myObject.postMessage(message) को कॉल करता है.
  3. मैसेज पाना और जवाब देना (ऐप्लिकेशन): ऐप्लिकेशन को लिसनर कॉलबैक में मैसेज मिलता है और वह दिए गए replyProxy.postMessage() का इस्तेमाल करके जवाब देता है.
  4. जवाब पाना (वेब): वेब पेज को एसिंक्रोनस जवाब myObject.onmessage() कॉलबैक फ़ंक्शन में मिलता है.

Kotlin

val myListener = WebViewCompat.WebMessageListener { _, _, _, _, replyProxy ->
    // Handle the message from JS
    replyProxy.postMessage("Acknowledged!")
}

// Check whether the WebView version supports the feature.
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
    val allowedOrigins = setOf("https://www.example.com")
    WebViewCompat.addWebMessageListener(webView, "myObject", allowedOrigins, myListener)
}

Java

WebMessageListener myListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
    // Handle the message from JS
    replyProxy.postMessage("Acknowledged!");
};

// Check whether the WebView version supports the feature.
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
    Set<String> allowedOrigins = Set.of("https://www.example.com");
    WebViewCompat.addWebMessageListener(webView, "myObject", allowedOrigins, myListener);
}

यहां दिए गए JavaScript में, addWebMessageListener को क्लाइंट-साइड पर लागू करने का तरीका दिखाया गया है. इससे वेब कॉन्टेंट, नेटिव ऐप्लिकेशन से मैसेज पा सकता है और myObject प्रॉक्सी के ज़रिए अपने मैसेज भेज सकता है.

myObject.onmessage = function(event) {
    console.log("App says: " + event.data);
};
myObject.postMessage("Hello world!");

postWebMessage का इस्तेमाल करना (वैकल्पिक)

Android ने इसे, वेब के window.postMessage की तरह, एसिंक्रोनस और मैसेजिंग पर आधारित विकल्प के तौर पर पेश किया है.

यह कैसे काम करता है: ऐप्लिकेशन, वेब पेज के मुख्य फ़्रेम को पेलोड भेजने के लिए, WebViewCompat.postWebMessage का इस्तेमाल करता है. दोतरफ़ा कम्यूनिकेशन चैनल बनाने के लिए, WebMessageChannel बनाया जा सकता है और इसके एक पोर्ट को वेब कॉन्टेंट को मैसेज के साथ पास किया जा सकता है.

खास बातें:

  • एसिंक्रोनस: addWebMessageListener की तरह, यह तरीका एसिंक्रोनस मैसेजिंग का इस्तेमाल करता है. इससे यह पक्का होता है कि ऐप्लिकेशन बैकग्राउंड में डेटा प्रोसेस करते समय, वेब पेज उपयोगकर्ता के इंटरैक्शन के लिए रिस्पॉन्सिव बना रहे.
  • ऑरिजिन के बारे में जानकारी: targetOrigin तय करके, यह पक्का किया जा सकता है कि WebView डेटा को सिर्फ़ भरोसेमंद वेबसाइट पर डिलीवर करे.

सीमाएं:

  • स्कोप: यह एपीआई, कम्यूनिकेशन को मुख्य फ़्रेम तक सीमित रखता है. यह iframe को सीधे तौर पर संबोधित करने या मैसेज भेजने की सुविधा नहीं देता.
  • यूआरआई से जुड़ी पाबंदियां: इस तरीके का इस्तेमाल, data: यूआरआई, file: यूआरआई या loadData() का इस्तेमाल करके लोड किए गए कॉन्टेंट के लिए नहीं किया जा सकता. हालांकि, अगर टारगेट ऑरिजिन के तौर पर "*" तय किया जाता है, तो इसका इस्तेमाल किया जा सकता है. ऐसा करने से, कोई भी पेज मैसेज पा सकता है.
  • पहचान से जुड़ा जोखिम: वेब कॉन्टेंट के पास, भेजने वाले की पहचान की पुष्टि करने का कोई साफ़ तरीका नहीं है. वेब पेज को मिलने वाला मैसेज, आपके नेटिव ऐप्लिकेशन या किसी दूसरे iframe से आ सकता है.

इस तरीके का इस्तेमाल तब करें, जब आपको Android के पुराने वर्शन में स्ट्रिंग-आधारित डेटा के लिए, आसान और एसिंक्रोनस चैनल की ज़रूरत हो. इन वर्शन में addWebMessageListener की सुविधा नहीं होती.

addJavascriptInterface का इस्तेमाल करना (पुराना तरीका)

सबसे पुराने तरीके में, नेटिव ऑब्जेक्ट इंस्टेंस को सीधे WebView में इंजेक्ट किया जाता है.

यह कैसे काम करता है: Kotlin या Java क्लास तय करें, अनुमति वाले तरीकों को @JavascriptInterface से एनोटेट करें, और क्लास का एक इंस्टेंस WebView में addJavascriptInterface(Object, String) का इस्तेमाल करके जोड़ें.

खास बातें:

  • सिंक्रोनस: JavaScript के एक्ज़ीक्यूशन एनवायरमेंट तब तक ब्लॉक रहते हैं, जब तक आपके Android कोड में मौजूद तरीका कोई वैल्यू नहीं दिखाता.
  • थ्रेड सुरक्षा: सिस्टम, बैकग्राउंड थ्रेड पर तरीकों को कॉल करता है, इसके लिए, Kotlin या Java साइड पर सावधानी से सिंक्रनाइज़ेशन करना ज़रूरी है.
  • सुरक्षा से जुड़ा जोखिम: डिफ़ॉल्ट रूप से, addJavascriptInterface WebView में मौजूद हर फ़्रेम के लिए उपलब्ध होता है. इसमें iframe भी शामिल हैं. इसमें ऑरिजिन के आधार पर ऐक्सेस कंट्रोल की सुविधा नहीं होती. WebView के एसिंक्रोनस व्यवहार की वजह से, आपके इंटरफ़ेस को कॉल करने वाले फ़्रेम के यूआरएल का सुरक्षित तरीके से पता लगाना मुमकिन नहीं है. सुरक्षा की पुष्टि करने के लिए, WebView.getUrl() जैसे तरीकों पर भरोसा न करें. इनकी सटीक जानकारी की कोई गारंटी नहीं होती. साथ ही, इनसे यह भी पता नहीं चलता कि अनुरोध किस खास फ़्रेम ने किया है.

तरीकों की खास जानकारी

यहां दी गई टेबल में, नेटिव ब्रिज लागू करने के तीन मुख्य तरीकों की तुलना की गई है:

तरीका addWebMessageListener postWebMessage addJavascriptInterface
लागू करना एसिंक्रोनस (मुख्य थ्रेड पर लिसनर) एसिंक्रोनस सिंक्रोनस
सुरक्षा सबसे ज़्यादा (अनुमति वाली सूची पर आधारित) ज़्यादा (ऑरिजिन के बारे में जानकारी) कम (ऑरिजिन की जांच नहीं की जाती)
जटिलता सामान्य सामान्य आसान सुविधा
दिशा दोतरफ़ा दोतरफ़ा वेब से ऐप्लिकेशन
WebView का कम से कम वर्शन वर्शन 82 (और Jetpack Webkit 1.3.0) वर्शन 45 (और Jetpack Webkit 1.1.0) सभी वर्शन
सुझाए गए हां नहीं नहीं

बड़े पैमाने पर डेटा ट्रांसफ़र करना

मल्टी-मेगाबाइट स्ट्रिंग या बाइनरी फ़ाइलों जैसे बड़े पेलोड को ट्रांसफ़र करते समय, मेमोरी को सावधानी से मैनेज करना ज़रूरी है. ऐसा न करने पर, 32-बिट डिवाइसों पर "ऐप्लिकेशन काम नहीं कर रहा है" (एएनआर) वाली गड़बड़ियां आ सकती हैं या ऐप्लिकेशन क्रैश हो सकते हैं. इस सेक्शन में, होस्ट करने वाले ऐप्लिकेशन और वेब कॉन्टेंट के बीच बड़े पैमाने पर डेटा ट्रांसफ़र करने से जुड़ी अलग-अलग तकनीकों और सीमाओं के बारे में बताया गया है.

बाइट कलेक्शन की मदद से बाइनरी डेटा ट्रांसफ़र करना

WebMessageCompat क्लास की मदद से, बाइनरी डेटा को Base64 स्ट्रिंग में सीरियल करने के बजाय, सीधे byte[] कलेक्शन भेजे जा सकते हैं. Base64, डेटा के साइज़ में करीब 33% ओवरहेड जोड़ता है. इसलिए, यह तरीका ज़्यादा मेमोरी-एफ़िशिएंट और तेज़ है.

  • बाइनरी का फ़ायदा: अपने नेटिव ऐप्लिकेशन और वेब कॉन्टेंट के बीच, इमेज फ़ाइलों या ऑडियो जैसे बाइनरी डेटा को ट्रांसफ़र करें.
  • सीमा: बाइट कलेक्शन के साथ भी, सिस्टम, ऐप्लिकेशन और आइसोलेटेड प्रोसेस के बीच इंटर-प्रोसेस कम्यूनिकेशन (आईपीसी) बाउंड्री पर डेटा कॉपी करता है. WebView, वेब कॉन्टेंट को रेंडर करने के लिए इस प्रोसेस का इस्तेमाल करता है. बहुत बड़ी फ़ाइलों के लिए, इसमें अब भी काफ़ी मेमोरी खर्च होती है.

यहां दिए गए कोड के उदाहरणों में, WebMessageCompat.TYPE_ARRAY_BUFFER के साथ मार्क किए गए मैसेज पाने और ज़रूरत पड़ने पर बाइनरी डेटा के साथ जवाब देने के लिए, खास ऐप्लिकेशन साइड पर addWebMessageListener को सेट अप करने का तरीका बताया गया है. इसके लिए, WebViewFeature.MESSAGE_ARRAY_BUFFER की जांच की जाती है.

Kotlin

fun setupWebView(webView: WebView) {
  if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
      val listener = WebViewCompat.WebMessageListener { view, message, sourceOrigin, isMainFrame, replyProxy ->

          // Check if the received message is an ArrayBuffer
          if (message.type == WebMessageCompat.TYPE_ARRAY_BUFFER) {
              val binaryData: ByteArray = message.arrayBuffer
              // Process your binary data (image, audio, etc.)
              println("Received bytes: ${binaryData.size}")

              // Optional: Send a binary reply back to JavaScript.
              // This example sends a 3-byte array for simplicity.
              if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER)) {
                  val replyBytes = byteArrayOf(0x01, 0x02, 0x03)
                  replyProxy.postMessage(replyBytes)
              }
          }
      }

      // "myBridge" matches the window.myBridge in JavaScript
      WebViewCompat.addWebMessageListener(
          webView,
          "myBridge",
          setOf("https://example.com"), // Security: restrict origins
          listener
      )
  }
}

Java

public void setupWebView(WebView webView) {
  if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
      WebViewCompat.WebMessageListener listener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {

          // Check if the received message is an ArrayBuffer
          if (message.getType() == WebMessageCompat.TYPE_ARRAY_BUFFER) {
              byte[] binaryData = message.getArrayBuffer();
              // Process your binary data (image, audio, etc.)
              System.out.println("Received bytes: " + binaryData.length);

              // Optional: Send a binary reply back to JavaScript.
              // This example sends a 3-byte array for simplicity.
              if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_ARRAY_BUFFER)) {
                  byte[] replyBytes = new byte[]{0x01, 0x02, 0x03};
                  replyProxy.postMessage(replyBytes);
              }
          }
      };

      // "myBridge" matches the window.myBridge in JavaScript
      WebViewCompat.addWebMessageListener(
          webView,
          "myBridge",
          Set.of("https://example.com"), // Security: restrict origins
          listener
      );
  }
}

यहां दिए गए JavaScript कोड में, addWebMessageListener को क्लाइंट-साइड पर लागू करने का तरीका दिखाया गया है. इससे वेब कॉन्टेंट, नेटिव ऐप्लिकेशन से बाइनरी डेटा (ArrayBuffer) भेज और पा सकता है. इसके लिए, पिछले उदाहरण में इंजेक्ट की गई window.myBridge प्रॉक्सी का इस्तेमाल किया जाता है.

// Function to send an image or binary buffer to the app
async function sendBinaryToApp() {
    const response = await fetch('image.jpg');
    const buffer = await response.arrayBuffer();

    // Check if the injected bridge object exists
    if (window.myBridge) {
        // You can send the ArrayBuffer directly
        window.myBridge.postMessage(buffer);
    }
}

// Receiving binary data from the app
if (window.myBridge) {
    window.myBridge.onmessage = function(event) {
        if (event.data instanceof ArrayBuffer) {
            console.log('Received binary data from App, length:', event.data.byteLength);
            // Process the binary data (for example, as a Uint8Array)
            const bytes = new Uint8Array(event.data);
            console.log('First byte:', bytes[0]);
        }
    };
}

बड़े पैमाने पर डेटा लोड करने का बेहतर तरीका

बहुत बड़ी फ़ाइलों (>10 एमबी) के लिए, डेटा स्ट्रीम करने के लिए shouldInterceptRequest तरीके का इस्तेमाल करें:

  1. वेब पेज, कस्टम प्लेसहोल्डर यूआरएल के लिए fetch() कॉल शुरू करता है. उदाहरण के लिए, https://app.local/large-file.
  2. Android ऐप्लिकेशन, WebViewClient.shouldInterceptRequest में इस अनुरोध को इंटरसेप्ट करता है.
  3. ऐप्लिकेशन, डेटा को InputStream के तौर पर दिखाता है.

इससे, पूरे पेलोड को एक साथ मेमोरी में लोड करने के बजाय, डेटा को हिस्सों में स्ट्रीम किया जा सकता है.

यहां दिए गए JavaScript फ़ंक्शन में, कस्टम प्लेसहोल्डर यूआरएल के लिए स्टैंडर्ड fetch() कॉल का इस्तेमाल करके, नेटिव ऐप्लिकेशन से बड़े बाइनरी फ़ाइल को एफ़िशिएंट तरीके से लोड करने के लिए, क्लाइंट-साइड कोड दिखाया गया है.

async function fetchBinaryFromApp() {
    try {
        // This URL doesn't need to exist on the internet
        const response = await fetch('https://app.local/data/large-file.bin');

        if (!response.ok) throw new Error('Network response was not okay');

        // For raw binary data:
        const arrayBuffer = await response.arrayBuffer();
        console.log('Received binary data, size:', arrayBuffer.byteLength);
        // Process buffer (for example, new Uint8Array(arrayBuffer))

        /*
        // OR for an image:
        const blob = await response.blob();
        const imageUrl = URL.createObjectURL(blob);
        document.getElementById('myImage').src = imageUrl;
        */

    } catch (error) {
        console.error('Fetch error:', error);
    }
}

यहां दिए गए कोड के उदाहरणों में, खास ऐप्लिकेशन साइड दिखाई गई है. इसमें, वेब कॉन्टेंट के अनुरोध किए गए कस्टम प्लेसहोल्डर यूआरएल को इंटरसेप्ट करके, बड़े बाइनरी फ़ाइल को स्ट्रीम करने के लिए, Kotlin और Java, दोनों में WebViewClient.shouldInterceptRequest तरीके का इस्तेमाल किया गया है.

Kotlin

webView.webViewClient = object : WebViewClient() {
  override fun shouldInterceptRequest(
      view: WebView?,
      request: WebResourceRequest?
  ): WebResourceResponse? {
      val url = request?.url ?: return null

      // Check if this is our custom placeholder URL
      if (url.host == "app.local" && url.path == "/data/large-file.bin") {
          try {
              // 1. Get your data as an InputStream
              // (from Assets, Files, or a generated byte stream)
              val inputStream: InputStream = context.assets.open("my_data.pb")

              // 2. Define Response Headers (Crucial for CORS/Fetch)
              val headers = mutableMapOf<String, String>()
              headers["Access-Control-Allow-Origin"] = "*" // Allow fetch from any origin

              // 3. Return the response
              return WebResourceResponse(
                  "application/octet-stream", // MIME type (for example, image/jpeg)
                  "UTF-8",                   // Encoding
                  200,                       // Status Code
                  "OK",                      // Reason Phrase
                  headers,                   // Custom Headers
                  inputStream                // The actual data stream
              )
          } catch (e: Exception) {
              // Handle exception
          }
      }
      return super.shouldInterceptRequest(view, request)
  }
}

Java

webView.setWebViewClient(new WebViewClient() {
  @Override
  public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
      String urlPath = request.getUrl().getPath();
      String host = request.getUrl().getHost();

      // Check if this is our custom placeholder URL
      if ("app.local".equals(host) && "/data/large-file.bin".equals(urlPath)) {
          try {
              // 1. Get your data as an InputStream
              // (from Assets, Files, or a generated byte stream)
              InputStream inputStream = getContext().getAssets().open("my_data.pb");

              // 2. Define Response Headers (Crucial for CORS/Fetch)
              Map<String, String> headers = new HashMap<>();
              headers.put("Access-Control-Allow-Origin", "*"); // Allow fetch from any origin

              // 3. Return the response
              return new WebResourceResponse(
                  "application/octet-stream", // MIME type (for example, image/jpeg)
                  "UTF-8",                   // Encoding
                  200,                       // Status Code
                  "OK",                      // Reason Phrase
                  headers,                   // Custom Headers
                  inputStream                // The actual data stream
              );
          } catch (Exception e) {
              // Handle exception
          }
      }
      return super.shouldInterceptRequest(view, request);
  }
});

सुरक्षा से जुड़े सुझावों का पालन करना

अपने ऐप्लिकेशन और उपयोगकर्ता के डेटा को सुरक्षित रखने के लिए, ब्रिज लागू करते समय इन दिशा-निर्देशों का पालन करें:

  • एचटीटीपीएस लागू करना: यह पक्का करने के लिए कि तीसरे पक्ष का नुकसान पहुंचाने वाला कॉन्टेंट, आपके ऐप्लिकेशन के नेटिव लॉजिक को लागू न कर पाए, सिर्फ़ सुरक्षित ऑरिजिन के साथ कम्यूनिकेशन की अनुमति दें.

  • ऑरिजिन के नियमों पर भरोसा करना: भरोसेमंद कनेक्शन बनाने का सबसे अच्छा तरीका है कि को सख्ती से तय किया जाए और मैसेज कॉलबैक में दिए गए allowedOriginRules और sourceOrigin की जांच की जाए. सिर्फ़ ऑरिजिन के नियम के तौर पर, पूरे वाइल्डकार्ड (*) का इस्तेमाल करने से बचें. इससे सभी ऑरिजिन मैच हो जाते हैं. हालांकि, अगर ऐसा करना ज़रूरी हो, तो इसका इस्तेमाल किया जा सकता है. सबडोमेन के लिए वाइल्डकार्ड (उदाहरण के लिए, *.example.com) का इस्तेमाल करना मान्य और सुरक्षित है. इससे कई सबडोमेन (उदाहरण के लिए, foo.example.com, bar.example.com) मैच किए जा सकते हैं.

    ध्यान दें: ऑरिजिन के नियम, तीसरे पक्ष की नुकसान पहुंचाने वाली वेबसाइटों और छिपे हुए iframe से सुरक्षा देते हैं. हालांकि, ये आपके भरोसेमंद डोमेन में मौजूद क्रॉस-साइट स्क्रिप्टिंग (एक्सएसएस) की कमज़ोरियों से सुरक्षा नहीं दे सकते. उदाहरण के लिए, अगर आपका वेब पेज, उपयोगकर्ता जनरेट किया गया कॉन्टेंट दिखाता है और इसमें सेव किए गए एक्सएसएस की कमज़ोरी है, तो हमलावर, आपके भरोसेमंद ऑरिजिन के तौर पर काम करने वाली स्क्रिप्ट को लागू कर सकता है. नेटिव प्लैटफ़ॉर्म पर संवेदनशील कार्रवाइयां करने से पहले, मैसेज पेलोड पर पुष्टि लागू करने पर विचार करें.

  • सरफ़ेस एरिया को कम करना: सिर्फ़ उन खास तरीकों या डेटा को दिखाएं जिनकी वेब पेज को ज़रूरत है.

  • रनटाइम पर सुविधाओं की जांच करना: ब्रिज के हाल ही के एपीआई, जिनमें addWebMessageListener भी शामिल है, Jetpack Webkit लाइब्रेरी का हिस्सा हैं. इसलिए, इन्हें कॉल करने से पहले, हमेशा इनकी उपलब्धता की जांच करेंWebViewFeature.isFeatureSupported().