บทความนี้จะพูดถึง Android WebView บน Android 5.0 Lollipop (API Level 21) เป็นต้นไป

เรามักจะพบว่าการพัฒนาแอปบนแอนดรอยด์ มักจะมีบางฟีเจอร์ที่ไม่เหมาะกับการใส่ไว้ในแอปซักเท่าไร และฟีเจอร์เหล่านั้นก็จะเหมาะกับการทำเป็นเว็ปแล้วแสดงผลบน WebView ภายในแอปซะมากกว่า แถมรองรับได้ทั้ง Android และ iOS ซะด้วย

โดย WebView บน iOS จะใช้ WebKit Framework บน iOS เป็นเบื้องหลัง ส่วน WebView บน Android จะเป็น Chromium แทน

เพื่อความกระชับของตัวหนังสือ ขอเรียก "Android WebView" ว่า "WebView" และเรียก "แอป Chrome for Android" ว่า "Chrome"

และถึงแม้ว่านักพัฒนาจะใช้ WebView เพื่อแสดงเว็ปในแอปแอนดรอยด์ได้ก็ตาม แต่จริง ๆ แล้ว WebView ที่แอปใด ๆ ก็เรียกใช้งานได้กับ Chrome นั้นไม่เหมือนกัน

นั่นก็คือที่มาของบทความนี้ เพื่อให้ผู้ที่หลงเข้ามาอ่านเข้าใจถึงความแตกต่างระหว่างทั้งคู่ และเข้าใจว่าทำไมเว็ปเดียวกันแต่เปิดบน WebView และ Chrome อาจจะทำงานได้ไม่เท่ากัน

WebView เป็นแค่ View ตัวหนึ่งบน Android UI System

WebView เป็น View ตัวหนึ่งที่มีความสามารถของ Chromium (Chromium Embedder) เพื่อรองรับการแสดงหน้าเว็ป แต่ Chromium Embedder ที่ว่านี้ก็ไม่ได้มีโครงสร้างและความสามารถเหมือนกับ Chrome แต่อย่างใด (อ้างอิงจากโครงสร้างของ WebView และ Chrome)

และนับตั้งแต่ Android 5.0 Lollipop (API Leve 21) เป็นต้นมา การทำงานของ WebView ถูกแยกออกจากระบบแอนดรอยด์ ทำให้ WebView กลายเป็นแอปตัวหนึ่งบนแอนดรอยด์แทน โดยมีจุดประสงค์หลักคือให้ผู้ใช้สามารถอัปเดต WebView เพื่อรองรับ Chromium เวอร์ชันใหม่ได้ตลอดเวลา

นั่นจึงเป็นที่มาของแอป Android System WebView ที่มีอยู่ในอุปกรณ์แอนดรอยด์ทุกเครื่อง ทำให้ในปัจุบันไม่ว่าเป็นผู้ใช้อุปกรณ์แอนดรอยด์เวอร์ชันใดก็ตาม ก็สามารถอัปเดต WebView ให้รองรับกับ Chromium เวอร์ชันใหม่ที่ปล่อยอัปเดตพร้อมกับ Chrome ช่วยลดช่องว่างระหว่างความสามารถที่มีให้ใช้ใน WebView และ Chrome ให้น้อยลง

รวมไปถึง Android Nougar 7.0 ที่จะใช้ Chrome แทนบนเครื่องที่มี Chrome ติดตั้งอยู่เพื่อลดการทำงานที่ซ้ำซ้อนกัน

แต่อย่างไรก็ตาม ปัญหาจากความแตกต่างในการทำงานระหว่าง Chrome กับ WebView ก็ยังคงมีอยู่ดี...

เปลี่ยนตัวเลือกจาก Chrome มาใช้ Trichrome บน Android 10

จากที่บอกไปก่อนหน้านี้ว่าถ้าในเครื่องมีแอป Chrome ก็จะใช้ Render Engine ของ Chrome แทน Android System WebView แต่บน Android 10 เป็นต้นมา ทีมพัฒนาตัดสินใจเปลี่ยนจาก Chrome ไปใช้เป็น Trichrome ที่เป็น Render Engine แยกออกมาเพื่อเป็น Shared Code ใช้ร่วมกันระหว่าง Android WebView กับ Chrome อีกที

