WebView की स्थिति को बेहतर तरीके से मैनेज करना

Android ऐप्लिकेशन के लाइफ़साइकल को मैनेज करते समय, बैकग्राउंड में मौजूद संसाधनों को वापस पाने के दौरान, उपयोगकर्ता की स्थिति को बनाए रखना, उपयोगकर्ता को बेहतर अनुभव देने के लिए ज़रूरी है. वेब वर्कफ़्लो को शामिल करने वाले ऐप्लिकेशन के लिए, WebView.saveState(Bundle) की मदद से, WebView के नेविगेशन इतिहास और स्थिति को Bundle में क्रम से सेव किया जा सकता है. इसके बाद, इस डेटा को WebView.restoreState(Bundle) का इस्तेमाल करके वापस लाया जा सकता है.

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

लेन-देन की 1 एमबी की सीमा और स्थिति मिटाना

Android, savedInstanceState में सेव किए जा सकने वाले डेटा के कुल साइज़ पर 1 एमबी की सीमा लागू करता है. यह 1 एमबी का बजट, ऐप्लिकेशन की पूरी प्रोसेस के लिए शेयर किया जाता है. अगर किसी ऐप्लिकेशन में WebView के कई इंस्टेंस शामिल हैं, तो उनके नेविगेशन की स्थिति और इतिहास को इस शेयर किए गए बजट में सेव किया जाना चाहिए. इस सीमा से ज़्यादा डेटा सेव करने पर, TransactionTooLargeException गड़बड़ी होती है. इससे ऐप्लिकेशन क्रैश हो जाता है.

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

  • पीछे की ओर नेविगेट न कर पाना: Android, अक्सर बैकग्राउंड में चल रहे ऐप्लिकेशन की प्रोसेस को बंद कर देता है, ताकि अन्य टास्क के लिए मेमोरी वापस पाई जा सके. नेविगेशन इतिहास को बनाए रखने के लिए, onSaveInstanceState() लाइफ़साइकल कॉलबैक में saveState(Bundle) का इस्तेमाल किया जा सकता है. अगर लेन-देन की 1 एमबी की सीमा से बचने के लिए, इस इतिहास को मिटा दिया जाता है, तो पूरा नेविगेशन स्टैक मिट जाता है. जब उपयोगकर्ता ऐप्लिकेशन पर वापस आता है, तो सिस्टम का 'वापस जाएं' बटन तुरंत कॉम्पोनेंट या ऐप्लिकेशन से बाहर निकल जाता है. ऐसा इसलिए होता है, क्योंकि पीछे की ओर नेविगेट करने के लिए कोई पुराना कॉन्टेक्स्ट मौजूद नहीं होता. भले ही, प्रोसेस रीस्टार्ट हुई हो या नहीं.

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

  • लेटेंसी बढ़ना: उपयोगकर्ता, WebView में अपनी मौजूदा स्थिति खो देते हैं. इसलिए, उन्हें फिर से नेविगेट करना और फिर से शुरू करना पड़ता है. इस प्रोसेस से, नेटवर्क ओवरहेड और लेन-देन की लेटेंसी काफ़ी बढ़ जाती है.

आर्किटेक्चर से जुड़ी गड़बड़ियों को कम करने की रणनीतियां

TransactionTooLargeException गड़बड़ी की वजह से ऐप्लिकेशन क्रैश होने से रोकने के लिए, आपको इतिहास को पूरी तरह से मिटाकर उपयोगकर्ता अनुभव को खराब होने से बचाना होगा. इसके लिए, आपको स्थिति बनाए रखने और मेमोरी की बचत के बीच सही संतुलन बनाए रखना होगा. यहां दी गई ऑप्टिमाइज़ेशन रणनीतियों को लागू करके, लेन-देन के 1 एमबी के बजट को सुरक्षित तरीके से मैनेज किया जा सकता है. साथ ही, नेविगेशन के ज़रूरी इतिहास और सेशन की अखंडता को बनाए रखा जा सकता है.

स्थिति को क्रम से सेव करने के लिए, साइज़ की सीमाएं लागू करना

नेविगेशन स्टैक के बहुत बड़ा होने पर, उसे पूरी तरह से मिटाने के बजाय, पुराने डेटा को छोटा करना ज़्यादा असरदार होता है:

  • टारगेटेड ड्रॉप पॉलिसी: स्थिति को क्रम से सेव करने के लिए, WebViewCompat.saveState() का इस्तेमाल करें. साथ ही, बाइट की कोई खास सीमा लागू करें. उदाहरण के लिए, WebViewCompat.saveState(webView, outState, maxSizeBytes). यह एपीआई पुराने नेविगेशन एंट्री को क्रम से तब तक अपने-आप ड्रॉप करता है, जब तक कि कुल पेलोड, आपके तय किए गए बजट में सेव न हो जाए. खास तौर पर, इससे क्रम से सेव किए गए Bundle को ही छोटा किया जाता है. साथ ही, चालू WebView के लाइव इतिहास में कोई बदलाव नहीं किया जाता या उसे मिटाया नहीं जाता. इससे, पीछे की ओर तुरंत नेविगेट करने की सुविधा पूरी तरह से बनी रहती है.

  • फ़ॉरवर्ड एंट्री हटाना: अगर ऐप्लिकेशन इंटरफ़ेस में 'वापस जाएं' बटन की सुविधा है लेकिन फ़ॉरवर्ड नेविगेशन के लिए कोई बटन नहीं है, तो फ़ॉरवर्ड नेविगेशन की सभी एंट्री को saveState एपीआई के includeForwardState पैरामीटर को false पर सेट करके हटाया जा सकता है. इससे, उपयोगकर्ता के लिए उपलब्ध नेविगेशन पाथ पर कोई असर नहीं पड़ता. साथ ही, पेलोड का साइज़ काफ़ी कम हो जाता है.

