میتوانید محتوای مبتنی بر وب مانند HTML، جاوا اسکریپت و CSS را برای برنامهتان فراهم کنید تا بهجای واکشی از طریق اینترنت، بهصورت ایستا در برنامه کامپایل کنید.
محتوای درون برنامه ای نیازی به دسترسی به اینترنت یا مصرف پهنای باند کاربر ندارد. اگر محتوا به طور خاص فقط برای WebView
طراحی شده باشد - یعنی به برقراری ارتباط با یک برنامه بومی بستگی دارد - کاربران نمی توانند به طور تصادفی آن را در یک مرورگر وب بارگذاری کنند.
با این حال، برخی از اشکالات در محتوای درون برنامه وجود دارد. بهروزرسانی محتوای مبتنی بر وب نیاز به ارسال بهروزرسانی جدید برنامه دارد و اگر کاربران نسخههای قدیمی برنامه را داشته باشند، احتمال عدم تطابق محتوای بین آنچه در وبسایت و آنچه در برنامه موجود است در دستگاه شما وجود دارد.
WebViewAssetLoader
WebViewAssetLoader
یک روش منعطف و کارآمد برای بارگیری محتوای درون برنامه در یک شی WebView
است. این کلاس موارد زیر را پشتیبانی می کند:
- در حال بارگیری محتوا با یک URL HTTP(S) برای سازگاری با خط مشی مبدا یکسان .
- بارگیری منابع فرعی مانند جاوا اسکریپت، CSS، تصاویر و iframes.
WebViewAssetLoader
در فایل فعالیت اصلی خود قرار دهید. در زیر نمونه ای از بارگیری محتوای وب ساده از پوشه assets آورده شده است:
کاتلین
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، جاوا اسکریپت و CSS به دارایی ها تعلق دارند.
- تصاویر و سایر فایل های باینری متعلق به منابع هستند.
برای افزودن فایل های وب مبتنی بر متن به پروژه، موارد زیر را انجام دهید:
- در Android Studio، روی برنامه > src > پوشه اصلی کلیک راست کرده و سپس New > Directory را انتخاب کنید.
- نام پوشه را "assets" بگذارید.
- روی پوشه assets کلیک راست کرده و سپس New > File را کلیک کنید.
index.html
را وارد کرده و کلید Return یا Enter را فشار دهید. - مرحله قبل را برای ایجاد یک فایل خالی برای
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
پروژه خود در هارد دیسک منتقل کنید.
شکل 4 تصویری را که اضافه کردید و متن نمونه کدهای قبلی ارائه شده در یک برنامه را نشان می دهد.
برای تکمیل برنامه، موارد زیر را انجام دهید:
هندلرها را ثبت کرده و
AssetLoader
را با افزودن کد زیر به متدonCreate()
پیکربندی کنید:کاتلین
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 شما با آن بارگذاری می شود. این باید یک URL HTTP(S) باشد. -
data
: این محتوای HTML است که می خواهید به عنوان یک رشته نمایش دهید. -
mimeType
: معمولاً باید رویtext/html
تنظیم شود. -
encoding
: زمانی کهbaseUrl
یک URL HTTP(S) باشد استفاده نمی شود، بنابراین می توان آن را رویnull
تنظیم کرد. -
historyUrl
: این مقدار به همان مقدارbaseUrl
تنظیم می شود.
ما اکیداً توصیه میکنیم از URL HTTP(S) بهعنوان baseUrl
استفاده کنید، زیرا این امر به شما کمک میکند تا مطمئن شوید که برنامه شما با خطمشی همان مبدا مطابقت دارد.
اگر نمی توانید یک baseUrl
مناسب برای محتوای خود پیدا کنید و ترجیح می دهید از loadData()
استفاده کنید، باید محتوا را با رمزگذاری درصد یا Base64 رمزگذاری کنید. همانطور که در نمونه کد زیر نشان داده شده است، اکیداً توصیه میکنیم رمزگذاری Base64 را انتخاب کنید و از APIهای 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:
نشانیهای اینترنتی منشأ غیرشفاف در نظر گرفته میشوند، به این معنی که نمیتوانند از APIهای وب قدرتمند مانندfetch()
یاXMLHttpRequest
استفاده کنند.loadData()
به صورت داخلی ازdata:
URL ها، بنابراین ما توصیه می کنیم به جای آن ازWebViewAssetLoader
یاloadDataWithBaseURL()
استفاده کنید. - اگرچه
WebSettings.setAllowFileAccessFromFileURLs()
وWebSettings.setAllowUniversalAccessFromFileURLs()
می توانند مشکلات مربوط به URL هایfile://
کنند، توصیه می کنیم این موارد را رویtrue
تنظیم نکنید زیرا انجام این کار برنامه شما را در برابر سوء استفاده های مبتنی بر فایل آسیب پذیر می کند. توصیه میکنیم به صراحت این موارد را رویfalse
در تمام سطوح API برای قویترین امنیت تنظیم کنید. - به همین دلایل، ما توصیه می کنیم از URL های
file://android_assets/
وfile://android_res/
جلوگیری کنید. کلاسهایAssetsHandler
وResourcesHandler
قرار است جایگزینهای کشویی باشند. - از استفاده از
MIXED_CONTENT_ALWAYS_ALLOW
خودداری کنید. این تنظیم معمولاً ضروری نیست و امنیت برنامه شما را ضعیف می کند. توصیه میکنیم محتوای درونبرنامه خود را از طریق همان طرح (HTTP یا HTTPS) بهعنوان منابع وبسایت خود بارگیری کنید و در صورت لزوم ازMIXED_CONTENT_COMPATIBILITY_MODE
یاMIXED_CONTENT_NEVER_ALLOW
استفاده کنید.