และนี่จึงเป็นอีกสาเหตุที่ทำให้การทำงานของเว็ปบน Android WebView อาจจะไม่ได้ผลลัพธ์ที่เหมือนกับบน Chrome เสมอไป

Web Technologies และ API ที่รองรับบน Chrome for Android ไม่ได้รองรับบน Android WebView เสมอไป

เนื่องจากเบื้องหลังการทำงานของ Android WebView กับแอป Chrome นั้นต่างกัน จึงเป็นเรื่องปกติที่นักพัฒนาเว็ปจะเจอปัญหาว่า API บางอย่างสามารถใช้บนแอป Chrome ได้ แต่ใช้บน Android WebView ไม่ได้ ยกตัวอย่างเช่น Web Share API เป็นต้น

Web Share API - Web APIs | MDN
The Web Share API provides a mechanism for sharing text, links, files, and other content to an arbitrary share target selected by the user.

ดังนั้นสำหรับนักพัฒนาเว็ปจึงไม่ควรเชื่อใจ Android WebView เทียบเท่ากับ Chrome และควรเช็คผ่านเว็ป Can I Use ก่อนเสมอ เพราะจะมีบอกข้อมูลของ Android WebView แยกออกมาจาก Chrome ให้ด้วย โดยในนั้นจะเรียกว่า Android Browser

ในขณะเดียวกันก็ต้องเช็คควบคู่กับ WebView ของ iOS ด้วยเช่นกัน เพราะในบางครั้งก็มีบางฟีเจอร์ที่สามารถใช้บน iOS ได้ แต่บน Android ไม่รองรับ อย่างเช่น Web Share API ที่เจ้าของบล็อกยกตัวอย่างขึ้นมาในตอนแรกนั่นเอง

765923 - chromium - An open-source project to help move the web forward. - Monorail

ในกรณีนี้จึงทำให้นักพัฒนาเว็ปต้องแก้ปัญหาเฉพาะหน้าด้วยการแยกโค้ดระหว่าง 2 Platform ออกจากกัน เพื่อให้เรียกใช้งานด้วยคนละวิธีเท่าที่ Platform นั้นจะรองรับได้

ทำให้ Android WebView รองรับ Android Intent  แบบ Chrome ได้เหมือนกันนะ

โดยปกติแล้วนักพัฒนามักจะใช้ Javascript Interface เพื่อให้เว็ปที่เปิดบน WebView ส่งข้อมูลหรือเรียกคำสั่งบางอย่างบนแอปแอนดรอยด์ได้ แต่ในกรณีที่ต้องการใช้งาน Android Intent แบบเดียวกับ Chrome ก็สามารถใช้ได้เช่นกัน

Android Intents with Chrome - Chrome Developers
How to launch Android apps directly from a web page.

แต่มีเงื่อนไขว่า WebView จะต้องเพิ่มโค้ดดัก URL Scheme ที่เป็น intent:// เพื่อนำไปสร้างเป็น Intent ผ่านโค้ดฝั่งแอนดรอยด์อีกที

const val INTENT_SCHEME = "intent://"

val defaultWebViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
        val url = request?.url?.toString()
        when {
            url?.startsWith(INTENT_SCHEME) == true -> {
                startWebIntent(url)
                return true
            }
            /* ... */
        }
        return super.shouldOverrideUrlLoading(view, request)
    }

    override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
        when {
            url.startsWith(INTENT_SCHEME) -> {
                startWebIntent(url)
                return true
            }
            /* ... */
        }
        return super.shouldOverrideUrlLoading(view, url)
    }
}

fun startWebIntent(url: String) {
    try {
        val intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
        startActivity(intent)
    } catch (e: ActivityNotFoundException) {
        intent.getPackage()?.let { packageName ->
            val marketIntent = Intent(Intent.ACTION_VIEW, "market://details?id=${packageName}".toUri())
            startActivity(marketIntent)
        }
    }
}

Chrome Custom Tabs ไม่ใช่ Android WebView แต่เป็น Chrome for Android

