WebViewCompat.navigate ব্যবহার করে উন্নত পেজ নেভিগেশন

WebViewCompat.navigate হলো WebView.loadUrl এর একটি উন্নত বিকল্প, যা WebView তে ওয়েব পেজ লোডিং, হিস্ট্রি ম্যানেজমেন্ট এবং নেভিগেশন লাইফসাইকেল ট্র্যাকিংয়ের ওপর সূক্ষ্ম নিয়ন্ত্রণ প্রদান করে।

পূর্বে, loadUrl ব্যবহার করে পৃষ্ঠা নেভিগেশন শুরু করার ক্ষেত্রে উল্লেখযোগ্য সীমাবদ্ধতা ছিল:

  • হিস্ট্রি এন্ট্রি প্রতিস্থাপন করা যাচ্ছে না: আপনি বর্তমান হিস্ট্রি এন্ট্রিটি প্রতিস্থাপন করতে পারেননি, যার ফলে ব্যাক স্ট্যাকে একটি এন্ট্রি যোগ না করে নতুন পৃষ্ঠায় যাওয়া অসম্ভব।
  • বিচ্ছিন্ন কলব্যাক: WebViewClient এ একটি নির্দিষ্ট loadUrl কলকে পরবর্তী কলব্যাক ইভেন্টগুলির সাথে সংযুক্ত করার কোনো সরাসরি ব্যবস্থা ছিল না।
  • অতিরিক্ত হেডার সংরক্ষিত হয়নি: loadUrl এ পাঠানো কাস্টম হেডারগুলো WebView স্টেটের অংশ হিসেবে সংরক্ষিত হয়নি, ফলে স্টেট পুনরুদ্ধার করার সময় সেগুলো হারিয়ে গেছে।

WebViewCompat.navigate API নিম্নলিখিত বৈশিষ্ট্যগুলি প্রবর্তনের মাধ্যমে এই সমস্যাগুলি সমাধান করে:

  • নেভিগেশন হিস্ট্রি এন্ট্রি প্রতিস্থাপন: এর মাধ্যমে আপনি WebView হিস্ট্রি স্ট্যাকে থাকা বর্তমান পৃষ্ঠাটি প্রতিস্থাপন করতে পারবেন।
  • পারস্পরিক সম্পর্কযুক্ত কলব্যাক ট্র্যাকিং: একটি Navigation অবজেক্ট রিটার্ন করে যা একটি নেভিগেশন লাইফসাইকেলের সকল পর্যায়ে একটি অনন্য শনাক্তকারী হিসেবে কাজ করে।
  • সংরক্ষিত স্টেট হেডার সমর্থন: অতিরিক্ত হেডারগুলো WebView স্টেট বান্ডেলে নির্ভরযোগ্যভাবে সংরক্ষিত থাকে, যাতে স্টেট পুনরুদ্ধারের সময় সেগুলো পুনরায় ব্যবহার করা যায়।

মূল সক্ষমতা এবং সীমাবদ্ধতা

WebViewCompat.navigate গ্রহণ করার আগে, নিম্নলিখিত পরিচালন নিয়ম এবং সীমাবদ্ধতাগুলো বিবেচনা করুন:

  • থ্রেড সুরক্ষা: আপনাকে অবশ্যই UI (প্রধান) থ্রেডে WebViewCompat.navigate কল করতে হবে।

  • বাতিলকরণ এবং অগ্রাধিকার: চলমান নেভিগেশন স্পষ্টভাবে বাতিল করা যায় না। তবে, একই WebView একটি নতুন navigate কল শুরু করলে তা যেকোনো সক্রিয় নেভিগেশনকে বাতিল করে দেয়।

  • URI স্কিম সমর্থন: স্ট্যান্ডার্ড (যেমন https: এবং http: :) এবং কাস্টম URI স্কিম সমর্থিত। javascript: স্কিমটি সমর্থিত নয়।

  • ইউআরএল আকারের সীমা: সর্বোচ্চ সমর্থিত ইউআরএল স্ট্রিংয়ের দৈর্ঘ্য হলো ২ মেগাবাইট।

  • ফিচার যাচাইকরণ: বিভিন্ন WebView APK সংস্করণের মধ্যে সামঞ্জস্য বজায় রাখতে, API কল করার আগে সর্বদা WebViewFeature.isFeatureSupported ব্যবহার করে ফিচারের প্রাপ্যতা যাচাই করুন।

নেভিগেশন শুরু করুন এবং জীবনচক্র ট্র্যাক করুন

