พื้นที่จัดเก็บภายนอกบนอุปกรณ์มือถือคือสื่อข้อมูลที่ถอดออกได้ซึ่งแอปพลิเคชันใดๆ ที่มีสิทธิ์ที่เหมาะสมสามารถเข้าถึงได้ ตาม Android Open Source Project, 2026 ตั้งแต่ Android 10 เป็นต้นไป Google ได้แนะนำ Scoped Storage — โมเดลที่จำกัดการเข้าถึงระบบไฟล์โดยตรงและกำหนดให้ใช้ MediaStore API สำหรับการทำงานกับไฟล์สื่อที่ใช้ร่วมกัน แนวทางนี้ช่วยเพิ่มความปลอดภัยของข้อมูลผู้ใช้และป้องกันการรั่วไหลของข้อมูลระหว่างแอปพลิเคชัน
ประเด็นสำคัญ
READ_EXTERNAL_STORAGE และ WRITE_EXTERNAL_STORAGE จำเป็นสำหรับ Android 9 และต่ำกว่าพื้นที่จัดเก็บภายนอก คือพื้นที่หน่วยความจำที่ไม่ได้เป็นส่วนหนึ่งของแซนด์บ็อกซ์ที่ได้รับการป้องกันของแอปพลิเคชันและสามารถเข้าถึงได้โดยโปรแกรมอื่นๆ บน Android คำนี้มักหมายถึงการ์ด SD แต่พื้นที่จัดเก็บภายนอกยังรวมถึงไดรฟ์ USB ที่เชื่อมต่อผ่านอะแดปเตอร์ OTG และไดรฟ์คลาวด์ที่รวมเข้ากับระบบไฟล์ในระดับระบบไฟล์ ความแตกต่างหลักจากพื้นที่จัดเก็บภายในคือการขาดการแยกตัว: แอปพลิเคชันใดๆ ที่มีสิทธิ์ที่เหมาะสมสามารถอ่านและแก้ไขไฟล์ในพื้นที่จัดเก็บภายนอกได้
บน Android พื้นที่จัดเก็บภายนอกมี สองโหมดหลัก: แบบพกพาและแบบปรับใช้ได้ (adoptable) เมื่อการ์ด SD ถูกฟอร์แมตเป็นพื้นที่จัดเก็บแบบพกพา การ์ดจะยังคงถอดออกได้และถูกฟอร์แมตเป็น FAT32 หรือ exFAT ในโหมดพื้นที่จัดเก็บแบบปรับใช้ได้ การ์ดจะถูกฟอร์แมตเป็น ext4 และเข้ารหัสด้วย AES-128 หลังจากนั้นระบบจะถือว่าการ์ดเป็นส่วนขยายของหน่วยความจำภายใน โหมดปรับใช้ได้มีให้ใช้งานตั้งแต่ Android 6.0 Marshmallow แต่ผู้ผลิตอุปกรณ์มักจะปิดใช้งานคุณสมบัตินี้ในเฟิร์มแวร์ของตน ตามสถิติของ Google Play Console มีเพียงประมาณ 12% ของอุปกรณ์ Android ที่รองรับพื้นที่จัดเก็บแบบปรับใช้ได้ ดังนั้นจึงไม่แนะนำให้พึ่งพาการขยายหน่วยความจำภายในผ่านการ์ด SD เป็นตัวเลือกเดียว
บน iOS ไม่มีการ์ด SD แบบดั้งเดิม Apple ใช้สถาปัตยกรรมแบบปิดซึ่งพื้นที่จัดเก็บทั้งหมดสร้างขึ้นบนหน่วยความจำแฟลชภายในและ iCloud ไดรฟ์ภายนอกได้รับการรองรับผ่านพอร์ต Lightning หรือ USB-C แต่การเข้าถึงไดรฟ์เหล่านั้นถูกจำกัดไว้ที่ตัวจัดการไฟล์ระบบ Files และแอปพลิเคชันที่รวมเข้ากับ Document Picker ผู้ใช้เป็นผู้ตัดสินใจว่าไฟล์ใดที่จะเปิดจากแหล่งภายนอก — แอปพลิเคชันไม่สามารถสแกนไดรฟ์ที่เชื่อมต่อโดยไม่ได้รับความยินยอมอย่างชัดแจ้ง
การเลือก สื่อภายนอก ขึ้นอยู่กับข้อกำหนดด้านความเร็ว ความจุ และการพกพา สื่อประเภทต่างๆ มีลักษณะความเร็ว ระบบไฟล์ และกรณีการใช้งานที่แตกต่างกันในแอปพลิเคชันมือถือ
| ประเภทสื่อ | ความจุสูงสุด | ความเร็วในการอ่าน | ระบบไฟล์ |
|---|---|---|---|
| SD UHS-I | 2 TB | สูงสุด 104 MB/s | exFAT / FAT32 |
| SD UHS-II | 2 TB | สูงสุด 312 MB/s | exFAT / FAT32 |
| USB 3.0 OTG | 2 TB | สูงสุด 400 MB/s | exFAT / NTFS / FAT32 |
| USB-C SSD | 4 TB | สูงสุด 1000 MB/s | exFAT / APFS / NTFS |
การ์ด SD ถูกจัดประเภทตามความเร็วในการเขียน: Class 10 (10 MB/s), U1 (10 MB/s), U3 (30 MB/s), V30 (30 MB/s) และ V90 (90 MB/s) การบันทึกวิดีโอ 4K ต้องการการ์ดอย่างน้อย U3 หรือ V30 สำหรับแอปพลิเคชันมือถือที่ทำงานกับไฟล์สื่อขนาดใหญ่ (การประมวลผลภาพถ่าย, การตัดต่อวิดีโอ) แนะนำให้ใช้การ์ดคลาส U3 ขึ้นไป ความเร็วของการ์ดส่งผลโดยตรงต่อประสิทธิภาพของแอปพลิเคชัน: การบันทึกวิดีโอ 4K บนการ์ด Class 10 อาจทำให้เฟรมตกเนื่องจากแบนด์วิดท์ไม่เพียงพอ เมื่อเลือกการ์ด SD สำหรับแอปพลิเคชัน ให้ใส่ใจไม่เพียงแต่คลาสความเร็วเท่านั้น แต่ยังรวมถึงระดับคลาสประสิทธิภาพของแอปพลิเคชันด้วย: A1 และ A2 ระบุประสิทธิภาพการอ่านและเขียนแบบสุ่มขั้นต่ำซึ่งมีความสำคัญต่อการทำงานของฐานข้อมูลและแคชของแอปพลิเคชัน
USB-OTG (On-The-Go) ช่วยให้สามารถเชื่อมต่อไดรฟ์ USB ภายนอกเข้ากับอุปกรณ์มือถือผ่านอะแดปเตอร์ Android รองรับ OTG ตั้งแต่เวอร์ชัน 3.1 แต่การเมานต์ไดรฟ์จำเป็นต้องมีเคอร์เนลที่รองรับระบบไฟล์ FAT32 และ exFAT รองรับโดยค่าเริ่มต้น NTFS — เฉพาะบนอุปกรณ์ที่มีเคอร์เนลที่กำหนดเองหรือผ่านไลบรารี Paragon บน iOS การรองรับไดรฟ์ USB ปรากฏใน iOS 13 พร้อมกับแอป Files ในการทำงานกับไดรฟ์ แอปพลิเคชันต้องใช้ UIDocumentPickerViewController ซึ่งให้การเข้าถึงเฉพาะไฟล์ที่ผู้ใช้เลือกเท่านั้น — iOS ไม่อนุญาตให้เข้าถึงระบบไฟล์ของไดรฟ์อย่างเต็มรูปแบบ
บริการคลาวด์ — iCloud, Google Drive, Dropbox — สามารถรวมเข้ากับระบบไฟล์ของอุปกรณ์ผ่านผู้ให้บริการระบบ บน iOS iCloud Drive เป็นส่วนหนึ่งของคอนเทนเนอร์ Sandbox ของแอปพลิเคชันและไฟล์จะถูกซิงค์โดยอัตโนมัติระหว่างอุปกรณ์ของผู้ใช้ บน Android Google Drive มี API สำหรับการอ่านและเขียนไฟล์ แต่ไม่มีการเมานต์โดยตรงในระบบไฟล์ สำหรับแอปพลิเคชันมือถือที่ทำงานกับข้อมูลปริมาณมาก พื้นที่จัดเก็บคลาวด์สามารถเป็นทางเลือกแทนการ์ด SD โดยเฉพาะอย่างยิ่งบนอุปกรณ์ที่ไม่มีช่องเสียบขยาย
การทำงานกับ พื้นที่จัดเก็บภายนอกบน Android ขึ้นอยู่กับเวอร์ชันของระบบปฏิบัติการและโมเดล Scoped Storage กระบวนการเข้าถึงไฟล์แตกต่างกันสำหรับ Android 9 และต่ำกว่า, Android 10–12 และ Android 13+
ตั้งแต่ Android 10 เป็นต้นไป วิธีหลักในการเข้าถึงไฟล์สื่อที่ใช้ร่วมกันคือ MediaStore API API นี้มีอินเทอร์เฟซแบบรวมสำหรับการอ่านและเขียนรูปภาพ วิดีโอ และไฟล์เสียงในพื้นที่จัดเก็บที่ใช้ร่วมกัน แอปพลิเคชันไม่ต้องการสิทธิ์ READ_EXTERNAL_STORAGE ในการเข้าถึงไฟล์ของตนเอง แต่การอ่านไฟล์จากแอปพลิเคชันอื่นยังคงต้องได้รับสิทธิ์อย่างชัดแจ้งจากผู้ใช้ MediaStore จะจัดทำดัชนีไฟล์สื่อโดยอัตโนมัติและมี ContentResolver สำหรับการค้นหา
val collection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME
)
val cursor = contentResolver.query(collection, projection, null, null, null)
หลังจากดำเนินการค้นหา คุณจะได้รับ Cursor ที่มี URI ของไฟล์ ในการอ่านไฟล์ ให้เปิด InputStream ผ่าน contentResolver.openInputStream(uri) การเขียนทำได้ในลักษณะเดียวกันผ่าน contentResolver.openOutputStream(uri) MediaStore จัดการข้อขัดแย้งของชื่อโดยอัตโนมัติและให้ความสามารถในการแทรกไฟล์ใหม่ผ่าน contentResolver.insert(uri, values) ซึ่งจะส่งคืน URI ของไฟล์ที่สร้างขึ้น
Storage Access Framework (SAF) เป็น วิธีที่แนะนำ สำหรับการเข้าถึงไฟล์ตามอำเภอใจบน Android 10+ SAF มีไดอะล็อกตัวเลือกไฟล์ของระบบซึ่งผู้ใช้ให้สิทธิ์แอปพลิเคชันในการเข้าถึงไฟล์หรือไดเรกทอรีที่ระบุ แอปพลิเคชันได้รับ URI การเข้าถึงซึ่งมีผลจนกว่าอุปกรณ์จะรีบูตหรือจนกว่าสิทธิ์จะถูกเพิกถอนอย่างชัดแจ้งในการตั้งค่า SAF ไม่ต้องการสิทธิ์ READ_EXTERNAL_STORAGE หรือ WRITE_EXTERNAL_STORAGE ซึ่งช่วยลดความยุ่งยากในการเผยแพร่บน Google Play และลดจำนวนคำขอสิทธิ์
val requestCode = 42
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
startActivityForResult(intent, requestCode)
บน iOS การทำงานกับ ไฟล์ภายนอก สร้างขึ้นรอบ UIDocumentPickerViewController ซึ่งผู้ใช้เปิดเพื่อเลือกไฟล์หรือไดเรกทอรีที่ระบุ แอปพลิเคชันไม่สามารถเข้าถึงระบบไฟล์ของไดรฟ์ภายนอกได้โดยตรง — เฉพาะไฟล์ที่ผู้ใช้เลือกอย่างชัดแจ้งเท่านั้น หลังจากเลือกไฟล์ แอปพลิเคชันจะได้รับ URL ชั่วคราวในคอนเทนเนอร์ Sandbox และสามารถทำงานกับไฟล์ผ่าน FileManager
UIDocumentPickerViewController ช่วยให้ผู้ใช้สามารถเลือกไฟล์หนึ่งไฟล์หรือมากกว่าจากแหล่งที่มาที่มีอยู่: iCloud Drive, ไดรฟ์ USB ที่เชื่อมต่อ หรือบริการคลาวด์ของบุคคลที่สาม หลังจากเลือกแล้ว ตัวควบคุมจะส่งคืนอาร์เรย์ของ URL ที่แอปพลิเคชันสามารถอ่านได้ในระหว่างเซสชัน เพื่อรักษาการเข้าถึงหลังจากแอปพลิเคชันปิด คุณต้องเรียก startAccessingSecurityScopedResource() และบันทึกบุ๊กมาร์กที่กำหนดขอบเขตความปลอดภัยใน UserDefaults
let picker = UIDocumentPickerViewController(
forOpeningContentTypes: [.data, .image],
asCopy: true
)
picker.delegate = self
func documentPicker(
controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]
) {
guard let url = urls.first else { return }
let data = try Data(contentsOf: url)
}
พารามิเตอร์ asCopy: true หมายความว่า iOS จะคัดลอกไฟล์ไปยังคอนเทนเนอร์ Sandbox ของแอปพลิเคชัน และแอปพลิเคชันจะได้รับสำเนาของตัวเองที่ไม่ขึ้นอยู่กับไฟล์ต้นฉบับ หากระบุ asCopy: false แอปพลิเคชันจะได้รับการอ้างอิงไปยังไฟล์ต้นฉบับ แต่ในการเข้าถึงไฟล์นั้น ต้องเรียก url.startAccessingSecurityScopedResource() หากไม่เรียกนี้ การอ่านไฟล์จะทำให้เกิดข้อยกเว้น หลังจากทำงานกับไฟล์เสร็จแล้ว ให้เรียก url.stopAccessingSecurityScopedResource() เสมอเพื่อปล่อยทรัพยากรและป้องกันการรั่วไหลของตัวอธิบาย
ความปลอดภัย ของพื้นที่จัดเก็บภายนอกต่ำกว่าพื้นที่จัดเก็บภายในเนื่องจากไฟล์สามารถเข้าถึงได้โดยแอปพลิเคชันอื่น แอปพลิเคชันใดๆ ที่มีสิทธิ์ READ_EXTERNAL_STORAGE สามารถอ่านไฟล์ทั้งหมดบนการ์ด SD รวมถึงไฟล์ที่แอปพลิเคชันของคุณสร้างขึ้นเพื่อจัดเก็บข้อมูลที่ละเอียดอ่อนชั่วคราว แอปพลิเคชันที่เป็นอันตรายอาจสแกนการ์ด SD และดึงข้อมูลผู้ใช้หากไม่ได้เข้ารหัส ดังนั้นจึงไม่แนะนำอย่างยิ่งให้เก็บโทเค็นการตรวจสอบสิทธิ์ รหัสผ่าน หรือข้อมูลส่วนตัวของผู้ใช้ในพื้นที่จัดเก็บภายนอกในรูปแบบข้อความธรรมดา
บน Android 10+ Scoped Storage จำกัดความสามารถของแอปพลิเคชันในการเข้าถึงระบบไฟล์ที่ใช้ร่วมกันอย่างมาก แอปพลิเคชันสามารถอ่านไฟล์ที่สร้างขึ้นเองเท่านั้นโดยไม่ต้องมีสิทธิ์ และการเข้าถึงไฟล์จากแอปพลิเคชันอื่นต้องได้รับความยินยอมอย่างชัดแจ้งจากผู้ใช้ผ่านไดอะล็อก SAF อย่างไรก็ตาม ข้อจำกัดนี้ใช้ไม่ได้กับแอปพลิเคชันที่มีเวอร์ชัน SDK เป้าหมายต่ำกว่า 29 — แอปพลิเคชันเหล่านั้นยังคงทำงานภายใต้โมเดลเก่า ซึ่งสร้างความเสี่ยงสำหรับผู้ใช้ที่ไม่ได้อัปเดตแอปพลิเคชันของตน Google Play กำหนดให้ targetSdkVersion 29+ สำหรับแอปพลิเคชันใหม่และที่อัปเดตทั้งหมดตั้งแต่ปี 2021
การฟอร์แมตและการเข้ารหัส เป็นอีกด้านที่สำคัญของความปลอดภัย การ์ด SD ที่ฟอร์แมตเป็นพื้นที่จัดเก็บแบบพกพาจะไม่ถูกเข้ารหัสโดยระบบตามค่าเริ่มต้น แม้เมื่อใช้พื้นที่จัดเก็บแบบปรับใช้ได้ การเข้ารหัสจะเปิดใช้งานก็ต่อเมื่อผู้ผลิตอุปกรณ์เปิดใช้งานคุณสมบัตินี้ในเฟิร์มแวร์แล้วเท่านั้น เพื่อปกป้องข้อมูลที่ละเอียดอ่อนที่บันทึกไว้ในพื้นที่จัดเก็บภายนอก ให้ใช้ไลบรารี EncryptedFile จาก AndroidX Security ซึ่งเข้ารหัสแต่ละไฟล์แยกต่างหากโดยใช้ AES256-GCM โดยไม่ขึ้นอยู่กับการเข้ารหัสของระบบ
การใช้พื้นที่จัดเก็บภายนอกอย่างมีประสิทธิภาพ จำเป็นต้องมีความสมดุลระหว่างความพร้อมของข้อมูลและความปลอดภัย ปฏิบัติตามกฎเหล่านี้เพื่อให้แน่ใจว่าการจัดเก็บไฟล์ผู้ใช้มีความน่าเชื่อถือ
Environment.getExternalStorageState() เพื่อตรวจสอบสถานะการ์ด SD การ์ดอาจถูกถอดออก เสียหาย หรือไม่พร้อมใช้งานสำหรับการเขียนสิ่งสำคัญที่ต้องจำคือ พื้นที่จัดเก็บภายนอก ไม่รับประกันความสมบูรณ์ของข้อมูลระหว่างที่เกิดความล้มเหลว การ์ด SD มีจำนวนรอบการเขียนซ้ำที่จำกัด โดยเฉพาะรุ่นประหยัดของ Class 4 และ Class 6 ด้วยการเขียนที่เข้มข้น (เช่น การบันทึกบันทึกหรือการแคชข้อมูลสตรีมมิ่ง) การ์ดอาจเสียภายในไม่กี่เดือน สำหรับสถานการณ์ดังกล่าว ให้ใช้หน่วยความจำภายในหรือพื้นที่จัดเก็บคลาวด์ และบันทึกเฉพาะไฟล์ในพื้นที่จัดเก็บภายนอกที่ผู้ใช้ยอมรับได้หากสูญเสีย ตรวจสอบสถานะการ์ด SD เป็นประจำผ่าน StatFs และแจ้งให้ผู้ใช้ทราบเกี่ยวกับข้อผิดพลาดระบบไฟล์ที่ร้ายแรง
คำถามที่พบบ่อย
บน Android 13+ สิทธิ์ READ_EXTERNAL_STORAGE ถูกแทนที่ด้วยสิทธิ์ที่ละเอียดมากขึ้น: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO และ READ_MEDIA_AUDIO สำหรับไฟล์ประเภทอื่น ให้ใช้ SAF
ใช่ คุณสมบัติ adoptable storage มีให้ใช้งานบน Android 6.0+ การ์ดจะถูกฟอร์แมตเป็น ext4 ด้วยการเข้ารหัส AES-128 อย่างไรก็ตาม ผู้ผลิตหลายรายปิดใช้งานตัวเลือกนี้ และประมาณ 88% ของอุปกรณ์ไม่รองรับพื้นที่จัดเก็บแบบปรับใช้ได้
ใช้เมธอด Environment.getExternalStorageState() ซึ่งส่งคืนสตริงสถานะ ค่า MEDIA_MOUNTED หมายถึงการ์ดพร้อมใช้งานสำหรับการอ่านและเขียน ค่าอื่นๆ บ่งชี้ข้อผิดพลาดหรือไม่มีการ์ด
Scoped Storage จำกัดแอปพลิเคชันให้อยู่ในคอนเทนเนอร์ของตัวเองและแกลเลอรีสื่อ MediaStore ที่ใช้ร่วมกัน การเข้าถึงแบบเต็มอนุญาตให้อ่านไฟล์ใดๆ บนอุปกรณ์ Scoped Storage ช่วยเพิ่ม ความปลอดภัย ของข้อมูลผู้ใช้และจำเป็นสำหรับแอปพลิเคชันใหม่
เรียกใช้ Intent ด้วยการดำเนินการ ACTION_OPEN_DOCUMENT_TREE ซึ่งจะเปิดไดอะล็อกตัวเลือกไดเรกทอรีของระบบ หลังจากเลือกแล้ว คุณจะได้รับสิทธิ์ URI ที่มีผลจนกว่าจะรีบูต บันทึก URI นี้ใน SharedPreferences สำหรับการใช้ในภายหลัง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม