Storage Access Framework là một framework Android để truy cập an toàn vào tệp và tài liệu thông qua hộp thoại chọn của hệ thống. Thay vì yêu cầu quyền đọc bộ nhớ rộng rãi, ứng dụng nhận được một liên kết URI đến tệp do người dùng chọn. Theo Android Developers (2026), SAF hỗ trợ bộ nhớ cục bộ, các dịch vụ đám mây Google Drive và Dropbox thông qua DocumentProvider. Framework được giới thiệu trong Android 4.4 và trở thành tiêu chuẩn làm việc với tài liệu từ Android 10.
Các điểm chính
Storage Access Framework là một phần của Android SDK cung cấp giao diện thống nhất để chọn và tạo tài liệu thông qua hộp thoại hệ thống. SAF trừu tượng hóa vị trí vật lý của tệp: ứng dụng không biết tệp được đọc từ đâu — đĩa cục bộ, Google Drive hay Dropbox.
Kiến trúc SAF bao gồm ba thành phần: ứng dụng khách khởi tạo yêu cầu, trình chọn hệ thống — hộp thoại chọn tệp tiêu chuẩn, và DocumentProvider — nhà cung cấp nội dung thực hiện quyền truy cập vào tệp của một bộ nhớ cụ thể. Người dùng thấy một giao diện thống nhất bất kể nguồn dữ liệu.
SAF có sẵn từ Android 4.4 (API 19). Ban đầu, framework chỉ hỗ trợ tài liệu, nhưng Android 5.0 đã thêm hỗ trợ thư mục thông qua ACTION_OPEN_DOCUMENT_TREE. Từ Android 10, SAF trở thành phương pháp được khuyến nghị để truy cập bất kỳ tệp nào bên ngoài bộ nhớ dành riêng cho ứng dụng.
SAF khởi chạy hộp thoại chọn tệp hệ thống thông qua Intent với hành động ACTION_OPEN_DOCUMENT. Người dùng thấy danh sách các nguồn khả dụng: bộ nhớ trong, Google Drive, Dropbox và các nhà cung cấp đã đăng ký khác. Sau khi chọn tệp, hệ thống trả về content URI với quyền truy cập tạm thời.
Content URI có định dạng content://com.android.externalstorage.documents/document/primary/Download/file.pdf. Không giống như URI file://, content URI không tiết lộ đường dẫn tệp thực tế và hoạt động thông qua DocumentProvider. Ứng dụng đọc tệp qua ContentResolver.openInputStream bằng URI nhận được.
Trình chọn hệ thống tự động hỗ trợ tìm kiếm, sắp xếp và lọc tệp theo loại MIME. Nhà phát triển chỉ định các loại cần thiết qua Intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("application/pdf", "image/*")), và trình chọn chỉ hiển thị các tệp liên quan.
Theo mặc định, URI có hiệu lực cho đến khi khởi động lại ứng dụng hoặc thiết bị. Để truy cập dài hạn, ứng dụng yêu cầu takePersistableUriPermission — điều này cho phép đọc tệp trong các lần khởi chạy sau mà không cần chọn lại qua hộp thoại.
SAF cung cấp ba hành động chính để làm việc với tệp: mở, tạo và chọn cây thư mục. ACTION_OPEN_DOCUMENT mở trình chọn hệ thống để chọn tệp hiện có. ACTION_CREATE_DOCUMENT tạo tệp mới — người dùng nhập tên trong hộp thoại và ứng dụng nhận URI để ghi.
ACTION_OPEN_DOCUMENT_TREE cho phép chọn toàn bộ thư mục và truy cập tất cả tệp bên trong nó. Điều này được sử dụng trong trình quản lý tệp, ứng dụng sao lưu và đồng bộ hóa. Ứng dụng nhận URI thư mục và có thể liệt kê đệ quy nội dung qua DocumentFile.
| Hành động | Mục đích | Cờ |
|---|---|---|
| ACTION_OPEN_DOCUMENT | Chọn tệp hiện có | READ_FLAG |
| ACTION_CREATE_DOCUMENT | Tạo tệp mới | WRITE_FLAG |
| ACTION_OPEN_DOCUMENT_TREE | Chọn thư mục | READ + WRITE |
Cho mỗi hành động, các loại MIME được chỉ định qua EXTRA_MIME_TYPES. Có thể chỉ định nhiều loại: "application/pdf", "image/*", "text/plain". Nếu không chỉ định loại nào, trình chọn hiển thị tất cả tệp.
Persistent URI permissions là một cơ chế SAF cho phép duy trì quyền truy cập vào tệp sau khi phiên hiện tại kết thúc. Không có cờ này, URI chỉ có hiệu lực cho đến khi khởi động lại ứng dụng. Ứng dụng yêu cầu cờ FLAG_GRANT_PERSISTABLE_URI_PERMISSION cùng với các cờ READ và WRITE.
Để lưu quyền, phương thức ContentResolver.takePersistableUriPermission được sử dụng. Hệ thống lưu URI vào một sổ đăng ký đặc biệt và khôi phục quyền truy cập ở lần khởi động ứng dụng tiếp theo. Để kiểm tra xem ứng dụng có quyền truy cập liên tục vào URI hay không, sử dụng ContentResolver.persistedUriPermissions.
Người dùng có thể thu hồi quyền đã lưu qua Cài đặt → Ứng dụng → Quyền. Ứng dụng nên xử lý tình huống mất quyền truy cập vào tệp bất ngờ. Khuyến nghị kiểm tra quyền truy cập qua ContentResolver.openInputStream trước khi bắt đầu làm việc và xử lý SecurityException đúng cách.
SAF được khởi chạy qua Intent tiêu chuẩn. Mã rất đơn giản: tạo Intent với ACTION_OPEN_DOCUMENT, chỉ định loại MIME và khởi chạy qua ActivityResultContracts.StartActivityForResult. Sau khi chọn tệp, callback nhận URI trong data.data, sau đó được sử dụng để đọc.
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)
Để ghi tệp mới, sử dụng ACTION_CREATE_DOCUMENT. Intent chấp nhận loại MIME và tên tệp qua EXTRA_TITLE. Sau khi chọn thư mục và xác nhận, người dùng trả về URI mà ứng dụng ghi dữ liệu qua ContentResolver.openOutputStream. Hệ thống tự động tạo tệp tại vị trí đã chọn.
SAF khác với READ_EXTERNAL_STORAGE truyền thống ở cách tiếp cận bảo mật hoàn toàn khác. Thay vì yêu cầu quyền truy cập toàn bộ bộ nhớ cùng một lúc, SAF chỉ yêu cầu quyền truy cập vào một tệp cụ thể. Điều này giảm thiểu bề mặt tấn công và tăng niềm tin của người dùng.
READ_EXTERNAL_STORAGE cấp quyền truy cập vào tất cả tệp trên thiết bị, bao gồm ảnh và tài liệu từ ứng dụng khác. Trên Android 10+, cách tiếp cận này bị hạn chế. Ngược lại, SAF chỉ cung cấp quyền truy cập vào tệp do người dùng chọn và yêu cầu xác nhận rõ ràng cho mỗi tệp. Đối với thao tác hàng loạt trên phương tiện, hãy sử dụng MediaStore; đối với tài liệu riêng lẻ, hãy sử dụng SAF.
Nhược điểm chính của SAF là cần chọn từng tệp riêng lẻ. Đối với thao tác hàng loạt (sao lưu, đồng bộ thư mục), sử dụng ACTION_OPEN_DOCUMENT_TREE, cấp quyền truy cập vào tất cả tệp trong thư mục đã chọn. Giải pháp phụ thuộc vào kịch bản: SAF tối ưu cho lựa chọn của người dùng, MediaStore cho truy cập phương tiện theo chương trình.
Câu hỏi thường gặp
Storage Access Framework là một framework Android để truy cập tệp an toàn thông qua hộp thoại chọn của hệ thống. Ứng dụng nhận content URI cho tệp đã chọn mà không yêu cầu quyền đọc bộ nhớ rộng rãi.
Tạo Intent với ACTION_OPEN_DOCUMENT, chỉ định loại MIME qua setType và khởi chạy qua ActivityResultContracts. Trong callback, lấy URI từ data.data và đọc qua ContentResolver.openInputStream.
Persistent URI permissions là cơ chế duy trì quyền truy cập vào URI sau khi khởi động lại ứng dụng. Nó được yêu cầu qua cờ FLAG_GRANT_PERSISTABLE_URI_PERMISSION và phương thức takePersistableUriPermission.
SAF hỗ trợ mọi loại MIME: application/pdf, image/*, text/plain, application/zip và các loại khác. Các loại được chỉ định qua Intent.putExtra với mảng EXTRA_MIME_TYPES.
SAF được thiết kế để người dùng chọn tệp riêng lẻ thông qua hộp thoại hệ thống. MediaStore cung cấp quyền truy cập theo chương trình vào tất cả tệp phương tiện trên thiết bị thông qua cơ sở dữ liệu phương tiện mà không cần người dùng tương tác.
Tóm tắt
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm