میتوانید محتوای مبتنی بر وب (مانند HTML، جاوا اسکریپت، و CSS) را برای استفاده برنامهتان ارائه دهید که بهجای واکشی ازطریق اینترنت، آن را بهصورت ایستا در برنامه کامپایل میکنید.
محتوای درونبرنامه به دسترسی به اینترنت نیاز ندارد یا پهنای باند کاربر را مصرف نمیکند. اگر
محتوا بهطور خاص فقط برای WebView طراحی شده باشد—یعنی
به برقراری ارتباط با برنامه به زبان اصلی دستگاه وابسته باشد—کاربران نمیتوانند بهطور تصادفی
آن را در مرورگر وب بار کنند.
بااینحال، محتوای درونبرنامه معایبی هم دارد. بهروزرسانی محتوای مبتنی بر وب مستلزم ارسال بهروزرسانی جدید برنامه است و اگر کاربران نسخههای قدیمی برنامه را داشته باشند، احتمال عدم تطابق محتوای موجود در وبسایت با محتوای موجود در برنامه دستگاه شما وجود دارد.
WebViewAssetLoader
WebViewAssetLoader روشی
انعطافپذیر و کارآمد برای بار کردن محتوای درونبرنامه در
شیء WebView است. این کلاس از موارد زیر
پشتیبانی میکند:
- بار کردن محتوا با نشانی وب HTTP(S) برای سازگاری با خطمشی هممبدأ.
- بار کردن زیرمنابعی مثل جاوا اسکریپت، CSS، تصاویر، و iframe.
WebViewAssetLoader را در فایل فعالیت اصلیتان بگنجانید. در زیر نمونهای از بار کردن محتوای وب ساده از پوشه داراییها آورده شده است:
کاتلین
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 بهترتیب
AssetsPathHandler
و
ResourcesPathHandler
را برای بار کردن داراییها و منابع Android بستهبندی میکند.
برای شروع، داراییها و منابعی برای برنامهتان ایجاد کنید. بهطور کلی، موارد زیر اعمال میشود:
- فایلهای نوشتاری مانند HTML، JavaScript، و CSS به داراییها تعلق دارند.
- تصاویر و دیگر فایلهای دودویی به منابع تعلق دارند.
برای افزودن فایلهای وب نوشتاری به پروژه، کارهای زیر را انجام دهید:
- در «استودیو Android»، روی پوشه app > src > main کلیک راست کنید
و سپس جدید > دایرکتوری را انتخاب کنید.
شکل ۱. پوشه داراییها را برای پروژهتان ایجاد کنید. - نام پوشه را «assets» بگذارید.
شکل ۲. پوشه داراییها را نامگذاری کنید. - روی پوشه assets کلیک راست کنید و سپس روی New (جدید) > File (فایل) کلیک کنید.
index.htmlرا وارد کنید و کلید Return یا Enter را فشار دهید.
شکل ۳. فایل index.htmlرا ایجاد کنید. - مرحله قبلی را تکرار کنید تا فایل خالی برای
stylesheet.cssایجاد شود. - فایلهای خالیای را که ایجاد کردهاید با محتوای دو نمونه کد بعدی پر کنید.
```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;
}
```
برای افزودن فایل وب مبتنی بر تصویر به پروژهتان، کارهای زیر را انجام دهید:
فایل
Android_symbol_green_RGB.pngرا در ماشین محلیتان بارگیری کنید.نام فایل را به
android_robot.pngتغییر دهید.فایل را بهطور دستی به فهرست راهنمای
main/res/drawableپروژهتان در دیسک سخت منتقل کنید.
شکل ۴ تصویری را که اضافه کردید و نوشتار نمونه کدهای قبلی را نشان میدهد که در برنامه ارائه شده است.
برای تکمیل برنامه، کارهای زیر را انجام دهید:
با افزودن کد زیر به روش
onCreate()، گردانندهها را ثبت کنید وAssetLoaderرا پیکربندی کنید:کاتلین
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));
با افزودن کد زیر به روش
onCreate()، محتوا را بار کنید:کاتلین
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
جاوا
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
محتوای درونبرنامه را با منابع وبسایتتان ترکیب کنید
ممکن است برنامهتان نیاز داشته باشد ترکیبی از محتوای درونبرنامه و محتوای اینترنت را بار کند، مثل صفحه HTML درونبرنامه که با CSS وبسایتتان سبکبندی شده است.
WebViewAssetLoader از این مورد استفاده پشتیبانی میکند. اگر هیچکدام از نمونههای ثبتشده
PathHandler نتوانند منبعی برای مسیر ارائهشده پیدا کنند، WebView
به بار کردن محتوا از اینترنت برمیگردد. اگر محتوای درونبرنامه را با منابع وبسایتتان ترکیب میکنید، مسیرهای دایرکتوری، مثل /assets/ یا /resources/ را برای منابع درونبرنامه رزرو کنید. از ذخیره کردن منابع وبسایتتان در این مکانها خودداری کنید.
کاتلین
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 میزبانیشده در وب را واکشی میکند،
WebView نسخه نمایشی را در GitHub ببینید.
loadDataWithBaseURL
وقتی برنامهتان فقط باید صفحه HTML را بار کند و نیازی به رهگیری
زیرمنابع ندارد، از
loadDataWithBaseURL()
استفاده کنید که به داراییهای برنامه نیاز ندارد. میتوانید از آن همانطور که در نمونه کد زیر نشان داده شده است استفاده کنید:
کاتلین
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: این نشانی وب است که محتوای HTML شما بهعنوان آن بار میشود. این باید نشانی وب HTTP(S) باشد. -
data: این محتوای HTML است که میخواهید بهصورت رشته نمایش دهید. mimeType: این مقدار معمولاً باید رویtext/htmlتنظیم شود.encoding: وقتیbaseUrlنشانی وب HTTP(S) باشد، این مورد استفاده نمیشود، بنابراین میتوان آن را رویnullتنظیم کرد.historyUrl: این مقدار با مقدارbaseUrlیکسان است.
قویاً توصیه میکنیم از نشانی وب HTTP(S) بهعنوان baseUrl استفاده کنید، زیرا این کار کمک میکند
مطمئن شوید برنامهتان از خطمشی هممبدأ تبعیت میکند.
اگر نمیتوانید baseUrl مناسبی برای محتوایتان پیدا کنید و ترجیح میدهید از
loadData() استفاده کنید،
باید محتوا را با
کدبندی درصدی
یا
کدبندی
Base64 کدبندی کنید.
اکیداً توصیه میکنیم کدگذاری Base64 را انتخاب کنید و از میاناهای برنامهسازی کاربردی Android برای کدگذاری
این بهصورت برنامهنویسیشده استفاده کنید، همانطور که در نمونه کد زیر نشان داده شده است:
کاتلین
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://و نشانیهای وبdata:بهعنوان مبدأهای مبهم درنظر گرفته میشوند، یعنی نمیتوانند از میاناهای برنامهسازی کاربردی وب قدرتمند مانندfetch()یاXMLHttpRequestاستفاده کنند.loadData()بهطور داخلی از نشانیهای وبdata:استفاده میکند، بنابراین توصیه میکنیم بهجای آن ازWebViewAssetLoaderیاloadDataWithBaseURL()استفاده کنید. - اگرچه
WebSettings.setAllowFileAccessFromFileURLs()وWebSettings.setAllowUniversalAccessFromFileURLs()میتوانند مشکلات مربوط به نشانیهای وبfile://را حل کنند، توصیه میکنیم این موارد را رویtrueتنظیم نکنید زیرا انجام این کار برنامهتان را دربرابر سوءاستفادههای مبتنی بر فایل آسیبپذیر میکند. توصیه میکنیم برای داشتن قویترین امنیت، این موارد را بهطور صریح رویfalseدر همه سطوح API تنظیم کنید. - به همین دلایل، توصیه میکنیم از نشانیهای وب
file://android_assets/وfile://android_res/استفاده نکنید. کلاسهایAssetsHandlerوResourcesHandlerبهعنوان جایگزینهای مستقیم درنظر گرفته شدهاند. - از
MIXED_CONTENT_ALWAYS_ALLOWاستفاده نکنید. این تنظیم معمولاً ضروری نیست و امنیت برنامهتان را تضعیف میکند. توصیه میکنیم محتوای درونبرنامهایتان را ازطریق همان طرحی بار کنید که منابع وبسایتتان بار میشوند (HTTP یا HTTPS) و ازMIXED_CONTENT_COMPATIBILITY_MODEیاMIXED_CONTENT_NEVER_ALLOWبهطور مناسب استفاده کنید.