ন্যাভিগেশন কনফিগার করতে এবং এর জীবনচক্র ট্র্যাক করতে, নিম্নলিখিতগুলি করুন:

  1. স্ট্রাকচার্ড লাইফসাইকেল কলব্যাক গ্রহণ করার জন্য WebView সেটআপের সময় WebViewCompat.addNavigationListener ব্যবহার করে একটি NavigationListener ইমপ্লিমেন্টেশন রেজিস্টার করুন। মেমরি লিক এবং ডুপ্লিকেট কলব্যাক এক্সিকিউশন প্রতিরোধ করতে লিসেনারটি প্রতিটি নেভিগেশন কলের পরিবর্তে একবার রেজিস্টার করুন।
  2. হিস্ট্রি রিপ্লেসমেন্ট বা কাস্টম HTTP হেডারের মতো ঐচ্ছিক আচরণগুলো নির্দিষ্ট করতে NavigationParameters.Builder ব্যবহার করে একটি NavigationParameters ইনস্ট্যান্স তৈরি করুন।
  3. আপনার WebView ইনস্ট্যান্স, গন্তব্য URL এবং প্যারামিটারগুলো পাস করে WebViewCompat.navigate কল করুন।

WebViewCompat.navigate একটি Navigation অবজেক্ট রিটার্ন করে যা রিকোয়েস্টটিকে অনন্যভাবে শনাক্ত করে। আপনার NavigationListener কলব্যাকগুলিতে, সেই নির্দিষ্ট নেভিগেশনটি ট্র্যাক করার জন্য এই অবজেক্টটিকে আগত Navigation প্যারামিটারের সাথে তুলনা করুন।

বাস্তবায়নের উদাহরণ

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে নেভিগেশন প্যারামিটার কনফিগার করতে হয়, WebViewCompat.navigate কল করতে হয় এবং নেভিগেশন লাইফসাইকেল ইভেন্টগুলির জন্য লিসেন করতে হয়:

কোটলিন

class WebNavigationManager(private val webView: WebView) {
    // Track the navigation instance returned by the API
    private var currentNavigation: Navigation? = null

    init {
        // 1. Define listener to observe navigation lifecycle events
        val listener = object : NavigationListener {
            override fun onNavigationStarted(navigation: Navigation) {
                if (navigation == currentNavigation) {
                    // Navigation started
                }
            }

            override fun onNavigationRedirected(navigation: Navigation) {
                if (navigation == currentNavigation) {
                    // Navigation encountered a redirect
                }
            }

            override fun onNavigationCompleted(navigation: Navigation) {
                if (navigation == currentNavigation) {
                    if (navigation.didCommit()) {
                        // Navigation committed successfully
                    } else if (navigation.didCommitErrorPage()) {
                        // Navigation committed an error page
                        val statusCode = navigation.statusCode
                        val error = navigation.webResourceError
                    }
                }
            }

            override fun onFirstContentfulPaintMillis(page: Page, durationMillis: Long) {
                // Match page with current navigation
                if (page == currentNavigation?.page) {
                    // Page rendering started (First Contentful Paint achieved)
                }
            }
        }

        // 2. Register listener on the main thread
        WebViewCompat.addNavigationListener(webView, listener)
    }

    @UiThread
    fun navigateToPage(url: String) {
        // Check feature availability
        if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
            // Fall back to standard loadUrl if navigate API is unavailable
            webView.loadUrl(url)
            return
        }

        // 3. Configure navigation parameters
        val params = NavigationParameters.Builder()
            .setShouldReplaceCurrentEntry(true)
            .addAdditionalHeaders(
                mapOf("X-Test-Navigate-Header" to "TestValue")
            )
            .build()

        // 4. Initiate navigation on the UI thread
        currentNavigation = WebViewCompat.navigate(webView, url, params)
    }
}

জাভা

public class WebNavigationManager {

    private Navigation mCurrentNavigation;
    private final WebView mWebView;

    public WebNavigationManager(@NonNull WebView webView) {
        mWebView = webView;
        setupListener();
    }

