Storage Access Framework คือเฟรมเวิร์ก Android สำหรับการเข้าถึงไฟล์และเอกสารอย่างปลอดภัยผ่านไดอะล็อกการเลือกของระบบ แทนที่จะขอสิทธิ์การอ่านพื้นที่จัดเก็บในวงกว้าง แอปจะได้รับลิงก์ URI ไปยังไฟล์ที่ผู้ใช้เลือก ตามข้อมูลจาก Android Developers (2026) SAF รองรับพื้นที่จัดเก็บในเครื่อง บริการคลาวด์ Google Drive และ Dropbox ผ่าน DocumentProvider เฟรมเวิร์กถูกนำมาใช้ใน Android 4.4 และกลายเป็นมาตรฐานสำหรับการทำงานกับเอกสารตั้งแต่ Android 10
ประเด็นสำคัญ
Storage Access Framework เป็นส่วนหนึ่งของ Android SDK ที่ให้อินเทอร์เฟซแบบรวมศูนย์สำหรับการเลือกและสร้างเอกสารผ่านไดอะล็อกของระบบ SAF ซ่อนตำแหน่งทางกายภาพของไฟล์: แอปไม่ทราบว่าไฟล์ถูกอ่านจากที่ใด — ดิสก์ภายใน, Google Drive หรือ Dropbox
สถาปัตยกรรม SAF ประกอบด้วยสามองค์ประกอบ: แอปไคลเอ็นต์ ที่เริ่มต้นคำขอ, ตัวเลือกระบบ — ไดอะล็อกการเลือกไฟล์มาตรฐาน, และ DocumentProvider — ผู้ให้บริการเนื้อหาที่ดำเนินการเข้าถึงไฟล์ของพื้นที่จัดเก็บเฉพาะ ผู้ใช้เห็นอินเทอร์เฟซแบบรวมศูนย์โดยไม่คำนึงถึงแหล่งที่มาของข้อมูล
SAF พร้อมใช้งานตั้งแต่ Android 4.4 (API 19) ในตอนแรกเฟรมเวิร์กรองรับเฉพาะเอกสาร แต่ Android 5.0 เพิ่มการรองรับไดเรกทอรีผ่าน ACTION_OPEN_DOCUMENT_TREE ตั้งแต่ Android 10 SAF กลายเป็นวิธีที่แนะนำสำหรับการเข้าถึงไฟล์ใดๆ ที่อยู่นอกพื้นที่จัดเก็บเฉพาะของแอป
SAF เริ่มไดอะล็อกการเลือกไฟล์ของระบบผ่าน Intent ด้วยการดำเนินการ ACTION_OPEN_DOCUMENT ผู้ใช้เห็นรายการแหล่งที่มาที่มีอยู่: พื้นที่จัดเก็บภายใน, Google Drive, Dropbox และผู้ให้บริการที่ลงทะเบียนอื่นๆ หลังจากเลือกไฟล์ ระบบจะส่งคืน content URI พร้อมสิทธิ์การเข้าถึงชั่วคราว
content URI มีรูปแบบ content://com.android.externalstorage.documents/document/primary/Download/file.pdf ต่างจาก URI แบบ file:// ตรงที่ content URI ไม่เปิดเผยพาธไฟล์จริงและทำงานผ่าน DocumentProvider แอปอ่านไฟล์ผ่าน ContentResolver.openInputStream โดยใช้ URI ที่ได้รับ
ตัวเลือกระบบรองรับ การค้นหา การเรียงลำดับ และการกรอง ไฟล์ตามประเภท MIME โดยอัตโนมัติ นักพัฒนากำหนดประเภทที่จำเป็นผ่าน Intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("application/pdf", "image/*")) และตัวเลือกจะแสดงเฉพาะไฟล์ที่เกี่ยวข้อง
โดยค่าเริ่มต้น URI จะมีผลจนกว่าแอปจะรีสตาร์ทหรืออุปกรณ์รีบูต สำหรับการเข้าถึงระยะยาว แอปจะขอ takePersistableUriPermission — ซึ่งอนุญาตให้อ่านไฟล์ในการเปิดใช้ครั้งต่อไปโดยไม่ต้องเลือกใหม่ผ่านไดอะล็อก
SAF มีสามการดำเนินการหลักสำหรับการทำงานกับไฟล์: เปิด, สร้าง และเลือกโครงสร้างโฟลเดอร์ ACTION_OPEN_DOCUMENT เปิดตัวเลือกระบบเพื่อเลือกไฟล์ที่มีอยู่ ACTION_CREATE_DOCUMENT สร้างไฟล์ใหม่ — ผู้ใช้ป้อนชื่อในไดอะล็อก และแอปได้รับ URI สำหรับเขียน
ACTION_OPEN_DOCUMENT_TREE อนุญาตให้เลือกไดเรกทอรีทั้งหมดและเข้าถึงไฟล์ทั้งหมดภายในนั้น ใช้ในตัวจัดการไฟล์ แอปสำรองข้อมูล และการซิงโครไนซ์ แอปได้รับ URI ไดเรกทอรีและสามารถนับเนื้อหาแบบเรียกซ้ำผ่าน DocumentFile
| การดำเนินการ | วัตถุประสงค์ | แฟล็ก |
|---|---|---|
| ACTION_OPEN_DOCUMENT | เลือกไฟล์ที่มีอยู่ | READ_FLAG |
| ACTION_CREATE_DOCUMENT | สร้างไฟล์ใหม่ | WRITE_FLAG |
| ACTION_OPEN_DOCUMENT_TREE | เลือกไดเรกทอรี | READ + WRITE |
สำหรับแต่ละการดำเนินการ ประเภท MIME จะถูกกำหนดผ่าน EXTRA_MIME_TYPES สามารถกำหนดหลายประเภทได้: "application/pdf", "image/*", "text/plain" หากไม่ได้กำหนดประเภท ตัวเลือกจะแสดงไฟล์ทั้งหมด
Persistent URI permissions เป็นกลไก SAF ที่อนุญาตให้คงการเข้าถึงไฟล์ไว้หลังจากเซสชันปัจจุบันสิ้นสุดลง หากไม่มีแฟล็กนี้ URI จะมีผลจนกว่าแอปจะรีสตาร์ทเท่านั้น แอปขอแฟล็ก FLAG_GRANT_PERSISTABLE_URI_PERMISSION พร้อมกับแฟล็ก READ และ WRITE
ในการบันทึกสิทธิ์ จะใช้เมธอด ContentResolver.takePersistableUriPermission ระบบจะบันทึก URI ลงในรีจิสทรีพิเศษและกู้คืนการเข้าถึงเมื่อเปิดแอปครั้งถัดไป หากต้องการตรวจสอบว่าแอปมีการเข้าถึง URI แบบถาวรหรือไม่ ให้ใช้ ContentResolver.persistedUriPermissions
ผู้ใช้สามารถเพิกถอนสิทธิ์ที่บันทึกไว้ผ่าน การตั้งค่า → แอป → สิทธิ์ แอปควรจัดการสถานการณ์ที่การเข้าถึงไฟล์หายไปโดยไม่คาดคิด ขอแนะนำให้ตรวจสอบการเข้าถึงผ่าน ContentResolver.openInputStream ก่อนเริ่มทำงานและจัดการ SecurityException อย่างถูกต้อง
SAF เริ่มทำงานผ่าน Intent มาตรฐาน โค้ดมีน้อยมาก: สร้าง Intent ด้วย ACTION_OPEN_DOCUMENT ระบุประเภท MIME และเริ่มผ่าน ActivityResultContracts.StartActivityForResult หลังจากเลือกไฟล์ callback จะได้รับ URI ใน data.data ซึ่งจากนั้นใช้สำหรับการอ่าน
val pickFile = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
result.data?.data?.let { uri ->
val inputStream = contentResolver?.openInputStream(uri)
// read from inputStream
}
}
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
setType("application/pdf")
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
}
pickFile.launch(intent)
ในการเขียนไฟล์ใหม่ ให้ใช้ ACTION_CREATE_DOCUMENT Intent ยอมรับประเภท MIME และชื่อไฟล์ผ่าน EXTRA_TITLE หลังจากเลือกโฟลเดอร์และยืนยัน ผู้ใช้จะส่งคืน URI ที่แอปเขียนข้อมูลผ่าน ContentResolver.openOutputStream ระบบจะสร้างไฟล์โดยอัตโนมัติในตำแหน่งที่เลือก
SAF แตกต่างจาก READ_EXTERNAL_STORAGE แบบดั้งเดิมในแนวทางด้านความปลอดภัยที่แตกต่างกันโดยพื้นฐาน แทนที่จะขอการเข้าถึงพื้นที่จัดเก็บทั้งหมดในครั้งเดียว SAF ขอการเข้าถึงเฉพาะไฟล์ที่ระบุเท่านั้น สิ่งนี้ช่วยลดพื้นที่การโจมตีและเพิ่มความไว้วางใจของผู้ใช้
READ_EXTERNAL_STORAGE ให้การเข้าถึงไฟล์ทั้งหมดบนอุปกรณ์ รวมถึงรูปภาพและเอกสารจากแอปอื่นๆ บน Android 10+ แนวทางนี้ถูกจำกัด SAF ในทางกลับกัน ให้การเข้าถึงเฉพาะไฟล์ที่ผู้ใช้เลือกเท่านั้นและต้องการการยืนยันอย่างชัดแจ้งสำหรับแต่ละไฟล์ สำหรับการดำเนินการสื่อเป็นชุด ให้ใช้ MediaStore สำหรับเอกสารแต่ละรายการ ให้ใช้ SAF
ข้อเสียหลักของ SAF คือความจำเป็นในการเลือกแต่ละไฟล์แยกกัน สำหรับการดำเนินการจำนวนมาก (การสำรองข้อมูล การซิงโครไนซ์โฟลเดอร์) ให้ใช้ ACTION_OPEN_DOCUMENT_TREE ซึ่งให้การเข้าถึงไฟล์ทั้งหมดในไดเรกทอรีที่เลือก วิธีแก้ไขขึ้นอยู่กับสถานการณ์: SAF เหมาะสมที่สุดสำหรับการเลือกโดยผู้ใช้ MediaStore สำหรับการเข้าถึงสื่อโดยทางโปรแกรม
คำถามที่พบบ่อย
Storage Access Framework คือเฟรมเวิร์ก Android สำหรับการเข้าถึงไฟล์อย่างปลอดภัยผ่านไดอะล็อกการเลือกของระบบ แอปได้รับ content URI สำหรับไฟล์ที่เลือกโดยไม่ต้องขอสิทธิ์การอ่านพื้นที่จัดเก็บในวงกว้าง
สร้าง Intent ด้วย ACTION_OPEN_DOCUMENT ระบุประเภท MIME ผ่าน setType และเริ่มผ่าน ActivityResultContracts ใน callback รับ URI จาก data.data และอ่านผ่าน ContentResolver.openInputStream
Persistent URI permissions เป็นกลไกในการคงการเข้าถึง URI ไว้หลังจากรีสตาร์ทแอป โดยขอผ่านแฟล็ก FLAG_GRANT_PERSISTABLE_URI_PERMISSION และเมธอด takePersistableUriPermission
SAF รองรับทุกประเภท MIME: application/pdf, image/*, text/plain, application/zip และอื่นๆ ประเภทถูกกำหนดผ่าน Intent.putExtra ด้วยอาร์เรย์ EXTRA_MIME_TYPES
SAF ออกแบบมาสำหรับการเลือกไฟล์แต่ละไฟล์โดยผู้ใช้ผ่านไดอะล็อกของระบบ MediaStore ให้การเข้าถึงไฟล์สื่อทั้งหมดบนอุปกรณ์โดยทางโปรแกรมผ่านฐานข้อมูลสื่อโดยไม่ต้องให้ผู้ใช้มีส่วนร่วม
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม