android-espresso-permission
วันนี้เจอปัญหาที่น่าสนใจสำหรับการทดสอบ Android app ด้วย Espresso
มีอาการ คือ ไม่สามารถทำการทดสอบได้ และ ผลการทดสอบผิดพลาด

ซึ่งเป็นปัญหาเกี่ยวกับ permission ของ Android app นั่นเอง
โดยจะเจอปัญหานี้บน Android M หรือ Android 6 Marshmallow
เนื่องจากรูปแบบของการจัดการ permission ที่เปลี่ยนไป

มาดูวิธีการแก้ไขว่าทำอย่างไร ?

ป.ล.
สามารถอ่านเพิ่มเติมเรื่อง Working with Permission ได้ที่ Android Developer
ขอขอบคุณผู้สร้างปัญหา คุณเก้อ

ปัญหาที่พบเจอเป็นดังนี้

  • ผลการทดสอบผิดพลาด
  • จำนวน test case ลดลง !!

ที่สำคัญจะมีปัญหาบน Android M เท่านั้น
และใน Logcat จะเจอ exception แบบนี้เยอะมาก ๆ

java.lang.SecurityException: getDeviceId:
Neither user 10340 nor current process has android.permission.READ_PHONE_STATE.

วิเคราะห์ปัญหากันหน่อย

ประเด็นหลักคือ เจอเฉพาะบน Android M เท่านั้น
รวมทั้งมี exception ใน Logcat ซึ่งบอกปัญหาเรื่อง permission
ทำให้นึกถึงสิ่งที่เปลี่ยนแปลงไปใน Android M คือ
รูปแบบการจัดการ permission และ การขอ permission จากผู้ใช้งาน
นั่นคือ จะทำการขอสิทธ์ทีละ permission

ดังนั้นจึงลองทดสอบสมมุติฐาน
ด้วยการติดตั้งไฟล์ APK ของ Android App ในเครื่องทดสอบ
จากนั้นเข้าไปดู permission ของ app ก็พบว่า
permission ที่กำหนดไว้ในไฟล์ AndroidManifest.xml นั้น
ไม่ได้เปิด หรือ อนุญาตเลย
เป็นที่มาของปัญหาข้างต้นนั้นเอง !!

เมื่อรู้ปัญหาเรียบร้อยแล้ว ต่อมาคือ เราจะแก้ไขอย่างไรดีล่ะ ?

เริ่มจากการทำความเข้าใจขั้นตอนการทำงานก่อน
เนื่องจากใน Android Studio นั้นทำการ build และ deploy ด้วย Gradle
ดังนั้น เราควรรู้ว่า tasks หรือ ขั้นตอนการทำงานต่าง ๆ ของ Gradle เป็นอย่างไรบ้าง
สามารถดู task ต่าง ๆ ด้วยคำสั่ง

$gradlew tasks

จากนั้นต้องรู้ขั้นตอนการทำงานของแต่ละ task ด้วย
โดยขั้นตอนที่ต้องรู้ เพื่อแก้ไขปัญหาประกอบไปด้วย

  • ทำการสร้างไฟล์ APK ตอนไหน ?
  • ทำการติดตั้งไฟล์ APK ไปยัง device ตอนไหน ?
  • ทำการทดสอบด้วย Espresso ตอนไหน ?

ซึ่งเราต้องตอบคำถามเหล่านี้ให้ครบ โดยผมเน้นที่ส่วนของ Dev คือ

  • assembleDevDebugAndroidTest
  • installDevDebug
  • connectedDevDebugAndroidTest

ถ้าอยากรู้ว่าเราเข้าใจถูกหรือไม่ ก็ลองใช้คำสั่ง

$gradlew assembleDevDebugAndroidTest
$gradlew installDevDebug
$gradlew connectedDevDebugAndroidTest

ปัญหาต่อมาคือ เราจะเพิ่มสิทธิ์ permission ตรงไหนดีล่ะ ?