Custom Tabs เป็นหนึ่งในความสามารถของ Chrome for Android ที่ให้แอปสามารถเปิดเว็ปจากในแอปตัวเองได้ ซึ่งต่างจากการเปิดเว็ปบน Android WebView ตรงที่การใช้ Custom Tabs จะทำงานอยู่บน Chrome เหมือนกับเปิดหน้าเว็ปนั้นบนแอป Chrome โดยตรง จึงทำให้หน้าเว็ปดังกล่าวสามารถใช้ความสามารถบน Chrome ได้เต็มที่

การใช้ Custom Tabs จะพบได้บ่อยในแอปที่มี User-generated Content โดยเวลากดดูเนื้อหาใด ๆ ที่สามารถเปิดเว็ปได้ ก็จะเปิดบน In-app Browser แทนที่จะเปิด Default Browser ของแต่ละเครื่อง

ในกรณีที่อยากรู้ว่าแอปมีการใช้ Custom Tabs หรือไม่ สามารถกดดูที่เมนูขวาบนตอนเปิดหน้าเว็ปได้เลย เพราะจะมีระบุไว้ชัดเจนว่า "Running in Chrome"

สำหรับนักพัฒนาคนไหนที่อยากจะลองใช้ Custom Tabs ในแอปของตัวเองก็สามารถดูขั้นตอนการใช้งานได้จากบทความ Chrome Custom Tabs ของดีที่จะช่วยให้การเปิดเว็ปในแอปเป็นเรื่องง่ายๆ

Chrome Custom Tabs ของดีที่จะช่วยให้การเปิดเว็ปในแอปเป็นเรื่องง่ายๆ
วันนี้เจ้าของบล็อกจะมาแนะนำสิ่งใหม่ที่ดีกว่านั้นอีก นั่นก็คือ Chrome Custom Tabs ที่จะเพิ่มความสามารถให้มากขึ้น โดยไม่ต้องเสียเวลาเขียนโค้ดเพิ่มใน WebView เอง Chrome Custom Tabs เป็นลูกเล่นอย่างหนึ่งของ Chrome

Facebook ไม่ได้ใช้ Chrome Custom Tabs แต่เป็น Android WebView ที่เพิ่มความสามารถเข้าไปเองเยอะมาก

เมื่อพูดถึง Custom Tabs ของ Chrome แล้ว หลายคนอาจจะคิดว่าแอปอย่าง Facebook for Android ก็ใช้ Custom Tabs เหมือนกัน แต่จริง ๆ แล้วแอป Facebook เลือกที่จะสร้าง Android WebView ขึ้นมาเองและทำให้มีความสามารถต่าง ๆ ใกล้เคียงกับ Custom Tabs ของ Chrome แทน

Launching a new Chromium-based WebView for Android
Facebook’s in-app browser on Android devices is being updated to improve security, performance, and overall user experience.

ดังนั้นถ้าเว็ปเปิดบน In-app Browser ของ Facebook แล้วมีบางอย่างที่ทำไมไม่ถูกต้อง ก็ให้คำนึงไว้ว่าอาจจะเป็นปัญหาจากฝั่งแอป Facebook ก็เป็นได้

สรุป

Android WebView เป็นหนึ่งใน Android UI Component ที่แอปจำนวนมากนิยมใช้กันในบางฟีเจอร์หรือบางหน้าของแอปที่มีการเปลี่ยนแปลงบ่อยหรือเปิดให้ใช้งานในช่วงระยะเวลาไม่นานมากนัก ดังนั้นการพัฒนาหน้าเว็ปแล้วเปิดด้วย WebView ในแอปจึงเป็นทางเลือกที่ดีกว่า

และสิ่งที่ต้องระวังก็คือ WebView มีความสามารถและ API ที่ให้เรียกใช้งานแตกต่างไปจาก Chrome ถึงแม้ว่าเบื้องหลังจะใช้ Chromium ก็ตาม ดังนั้นเวลาพัฒนาเว็ปเพื่อเปิดใช้งานบน WebView จึงไม่ควรทดสอบด้วยการเปิดบน Chrome เด็ดขาด ถ้าไม่อยากงานเข้าในภายหลัง

แหล่งข้อมูลอ้างอิง