HTTP Cache Quota API की मदद से, संसाधन की लेटेंसी मैनेज करना

saveState की मदद से, कुछ समय के लिए सेव किए गए नेविगेशन इतिहास के लिए, Bundle की 1 एमबी की सीमा को मैनेज किया जाता है. वहीं, HTTP Cache Quota API की मदद से, सेव किए गए वेब संसाधनों (डिस्क की कैश मेमोरी) को हर प्रोफ़ाइल के हिसाब से मैन्युअल तरीके से कंट्रोल किया जा सकता है. इससे, कम समय के लिए सेव किए गए नेविगेशन कॉन्टेक्स्ट और लंबे समय के लिए कैश किए गए ऐसेट के बीच साफ़ तौर पर अंतर किया जा सकता है.

सही कोटा चुनने के लिए, परफ़ॉर्मेंस से समझौता करना पड़ता है:

  • ज़्यादा कोटा होने पर, डिस्क पर ज़्यादा ऐसेट सेव की जा सकती हैं. इससे ऑफ़लाइन उपलब्धता बेहतर होती है और संसाधन लोड होने में लगने वाला समय कम हो जाता है.
  • कम कोटा होने पर, ऐप्लिकेशन के डिस्क फ़ुटप्रिंट को कम किया जा सकता है. साथ ही, ओएस की वजह से, ऐप्लिकेशन के अन्य ज़रूरी डेटा को कैश से हटाने से रोका जा सकता है.

ये सेटिंग, ऐप्लिकेशन को रीस्टार्ट करने पर भी बनी रहती हैं. इन्हें मुख्य थ्रेड से कॉन्फ़िगर किया जाना चाहिए.

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

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
    WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
    val defaultProfile = ProfileStore.getInstance()
        .getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME)
    val httpCache = defaultProfile.httpCache

    // Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
    httpCache.setQuotaBytes(50L * 1024 * 1024)
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.MULTI_PROFILE) &&
    WebViewFeature.isFeatureSupported(WebViewFeature.HTTP_CACHE)) {
    Profile defaultProfile = ProfileStore.getInstance()
        .getOrCreateProfile(Profile.DEFAULT_PROFILE_NAME);
    HttpCache httpCache = defaultProfile.getHttpCache();

    // Set explicit cache size to 50MB (50 * 1024 * 1024 bytes)
    httpCache.setQuotaBytes(50L * 1024 * 1024);
}

कोटा के साइज़ की रणनीतियों, लाइफ़साइकल मैनेजमेंट, और प्रोफ़ाइल की सीमाओं के बारे में ज़्यादा जानने के लिए, WebView में एचटीटीपी कैश कोटा मैनेज करना लेख पढ़ें.

परफ़ॉर्मेंस से जुड़ी ज़रूरी बातें

यहां दी गई बातों में, तकनीकी सीमाओं और इंटरनल डेटा के व्यवहार के बारे में बताया गया है. इनसे WebView की स्थिति के व्यवहार को कंट्रोल किया जाता है:

  • Opaque PageState blob: saveState से सेव किए गए डेटा का करीब 70% हिस्सा, रेंडरिंग इंजन से मिले इंटरनल PageState blob से बना होता है. इस डेटा में, सेशन की विस्तृत स्थितियां शामिल होती हैं. जैसे, फ़ॉर्म में डाली गई जानकारी और iframe की स्क्रोल पोज़िशन. इन blob से, अलग-अलग सेगमेंट को मैन्युअल तरीके से पार्स या स्ट्रिप करने की कोशिश न करें. ऐसा करने से, सुरक्षा से जुड़े गंभीर जोखिम पैदा हो सकते हैं और सेशन को वापस लाने की अखंडता टूट सकती है.

  • इतिहास को अलग-अलग हिस्सों में मैनेज करना: स्टैंडर्ड WebBackForwardList एपीआई, इतिहास के अलग-अलग एलिमेंट को मनमाने तरीके से हटाने की सुविधा नहीं देता. स्थिति को बेहतर तरीके से मैनेज करने के लिए, आपको WebViewCompat.saveState() में maxSizeBytes और includeForwardState पैरामीटर का इस्तेमाल करके, डेटा को छोटा करने की रणनीतियां लागू करनी होंगी. इससे, आर्किटेक्चर की सुरक्षा पक्की की जा सकती है.