Android มี API หลายรายการที่จะช่วยคุณจัดการออบเจ็กต์ WebView ที่แสดงเนื้อหาเว็บในแอป
หน้านี้อธิบายวิธีใช้ API เหล่านี้เพื่อทำงานกับออบเจ็กต์ WebView ได้อย่างมีประสิทธิภาพมากขึ้น ซึ่งจะช่วยปรับปรุงความเสถียรและความปลอดภัยของแอป
เวอร์ชัน API
ตั้งแต่ Android 7.0 (ระดับ API 24) เป็นต้นไป ผู้ใช้สามารถเลือกแพ็กเกจต่างๆ เพื่อแสดงเนื้อหาเว็บในออบเจ็กต์ WebView ได้
ไลบรารี Jetpack Webkit
มีเมธอด
getCurrentWebViewPackage()
สำหรับดึงข้อมูลที่เกี่ยวข้องกับแพ็กเกจที่แสดงเนื้อหาเว็บ
ในแอป เมธอดนี้มีประโยชน์เมื่อวิเคราะห์ข้อผิดพลาดที่เกิดขึ้นเฉพาะ
เมื่อแอปพยายามแสดงเนื้อหาเว็บโดยใช้การติดตั้งใช้งาน WebView ของแพ็กเกจหนึ่งๆ
หากต้องการใช้เมธอดนี้ ให้เพิ่มตรรกะที่แสดงในข้อมูลโค้ดต่อไปนี้
Kotlin
val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext) Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")
Java
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext); Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
บริการ Google Safe Browsing
ออบเจ็กต์ WebView
จะตรวจสอบ URL โดยใช้
Google Safe Browsing เพื่อมอบประสบการณ์การท่องเว็บที่ปลอดภัยยิ่งขึ้นให้แก่ผู้ใช้
ซึ่งจะช่วยให้แอปแสดงคำเตือนแก่ผู้ใช้เมื่อพยายามไปยังเว็บไซต์ที่
อาจไม่ปลอดภัย
แม้ว่าค่าเริ่มต้นของ EnableSafeBrowsing จะเป็น "จริง" แต่ก็มีบางกรณีที่คุณอาจต้องการเปิดใช้ Google Safe Browsing แบบมีเงื่อนไขเท่านั้นหรือปิดใช้ไปเลย Android 8.0 (ระดับ API 26) ขึ้นไปรองรับการใช้
setSafeBrowsingEnabled()
เพื่อสลับ Google Safe Browsing สำหรับออบเจ็กต์ WebView แต่ละรายการ
หากต้องการให้ออบเจ็กต์ WebView ทั้งหมดเลือกไม่ใช้การตรวจสอบ Google Safe Browsing ให้เพิ่มองค์ประกอบ <meta-data> ต่อไปนี้ลงในไฟล์ Manifest ของแอป
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
กำหนดการดำเนินการแบบเป็นโปรแกรม
เมื่ออินสแตนซ์ของ WebView พยายามโหลดหน้าที่ Google จัดประเภทเป็นภัยคุกคามที่ทราบ WebView จะแสดงโฆษณาคั่นระหว่างหน้าซึ่งเตือนผู้ใช้ถึงภัยคุกคามที่ทราบโดยค่าเริ่มต้น หน้าจอนี้จะให้ตัวเลือกแก่ผู้ใช้ในการโหลด URL ต่อไปหรือกลับไปยังหน้าที่ปลอดภัยก่อนหน้านี้
หากกำหนดเป้าหมายเป็น Android 8.1 (ระดับ API 27) ขึ้นไป คุณสามารถกำหนดแบบเป็นโปรแกรมได้ว่าแอปจะตอบสนองต่อภัยคุกคามที่ทราบอย่างไรในลักษณะต่อไปนี้
- คุณสามารถควบคุมได้ว่าแอปจะรายงานภัยคุกคามที่ทราบไปยัง Safe Browsing หรือไม่
- คุณสามารถตั้งค่าให้แอปดำเนินการบางอย่างโดยอัตโนมัติ เช่น กลับไปที่หน้าปลอดภัย ทุกครั้งที่พบ URL ที่จัดประเภทเป็นภัยคุกคามที่ทราบ
ข้อมูลโค้ดต่อไปนี้แสดงวิธีตั้งค่าให้อินสแตนซ์ WebView ของแอปกลับไปที่หน้าปลอดภัยเสมอหลังจากพบภัยคุกคามที่ทราบ
MyWebActivity.java
Kotlin
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!") } }) } }
Java
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
Kotlin
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() } } }
Java
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) ขึ้นไป ระบบจะรองรับ Geolocation API ในต้นทางที่ปลอดภัย เช่น HTTPS เท่านั้น ระบบจะปฏิเสธคำขอที่ส่งไปยัง Geolocation API ในต้นทางที่ไม่ปลอดภัยโดยอัตโนมัติโดยไม่เรียกใช้เมธอด onGeolocationPermissionsShowPrompt() ที่เกี่ยวข้อง
เลือกไม่ใช้การเก็บรวบรวมเมตริก
WebView สามารถอัปโหลดข้อมูลการวินิจฉัยที่ไม่ระบุตัวตนไปยัง Google ได้เมื่อผู้ใช้ให้ความยินยอม ระบบจะเก็บรวบรวมข้อมูลตามแอปสำหรับแต่ละแอปที่สร้างอินสแตนซ์ WebView คุณสามารถเลือกไม่ใช้ฟีเจอร์นี้ได้โดยสร้างแท็กต่อไปนี้ในองค์ประกอบของ Manifest
<application>
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
ระบบจะอัปโหลดข้อมูลจากแอปก็ต่อเมื่อผู้ใช้ให้ความยินยอม และ แอปไม่ได้เลือกไม่ใช้ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเลือกไม่ใช้การรายงานข้อมูลการวินิจฉัย ได้ที่ ความเป็นส่วนตัวของผู้ใช้ในการรายงาน WebView
Termination Handling API
Termination Handling API จะจัดการกรณีที่กระบวนการแสดงผลสำหรับออบเจ็กต์ WebView หายไป ไม่ว่าจะเป็นเพราะระบบตัดกระบวนการแสดงผลเพื่อเรียกคืนหน่วยความจำที่จำเป็น หรือกระบวนการแสดงผลขัดข้อง การใช้ API นี้จะช่วยให้แอปทำงานต่อไปได้แม้ว่ากระบวนการแสดงผลจะหายไป
หากการแสดงผลขัดข้องขณะโหลดหน้าเว็บหนึ่งๆ การพยายามโหลดหน้าเดียวกันอีกครั้งอาจทำให้เกิดพฤติกรรมการแสดงผลขัดข้องแบบเดียวกันในออบเจ็กต์ WebView ใหม่
ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้ API นี้ภายใน Activity
Kotlin
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 } }
Java
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 เพื่อกำหนดนโยบายลำดับความสำคัญสำหรับ Renderer ที่กำหนดให้กับออบเจ็กต์ WebView หนึ่งๆ โดยเฉพาะอย่างยิ่ง คุณอาจต้องการให้ส่วนหลักของแอปทำงานต่อไปเมื่อ Renderer ที่แสดงออบเจ็กต์ WebView ของแอปถูกตัด คุณอาจทำเช่นนี้ในกรณีที่คุณคาดว่าจะไม่แสดงออบเจ็กต์ WebView เป็นเวลานาน เพื่อให้ระบบเรียกคืนหน่วยความจำที่ Renderer ใช้ได้
ข้อมูลโค้ดต่อไปนี้แสดงวิธีกำหนดลำดับความสำคัญให้กับกระบวนการแสดงผลที่เชื่อมโยงกับออบเจ็กต์ WebView ของแอป
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
ในข้อมูลโค้ดนี้ ลำดับความสำคัญของ Renderer จะเท่ากับหรือเชื่อมโยงกับลำดับความสำคัญเริ่มต้นของแอป อาร์กิวเมนต์ true จะลดลำดับความสำคัญของ Renderer เป็น RENDERER_PRIORITY_WAIVED เมื่อออบเจ็กต์ WebView ที่เชื่อมโยงไม่ปรากฏอีกต่อไป กล่าวอีกนัยหนึ่งคือ อาร์กิวเมนต์ true บ่งชี้ว่าแอปไม่สนใจว่าระบบจะรักษากระบวนการแสดงผลให้ทำงานต่อไปหรือไม่ อันที่จริง ระดับความสำคัญที่ต่ำกว่านี้ทำให้มีแนวโน้มที่กระบวนการแสดงผลจะถูกตัดในสถานการณ์ที่หน่วยความจำไม่เพียงพอ
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ระบบจัดการกับสถานการณ์ที่หน่วยความจำเหลือน้อยได้ที่ กระบวนการและวงจรการทำงานของแอป