เป็นอีกหนึ่งเรื่องที่เจอกันได้บ่อยๆ ในเวลาที่นักพัฒนาเอาแอปขึ้น 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 ถือว่าเป็นเรื่องที่ควรรู้ไว้อย่างยิ่ง เพื่อให้แอปของผู้ที่หลงเข้ามาอ่านสามารถรองรับกับอุปกรณ์แอนดรอยด์ให้มากที่สุดเท่าที่ทำได้นั่นเอง