feature-image-appium-cordova-crosswalk-issues
วิธีจัดการแก้ไขปัญหา socket convention ระหว่าง appium cordova crosswalk

ในยุคนี้แล้วการเขียนแอพมือถือด้วย Native น้อยลงอย่างมาก ถ้าไม่ใช่แอพที่มีการใช้ Animation หรือเรื่องของ Hardware หนักๆนั้นก็คงไม่เลือก Native เป็นแน่ ด้วยเหตุผลหลายๆอย่างๆทั้งเวลา และ ค่าใช้จ่ายในการจัดการดูแลมัน

มันเลยก็เป็นเหตุผลที่ทําให้ Apache Cordova กลายมาเป็นฮิตสุดๆๆไปเลย โดยจุดเด่นของ Cordova เนี่ยก็คือ

  1. เขียนทีเดียว Reuseable ได้ทุก Platform ทั้ง Android,IOS,Window
  2. สามารถเข้าถึง Native device API ได้

ด้วยเหตุผลพวกนี้ทําให้ แอพ ส่วนใหญ่ในปัจจุบันนี้กลายเป็น Web Application หรือ Hybrid กันไปซะหมดแล้วด้วยเหตุผลง่ายๆคือมันพัฒนาได้เร็วกว่า ถูกกว่า และ ดูแลรักษาพวก html,css,js ง่ายกว่ามาก (หรือเหตุผลอื่นๆอีกมากมาย)

ทีนี้อย่างที่รู้กันว่าแอพพวกนี้ถูกพัฒนาขึ้นมาด้วย html,css และ js นั่นก็หมายความว่ามันจะต้องถูกเรนเดอร์หรือแสดงผลด้วย Web Browser นั่นเอง ซึ่งการที่ใช้ Browser แสดงผลนี่มันก็เป็นจุดเริ่มต้นของปัญหาทุกอย่างนั่นเอง

ถ้าบน Apple device อาจจะมีปัญหาเรื่อง WebView ไม่มากนัก เพราะ Apple device ได้มีการควบคุม device ที่ชัดเจน เช่น iphone5,iphone6 และระบบเป็นระบบปิด แต่เมื่อเรามองถึง Android จะพบว่า ปัญหาหลักของ Android ทุกยุคทุกสมัยนั่นก็คือเรื่องของ Fragmentation นั่นเอง (ภาษาคน ก็คือ มันเป็นระบบเปิดใครเอาไปใช้ได้ เอาไปลงมือถือรุ่นอะไร หน้าจอแบบไหน เฟริ์มแวร์เก่าไม่เก่าลงได้หมด ทีนี้มันก็มีความหลากหลายมากๆนั่นคือ Fragmentation)

เจ้า Fragmentation เนี่ยนอกจากมีผลกับการแสดงผลที่หลากหลายบนหน้าจอเนี่ย ยังก่อให้เกิดเรื่องของ เวอร์ชั่นของ Browser หรือ แอพอื่นๆ ไม่เท่ากันอีกด้วย! ฟังดูไม่มีผลอะไรน่ะ แต่ถ้าย้อนกลับไปอ่านข้างบนจะเห็นว่า Apache Cordova พัฒนาด้วย html,css และ JS น่ะ! แปลว่ามันต้องไปรับมือกับ Browser ที่เก่าและใหม่ไม่เท่ากัน ทําให้เราไม่สามารถควบคุม engine browser ได้ ซึ่งแปลว่า JavaScript บางตัวจะทํางานไม่ถูก หรือ แม้กระทั่งทํางานกับบาง Device ไม่ได้เลยด้วยซำ้……..ชีวิตบัดซบมาก ใครบอก Write Once,Run Anywhere ไง

ด้วยความที่เราเหล่า developer คงจะนั่งเฉยๆแล้วบ่นผ่านไปไม่ได้ เราต้องหาทางแก้ไข และหนทางก็คือ โปรเจคนี้ crosswalk ซึ่งถ้าอยากรู้รายละเอียดเยอะๆ อ่านได้ที่บทความนี้ Crosswalk คืออะไร? ทําไมเราต้องใช้?หรือจะสรุปย่อๆก็คือ ถ้ามันมีความหลากหลายของ Browser เยอะนักก็ใช้ Browser เดียวกับให้หมด ด้วย Chromium (Chrome version opensource) ไปเลยทีเดียว