    private void setupListener() {
        // 1. Define listener to observe navigation lifecycle events
        NavigationListener listener = new NavigationListener() {
            @Override
            public void onNavigationStarted(@NonNull Navigation navigation) {
                if (navigation.equals(mCurrentNavigation)) {
                    // Navigation started
                }
            }

            @Override
            public void onNavigationRedirected(@NonNull Navigation navigation) {
                if (navigation.equals(mCurrentNavigation)) {
                    // Navigation encountered a redirect
                }
            }

            @Override
            public void onNavigationCompleted(@NonNull Navigation navigation) {
                if (navigation.equals(mCurrentNavigation)) {
                    if (navigation.didCommit()) {
                        // Navigation committed successfully
                    } else if (navigation.didCommitErrorPage()) {
                        // Navigation committed an error page
                        int statusCode = navigation.getStatusCode();
                        WebResourceErrorCompat error = navigation.getWebResourceError();
                    }
                }
            }

            @Override
            public void onFirstContentfulPaintMillis(@NonNull Page page, long durationMillis) {
                if (mCurrentNavigation != null && page.equals(mCurrentNavigation.getPage())) {
                    // Page rendering started (First Contentful Paint achieved)
                }
            }
        };

        // 2. Register listener on the main thread
        WebViewCompat.addNavigationListener(mWebView, listener);
    }

    @UiThread
    public void navigateToPage(@NonNull String url) {
        // Check feature availability
        if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEBVIEW_NAVIGATE_EXPERIMENTAL_V1)) {
            // Fall back to standard loadUrl if navigate API is unavailable
            mWebView.loadUrl(url);
            return;
        }

        // 3. Configure navigation parameters
        NavigationParameters params = new NavigationParameters.Builder()
            .setShouldReplaceCurrentEntry(true)
            .addAdditionalHeaders(Collections.singletonMap(
                "X-Test-Navigate-Header", "TestValue"
            ))
            .build();

        // 4. Initiate navigation on the UI thread
        mCurrentNavigation = WebViewCompat.navigate(mWebView, url, params);
    }
}

ব্যর্থতার ধরণ এবং ত্রুটি পরিচালনা

WebViewCompat.navigate API কনফিগারেশন ত্রুটি এবং রানটাইম নেভিগেশন ব্যর্থতা পরিচালনা করার জন্য স্বতন্ত্র ব্যবস্থা প্রদান করে:

অবৈধ আর্গুমেন্ট ব্যতিক্রম

অবৈধ আর্গুমেন্ট পাস করলে একটি সিনক্রোনাস IllegalArgumentException ট্রিগার হয়। এর সাধারণ কারণগুলোর মধ্যে নিম্নলিখিতগুলো অন্তর্ভুক্ত:

  • প্রয়োজনীয় নন-নাল প্যারামিটারগুলোর ( webView , url , বা params ) জন্য null পাস করা হচ্ছে।
  • একটি অসমর্থিত ইউআরএল স্কিম সরবরাহ করা, যেমন javascript: .
  • RFC 2616 স্পেসিফিকেশন মেনে চলে না এমন ত্রুটিপূর্ণ HTTP হেডার কী বা ভ্যালু পাস করা।

নেটওয়ার্ক অনুরোধ বা পৃষ্ঠা লোড হওয়ার সময় কোনো ব্যর্থতা ঘটলে (যেমন HTTP 404 স্ট্যাটাস কোড, DNS রেজোলিউশন ব্যর্থতা, বা SSL ত্রুটি), WebViewCompat.navigate তবুও একটি বৈধ Navigation অবজেক্ট ফেরত দেয়।

নেভিগেশন শেষ হলে, ব্যর্থতা নির্ণয় করার জন্য আপনার onNavigationCompleted কলব্যাকের ভিতরে Navigation ইনস্ট্যান্সের নিম্নলিখিত মেথডগুলো পরীক্ষা করুন:

  • getStatusCode : HTTP রেসপন্সের স্ট্যাটাস কোড রিটার্ন করে (যেমন, 404 বা 500 )।
  • getWebResourceError : একটি WebResourceErrorCompat অবজেক্ট রিটার্ন করে, যা নেটওয়ার্ক ত্রুটি, যেমন সংযোগের সময়সীমা অতিক্রান্ত হওয়া বা হোস্ট অনুসন্ধানে ব্যর্থতার বিবরণ দেয়।
  • didCommitErrorPage : এটি নির্দেশ করে যে WebView কমিট করেছে কিনা এবং ব্যবহারকারীকে একটি ত্রুটির পৃষ্ঠা প্রদর্শন করেছে কিনা।
  • didCommit : নেভিগেশনটি বাতিল না হয়ে সফলভাবে লক্ষ্য পৃষ্ঠায় কমিট হয়েছে কিনা তা নির্দেশ করে।

