เป็นอีกหนึ่งเรื่องที่เจอกันได้บ่อยๆ ในเวลาที่นักพัฒนาเอาแอปขึ้น Google Play แล้วลองใช้เครื่องตัวเองลงแอปดู แล้วพบว่ามีปัญหาเครื่องที่ใช้นั้นไม่รองรับกับแอปซะงั้น (Incompatible) ทั้งๆที่ตอนนั่งเขียนโค้ดก็ยังลงได้อยู่เลย
ซึ่งบทความนี้เจ้าของบล็อกจึงจะมาเล่าถึง App Filter บน Google Play ที่เป็นสาเหตุที่ทำให้อุปกรณ์แอนดรอยด์ไม่สามารถดาวน์โหลดแอปบางตัว
รู้จักกับการ Filter บน Google Play กันก่อน
โดยปกติบน Google Play นั้นจะมีการเลือกแสดงเฉพาะแอปที่เครื่องนั้นๆรองรับ (เพราะไม่จำเป็นต้องแสดงแอปที่ไม่รองรับ) และถ้าเปิดดูบนคอมก็จะเห็นได้ทั้งหมด
ซึ่งแอปที่จะแสดงผลบน Google Play จะถูก Filter ด้วยเงื่อนไขต่างๆที่นักพัฒนาควรรู้ มีอยู่ทั้งหมด 4-5 เงื่อนไขด้วยกัน
สถานะบน Google Play (Publishing Status)
บน Google Play สามารถเลือกได้ว่าจะ Publish หรือ Unpublish แอปของเรา ซึ่งปกติแล้วจะ Publish เพื่อให้ผู้ใช้สามารถเข้ามาดาวน์โหลดและติดตั้งได้ แต่ในบางครั้งอาจจะมีปัญหาบางอย่างจนต้องหยุดไม่ให้ดาวน์โหลด นั่นก็คือ Unpublish นั่นเอง
แต่การ Unpublish ไม่ได้หมายความว่าจะหยุดไม่ให้ผู้ใช้ดาวน์โหลดได้ 100% นะ เพราะถ้าผู้ใช้คนไหนเคยลงแอปมาก่อน ก็จะยังเข้ามาดาวน์โหลดได้อยู่ดี (แต่ต้องเข้าผ่าน URL ตรง ค้นหาจาก Google Play ไม่ได้) ในขณะที่ผู้ใช้ที่ยังไม่เคยติดตั้งแอปมาก่อนก็จะไม่สามารถเข้าไปดาวน์โหลดได้ (ถึงแม้ว่าจะเข้าผ่าน URL ก็ตาม)
หรือพูดอีกนัยนึงก็คือ นักพัฒนาไม่สามารถนำแอปออกไปจาก Google Play แบบถาวรได้เลย ทำได้แค่ซ่อนไว้ไม่ให้ผู้ใช้ใหม่ๆเข้ามาดาวน์โหลด
เว้นแต่ว่าแอปจะโดนแบน...อันนั้นได้ออกจาก Google Play ชัวร์ๆจ้า
ประเทศ
อันนี้น่าจะรู้กันอยู่แล้วเนอะว่านักพัฒนาสามารถกำหนดได้ว่าจะให้ดาวน์โหลดได้เฉพาะประเทศไหนบ้าง ซึ่งเจอได้บ่อยมากกับแอปเกมจากญี่ปุ่นที่มักจะเปิดให้ดาวน์โหลดได้เฉพาะที่ญี่ปุ่นเท่านั้น
และ Google Play จะอ้างอิงตามประเทศใน Google Account ของผู้ใช้ อย่างกรณีของเจ้าของบล็อกมีเหตุสุดวิสัยเล็กน้อยจึงทำให้ Google Account ของเจ้าของบล็อกกลายเป็น US แบบเปลี่ยนกลับไม่ได้ ทำให้เจ้าของบล็อกดาวน์โหลดแอปที่กำหนดเฉพาะประเทศไทยไม่ได้เช่นกัน ถึงแม้ว่าจะอยู่ที่ประเทศไทย ใช้ WiFi หรือเนตมือถือของไทยก็ตาม
ดังนั้นถ้าเป็นไปได้ก็พยายามทำให้แอปมัน Global หน่อย (ขอร้องล่ะ) คิดซะว่าเพื่อคนจากต่างประเทศมาที่ประเทศไทยแล้วโหลดแอปเพื่อใช้ในไทยไม่ได้ละกันนะ
CPU Architecture (สำหรับ NDK)
บางแอปนั้นอาจจะมีการใช้ NDK ในการพัฒนา ซึ่งมันก็จะมี Native Library ที่เฉพาะเจาะจงสำหรับ CPU Architecture แต่ละประเภทครับ ไม่ว่าจะเป็น ARM, MIPS หรือ x86 ถ้าบางแอปไม่ได้ทำมาครอบคลุม ก็อาจจะทำให้เครื่องบางเครื่องที่ใช้ CPU ต่างออกไปไม่สามารถติดตั้งแอปตัวนั้นได้ครับ
App Manifest Element
นักพัฒนาสามารถกำหนดได้ว่าอุปกรณ์แบบไหนที่จะสามารถดาวน์โหลดได้ โดยกำหนดลงไปใน Android Manefest แล้ว Google Play จะไปดึงข้อมูลตรงนั้นมา Filter เครื่องที่รองรับให้เอง ไม่ว่าจะเป็นขนาดเครื่อง, Hardware ที่มีในเครื่อง หรือเวอร์ชันแอนดรอยด์ที่รองรับ
Excluded Manually
ถึงแม้ว่าจะมีบางเครื่องที่รองรับเงื่อนไขข้างบนทั้งหมดนี้ แต่นักพัฒนาก็สามารถเลือกได้ว่าจะมีเครื่องไหนที่ไม่อยากให้ดาวนโหลดได้ เพราะบางแอปก็อาจจะรองรับกับอุปกรณ์แอนดรอยด์บางรุ่นเท่านั้น
โดยสามารถเข้าไปเลือก Exclude ได้ใน Device Catalog ของแอปนั้นๆบน Google Play Console
โดยปกติแล้วมักจะ Default เป็น Include (Supported) อยู่แล้ว แต่ถ้าจะ Exclude ด้วยเหตุผลอะไรก็ขึ้นอยู่กับนักพัฒนาของแต่ละแอปนะ
Manifest Element ที่มีผลกับการ Filter บน Google Play
supports-screens
สำหรับกำหนดค่าเกี่ยวกับหน้าจอของอุปกรณ์แอนดรอยด์ที่ต้องการรองรับ ไม่ว่าจะเป็น Size หรือ Density ก็ตาม หรือจะกำหนดเป็นหน่วย DP ก็ได้ สามารถดู Attribute แต่ละตัวได้ที่ supports-screens [Android Developers]
ในกรณีที่รองรับกับหน้าจอทุกขนาด ก็ไม่ต้องกำหนดอะไรเลย
uses-configuration
สำหรับกำหนดเกี่ยวกับพวกคีย์บอร์ดหรือ Navigation Key ของตัวเครื่อง ซึ่งไม่ค่อยได้ใช้แล้วล่ะ สามารถดู Attribute แต่ละตัวได้ที่ uses-configuration [Android Developers]
ที่จะได้ใช้ก็คงจะมี Hardware Keyboard กับ Touchscreen Required สำหรับบางแอป
uses-feature
สำหรับกำหนดเกี่ยวกับ Feature ต่างๆที่เครื่องรองรับ เป็น Element ที่ใช้บ่อยที่สุด และเป็นต้นเหตุที่ทำให้เจอปัญหาเครื่องบางเครื่องติดตั้งบางแอปจาก Google Play ไม่ได้ สามารถดู Attribute แต่ละตัวได้ที่ uses-feature [Android Developers]
เดี๋ยวเขียนรายละเอียดเกี่ยวกับ Element นี้ให้ในช่วงท้ายๆบทความนะ
uses-library
สำหรับกำหนด Shared Library ที่ต้องการในแอปตัวนั้นๆ ถ้านึกไม่ออกก็ลองนึกถึง Play Services Library น่ะแหละครับ ที่เค้าทำมาให้แอปไหนๆก็ได้สามารถใช้ฟีเจอร์บางอย่างของ Play Services ได้ โดยบังคับว่าเครื่องนั้นๆจะต้องลง Play Services ไว้ในเครื่องด้วย นั่นล่ะครับ Shared Library สามารถดู Attribute แต่ละตัวได้ที่ uses-library [Android Developers]
แต่ปกติจะไม่ค่อยได้ใช้ Element ตัวนี้เลย เพราะว่า Shared Library มีให้ใช้งานน้อยมาก หลักๆก็จะมีแค่ Play Services เป็นหลัก และถ้าเครื่องที่ไม่ได้ติดตั้ง Play Services ไว้ในเครื่อง ตัว Library ก็จะแจ้งให้ผู้ใช้ไปดาวน์โหลดมาลงก่อนอยู่แล้ว
uses-permission
สำหรับกำหนด Permission ในแอปตัวนั้นๆ อันนี้น่าจะรู้จักกันอยู่แล้ว เพราะว่าบางอย่างในเครื่อง ถ้าจะเรียกใช้งานก็ต้องประกาศขอ Permission ไว้ใน Android Manefest อยู่แล้ว สามารถดูรายละเอียดของ Attibute แต่ละตัวได้ที่ uses-permission [Android Developers]
uses-permission-sdk-23
จะเหมือนกับ <uses-permission>
แต่สมมติว่าแอปตัวไหนต้องการ Permission บางตัวสำหรับ API 23 ขึ้นไปเท่านั้น (ไม่ต้องการสำหรับ API 22 หรือต่ำกว่านั้น) ก็ให้ประกาศผ่าน Element ตัวนี้แทน ส่วนรูปแบบของ Attribute ก็เหมือนกับ <uses-permission>
เป๊ะๆ uses-permission-sdk-23 [Android Developers]
uses-sdk
เป็น Element อีกตัวที่ไม่มีนักพัฒนาคนไหนไม่รู้จักเนอะ เพราะมันมีไว้กำหนดเวอร์ชันที่รองรับสำหรับแอปนั้นๆ ซึ่งภายหลังถูกกำหนดผ่าน build.gradle ไปแล้ว แล้วเดี๋ยว Gradle ก็จะเอามากำหนดเป็น Element ตัวนี้ใน Android Manifest ให้เองนั่นแหละ
สำหรับ Attribute ของแต่ละตัวสามารถดูได้ที่ uses-sdk [Android Developers]
นอกจากนี้ยังมี Element อีก 2 ตัวคือ <compatible-screens>
กับ <supports-gl-texture>
ที่ไม่ค่อยได้ใช้งาน และเป็นการใช้งานเฉพาะทางมากเกินไป อย่างเช่น <compatible-screen>
ทางทีมแอนดรอยด์ก็แนะนำมาว่าอย่าใช้ เพราะมันจะเป็นทำให้อุปกรณ์ที่รองรับมีเหลือน้อย (ซึ่งในความเป็นจริงนักพัฒนาควรทำแอปที่รองรับกับเครื่องได้หลากหลายขนาด) <supports-gl-texture>
มีไว้กำหนด Compression Format ใน OpenGL เพื่อให้ใช้งานได้เฉพาะเครื่องที่รองรับเท่านั้น ซึ่งไม่ค่อยได้ใช้ซักเท่าไร
อุปกรณ์แอนดรอยด์บางรุ่นดันไม่รองรับ จะทำยังไงให้ติดตั้งจาก Google Play ได้?
ถือว่าเป็น Key ของบทความนี้เลยก็ว่าได้ เพราะเจ้าของบล็อกเชื่อว่ามีนักพัฒนาหลายๆคนได้ส่งแอปขึ้น Google Play ไป แล้วแบบว่า "เฮ้ย ทำไมเครื่องเรามันติดตั้งแอปไม่ได้?"
ซึ่งเจ้าของบล็อกคิดว่าการเป็นนักพัฒนาแอนดรอยด์แล้วเจอปัญหานี้ซักครั้งมันก็ดีนะ เพราะถ้ายังไม่เคยเจอก็จะไม่รู้ว่าอาจจะมีอีกหลายๆเครื่องที่ติดตั้งแอปไม่ได้ ทำให้เราตระหนักเรื่องนี้ทุกครั้งเวลาที่ส่งแอปขึ้น Google Play
แต่ถ้าพึ่งเจอเป็นครั้งแรกล่ะ? จะทำยังไงดี?
ก่อนอื่นให้ตรวจสอบเงื่อนไขพื้นฐานของ Filter ก่อนว่ารองรับจริงๆ และไม่ได้ไป Excluded Manually ไว้ ถ้า Exclude ไว้ก็เช็คให้ดีก่อนว่ามีปัญหาอะไรหรือป่าวถึงไป Exclude ไว้
และนอกจากถึงถ้าอุปกรณ์แอนดรอยด์นั้นๆไม่รองรับก็จะขึ้นบอกว่า Not opted in หรือ Unsupported ซึ่งเมื่อกดเข้าไปดูรายละเอียดข้างในอุปกรณ์นั้นๆก็จะมีบอกคร่าวๆว่าทำไมถึงไม่รองรับ
Not opted in จะหมายถึงแอปของเราไม่รองรับ Form Factor นั้นๆ
ส่วน Unsupported ก็จะหมายถึงไม่รองรับตามที่เรากำหนดไว้ใน Android Manifest ของแอป โดยเช็คได้ด้วยการเข้าไปดูที่รายละเอียดของ APK/AAB ของแอปที่ Publish ไว้ล่าสุดที่อยู่ใน App Release นั่นเอง
เมื่อเข้าไปดูรายละเอียดของแอปตัวล่าสุดก็จะมีข้อมูลคร่าวๆของแอปนั้นๆ และสามารถดูได้ว่ามีการกำหนดค่าอะไรไว้ที่อาจจะทำให้แอปไม่รองรับกับบางเครื่องด้วยนะ
โดยเจ้าของบล็อกแนะนำให้ตรวจสอบตามลำดับดังนี้
• API Levels ว่าเวอร์ชันขั้นต่ำไว้เท่าไร เครื่องที่ดาวน์โหลดไม่ได้เป็นเวอร์ชันที่ต่ำกว่าหรือไม่
• Screen Layouts โดยปกติแล้วจะรองรับทุกขนาดหน้าจอ เว้นแต่ว่ามีการกำหนดไว้ใน Android Manifest
• Features ต้นเหตุส่วนใหญ่จะอยู่ที่ตรงจุดนี้ โดยมีรายละเอียดเยอะมาก ดังนั้นเขียนแยกออกมาให้อ่านต่อข้างล่างแทน
• Required Permissions ถ้าเป็น Permission พื้นฐานของ Android อยู่แล้วก็ไม่มีปัญหาอะไร (เช่น Internet เป็นต้น)
• OpenGL ES Version สำหรับแอปที่มีการเรียกใช้งาน OpenGL ES ต้องดูด้วยว่ากำลังใช้เวอร์ชันอะไรอยู่ และเครื่องที่ทดสอบรองรับหรือไม่ (บางทีกำหนดเป็นเวอร์ชันสูงเกินไป แต่โค้ดเป็นของเวอร์ชันที่ต่ำกว่าก็มี)
• OpenGL Textures อันนี้น่าจะเฉพาะทางเกินไปละ ถ้าไม่ได้ใช้ OpenGL ระดับลึกมากๆก็ไม่ต้องสนใจ
ส่วนใหญ่ที่เครื่องไม่รองรับ เพราะว่า Features นั่นเอง
ทั้งนี้เพราะว่าข้อมูลส่วนนี้จะไม่แสดงให้นักพัฒนาเห็นในตอนเขียนโค้ดเลย ไม่มีแสดงใน Android Manifest ว่าแอปตัวนั้นจะต้องใช้ Feature อะไรบ้าง และส่วนใหญ่ก็จะไม่รู้ว่าเครื่องที่ใช้นั้นรองรับ Feature ไหนด้วยเช่นกัน
ถ้าดูภาพตัวอย่างก่อนหน้าจะเห็นว่าแอปตัวอย่างต้องการอยู่ 2 Feature คือ android.hardware.faketouch
และ android.hardware.wifi
ซึ่งสิ่งที่นักพัฒนาควรจะรู้ก็คือ
• ควรรู้ว่าแอปของผู้ที่หลงเข้ามาอ่าน Required Feature ตัวไหน
• ควรรู้ว่าเครื่องที่มีปัญหานั้น Supported Feature ตัวไหนบ้าง
สำหรับ Required Feature ของแอปสามารถดูได้ในช่อง Features นั่นแหละ ซึ่งจะสัมพันธ์กับ Permission ที่เรียกใช้งานดังนี้
BLUETOOTH
• android.hardware.bluetooth
BLUETOOTH_ADMIN
• android.hardware.bluetooth
CAMERA
• android.hardware.camera
• android.hardware.camera.autofocus
ACCESS_MOCK_LOCATION
• android.hardware.location
ACCESS_LOCATION_EXTRA_COMMANDS
• android.hardware.location
INSTALL_LOCATION_PROVIDER
• android.hardware.location
ACCESS_COARSE_LOCATION
• android.hardware.location
• android.hardware.location.network
ACCESS_FINE_LOCATION
• android.hardware.location
• android.hardware.location.gps
RECORD_AUDIO
• android.hardware. microphone
CALL_PHONE
• android.hardware.telephony
CALL_PRIVILEGED
• android.hardware.telephony
MODIFY_PHONE_STATE
• android.hardware.telephony
PROCESS_OUTGOING_CALLS
• android.hardware.telephony
READ_SMS
• android.hardware.telephony
RECEIVE_SMS
• android.hardware.telephony
RECEIVE_MMS
• android.hardware.telephony
RECEIVE_WAP_PUSH
• android.hardware.telephony
SEND_SMS
• android.hardware.telephony
WRITE_APN_SETTINGS
• android.hardware.telephony
WRITE_SMS
• android.hardware.telephony
ACCESS_WIFI_STATE
• android.hardware.wifi
CHANGE_WIFI_STATE
• android.hardware.wifi
CHANGE_WIFI_MULTICAST_STATE
• android.hardware.wifi
ดังนั้นถ้าแอปมีการประกาศ Permission ตัวไหนไว้ ก็ให้ดูด้วยว่า Required Features อะไรหรือป่าว
แต่ถ้าการมานั่งไล่ดูมันลำบากเกินไป วิธีที่ง่ายกว่านั้นก็คือดู Android Manifest ผ่าน APK Analyzer ใน Android Studio
จากนั้นก็ให้เช็คว่าเครื่องที่ทดสอบนั้นรองรับ Feature ดังกล่าวหรือป่าว ก็ให้ใช้แอปเช็คเอา อย่างกรณีของเจ้าของบล็อกจะมีแอปที่เอาไว้ดูข้อมูลตรงนี้อยู่แล้ว
เท่านี้ก็จะรู้แล้วว่าเพราะอะไรเครื่องที่ใช้ทดสอบถึงติดตั้งแอปจาก Google Play ไม่ได้
สำหรับ Camera Permission จะ Require ทั้งandroid.hardware.camera
และandroid.hardware.camera.autofocus
ซึ่งที่เจ้าของบล็อกเจอก็คืออุปกรณ์แอนดรอยด์บางรุ่น (โดยเฉพาะแบรนด์จีน) มักจะกำหนดข้อมูลใน ROM มาผิดเองว่าเครื่องนั้นๆไม่มีandroid.hardware.camera.autofocus
ทั้งๆที่ตัวเครื่องก็รองรับ Autofocus อยู่แล้ว (เพราะข้อมูลในส่วนของ Feature ผู้พัฒนา ROM จะต้องมานั่งกำหนดเอง) Google Play ก็เลย Filter อุปกรณ์แอนดรอยด์เครื่องดังกล่าวออกไปให้ไม่สามารถติดตั้งแอปได้
ถ้าอยากให้มันติดตั้งได้ โดยไม่สน Required Feature ล่ะ?
นักพัฒนาสามารถกำหนดได้ครับว่าจะให้แอปนั้น Require Feature ตัวนั้นๆจริงๆหรือไม่ เพราะในบางครั้ง Feature ตัวนั้นๆก็ไม่ใช่การทำงานหลักของแอป เป็นแค่เพียงส่วนหนึ่งเท่านั้น ยกตัวอย่างเช่น แอปที่มีฟีเจอร์สามารถใช้งานกล้องได้ โดยที่ไม่จำเป็นว่าจะต้องใช้งานกล้องทุกครั้งไป ดังนั้นก็สามารถกำหนดใน Android Manifest ได้ว่าไม่ต้อง Require Feature ของ android.hardware.faketouch
กับ android.hardware.wifi
นะ
<manifest>
<!-- ... -->
<uses-feature
android:name="android.hardware.faketouch"
android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
</manifest>
และอย่าลืมนะว่าเมื่อกำหนด android:required
เป็น False ไปแล้ว นั่นหมายความว่าเครื่องที่ไม่รองรับ Feature ดังกล่าวจะติดตั้งได้ ดังนั้นโค้ดของผู้ที่หลงเข้ามาอ่านก็จะต้องรองรับในกรณีที่ไม่สามารถใช้งานฟีเจอร์เหล่านั้นได้ด้วย
สำหรับ Feature ที่สามารถกำหนดได้ เข้าไปดูได้ที่ <uses-feature> [Android Developers]
สรุป
การ Filter ของแอปต่างๆบน Google Play ถือว่าเป็นสิ่งที่นักพัฒนาควรจะรู้จักไว้ครับ เพราะมันจะช่วยให้แอปของผู้ที่หลงเข้ามาอ่านนั้นสามารถกำหนดได้ว่าอุปกรณ์แอนดรอยด์แบบไหนที่จะรองรับหรือไม่รองรับ โดยเฉพาะเรื่องของ <uses-feature>
ที่กำหนดผ่าน Android Manifest ถือว่าเป็นเรื่องที่ควรรู้ไว้อย่างยิ่ง เพื่อให้แอปของผู้ที่หลงเข้ามาอ่านสามารถรองรับกับอุปกรณ์แอนดรอยด์ให้มากที่สุดเท่าที่ทำได้นั่นเอง