অ্যাপ-মধ্যস্থ কন্টেন্ট লোড করুন

আপনার অ্যাপে ব্যবহার করার জন্য আপনি ওয়েব-ভিত্তিক কন্টেন্ট—যেমন HTML, JavaScript এবং CSS—প্রদান করতে পারেন যা আপনি ইন্টারনেট থেকে ফেচ করার পরিবর্তে অ্যাপে স্ট্যাটিক্যালি কম্পাইল করেন।

অ্যাপ-মধ্যস্থ কন্টেন্টের জন্য ইন্টারনেট অ্যাক্সেসের প্রয়োজন হয় না বা ব্যবহারকারীর ব্যান্ডউইথ খরচ হয় না। যদি কন্টেন্টটি বিশেষভাবে শুধুমাত্র WebView-এর জন্য ডিজাইন করা হয়—অর্থাৎ, এটি নেটিভ অ্যাপের সাথে যোগাযোগের উপর নির্ভর করে—তাহলে ব্যবহারকারীরা ভুলবশত এটি ওয়েব ব্রাউজারে লোড করতে পারবেন না।

তবে, অ্যাপ-মধ্যস্থ কন্টেন্টের কিছু অসুবিধা আছে। ওয়েব-ভিত্তিক কন্টেন্ট আপডেট করার জন্য নতুন অ্যাপ আপডেট শিপ করতে হয় এবং ব্যবহারকারীর কাছে অ্যাপের পুরনো ভার্সন থাকলে, ওয়েবসাইটে যা আছে এবং আপনার ডিভাইসে অ্যাপে যা আছে, তার মধ্যে কন্টেন্ট অমিল হওয়ার সম্ভাবনা থাকে।

WebViewAssetLoader

WebViewAssetLoader হল WebView অবজেক্টে অ্যাপ-মধ্যস্থ কন্টেন্ট লোড করার একটি নমনীয় এবং পারফর্ম্যান্ট উপায়। এই ক্লাস নিম্নলিখিত বিষয়গুলি সাপোর্ট করে:

  • একই-উৎপত্তি নীতির সাথে মানানসই করার জন্য HTTP(S) URL-এর মাধ্যমে কন্টেন্ট লোড করা হচ্ছে।
  • জাভাস্ক্রিপ্ট, CSS, ছবি ও iframe-এর মতো সাবরিসোর্স লোড করা।

আপনার মূল অ্যাক্টিভিটি ফাইলে WebViewAssetLoader অন্তর্ভুক্ত করুন। অ্যাসেট ফোল্ডার থেকে সাধারণ ওয়েব কন্টেন্ট লোড করার উদাহরণ নিচে দেওয়া হল:

Kotlin

private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() {
    @RequiresApi(21)
    override fun shouldInterceptRequest(
        view: WebView,
        request: WebResourceRequest
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(request.url)
    }

    // To support API < 21.
    override fun shouldInterceptRequest(
        view: WebView,
        url: String
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(Uri.parse(url))
    }
}

জাভা

private static class LocalContentWebViewClient extends WebViewClientCompat {

    private final WebViewAssetLoader mAssetLoader;

    LocalContentWebViewClient(WebViewAssetLoader assetLoader) {
        mAssetLoader = assetLoader;
    }

    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     WebResourceRequest request) {
        return mAssetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // To support API < 21.
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     String url) {
        return mAssetLoader.shouldInterceptRequest(Uri.parse(url));
    }
}

আপনার অ্যাপের প্রয়োজন অনুযায়ী WebViewAssetLoader ইনস্ট্যান্স কনফিগার করতে হবে। পরবর্তী বিভাগে একটি উদাহরণ দেওয়া আছে।

অ্যাপ-মধ্যস্থ অ্যাসেট ও রিসোর্স তৈরি করুন

WebViewAssetLoader PathHandler ইনস্ট্যান্সের উপর নির্ভর করে প্রদত্ত রিসোর্স পাথের সাথে সম্পর্কিত রিসোর্স লোড করে। আপনার অ্যাপের প্রয়োজন অনুযায়ী রিসোর্স ফিরিয়ে আনার জন্য আপনি এই ইন্টারফেস প্রয়োগ করতে পারলেও, Webkit লাইব্রেরি যথাক্রমে Android অ্যাসেট ও রিসোর্স লোড করার জন্য AssetsPathHandler এবং ResourcesPathHandler বান্ডেল করে।

শুরু করতে, আপনার অ্যাপের জন্য অ্যাসেট ও রিসোর্স তৈরি করুন। সাধারণত, নিম্নলিখিত বিষয়গুলি প্রযোজ্য হয়:

  • HTML, JavaScript ও CSS-এর মতো টেক্সট ফাইল অ্যাসেটের মধ্যে পড়ে।
  • ছবি ও অন্যান্য বাইনারি ফাইল রিসোর্সের মধ্যে পড়ে।

কোনও প্রোজেক্টে টেক্সট-ভিত্তিক ওয়েব ফাইল যোগ করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. Android Studio-তে, অ্যাপ > src > main ফোল্ডারের উপর ডানদিকের বোতামে ক্লিক করুন এবং তারপরে নতুন > ডিরেক্টরি বিকল্প বেছে নিন।
    Android Studio-র ক্রিয়েট-ডিরেক্টরি মেনু দেখানো একটি ছবি
    ছবি ১. আপনার প্রোজেক্টের জন্য অ্যাসেট ফোল্ডার তৈরি করুন।
  2. ফোল্ডারের নাম "assets" দিন।
    অ্যাসেট ফোল্ডার দেখানো ছবি
    ছবি ২. অ্যাসেট ফোল্ডারের নাম দিন।
  3. অ্যাসেট ফোল্ডারের উপর ডানদিকের মাউস বোতামে ক্লিক করুন এবং তারপরে নতুন > ফাইল বিকল্পে ক্লিক করুন। index.html লিখে Return বা Enter কী প্রেস করুন।
  4. stylesheet.css-এর জন্য খালি ফাইল তৈরি করতে আগের ধাপটি আবার করুন।
  5. পরবর্তী দুটি কোড স্যাম্পেলে থাকা কন্টেন্ট দিয়ে আপনার তৈরি করা খালি ফাইলগুলি পূরণ করুন।
```html
<!-- index.html content -->

<html>
  <head>
    <!-- Tip: Use relative URLs when referring to other in-app content to give
              your app code the flexibility to change the scheme or domain as
              necessary. -->
    <link rel="stylesheet" href="/assets/stylesheet.css">
  </head>
  <body>
    <p>This file is loaded from in-app content.</p>
    <p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p>
  </body>
</html>
```

```css
<!-- stylesheet.css content -->

body {
  background-color: lightblue;
}
```

আপনার প্রোজেক্টে ছবি-ভিত্তিক ওয়েব ফাইল যোগ করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. আপনার লোকাল মেশিনে Android_symbol_green_RGB.png ফাইল ডাউনলোড করুন।

  2. ফাইলের নাম পরিবর্তন করে android_robot.png করুন।

  3. আপনার হার্ড ড্রাইভে প্রোজেক্টের main/res/drawable ডিরেক্টরিতে ম্যানুয়ালি ফাইলটি সরান।

ছবি ৪-এ আপনার যোগ করা ছবি এবং আগের কোড স্যাম্পেল থেকে নেওয়া টেক্সট দেখানো হয়েছে যা অ্যাপে রেন্ডার করা হয়েছে।

অ্যাপের রেন্ডার করা আউটপুট দেখানো ছবি
ছবি ৪. অ্যাপ-মধ্যস্থ HTML ফাইল এবং ছবির ফাইল অ্যাপে রেন্ডার করা হয়েছে।

অ্যাপ সম্পূর্ণ করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. হ্যান্ডলার রেজিস্টার করুন এবং onCreate() পদ্ধতিতে নিম্নলিখিত কোড যোগ করে AssetLoader কনফিগার করুন:

    Kotlin

    val assetLoader = WebViewAssetLoader.Builder()
                           .addPathHandler("/assets/", AssetsPathHandler(this))
                           .addPathHandler("/res/", ResourcesPathHandler(this))
                           .build()
    webView.webViewClient = LocalContentWebViewClient(assetLoader)

    জাভা

    final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
             .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
             .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
             .build();
    mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
  2. onCreate() পদ্ধতিতে নিম্নলিখিত কোড যোগ করে কন্টেন্ট লোড করুন:

    Kotlin

    webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")

    জাভা

    mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");