স্টেট বান্ডেল ব্যবস্থাপনা সংরক্ষণ করুন

যখন আপনি NavigationParameters সাথে অতিরিক্ত হেডার পাস করেন, WebView এই হেডারগুলিকে তার সেভড স্টেট বান্ডেলে সংরক্ষণ করে, যাতে স্টেট রিস্টোর করার সময় সেগুলি পুনরায় ব্যবহার করা যায়। তবে, বিপুল সংখ্যক হেডার সেভড স্টেট Bundle আকার উল্লেখযোগ্যভাবে বাড়িয়ে দিতে পারে।

অ্যান্ড্রয়েড স্টেট সেভ করার সময় TransactionTooLargeException এড়াতে যদি বান্ডেল সাইজ সীমিত করার প্রয়োজন হয়, তাহলে WebViewCompat.saveState ব্যবহার করুন। এই মেথডটি আপনাকে বাইটে সর্বোচ্চ বান্ডেল সাইজের সীমা নির্ধারণ করতে এবং ঐচ্ছিকভাবে ফরওয়ার্ড হিস্ট্রি আইটেম বাদ দিতে দেয়:

কোটলিন

// Save state with a maximum bundle size limit (for example, 64 KB)
val maxSizeBytes = 64 * 1024
val includeForwardState = false
val outState = Bundle()

WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState)

জাভা

// Save state with a maximum bundle size limit (for example, 64 KB)
int maxSizeBytes = 64 * 1024;
boolean includeForwardState = false;
Bundle outState = new Bundle();

WebViewCompat.saveState(webView, outState, maxSizeBytes, includeForwardState);

ফলস্বরূপ বান্ডেলটি স্ট্যান্ডার্ড WebView.restoreState পদ্ধতির সাথে সামঞ্জস্যপূর্ণ থাকে।

অভিবাসন এবং বাস্তবায়ন সুপারিশ

WebView তে নেভিগেট করার সময় সর্বোত্তম পারফরম্যান্স ও স্থিতিশীলতা নিশ্চিত করতে, এই সুপারিশগুলো অনুসরণ করুন:

  • loadUrl থেকে navigate এ স্থানান্তর করুন: পুরোনো সমস্ত WebView.loadUrl কলকে WebViewCompat.navigate এ রূপান্তর করুন। এটি অভিন্ন হিস্ট্রি ম্যানেজমেন্ট নিশ্চিত করে এবং হেডারগুলো সর্বদা সেভড স্টেটের অংশ হিসেবে সংরক্ষিত থাকা নিশ্চিত করে।

  • সর্বদা ফিচার সাপোর্ট যাচাই করুন: API কল করার আগে, WebView-এর পুরোনো সংস্করণগুলোর বিরুদ্ধে সুরক্ষার জন্য WebViewFeature.isFeatureSupported ব্যবহার করে রানটাইম সাপোর্ট নিশ্চিত করুন।

  • ন্যাভিগেশন ইনস্ট্যান্সগুলোর মধ্যে সম্পর্ক স্থাপন করুন: একাধিক WebView ইনস্ট্যান্স পরিচালনা করার সময়, যুগপৎ ন্যাভিগেশনগুলোকে আলাদা করতে বা কলব্যাক ফিল্টার করতে ফেরত আসা Navigation অবজেক্টটি ব্যবহার করুন।

  • ইনিশিয়ালাইজেশনের সময় একবার লিসেনার রেজিস্টার করুন: যেহেতু WebViewCompat.addNavigationListener বিদ্যমান কোনো লিসেনারকে প্রতিস্থাপন না করে একটি নতুন লিসেনার যোগ করে, তাই মেমরি লিক এবং পরবর্তী নেভিগেশনগুলোতে ডুপ্লিকেট কলব্যাক এক্সিকিউশন এড়াতে WebView সেটআপের সময় আপনার NavigationListener একবার রেজিস্টার করুন।

  • সংরক্ষিত স্টেট ডেটার আকার নিরীক্ষণ করুন: বড় আকারের হেডার পেলোড পাঠানোর সময়, অতিরিক্ত স্টেট ডেটা সংরক্ষণ এড়াতে সুস্পষ্ট আকারের সীমা সহ WebViewCompat.saveState ব্যবহার করুন।

অতিরিক্ত সম্পদ

এমবেডেড ওয়েব সক্ষমতা এবং পারফরম্যান্স অপ্টিমাইজেশন সম্পর্কে আরও জানতে, নিম্নলিখিত গাইডগুলি দেখুন: