WebViewCompat.navigate یک جایگزین بهبود یافته برای WebView.loadUrl است که کنترل دقیقی بر بارگذاری صفحه وب، مدیریت تاریخچه و ردیابی چرخه حیات ناوبری در WebView ارائه میدهد.
پیش از این، شروع پیمایش صفحات با استفاده از loadUrl محدودیتهای قابل توجهی داشت:
- بدون جایگزینی ورودی تاریخچه: شما نمیتوانستید ورودی تاریخچه فعلی را جایگزین کنید، و این باعث میشد که بدون اضافه کردن یک ورودی به پشته، نتوانید به صفحه جدید بروید.
- فراخوانیهای جداگانه: هیچ مکانیسم مستقیمی برای مرتبط کردن یک فراخوانی
loadUrlخاص با رویدادهای فراخوانی بعدی درWebViewClientوجود نداشت. - هدرهای اضافی ذخیره نشدند: هدرهای سفارشی ارسال شده به
loadUrlبه عنوان بخشی از وضعیتWebViewذخیره نشدند، بنابراین هنگام بازیابی وضعیت از بین رفتند.
API مربوط به WebViewCompat.navigate با معرفی ویژگیهای زیر، این مشکلات را حل میکند:
- جایگزینی ورودی تاریخچه ناوبری: به شما امکان میدهد صفحه فعلی را در پشته تاریخچه
WebViewجایگزین کنید. - ردیابی فراخوانیهای همبسته: یک شیء
Navigationرا برمیگرداند که به عنوان یک شناسه منحصر به فرد در تمام مراحل چرخه حیات ناوبری عمل میکند. - پشتیبانی از هدر وضعیت ذخیرهشده: هدرهای اضافی بهطور قابل اعتمادی در بسته وضعیت
WebViewذخیره میشوند تا بتوان پس از بازیابی وضعیت، دوباره از آنها استفاده کرد.
قابلیتها و محدودیتهای کلیدی
قبل از اتخاذ WebViewCompat.navigate ، قوانین و محدودیتهای عملیاتی زیر را در نظر بگیرید:
ایمنی نخ: شما باید
WebViewCompat.navigateدر نخ UI (اصلی) فراخوانی کنید.لغو و اولویت: پیمایشهای درون برنامهای را نمیتوان به صراحت لغو کرد. با این حال، شروع یک فراخوانی
navigateجدید در همانWebView، هرگونه پیمایش فعال را لغو میکند.پشتیبانی از طرحوارههای URI: طرحوارههای URI استاندارد (مانند
https:وhttp::) و سفارشی پشتیبانی میشوند. طرحوارهjavascript:پشتیبانی نمیشود.محدودیت اندازه URL: حداکثر طول رشته URL پشتیبانی شده ۲ مگابایت است.
بررسی ویژگی: همیشه قبل از فراخوانی API، با استفاده از
WebViewFeature.isFeatureSupportedدر دسترس بودن ویژگی را بررسی کنید تا سازگاری بین نسخههای مختلف APK WebView حفظ شود.
شروع ناوبری و پیگیری چرخه حیات
برای پیکربندی ناوبری و پیگیری چرخه حیات آن، موارد زیر را انجام دهید:
- هنگام راهاندازی
WebViewبا استفاده ازWebViewCompat.addNavigationListenerیک پیادهسازیNavigationListenerثبت کنید تا فراخوانیهای چرخه عمر ساختاریافته را دریافت کنید. شنونده را یک بار (به جای هر فراخوانی ناوبری) ثبت کنید تا از نشت حافظه و اجرای تکراری فراخوانیها جلوگیری شود. - با استفاده از
NavigationParameters.Builderیک نمونهNavigationParametersبسازید تا رفتارهای اختیاری، مانند جایگزینی تاریخچه یا هدرهای HTTP سفارشی، را مشخص کنید. - با ارسال نمونه
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);
}
}
حالتهای خرابی و مدیریت خطا
API WebViewCompat.navigate مکانیزمهای متمایزی برای مدیریت خطاهای پیکربندی و خطاهای ناوبری زمان اجرا ارائه میدهد:
استثنائات آرگومان نامعتبر
ارسال آرگومانهای نامعتبر باعث ایجاد خطای IllegalArgumentException همزمان میشود. دلایل رایج آن عبارتند از:
- ارسال
nullبرای پارامترهای غیر null مورد نیاز (webView،urlیاparams). - ارائه یک طرح URL پشتیبانی نشده، مانند
javascript:. - ارسال کلیدهای هدر HTTP ناقص یا مقادیری که با مشخصات RFC 2616 مطابقت ندارند.
خطاهای فرآیند ناوبری
اگر در طول درخواست شبکه یا بارگذاری صفحه، خطایی رخ دهد (مانند کد وضعیت HTTP 404، خطای DNS resolution یا خطای SSL)، WebViewCompat.navigate همچنان یک شیء Navigation معتبر را برمیگرداند.
وقتی پیمایش تمام شد، متدهای زیر را در نمونهی Navigation درون فراخوانی onNavigationCompleted خود بررسی کنید تا مشکل را تشخیص دهید:
-
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، پشتیبانی زمان اجرا را با
WebViewFeature.isFeatureSupportedتأیید کنید تا در برابر نسخههای قدیمیتر WebView محافظت شوید.مرتبط کردن نمونههای ناوبری: از شیء
Navigationبازگشتی برای تمایز ناوبریهای همزمان یا فیلتر کردن فراخوانیهای برگشتی هنگام مدیریت چندین نمونهWebViewاستفاده کنید.یک بار در طول مقداردهی اولیه، شنونده را ثبت کنید: از آنجا که
WebViewCompat.addNavigationListenerبه جای جایگزینی یک شنونده موجود، یک شنونده اضافه میکند،NavigationListenerخود را یک بار در طول راهاندازیWebViewثبت کنید تا از نشت حافظه و تکرار اجراهای callback در پیمایشهای بعدی جلوگیری شود.نظارت بر اندازه وضعیت ذخیره: هنگام ارسال بارهای هدر بزرگ، از
WebViewCompat.saveStateبا مرزهای اندازه صریح استفاده کنید تا از ذخیره دادههای وضعیت بیش از حد جلوگیری شود.
منابع اضافی
برای کسب اطلاعات بیشتر در مورد قابلیتهای وب تعبیهشده و بهینهسازی عملکرد، به راهنماهای زیر مراجعه کنید:
- پیادهسازی WebView خود را با Jetpack Webkit ساده کنید
- بارگذاری حدسی در وب ویو
- بهینهسازی راهاندازی WebView
- مدیریت خاتمه فرآیند رندر WebView