আপনার ওয়েবসাইট থেকে পাওয়া রিসোর্সের সাথে অ্যাপ-মধ্যস্থ কন্টেন্ট মিশিয়ে দিন

আপনার অ্যাপে ইন-অ্যাপ কন্টেন্ট এবং ইন্টারনেট থেকে পাওয়া কন্টেন্ট, দু'টিই লোড করার প্রয়োজন হতে পারে, যেমন, আপনার ওয়েবসাইটের CSS দ্বারা স্টাইল করা ইন-অ্যাপ HTML পৃষ্ঠা। WebViewAssetLoader এই ব্যবহারের ক্ষেত্রে কাজ করে। রেজিস্টার করা কোনও PathHandler ইনস্ট্যান্স যদি প্রদত্ত পাথের জন্য কোনও রিসোর্স খুঁজে না পায়, তাহলে WebView ইন্টারনেট থেকে কন্টেন্ট লোড করার বিকল্পে ফিরে যায়। আপনি যদি অ্যাপ-মধ্যস্থ কন্টেন্ট আপনার ওয়েবসাইটের রিসোর্সের সাথে মিক্স করেন, তাহলে অ্যাপ-মধ্যস্থ রিসোর্সের জন্য ডিরেক্টরি পাথ, যেমন /assets/ বা /resources/ রিজার্ভ করুন। আপনার ওয়েবসাইটের কোনও রিসোর্স এইসব লোকেশনে স্টোর করবেন না।

Kotlin

val assetLoader = WebViewAssetLoader.Builder()
                        .setDomain("example.com") // Replace this with your website's domain.
                        .addPathHandler("/assets/", AssetsPathHandler(this))
                        .build()

webView.webViewClient = LocalContentWebViewClient(assetLoader)
val inAppHtmlUrl = "https://example.com/assets/index.html"
webView.loadUrl(inAppHtmlUrl)
val websiteUrl = "https://example.com/website/data.json"

// JavaScript code to fetch() content from the same origin.
val jsCode = "fetch('$websiteUrl')" +
        ".then(resp => resp.json())" +
        ".then(data => console.log(data));"

webView.evaluateJavascript(jsCode, null)

জাভা

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
           .setDomain("example.com") // Replace this with your website's domain.
           .addPathHandler("/assets/", new AssetsPathHandler(this))
           .build();

mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
String inAppHtmlUrl = "https://example.com/assets/index.html";
mWebView.loadUrl(inAppHtmlUrl);
String websiteUrl = "https://example.com/website/data.json";

// JavaScript code to fetch() content from the same origin.
String jsCode = "fetch('" + websiteUrl + "')" +
      ".then(resp => resp.json())" +
      ".then(data => console.log(data));";

mWebView.evaluateJavascript(jsCode, null);

অ্যাপ-মধ্যস্থ HTML পৃষ্ঠা কীভাবে ওয়েব-হোস্ট করা JSON ডেটা ফেচ করে তার উদাহরণ দেখতে, GitHub-এ WebView ডেমো দেখুন।

loadDataWithBaseURL

আপনার অ্যাপকে যখন শুধু HTML পৃষ্ঠা লোড করতে হয় এবং সাবরিসোর্স ইন্টারসেপ্ট করতে হয় না, তখন loadDataWithBaseURL() ব্যবহার করার কথা বিবেচনা করুন, যার জন্য অ্যাপ অ্যাসেটের প্রয়োজন হয় না। আপনি নিম্নলিখিত কোড স্যাম্পেলে দেখানো উপায়ে এটি ব্যবহার করতে পারবেন:

Kotlin

val html = "<html><body><p>Hello world</p></body></html>"
val baseUrl = "https://example.com/"

webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)

জাভা

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";

mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

