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

اندروید چندین API ارائه می‌دهد تا به شما در مدیریت اشیاء WebView که محتوای وب را در برنامه شما نمایش می‌دهند، کمک کند.

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

نسخه API

از اندروید ۷.۰ (API سطح ۲۴)، کاربران می‌توانند از بین چندین بسته مختلف برای نمایش محتوای وب در یک شیء 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);

سرویس مرور امن گوگل

برای ارائه یک تجربه مرور امن‌تر به کاربران، اشیاء WebView با استفاده از مرور ایمن گوگل ، URLها را تأیید می‌کنند، که به برنامه شما اجازه می‌دهد هنگام تلاش برای پیمایش به یک وب‌سایت بالقوه ناامن، به کاربران هشدار دهد.

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

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

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

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

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

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

  • می‌توانید کنترل کنید که آیا برنامه شما تهدیدهای شناخته‌شده را به «مرور ایمن» گزارش دهد یا خیر.
  • شما می‌توانید کاری کنید که برنامه‌تان هر بار که با یک URL که به عنوان یک تهدید شناخته شده طبقه‌بندی شده است، مواجه می‌شود، به طور خودکار یک عمل خاص - مانند بازگشت به حالت امن - را انجام دهد.

قطعه کدهای زیر نشان می‌دهند که چگونه می‌توان به نمونه‌های 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();
        }
    }
}

API موقعیت جغرافیایی HTML5

برای برنامه‌هایی که اندروید ۶.۰ (سطح API ۲۳) و بالاتر را هدف قرار می‌دهند، API موقعیت جغرافیایی فقط در مبداهای امن، مانند HTTPS، پشتیبانی می‌شود. هرگونه درخواست به API موقعیت جغرافیایی در مبداهای غیر امن، بدون فراخوانی متد مربوطه onGeolocationPermissionsShowPrompt() ، به طور خودکار رد می‌شود.

انصراف از مجموعه معیارها

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

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

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

API مدیریت خاتمه

API مدیریت خاتمه مواردی را مدیریت می‌کند که در آن‌ها فرآیند رندرینگ برای یک شیء WebView از بین می‌رود، یا به این دلیل که سیستم رندرینگ را برای بازیابی حافظه لازم از بین می‌برد یا به این دلیل که فرآیند رندرینگ از کار می‌افتد. با استفاده از این API، به برنامه خود اجازه می‌دهید که حتی با وجود از بین رفتن فرآیند رندرینگ، به اجرای خود ادامه دهد.

اگر یک رندرکننده هنگام بارگذاری یک صفحه وب خاص از کار بیفتد، تلاش برای بارگذاری مجدد همان صفحه می‌تواند باعث شود یک شیء 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;
    }
}

API اهمیت رندرکننده

وقتی اشیاء WebView در حالت چندپردازشی کار می‌کنند ، شما در نحوه مدیریت موقعیت‌های کمبود حافظه در برنامه خود انعطاف‌پذیری دارید. می‌توانید از API اهمیت رندرکننده که در اندروید ۸.۰ معرفی شده است، برای تعیین یک سیاست اولویت برای رندرکننده اختصاص داده شده به یک شیء 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 نشان می‌دهد که برنامه شما اهمیتی نمی‌دهد که آیا سیستم فرآیند رندرکننده را زنده نگه می‌دارد یا خیر. در واقع، این سطح اولویت پایین‌تر باعث می‌شود که فرآیند رندرکننده در شرایط کمبود حافظه از بین برود.

برای کسب اطلاعات بیشتر در مورد نحوه مدیریت سیستم در شرایط کمبود حافظه، به بخش فرآیندها و چرخه حیات برنامه مراجعه کنید.