مدیریت اشیاء WebView

Android چندین میانای برنامه‌سازی کاربردی ارائه می‌دهد تا به شما کمک کند WebView اشیاء نمایش‌دهنده محتوای وب را در برنامه‌تان مدیریت کنید.

این صفحه نحوه استفاده از این میاناهای برنامه‌سازی کاربردی را برای کار کردن مؤثرتر با اشیای WebView شرح می‌دهد و پایداری و امنیت برنامه‌تان را بهبود می‌بخشد.

Version API

از Android 7.0 (سطح API 24) به بعد، کاربران می‌توانند از بین چندین بسته مختلف برای نمایش محتوای وب در یک شیء WebView انتخاب کنند. کتابخانه Jetpack Webkit شامل روش getCurrentWebViewPackage() برای واکشی اطلاعات مربوط به بسته‌ای است که محتوای وب را در برنامه‌تان نمایش می‌دهد. این روش هنگام تجزیه‌وتحلیل خطاهایی که فقط زمانی رخ می‌دهند که برنامه‌تان سعی می‌کند محتوای وب را بااستفاده از پیاده‌سازی WebView بسته خاصی نمایش دهد مفید است.

برای استفاده از این روش، منطق نشان‌داده‌شده در تکه‌کد زیر را اضافه کنید:

کاتلین

val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext)
Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")

جاوا

PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext);
Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);

خدمات مرور ایمن Google

برای ارائه تجربه مرور ایمن‌تر به کاربران، WebView اشیا نشانی‌های وب را بااستفاده از مرور ایمن Google درستی‌سنجی می‌کنند، که به برنامه شما امکان می‌دهد وقتی کاربران سعی می‌کنند به وب‌سایت بالقوه ناایمنی پیمایش کنند، به آن‌ها هشدار نشان دهد.

اگرچه مقدار پیش‌فرض EnableSafeBrowsing درست است، مواردی وجود دارد که ممکن است بخواهید «مرور ایمن» را فقط به‌صورت شرطی فعال کنید یا آن را غیرفعال کنید. Android نسخه ۸.۰ (سطح میانای برنامه‌سازی کاربردی ۲۶) و نسخه‌های بالاتر از استفاده از setSafeBrowsingEnabled() برای روشن/خاموش کردن «مرور ایمن» برای شیء WebView تکی پشتیبانی می‌کند.

اگر می‌خواهید همه WebView شیء از بررسی‌های «مرور ایمن» انصراف دهند، عنصر <meta-data> زیر را به فایل مانیفست برنامه‌تان اضافه کنید:

<manifest>
    <application>
        <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
                   android:value="false" />
        ...
    </application>
</manifest>

تعریف کردن کنش‌های برنامه‌ای

وقتی نمونه‌ای از WebView تلاش می‌کند صفحه‌ای را بار کند که توسط Google به‌عنوان تهدید شناخته‌شده طبقه‌بندی شده است، WebView به‌طور پیش‌فرض میان‌آگهی‌ای نشان می‌دهد که به کاربران درباره تهدید شناخته‌شده هشدار می‌دهد. این صفحه به کاربران امکان می‌دهد نشانی وب را درهرصورت بار کنند یا به صفحه قبلی که ایمن است برگردند.

اگر Android نسخه ۸.۱ (سطح میانای برنامه کاربردی ۲۷) یا بالاتر را هدف‌یابی می‌کنید، می‌توانید به‌صورت برنامه‌نویسی‌شده نحوه پاسخ برنامه‌تان به تهدید شناخته‌شده را به روش‌های زیر تعریف کنید:

  • می‌توانید کنترل کنید که برنامه‌تان تهدیدهای شناخته‌شده را به «مرور ایمن» گزارش کند یا نه.
  • می‌توانید برنامه‌تان را طوری تنظیم کنید که هر بار با نشانی وبی که به‌عنوان تهدید شناخته‌شده طبقه‌بندی شده است مواجه می‌شود، به‌طور خودکار کنش خاصی (مثلاً برگشتن به حالت ایمن) انجام دهد.

تکه‌کدهای زیر نشان می‌دهد چگونه به نمونه‌های برنامه خودتان از WebView دستور دهید که پس‌از مواجهه با تهدید شناخته‌شده همیشه به وضعیت ایمن برگردد:

MyWebActivity.java

کاتلین

private lateinit var superSafeWebView: WebView
private var safeBrowsingIsInitialized: Boolean = false

// ...

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    superSafeWebView = WebView(this)
    superSafeWebView.webViewClient = MyWebViewClient()
    safeBrowsingIsInitialized = false

    if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
        WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { success ->
            safeBrowsingIsInitialized = true
            if (!success) {
                Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!")
            }
        })
    }
}

جاوا

private WebView superSafeWebView;
private boolean safeBrowsingIsInitialized;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    superSafeWebView = new WebView(this);
    superSafeWebView.setWebViewClient(new MyWebViewClient());
    safeBrowsingIsInitialized = false;

    if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
        WebViewCompat.startSafeBrowsing(this, new ValueCallback<Boolean>() {
            @Override
            public void onReceiveValue(Boolean success) {
                safeBrowsingIsInitialized = true;
                if (!success) {
                    Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!");
                }
            }
        });
    }
}