আর্গুমেন্টের ভ্যালু সাবধানে বেছে নিন। নিম্নলিখিত বিষয়গুলি বিবেচনা করুন:

  • baseUrl: এই URL-এ আপনার HTML কন্টেন্ট লোড করা হয়। এটি অবশ্যই একটি HTTP(S) URL হতে হবে।
  • data: এটি হল HTML কন্টেন্ট যা আপনি স্ট্রিং হিসেবে দেখাতে চান।
  • mimeType: এটি সাধারণত text/html-এ সেট করতে হবে।
  • encoding: baseUrl একটি HTTP(S) URL হলে এটি অব্যবহৃত থাকে, তাই এটি null-এ সেট করা যেতে পারে।
  • historyUrl: এটি baseUrl-এর মতো একই ভ্যালুতে সেট করা হয়েছে।

আমরা baseUrl হিসেবে HTTP(S) URL ব্যবহার করার জন্য বিশেষভাবে সাজেস্ট করি, কারণ এটি আপনার অ্যাপ একই-উৎসের নীতি মেনে চলছে কিনা তা নিশ্চিত করতে সাহায্য করে।

আপনার কন্টেন্টের জন্য উপযুক্ত baseUrl খুঁজে না পেলে এবং loadData() ব্যবহার করতে চাইলে, আপনাকে অবশ্যই কন্টেন্ট এনকোড করতে হবে পার্সেন্ট-এনকোডিং বা Base64 এনকোডিং ব্যবহার করে। আমরা Base64 এনকোডিং বেছে নেওয়ার এবং প্রোগ্রাম্যাটিকভাবে এটি এনকোড করার জন্য Android API ব্যবহার করার জন্য সুপারিশ করি, যেমনটি নিম্নলিখিত কোড স্যাম্পেলে দেখানো হয়েছে:

Kotlin

val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING)

webView.loadData(encodedHtml, mimeType, "base64")

জাভা

String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);

mWebView.loadData(encodedHtml, mimeType, "base64");

যেসব কাজ এড়িয়ে যাবেন

অ্যাপ-মধ্যস্থ কন্টেন্ট লোড করার আরও অনেক উপায় আছে, তবে আমরা সেগুলি ব্যবহার না করার জন্য বিশেষভাবে সাজেস্ট করি:

  • file:// URL এবং data: URL-কে অস্বচ্ছ অরিজিন হিসেবে বিবেচনা করা হয়, যার অর্থ হল, এগুলি শক্তিশালী ওয়েব API-এর সুবিধা নিতে পারে না, যেমন fetch() অথবা XMLHttpRequest। loadData() ইন্টার্নালি data: URL ব্যবহার করে, তাই আমরা এর পরিবর্তে WebViewAssetLoader বা loadDataWithBaseURL() ব্যবহার করতে সাজেস্ট করি।
  • যদিও WebSettings.setAllowFileAccessFromFileURLs() এবং WebSettings.setAllowUniversalAccessFromFileURLs() file:// URL-এর সমস্যা সমাধান করতে পারে, আমরা এগুলি true-এ সেট করার সাজেশন দিই না কারণ এটি করলে আপনার অ্যাপ ফাইল-ভিত্তিক শোষণের জন্য অসুরক্ষিত হয়ে যায়। সবচেয়ে শক্তিশালী নিরাপত্তার জন্য সব API লেভেলে এগুলি স্পষ্টভাবে false-এ সেট করার জন্য সাজেস্ট করা হয়।
  • একই কারণে, আমরা file://android_assets/ এবং file://android_res/ URL ব্যবহার না করার সাজেশন দিই। AssetsHandler এবং ResourcesHandler ক্লাসগুলি ড্রপ-ইন রিপ্লেসমেন্ট হিসেবে ব্যবহার করার জন্য তৈরি করা হয়েছে।
  • MIXED_CONTENT_ALWAYS_ALLOW ব্যবহার করা এড়িয়ে চলুন। এই সেটিং সাধারণত প্রয়োজন হয় না এবং আপনার অ্যাপের নিরাপত্তা দুর্বল করে দেয়। আমরা সাজেস্ট করি যে আপনার ইন-অ্যাপ কন্টেন্ট একই স্কিমে লোড করুন—HTTP বা HTTPS—আপনার ওয়েবসাইটের রিসোর্স হিসেবে এবং MIXED_CONTENT_COMPATIBILITY_MODE বা MIXED_CONTENT_NEVER_ALLOW, উপযুক্ত হিসেবে ব্যবহার করুন।