WebViewCompat.navigate جایگزینی بهبودیافته برای
WebView.loadUrl است که کنترل دقیقی بر بار کردن صفحه وب،
مدیریت سابقه، و ردیابی چرخه حیات پیمایش در WebView ارائه میدهد.
قبلاً، آغاز کردن پیمایشهای صفحه بااستفاده از loadUrl محدودیتهای قابلتوجهی داشت:
- بدون جایگزینی ورودی سابقه: نتوانستید ورودی سابقه فعلی را جایگزین کنید، بنابراین پیمایش به صفحه جدید بدون افزودن ورودی به پشته قبلیها غیرممکن شد.
- فراخوانیهای جداشده: هیچ سازوکار مستقیمی برای مرتبط کردن یک تماس
loadUrlخاص با رویدادهای فراخوانی بعدی درWebViewClientوجود نداشت. - سرایندهای اضافی ذخیره نشدند: سرایندهای سفارشی ارسالشده به
loadUrlبهعنوان بخشی از وضعیتWebViewذخیره نشدند، بنابراین هنگام بازیابی وضعیت ازبین رفتند.
WebViewCompat.navigate API این مشکلات را با معرفی ویژگیهای زیر برطرف میکند:
- جایگزینی ورودی سابقه پیمایش: به شما امکان میدهد صفحه فعلی را در پشته سابقه
WebViewجایگزین کنید. - ردگیری فراخوانی همبسته: شیء
Navigationرا برمیگرداند که بهعنوان شناسه یکتا در همه مراحل چرخه حیات پیمایش عمل میکند. - پشتیبانی از سرصفحه حالت ذخیرهشده: سرصفحههای اضافی بهطور مطمئن در
WebViewبسته حالت ذخیره میشوند تا بتوان از آنها در بازگرداندن حالت استفاده مجدد کرد.
قابلیتها و محدودیتهای کلیدی
قبلاز پذیرش WebViewCompat.navigate، قوانین و محدودیتهای عملیاتی زیر را درنظر بگیرید:
ایمنی رشته: باید
WebViewCompat.navigateرا در رشته (اصلی) میانای کاربر فراخوانی کنید.لغو و تقدم: ناوبریهای درحال اجرا را نمیتوان بهطور صریح لغو کرد. بااینحال، شروع تماس
navigateجدید در همانWebViewجایگزین هرگونه ناوبری فعال میشود.پشتیبانی از طرحواره URI: طرحوارههای URI استاندارد (مانند
https:وhttp:) و سفارشی پشتیبانی میشوند. از طرحjavascript:پشتیبانی نمیشود.محدودیت اندازه نشانی وب: حداکثر طول رشته نشانی وب پشتیبانیشده ۲ مگابایت است.
بررسی ویژگی: همیشه دردسترس بودن ویژگی را بااستفاده از
WebViewFeature.isFeatureSupportedقبلاز فراخوانی میانای برنامهسازی کاربردی بررسی کنید تا سازگاری در نسخههای مختلف WebView APK حفظ شود.
شروع ناوبری و چرخه حیات قطعه
برای پیکربندی پیمایش و ردیابی چرخه حیات آن، کارهای زیر را انجام دهید:
- پیادهسازی
NavigationListenerرا بااستفاده ازWebViewCompat.addNavigationListenerدرطول راهاندازیWebViewثبت کنید تا فراخوانیهای برگشتی چرخه حیات ساختاریافته را دریافت کنید. برای جلوگیری از نشت حافظه و اجرای تکراری فراخوانی بازگشتی، شنونده را یکبار (بهجای هر تماس پیمایش) ثبت کنید. - بااستفاده از
NavigationParameters.Builder، نمونهNavigationParametersبسازید تا رفتارهای اختیاری را مشخص کنید، مثلاً جایگزینی سابقه یا سرایندهای HTTP سفارشی. WebViewCompat.navigateرا فراخوانی کنید و نمونهWebView، نشانی وب مقصد، و پارامترها را ارسال کنید.
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);
}
}
انتشار وضعیت برنامه بااستفاده از سرصفحههای HTTP
برنامههای وب اغلب به بافت برنامه Android میزبان نیاز دارند تا منطق پسزمینه را هماهنگ کنند یا محتوای وب را سفارشیسازی کنند. افزودن پارامترهای پُرسمان به نشانی وب برای ارسال این اطلاعات میتواند نشانیهای وب را بههم بریزد، در ذخیرهسازی تداخل ایجاد کند، و وضعیت داخلی برنامه را افشا کند.
درعوض، توصیه میکنیم بااستفاده از سرایندهای HTTP سفارشی، بافت برنامه را منتقل کنید. بااستفاده از
WebViewCompat.navigate و NavigationParameters، میتوانید این
دادهها را بهطور ایمن به سرورتان ارسال کنید. علاوهبراین، WebView این سرصفحهها را درطول بازیابی وضعیت حفظ میکند، که تضمین میکند محتوای وب در سراسر تغییرات پیکربندی ثابت باقی میماند. توجه داشته باشید که این پایداری فقط هنگام استفاده از
WebViewCompat.navigate اعمال میشود. اگر از WebView.loadUrl استفاده میکنید، سرصفحههای سفارشی در بسته حالت WebView ذخیره نمیشوند و پساز بازیابی ازبین میروند.
موارد استفاده رایج
موارد استفاده رایج برای ارسال بافت برنامه میزبان شامل موارد زیر است:
- نسخه برنامه (
X-App-Version): ارسال نسخه پخش برنامه میزبان (مانندBuildConfig.VERSION_NAME) به سرور زیرینه شما کمک میکند سازگاری پل جاوا اسکریپت بومی را تأیید کند، ویژگیها را کنترل کند، یا از کاربران بخواهد برنامههای قدیمیتر را بهروز کنند. - پلاتفرم کارخواه (
X-Client-Platform): شناسایی صریح محیط میزبان بهعنوان Android به سرور امکان میدهد تا میانای کاربری سفارشیشده برای پلاتفرم را ارائه دهد یا پیوندهای فروشگاه را بدون تکیه بر تجزیه رشتهUser-Agentمسیریابی کند.
نمونه پیادهسازی
مثال زیر نشان میدهد که چگونه نسخه برنامه و پلاتفرم مشتری را به سرور وب منتقل کنید:
کاتلین
// Attach host app metadata so the server can verify compatibility and tailor content
val params = NavigationParameters.Builder()
.addAdditionalHeaders(
mapOf(
"X-App-Version" to BuildConfig.VERSION_NAME,
"X-Client-Platform" to "Android"
)
)
.build()
// Use navigate instead of loadUrl to retain custom headers across state restoration
WebViewCompat.navigate(webView, "https://www.example.com", params)
جاوا
// Attach host app metadata so the server can verify compatibility and tailor content
Map<String, String> headers = new HashMap<>();
headers.put("X-App-Version", BuildConfig.VERSION_NAME);
headers.put("X-Client-Platform", "Android");
NavigationParameters params = new NavigationParameters.Builder()
.addAdditionalHeaders(headers)
.build();
// Use navigate instead of loadUrl to retain custom headers across state restoration
WebViewCompat.navigate(webView, "https://www.example.com", params);
حالتهای خرابی و رسیدگی به خطا
WebViewCompat.navigate API سازوکارهای متمایزی برای رسیدگی به
خطاهای پیکربندی و خرابیهای پیمایش زمان اجرا ارائه میدهد:
استثناهای متغیر مستقل نامعتبر
ارسال متغیرهای مستقل نامعتبر باعث راهاندازی IllegalArgumentException همگام میشود.
دلایل رایج شامل موارد زیر است:
- ارسال
nullبرای پارامترهای غیرتهی الزامی (webView،url، یاparams). - ارائه طرحواره نشانی وب پشتیبانینشده، مثل
javascript:. - ارسال کلیدها یا مقادیر سرایند HTTP بدشکل که با مشخصات RFC 2616 مطابقت ندارند.
خطاهای فرایند پیمایش
اگر درطول درخواست شبکه یا بار کردن صفحه خطایی رخ دهد (مانند کد وضعیت HTTP 404، خطای وضوح ساناد، یا خطای SSL)، WebViewCompat.navigate همچنان یک شیء Navigation معتبر برمیگرداند.
وقتی پیمایش تمام شد، روشهای زیر را در نمونه Navigation در داخل callback onNavigationCompleted خود بررسی کنید تا خرابی را تشخیص دهید:
getStatusCode: رمز وضعیت پاسخهای HTTP را برمیگرداند (برای مثال،404یا500).getWebResourceError: شیءWebResourceErrorCompatرا برمیگرداند که جزئیات خطاهای شبکه را نشان میدهد، مثل اتمام مهلت اتصال یا عدم موفقیت در جستجوی میزبان.didCommitErrorPage: نشان میدهد که آیاWebViewصفحه خطا را به کاربر نشان داده است یا نه.didCommit: نشان میدهد که آیا پیمایش با موفقیت به صفحه هدف منتقل شده است یا نه.
مدیریت بسته حالت ذخیره
وقتی سرایندهای اضافی را با NavigationParameters ارسال میکنید، WebView این سرایندها را در بسته حالت ذخیرهشده خود ذخیره میکند تا بتواند هنگام بازیابی حالت دوباره از آنها استفاده کند. بااینحال، مجموعههای بزرگ سرایندها میتوانند بهطور قابلتوجهی اندازه حالت ذخیرهشده Bundle را افزایش دهند.
اگر لازم است اندازه بسته را محدود کنید تا از TransactionTooLargeException
درطول ذخیره وضعیت Android جلوگیری کنید، از 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. این کار مدیریت یکنواخت سابقه را تضمین میکند و اطمینان میدهد که سرصفحهها همیشه بهعنوان بخشی از وضعیت ذخیرهشده ذخیره میشوند.همیشه پشتیبانی از ویژگی را تأیید کنید: قبلاز فراخوانی میانای برنامهسازی کاربردی، پشتیبانی زمان اجرا را با
WebViewFeature.isFeatureSupportedتأیید کنید تا دربرابر نسخههای قدیمیتر WebView محافظت شود.مرتبط کردن نمونههای پیمایش: از شیء
Navigationبرگرداندهشده برای متمایز کردن پیمایشهای همزمان یا فیلتر کردن فراخوانیهای برگشتی هنگام مدیریت چند نمونهWebViewاستفاده کنید.شنونده را یک بار درطول مقداردهی اولیه ثبت کنید: چون
WebViewCompat.addNavigationListenerشنونده اضافه میکند و شنونده موجود را جایگزین نمیکند،NavigationListenerرا یک بار درطول راهاندازیWebViewثبت کنید تا از نشت حافظه و اجرای تکراری فراخوانی برگشتی در پیمایشهای بعدی جلوگیری شود.اندازه وضعیت ذخیره را پایش کنید: هنگام ارسال محمولههای بزرگ سرصفحه، از
WebViewCompat.saveStateبا مرزهای اندازه صریح استفاده کنید تا از ذخیره کردن دادههای وضعیت بیشازحد جلوگیری شود.
منابع بیشتر
برای کسب اطلاعات بیشتر درباره قابلیتهای وب جاسازیشده و بهینهسازی عملکرد، راهنماهای زیر را ببینید:
- سادهسازی پیادهسازی WebView با Jetpack Webkit
- بار کردن حدسی در WebView
- بهینهسازی راهاندازی WebView
- رسیدگی به خاتمه فرایند پردازنده «وبنما»