MyWebViewClient.java

کاتلین

class MyWebViewClient : WebViewClientCompat() {
    // Automatically go "back to safety" when attempting to load a website that
    // Google identifies as a known threat. An instance of WebView calls this
    // method only after Safe Browsing is initialized, so there's no conditional
    // logic needed here.
    override fun onSafeBrowsingHit(
            view: WebView,
            request: WebResourceRequest,
            threatType: Int,
            callback: SafeBrowsingResponseCompat
    ) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) {
            callback.backToSafety(true)
            Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show()
        }
    }
}

جاوا

public class MyWebViewClient extends WebViewClientCompat {
    // Automatically go "back to safety" when attempting to load a website that
    // Google identifies as a known threat. An instance of WebView calls this
    // method only after Safe Browsing is initialized, so there's no conditional
    // logic needed here.
    @Override
    public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
            int threatType, SafeBrowsingResponseCompat callback) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) {
            callback.backToSafety(true);
            Toast.makeText(view.getContext(), "Unsafe web page blocked.",
                    Toast.LENGTH_LONG).show();
        }
    }
}

HTML5 Geolocation API

برای برنامه‌هایی که Android 6.0 (سطح میانای برنامه کاربردی ۲۳) و نسخه‌های بالاتر را هدف‌یابی می‌کنند، «میانای برنامه کاربردی جغرافیایی» فقط در مبدأهای امن، مثل HTTPS، پشتیبانی می‌شود. هرگونه درخواست به Geolocation API در مبدأهای ناامن به‌طور خودکار و بدون فراخوانی روش onGeolocationPermissionsShowPrompt() مربوطه رد می‌شود.

انصراف دادن از جمع‌آوری سنجه‌ها

WebView این قابلیت را دارد که وقتی کاربر رضایت می‌دهد داده‌های عیب‌یابی ناشناس را در Google بارگذاری کند. داده‌ها به‌صورت هر برنامه برای هر برنامه‌ای که WebView را نمونه‌سازی می‌کند جمع‌آوری می‌شود. با ایجاد برچسب زیر در عنصر <application> بیانیه می‌توانید از این ویژگی انصراف دهید:

<manifest>
    <application>
    ...
    <meta-data android:name="android.webkit.WebView.MetricsOptOut"
               android:value="true" />
    </application>
</manifest>

داده‌ها فقط درصورتی از برنامه بارگذاری می‌شود که کاربر موافقت کند و برنامه انصراف ندهد. برای اطلاعات بیشتر درباره انصراف از گزارش داده‌های عیب‌یابی، به حریم خصوصی کاربر در گزارش WebView مراجعه کنید.

Termination Handling API

«میانای برنامه‌سازی کاربردی مدیریت خاتمه» مواردی را که در آن‌ها فرایند تولیدکننده تصویر برای WebView شیء ازدست می‌رود مدیریت می‌کند، چه به‌دلیل اینکه سیستم تولیدکننده تصویر را برای بازپس‌گیری حافظه لازم متوقف می‌کند یا به‌دلیل اینکه فرایند تولیدکننده تصویر ازکار می‌افتد. بااستفاده از این میانای برنامه‌سازی کاربردی، به برنامه‌تان اجازه می‌دهید به اجرا ادامه دهد، حتی اگر فرایند پردازنده گرافیکی ازبین برود.

اگر پردازنده گرافیکی هنگام بار کردن صفحه وب خاصی از کار بیفتد، تلاش برای بار کردن مجدد همان صفحه می‌تواند باعث شود شیء WebView جدیدی همان رفتار ازکارافتادن پردازنده گرافیکی را نشان دهد.

تکه‌کد زیر نشان می‌دهد که چگونه از این API در Activity استفاده کنید:

کاتلین

    
inner class MyRendererTrackingWebViewClient : WebViewClient() {
    private var mWebView: WebView? = null

    override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean {
        if (!detail.didCrash()) {
            // Renderer is killed because the system ran out of memory. The app
            // can recover gracefully by creating a new WebView instance in the
            // foreground.
            Log.e("MY_APP_TAG", ("System killed the WebView rendering process " +
                "to reclaim memory. Recreating..."))

            mWebView?.also { webView ->
                val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container)
                webViewContainer.removeView(webView)
                webView.destroy()
                mWebView = null
            }

            // By this point, the instance variable "mWebView" is guaranteed to
            // be null, so it's safe to reinitialize it.

            return true // The app continues executing.
        }

        // Renderer crashes because of an internal error, such as a memory
        // access violation.
        Log.e("MY_APP_TAG", "The WebView rendering process crashed!")

        // In this example, the app itself crashes after detecting that the
        // renderer crashed. If you handle the crash more gracefully and let
        // your app continue executing, you must destroy the current WebView
        // instance, specify logic for how the app continues executing, and
        // return "true" instead.
        return false
    }
}