แปลว่าเมื่อไรก็ตามที่มือถือเครื่องใดๆที่เปิดแอพที่ทําจาก Cordova + Crosswalk plugin (a.k.a xwalk) มันจะไม่ใช่ Default Browser ของ device นั้นๆๆอีกต่อไป (based on cordova document) แต่จะไปใช้ Browser Chromium เป็น WebView แทนนั้นเอง

อ่านมาถึงตรงนี้ฟังแล้วจะจบลง Happy Ending แต่ไม่ใช่เลย เพราะมันมาถึงขั้นตอนของการเขียน automated test แล้วล่ะ แล้วที่นี้การทํา Automated test on device ที่เราจะพูดถึงก็คือ Appium นั่นเอง ดังนั้นเราเพิ่มตัวแปรอีกตัวเข้ามาในสมการคือ Appium + Cordova + Crosswalk

โดยอย่างที่บอกในบทความ Appium 101 ว่า Appium เป็น Server-Client Architecture หรือหมายถึง เวลามันทําการเทสแอพเนี่ยมันจะรับข้อมูลจาก Client ว่าต้องการจะเทสอะไรบ้างผ่าน capabilities และส่งต่อให้ chromedriver เพื่อนําไปส่งให้กับ แอพนั้นๆอีกทีเพื่อทําการเทส ดังนั้นรูปแบบจะออกมาตามข้างล่างนี้

 

จากรูปจะเห็นว่ามีก้อนเหลืองๆใน appium ด้วยมันคือ chromedriver แปลว่า appium มี built-in chromedriver ของตัวเอง (ใช้ Node.js เป็นตัว wrapper) ซึ่งเจ้าตัวเนี้ยแหละ จะเป็นตัวที่รับ capabilities จาก client แล้วนําไปประมวลผลงส่งไปจัดการกับ device นั่นเอง

ที่นี้ปัญหาคือ

แต่ละตัวมี convention name ของมันเอง ทําให้คุยกันไม่รู้เรื่อง…..

chromedriver = webview_devtools_remote_{pid}

xwalk = {package name}_devtools_remote

แปลง่ายๆว่าถ้า appium client ส่งข้อมูลให้ appium server เจ้า server ก็จะไม่สามารถคุยกับ device ผ่าน xwalk ได้ เพราะมันคุยกันคนละช่องทาง

ทําให้เวลาทําการเทสระบบจะพบว่าเราไม่สามารถ switch context ได้เลยเพราะมันคนละ convention กัน มันจะไม่ได้เก็บ webview นั้นไว้ใน array เลย

วิธีไล่โค้ด

ปัญหาคือ chromedriver ใช่ไหม? เพราะฉะนั้นแรกสุดเราต้องไปดูเรื่องของการจัดการ webview ของ appium ก่อน นั่นก็คือ android-hybrid.js ซึ่งเราจะพบว่าไฟล์แรกดั้งเดิมสุดเลย มัน Support แค่ convention ของ chromedriver เท่านั้น (webview_devtools_remote)

appium-default-android-hybrid.js

ด้วยโค้ดข้างบนแปลว่า มันจะรองรับเฉพาะ Chromedriver อย่างเดียวเลย ไม่รองรับ xwalk เพราะ pattern ของ xwalk คือ {package name}_devtools_remote มันก็เลยมีคน patch ไฟล์มาเป็นแบบข้างล่าง

appium-patched-android-hybrid.js

สังเกตุว่า pattern ในการจับ WebViewPID จะเปลี่ยนไปตาม Pattern ของ Xwalk ละคือ @?_devtools_remote แล้วเวลาที่มัน push ลงไปใน webviews เนี่ยมันก็จะเติม appPackage และ suffix name ว่า _devtools_remote ลงไปด้วย เพื่อที่จะได้เข้า pattern ของ

xwalk = {package name}_devtools_remote

ทีนี้ด้วยไฟล์ patchนี้มันก็จะทําให้ทํางานกับ xwalk ได้ แต่!!! ทํางานกับ chromedriver ไม่ได้…..อ่าว เห่ย! เพราะเราเลือกที่จะไม่เอา pattern ของ webview chromedriver และ ไม่ Push ลงไปใน webviews นั่นเอง

