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

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

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

نسخه API

با شروع Android 7.0 (سطح API 24)، کاربران می توانند از بین چندین بسته مختلف برای نمایش محتوای وب در یک شی WebView انتخاب کنند. کتابخانه AndroidX.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 نشانی‌های وب را با استفاده از مرور ایمن Google تأیید می‌کنند، که به برنامه شما اجازه می‌دهد وقتی کاربران سعی می‌کنند به یک وب‌سایت بالقوه ناامن حرکت کنند، هشداری را نشان دهد.

اگرچه مقدار پیش‌فرض EnableSafeBrowsing درست است، اما مواردی وجود دارد که ممکن است بخواهید فقط مرور ایمن را به صورت مشروط فعال کنید یا آن را غیرفعال کنید. Android 8.0 (سطح API 26) و نسخه های جدیدتر از استفاده از setSafeBrowsingEnabled() برای تغییر وضعیت Safe Browsing برای یک شی WebView منفرد پشتیبانی می کند.

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

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

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

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

اگر Android 8.1 (سطح API 27) یا جدیدتر را هدف قرار می‌دهید، می‌توانید به روش‌های زیر نحوه پاسخ برنامه‌تان به یک تهدید شناخته‌شده را به صورت برنامه‌نویسی تعریف کنید:

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

قطعه کد زیر نشان می‌دهد که چگونه به نمونه‌های برنامه 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 (سطح API 23) و جدیدتر را هدف قرار می‌دهند، API مکان جغرافیایی فقط در منابع امن مانند HTTPS پشتیبانی می‌شود. هرگونه درخواست به API Geolocation در مبداهای غیر ایمن به طور خودکار بدون فراخوانی متد مربوطه onGeolocationPermissionsShowPrompt() رد می شود.

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

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

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

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

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

Termination Handling 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;
    }
}

Renderer Importance API

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

قطعه کد زیر نحوه اختصاص اولویت به فرآیند رندر مرتبط با اشیاء WebView برنامه شما را نشان می دهد:

کاتلین

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

جاوا

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

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

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