جاوا

public class MyRendererTrackingWebViewClient extends WebViewClient {
    private WebView mWebView;

    @Override
    public boolean onRenderProcessGone(WebView view,
            RenderProcessGoneDetail detail) {
        if (!detail.didCrash()) {
            // Renderer is killed because the system ran out of memory. The app
            // can recover gracefully by creating a new WebView instance in the
            // foreground.
            Log.e("MY_APP_TAG", "System killed the WebView rendering process " +
                    "to reclaim memory. Recreating...");

            if (mWebView != null) {
                ViewGroup webViewContainer =
                        (ViewGroup) findViewById(R.id.my_web_view_container);
                webViewContainer.removeView(mWebView);
                mWebView.destroy();
                mWebView = null;
            }

            // By this point, the instance variable "mWebView" is guaranteed to
            // be null, so it's safe to reinitialize it.

            return true; // The app continues executing.
        }

        // Renderer crashes because of an internal error, such as a memory
        // access violation.
        Log.e("MY_APP_TAG", "The WebView rendering process crashed!");

        // In this example, the app itself crashes after detecting that the
        // renderer crashed. If you handle the crash more gracefully and let
        // your app continue executing, you must destroy the current WebView
        // instance, specify logic for how the app continues executing, and
        // return "true" instead.
        return false;
    }
}

Renderer Importance API

وقتی WebView شیء در حالت چندپردازشی عمل می‌کند، در نحوه مدیریت وضعیت‌های کمبود حافظه در برنامه‌تان انعطاف‌پذیری دارید. می‌توانید از «میانای برنامه‌سازی کاربردی اهمیت رندرکننده» که در Android 8.0 معرفی شده است برای تنظیم خط‌مشی اولویت برای رندرکننده اختصاص‌داده‌شده به یک شیء WebView خاص استفاده کنید. به‌طور خاص، ممکن است بخواهید بخش اصلی برنامه شما وقتی که یک رندرکننده که اشیاء WebView برنامه شما را نمایش می‌دهد کشته می‌شود، به اجرا ادامه دهد. برای مثال، اگر انتظار دارید شیء WebView را برای مدت طولانی نشان ندهید، ممکن است این کار را انجام دهید تا سیستم بتواند حافظه‌ای را که پردازنده استفاده می‌کرد بازیابی کند.

تکه‌کد زیر نشان می‌دهد چگونه اولویتی را به فرایند پردازنده گرافیکی مرتبط با اشیای WebView برنامه‌تان اختصاص دهید:

کاتلین

val myWebView: WebView = ...
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)

جاوا

WebView myWebView;
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);

در این قطعه کد خاص، اولویت پردازنده با اولویت پیش‌فرض برنامه یکسان است یا به آن محدود شده است. آرگومان true اولویت پردازنده را به RENDERER_PRIORITY_WAIVED کاهش می‌دهد وقتی شیء WebView مرتبط دیگر قابل‌مشاهده نباشد. به‌عبارت دیگر، یک آرگومان true نشان می‌دهد که برنامه شما اهمیتی نمی‌دهد که سیستم فرایند رندرکننده را زنده نگه دارد یا نه. درواقع، این سطح اولویت پایین‌تر احتمال اینکه روند پردازش تصویر در شرایط کمبود حافظه متوقف شود را افزایش می‌دهد.

برای کسب اطلاعات بیشتر درباره تشخیص و بهینه‌سازی ردپای حافظه برنامه هنگام استفاده از محتوای وب، به مدیریت و تشخیص حافظه «وب‌نما» مراجعه کنید. برای کسب اطلاعات بیشتر درباره نحوه مدیریت شرایط کمبود حافظه در فرایندها توسط سیستم، به فرایندها و چرخه حیات برنامه مراجعه کنید.

حفظ وضعیت و سابقه پیمایش

وقتی سیستم منابع پس‌زمینه را پس می‌گیرد یا دستگاه تحت تغییر پیکربندی قرار می‌گیرد، ممکن است فعالیت برنامه و اشیای WebView آن ازبین برود. برای حفظ بافت پیمایش کاربر، از روش saveState(Bundle) در onSaveInstanceState() استفاده کنید تا سابقه پیمایش را به Bundle تبدیل کنید و سپس آن را بااستفاده از restoreState(Bundle) بازیابی کنید.

ازآنجایی‌که Android در کل فرایند برای savedInstanceState محدودیت سخت‌گیرانه ۱ مگابایتی اعمال می‌کند، سریال‌سازی جلسات مرور بزرگ با میانای برنامه‌سازی کاربردی چارچوب استاندارد می‌تواند منجر به TransactionTooLargeException شود. برای اعمال محدودیت‌های اندازه یا حذف ایمن ورودی‌های سابقه جلوبردن، از روش Jetpack Webkit WebViewCompat.saveState() استفاده کنید.

برای استراتژی‌های دقیق و روال‌های مطلوب درباره مدیریت کارآمد وضعیت، به مدیریت کارآمد وضعیت WebView مراجعه کنید.