ตอบง่าย ๆ เลยก็คือ
หลังจากที่ทำการติดตั้ง APK ไปยัง device ไงล่ะ

ปัญหาต่อมาคือ เราจะเพิ่มสิทธิ์ permission อย่างไรดีล่ะ ?

สำหรับ Android Devleoper ไม่น่าจะยากเท่าไร
เพราะว่า เราจะทำการจัดการผ่านเครื่องมือที่ชื่อว่า adb (Android Debugging Bridge)
ซึ่งมีอยู่แล้วใน Android SDK

ถ้า Android Developer คนไหนไม่รู้ ขอแนะนำให้ศึกษาเพิ่มเติมนะครับ

โดยเราสามารถทดสอบเพิ่มสิทธ์ permission ด้วยคำสั่ง

$adb shell pm grant "package name of app" "YOUR PERMISSION"

ถ้าต้องการระบุ device ด้วย ใช้คำสั่ง

$adb -s "devicename" shell pm grant "package name of app" "YOUR PERMISSION"

เมื่อทดลองเพิ่มสิทธิ์ไปแล้ว
อย่าลืมไปลองเล่น app ใน device ด้วยนะ
ซึ่ง app ของเราจะไม่ถาม permission อีกเลย
แต่ถ้าเปิด app มาแล้วขึ้นหน้าจอแบบนี้ แสดงว่ายังทำไม่สำเร็จนะ !!
request_permission_dialog_2x

ปัญหาต่อมาคือ แล้วจะเพิ่มขั้นตอนการเพิ่มสิทธิ์เข้าไปในขั้นตอนของ Gradle อย่างไร ?

เนื่องจากไม่อยากทำงานเดิมซ้ำ ๆ มันน่าเบื่อมาก ๆ
ขั้นตอนการทำงานแบบอัตโนมัติต้องทำงานแบบนี้

  1. ทำการ uninstall app ออกจาก device ที่ต้องการ
  2. ทำการสร้างไฟล์ APK
  3. ทำการติดตั้งไฟล์ APK ไปยัง device ที่ต้องการ
  4. ทำการเพิ่มสิทธิ์ของ app ในแต่ละ device
  5. ทำการทดสอบการทำงานของ app ด้วย Espresso

ใน Gradle นั้นอนุญาตให้เราสามารถเพิ่ม task เข้ามาเองได้เลย
ดังนั้น ผมจึงทำการสร้าง task ใหม่ชื่อว่า grantPermissions
มีการทำงานดังนี้

  • ให้ทำงานหลังจากที่ทำงานติดตั้งไฟล์ APK ไปยัง device หรือ ก่อนการทดสอบด้วย Espresso
  • เนื่องจากสามารถต่อ device ได้หลาย ๆ เครื่อง ดังนั้นต้องทำการเพิ่มสิทธิ์ไปยังทุกเครื่องด้วย

ขั้นตอนการเขียน task ชื่อว่า grantPermissions เป็นดังนี้
สร้าง task ในไฟล์ build.grade ของ app

จากนั้นสร้างไฟล์ grant_permissions.sh ขึ้นมาเพื่อเพิ่มสิทธ์ให้ทุก ๆ device ดังนี้

เพียงเท่านี้ก็สามารถแก้ไขปัญหา และ ใช้งานได้แล้ว ด้วยคำสั่ง

$gradlew unInstallAll connectedDevDebugAndroidTest

ขอให้โลกสงบสุขครับ

Reference Websites
http://www.savinoordine.com/grantrevoke-permission-with-adb-android-m/
http://testdroid.com/news/how-android-m-new-app-permissions-impact-on-existing-apps
https://www.androidpit.com/android-m-release-date-news-features-name
https://greenify.uservoice.com/knowledgebase/articles/749142-how-to-grant-permissions-required-by-some-features
http://www.fulcrumapp.com/blog/automated-ui-testing-and-fulcrum-android-permissions/