มากำหนด Authority ของ Content Provider ให้เหมาะสมกับแอปของคุณกันเถอะ
Content Provider ถือเป็นหนึ่งใน Component พื้นฐานที่ใช้สำหรับควบคุมการเข้าถึงข้อมูลภายในเครื่องจากแอปต่างๆได้ ซึ่งในบทความนี้จะมาพูดถึงเรื่อง Authority ของ Content Provider กันล่ะ
นักพัฒนาหลายๆคนน่าจะได้สัมผัสกับ Content Provider กันมาบ้างแล้วล่ะ เช่น เวลาที่ต้องการทำแอปให้สามารถถ่ายรูปได้ โดยใช้วิธีสั่งเปิดกล้องจากแอปอื่นๆแทน ถ้าอยากจะให้ไฟล์ภาพถูกบันทึกลงใน Data Storage ไม่ว่าจะที่ใดก็ตาม จะต้องสร้าง Content Provider ขึ้นมาเพื่อให้แอปกล้องปลายทางนั้นบันทึกไฟล์ภาพผ่าน Content Provider ของเรานั่นเอง
การทำเช่นนี้จะช่วยให้แอปปลายทางไม่จำเป็นต้องสนใจเลยว่า Data Storage ที่จะให้บันทึกไฟล์นั้นเป็นที่ไหน สนใจแค่ Content Provider ที่ส่งมาให้เท่านั้นก็พอ
และการสร้าง Content Provider ขึ้นมาซักตัวหนึ่ง ก็จะต้องประกาศไว้ใน Android Manifest เหมือนกับ Component ตัวอื่นๆอย่าง Activity, Service และ Broadcast Receiver ด้วยทุกครั้ง
<!-- AndroidManifest.xml -->
<manifest ...>
<application ...>
<provider
android:name="..."
android:authorities="..."
...>
...
</provider>
</application>
</manifest>
จะเห็นว่าตัวอย่างโค้ดข้างบนนี้จะมีการกำหนด Attribute ที่จำเป็นสำหรับ Content Provider อยู่ด้วย ซึ่งหนึ่งในนั้นก็คือ Authority นั่นเอง
Authority คืออะไร?
Authority เป็นชื่อเฉพาะตัวของ Content Provider ที่นักพัฒนาจะต้องกำหนดเองทุกครั้งเพื่อให้ระบบแอนดรอยด์รู้จักกับ Content Provider ตัวนั้นๆ
โดย Content Provider นั้นสามารถกำหนด Authority ได้มากกว่า 1 ตัว (แต่ส่วนใหญ่มักจะกำหนดแค่ตัวเดียว) และถ้าอิงตาม Guideline ของแอนดรอยด์ จะแนะนำให้ตั้งชื่อตาม Java-style naming convention แบบเดียวกับที่กำหนด Package Name ของแอปนั่นเอง
ยกตัวอย่างเช่น
com.akexorcist.sleepingforless.imagepicker.provider
การกำหนด Authority ของ Content Provider โดยอิงจาก Package Name แล้วใส่คำต่อท้ายเข้าไป เป็นวิธีที่ง่ายที่สุดและนักพัฒนาส่วนใหญ่ก็มักจะทำแบบนี้กัน
<!-- AndroidManifest.xml -->
<manifest ...>
<application ...>
<provider
android:name="..."
android:authorities="com.akexorcist.sleepingforless.imagepicker.provider"
...>
...
</provider>
</application>
</manifest>
ในกรณที่มีหลาย Authority ก็ให้คั่นระหว่างชื่อด้วยเครื่องหมาย Semicolon
<!-- AndroidManifest.xml -->
<manifest ...>
<application ...>
<provider
android:name="..."
android:authorities="com.akexorcist.sleepingforless.imagepicker.provider;com.akexorcist.sleepingforless.filepicker.provider"
...>
...
</provider>
</application>
</manifest>
ชื่อที่กำหนดใน Authority จะต้องเป็น Unique เท่านั้น
อันนี้คือสิ่งที่สำคัญมากๆสำหรับการกำหนดชื่อให้กับ Authority ของ Content Provider เพราะว่าระบบแอนดรอยด์นั้นจะไม่ยอมให้แอปในอุปกรณ์แอนดรอยด์มี Content Provider ที่มี Authority ซ้ำกันเด็ดขาด ถึงแม้ว่าจะเป็น Content Provider ของแอปคนละตัวก็ตาม
ดังนั้นถ้าผู้ใช้ติดตั้งแอป 2 ตัวที่มี Authority เหมือนกัน แอปที่ติดตั้งหลังสุดจะไม่สามารถติดตั้งลงในเครื่องได้นั่นเอง หรือที่เรียกกันว่า Conflict Provider
จะเกิดอะไรขึ้นเมื่อเจอปัญหา Conflict Provider?
ฝั่งนักพัฒนา
นักพัฒนาอย่างเราๆก็จะรู้ได้ทันทีในตอนที่ติดตั้งแอปเพื่อทดสอบผ่าน Android Studio จะเจอข้อความที่บอกว่าไม่สามารถติดตั้งแอปได้เพราะ Conflicting Provider
ถ้าติดตั้งไฟล์ APK ผ่าน ADB ก็จะได้ข้อความในลักษณะเดียวกัน
ฝั่งผู้ใช้ทั่วไป
เนื่องจาก Content Provider ไม่ใช่เรื่องที่ผู้ใช้จำเป็นต้องรู้จัก ดังนั้นเวลาติดตั้งแอปผ่าน Google Play แล้วเจอปัญหาดังกล่าว สิ่งที่ผู้ใช้จะเห็นก็มีแค่หน้าต่างแจ้งว่าติดตั้งแอปไม่ได้ พร้อมกับวิธีแก้ไขที่ไม่ได้เกี่ยวกับเรื่องนี้เลยซักนิด
ในกรณีที่ผู้ใช้เอา APK มาติดตั้งเองภายในเครื่องสิ่งที่ผู้ใช้จะเห็นก็คือ หน้าจอที่บอกว่าติดตั้งแอปไม่ได้ โดยไม่ได้มีสาเหตุระบุไว้ว่าทำไมถึงติดตั้งไม่ได้เช่นกัน
อย่าให้แอปต้องตกม้าตายเพียงเพราะเจอปัญหา Conflict Provider
เพราะการที่ผู้ใช้ไม่สามารถติดตั้งแอปลงในเครื่องได้ก็สามารถทำให้แอปสูญเสียโอกาสส่วนหนึ่ง และถ้าเป็นปัญหา Conflict Provider ก็จะวิเคราะห์หาสาเหตุได้ยากมาก เนื่องจากฝั่งผู้ใช้ไม่สามารถเช็คอะไรได้เลย นอกจากนักพัฒนาจะทดลองสั่งติดตั้งไฟล์ APK ผ่าน ADB ดู ดังนั้นทางที่ดีจึงควรให้ความสำคัญในการตั้ง Authority ด้วย
- อย่าใช้ชื่อ Authority ที่ก๊อปโค้ดมาจากอินเตอร์เน็ตโดยตรง เพราะโอกาสซ้ำเยอะมาก
- ควรนำหน้าชื่อด้วย Package Name แล้วเพิ่มคำต่อท้าย เพื่อลดโอกาสซ้ำกับแอปอื่นๆ
- ใช้ Application ID ใน Gradle จะได้ไม่ต้องพิมพ์ Package Name เองทุกครั้ง
ลดปัญหาการกำหนดชื่อ Authority ให้กับ Content Provider ด้วยการ Inject Application ID จาก Gradle ลงใน Android Manifest
เนื่องจากการตั้งชื่อ Authority จะนิยมใช้ Package Name ของแอปเป็นคำนำหน้า ดังนั้นผู้ที่หลงเข้ามาอ่านจึงใช้ประโยชน์ของการกำหนด Application ID ใน Gradle เพื่อช่วยกำหนดชื่อให้กับ Authority ได้เช่นกัน
<!-- AndroidManifest.xml -->
<manifest ...>
<application ...>
<provider
android:name="..."
android:authorities="${applicationId}.imagepicker.provider"
...>
...
</provider>
</application>
</manifest>
ซึ่งการทำแบบนี้นอกจากจะช่วยให้นักพัฒนาสามารถทำ Provider ตัวนี้ไปใช้งานได้ง่าย เพราะรองรับกับการทำ Build Variant ที่แยก Package Name ของแต่ละ Flavor อยู่แล้วด้วย จึงไม่ต้องกังวลว่าจะเจอปัญหา Conflicting Provider เมื่อติดตั้งแอปหลายๆ Variant ไว้ในเครื่องเดียวกัน
นอกจากนี้ วิธีนี้ยังเหมาะกับการพัฒนาไลบรารีเพื่อให้แอปต่างๆนำไปใช้อีกด้วย เพื่อไม่ให้แอปที่นำไลบรารีไปใช้ต้องเจอปัญหา Conflicing Provider เพียงเพราะว่าใช้ไลบรารีตัวเดียวกัน
ดังนั้นการตั้งชื่อ Authority จึงมีความสำคัญอย่างมาก ถึงแม้ว่าจะเป็นเรื่องเล็กๆ แต่ก็ไม่ควรมองข้าม เพราะถ้าเกิดปัญหาขึ้นมาแล้วตอนหาสาเหตุจะทำได้ยากมาก แถมเสียโอกาสที่ผู้ใช้จะได้ติดตั้งแอปและใช้งานแอปของเราอีกด้วย ควรตรวจสอบให้ถี่ถ้วนก่อนจะ Publish ขึ้น Google Play นะ