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

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

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

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

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

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

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

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

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

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

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

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

मुख्य सुविधाएं:

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

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

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

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

    • WebView, स्कीम (एचटीटीपी/एचटीटीपीएस), होस्ट, और पोर्ट के हिसाब से नियमों का पालन करता है.
    • WebView, पाथ को अनदेखा करता है. उदाहरण के लिए, https://example.com में https://example.com/login और https://example.com/home की अनुमति है.
    • वेबव्यू, सबडोमेन के लिए होस्ट की शुरुआत में वाइल्डकार्ड को सीमित करता है. उदाहरण के लिए, https://*.example.com, https://foo.example.com से मेल खाता है, लेकिन https://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 के साथ रजिस्टर करता है और 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 से एनोटेट करें. इसके बाद, addJavascriptInterface(Object, String) का इस्तेमाल करके, क्लास का इंस्टेंस WebView में जोड़ें.

खास बातें:

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

मैकेनिज़्म की खास जानकारी

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

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

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

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

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

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

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

यहां दिए गए कोड के उदाहरणों में, नेटिव ऐप्लिकेशन पर addWebMessageListener को सेट अप करने का तरीका बताया गया है. इससे WebMessageCompat.TYPE_ARRAY_BUFFER के तौर पर मार्क किए गए मैसेज मिल सकते हैं. साथ ही, 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 को क्लाइंट-साइड पर लागू करने का तरीका दिखाया गया है. इससे वेब कॉन्टेंट, window.myBridge प्रॉक्सी का इस्तेमाल करके, नेटिव ऐप्लिकेशन को बाइनरी डेटा (ArrayBuffer) भेज और उससे बाइनरी डेटा पा सकता है. यह प्रॉक्सी, पिछले उदाहरण में इंजेक्ट की गई थी.

// 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 से सुरक्षा मिलती है. हालांकि, इनसे आपके भरोसेमंद डोमेन में मौजूद क्रॉस-साइट स्क्रिप्टिंग (एक्सएसएस) की कमियों से सुरक्षा नहीं मिलती. उदाहरण के लिए, अगर आपके वेब पेज पर यूज़र जनरेटेड कॉन्टेंट दिखता है और वह सेव किए गए XSS के लिए असुरक्षित है, तो हमलावर एक ऐसी स्क्रिप्ट को एक्ज़ीक्यूट कर सकता है जो आपके भरोसेमंद ऑरिजिन के तौर पर काम करती है. संवेदनशील नेटिव प्लैटफ़ॉर्म ऑपरेशन करने से पहले, मैसेज पेलोड की पुष्टि करने की सुविधा का इस्तेमाल करें.

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

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