ดังนั้นถ้าเราจะทําการรองรับทั้งสอง version เราก็ต้องไปใส่ if-else condition ไว้ให้มันรองรับได้ทั้งสองอย่างก็จะเป็นอันเสร็จ! ดูว่ามี package ไหม? กับ ดูว่ามี webviewpid ไหมนั่นเอง

วิธีแก้แบบละเอียด

  1. อย่างแรกเลย เราต้อง patch android-hybrid.js (ตัวจัดการกับ webview หรืออีกความหมายคือพวกแอพ html,css,hs) เพื่อแก้ chrome pattern บรรทัดที่ 24 ให้เป็น webview_devtools_remote กับ บรรทัดที่ 37 เพื่อให้มันแอด context name ลงไปในชื่อของ xwalk หรือ {package name}_devtools_remote นั่นเอง (สิ่งที่ไฟล์นี้ทําคือมันไปหา process information (pid ) จาก os และ pkg ที่ส่งเข้ามาว่ามีตัวไหนบ้างที่ตรงกับ Pattern นั้น แล้วเอาไปใส่ webview context เพื่อให้ connect ไปถูก socket)
  2. อย่างต่อไปก็คือ chromedriver.exe ต่อจาก android-hybrid.js คือ ตอนนี้ chromedriver มันไม่รองรับในการ connect ไป socket อื่นนอกจากตัว default มัน ทําให้เราต้อง Patch chrome driver ด้วยเพื่อให้มันไป connect ที่ socket อื่น ที่ android-hybrid.js หาเจอนั่นเอง (เราต้องเอาตัว patch ไป override ตอนรัน appium)

ซึ่งไฟล์ตัวอย่างและบทความต่างๆรวมไว้ที่นี้ล่ะ ที่ patch แล้วอยู๋ที่ข้างล่างนี้

Noted ปัญหาที่เกิดคือเกิดบน Appium 1.4.16

สรุป

การจัดการ Appium + cordova + crosswalk ไม่ใช่เรื่องยากเลย จริงๆต้องเข้าใจว่ามันทํางานกันยังไงมากกว่าถึงจะไล่ตามได้ถูกทาง ในอนาคตน่าจะมี patch ที่เข้ามาแก้ไขปัญหาเหล่านี้แต่ ณ เวลาที่เขียนบทความนี้ คือ Appium 1.4.16 ยังไม่มี patch อะไรใหม่ๆออกมา ใครใช้อยู่ก็นําไปแก้ซะน่ะ จะได้ปถูกทาง ถ้าเจออะไรแบบนี้ 🙂

Remark

  • เวลาที่เราทําการทดสอบพวก WebView พวกนี้น่ะ Chromedriver มีผลมากกับ Webview version ที่เรากําลังทําการทดสอบอยู่ ในกรณีไม่ใช่ xwalk plugin น่ะ เพราะฉะนั้นเราต้องเลิอกให้มัน Support กันผ่านทาง offical ของ chromedriver โดยให้ใช้ chrome://inspect/device#devices เพื่อดูว่า version ตรงกันไหม แล้วค่อยโหลดมาใช้
  • Capabilities ที่เราส่งจาก Appium Client ไปนะ แท้จริงแล้วมันก็คือส่งไปเพื่อบอก Chromedriver ว่าให้ connect ไปที่ๆไหนนั่นเอง Appium เป็นคน Parse ไปให้เฉยๆ เพราะฉะนั้นเราสามารถอ่านรายละเอียดเพิ่มเติมได้ที่ offical ของมันเช่นกัน
  • วิธีการ debug เจ้า android-hybrid.js ไม่ยากเลย เพียงแค่ใช้ “adb shell cat /proc/net/unix | grep devtools” หรือ เพิ่มเติม “cat -v ….” เพื่อดูว่า process ที่เปิดขึ้นมามีอะไรบ้าง แล้วก็มาแก้ไขให้ตรงกับ pattern (ใช้ logger.debug ค่อยๆไล่ไปก็ได้เหมือนกัน)

 

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.