파일 시스템 작업은 모든 모바일 애플리케이션의 기초입니다. 각 플랫폼은 자체 액세스 모델을 제공합니다. iOS의 Sandbox는 애플리케이션을 별도의 컨테이너에 격리하고, Android의 Scoped Storage는 공유 스토리지에 대한 직접 액세스를 제한합니다. Google Developer Documentation (2026)에 따르면, Android 10에서 Scoped Storage의 도입으로 데이터 스토리지 아키텍처의 완전한 재검토가 필요했습니다. 이 가이드에서는 두 플랫폼의 FileManager, MediaStore API, Storage Access Framework 및 DocumentProvider를 다룹니다.
주요 내용
모바일 애플리케이션의 파일 시스템은 iOS 및 Android 기기에서 데이터 저장 및 액세스를 정의하는 API, 보안 규칙 및 제약 조건의 집합입니다. 데스크톱 운영 체제와 달리, 모바일 플랫폼은 각 애플리케이션을 격리하여 다른 프로그램의 무단 읽기로부터 사용자 데이터를 보호합니다.
iOS는 Sandbox 모델을 사용하며, 각 앱은 엄격하게 제한된 권한으로 자체 컨테이너에 존재합니다. 버전 10 이전의 Android는 외부 스토리지에 대한 전체 액세스를 제공했지만, Scoped Storage의 도입으로 접근 방식이 iOS에 가까워졌습니다. 주요 차이점은 iOS가 파일 시스템을 완전히 격리하는 반면, Android는 개인 디렉토리, 공개 MediaStore 및 SAF를 통한 임시 액세스 등 여러 액세스 수준을 제공한다는 것입니다.
모바일 애플리케이션은 세 가지 유형의 데이터 스토리지를 사용합니다. 개인 스토리지 — 내부 파일 및 캐시를 위한 앱 전용 디렉토리입니다. 공유 스토리지 — MediaStore(Android) 또는 Files App(iOS)을 통한 미디어 파일입니다. 클라우드 스토리지 — 기기 간 동기화를 위한 iCloud Drive 및 Google Drive입니다. 각 유형에는 크기, 파일 수명 및 액세스 조건에 대한 자체 제한이 있습니다.
| 스토리지 유형 | iOS | Android |
|---|---|---|
| 개인 | Documents, Library, Caches | getFilesDir(), getCacheDir() |
| 공유 미디어 | PHPhotoLibrary(피커 통해) | MediaStore API (ContentResolver) |
| 공유 문서 | UIDocumentPicker 통한 Files App | Storage Access Framework (SAF) |
| 클라우드 | iCloud Drive (UIDocument) | Google Drive API |
| 캐시 | Caches 디렉토리(시스템이 정리) | getCacheDir(), getExternalCacheDir() |
Sandbox는 각 애플리케이션을 격리하는 iOS의 보안 아키텍처입니다. 앱은 자체 샌드박스 내에서만 읽고 쓸 수 있습니다. 연락처, 사진 또는 다른 앱의 파일에 액세스하려면 UIImagePickerController 또는 UIDocumentPickerViewController와 같은 시스템 피커를 사용해야 합니다. Files App에 대한 액세스는 Info.plist의 UIFileSharingEnabled 플래그를 통해 구성됩니다. iOS의 모바일 개발에서 파일 시스템을 이해하려면 디렉토리 구조를 파악하고 각 데이터 유형에 적합한 위치를 선택해야 합니다.
iOS 샌드박스는 여러 표준 디렉토리로 구성됩니다. Documents — 사용자 파일용, iCloud Backup에 포함됩니다. Caches — 스토리지 부족 시 시스템이 삭제할 수 있는 임시 데이터용입니다. Temporary — 현재 세션 파일용, 재시작 시 지워집니다. Application Support — 사용자에게 숨겨진 내부 앱 데이터용입니다. 잘못된 디렉토리를 선택하면 문제가 발생합니다. Documents에 캐시를 저장하면 iCloud 공간을 낭비하고 Apple의 파일 시스템 지침을 위반합니다.
import Foundation
let fileManager = FileManager.default
guard let documentsURL = fileManager.urls(
for: .documentDirectory,
in: .userDomainMask
).first else { return }
let fileURL = documentsURL.appendingPathComponent("notes.txt")
let text = "Содержимое файла"
// 암호화된 원자적 쓰기
try text.write(
to: fileURL,
atomically: true,
encoding: .utf8
)
FileManager 클래스는 iOS에서 파일을 관리하기 위한 완전한 메서드 세트를 제공합니다. FileManager.default는 스레드 안전한 싱글톤으로 대부분의 작업에 적합합니다. fileExists(atPath:), createDirectory(at:withIntermediateDirectories:attributes:), copyItem(at:to:) 및 removeItem(at:)와 같은 메서드는 기본 시나리오를 다룹니다. 1MB보다 큰 파일 작업은 DispatchQueue.global()을 통해 백그라운드 스레드에서 수행해야 합니다. 대용량 스트리밍의 경우 전체 파일을 메모리에 로드하는 대신 FileHandle을 사용하십시오.
func readDocumentsFile(named fileName: String) -> String? {
guard let docsURL = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
).first else { return nil }
let fileURL = docsURL.appendingPathComponent(fileName)
return try? String(contentsOf: fileURL)
}
Android 10 출시와 함께 Google은 Scoped Storage — 파일 시스템에 대한 제한된 액세스 모델을 도입했습니다. 앱은 개인 디렉토리에서만 자유롭게 읽고 쓸 수 있습니다. 미디어 파일(사진, 동영상, 오디오)의 경우 ContentResolver를 통해 MediaStore API를 사용합니다. 임의 문서의 경우 Intent ACTION_OPEN_DOCUMENT를 통해 Storage Access Framework를 사용합니다. Android 11+에서는 외부 스토리지의 루트에 대한 직접 액세스가 완전히 금지되며, 모든 개발자는 새로운 API를 사용해야 합니다.
MediaStore는 기기에서 미디어 파일에 액세스하기 위한 시스템 ContentProvider입니다. ContentResolver를 통해 앱은 직접 경로 대신 파일 Uri를 요청합니다. MediaStore.Files — 모든 파일 유형용, Images — 이미지용, Video — 비디오용, Audio — 오디오 녹음용입니다. 공유 디렉토리에 쓰기는 DISPLAY_NAME, MIME_TYPE 및 RELATIVE_PATH와 함께 insert()를 통해 수행됩니다. 삽입 후 앱은 Uri를 받고 이를 통해 바이트가 기록됩니다. MIME 유형이 중요한 역할을 합니다 — 잘못된 유형은 파일을 열 때 오류를 발생시킵니다.
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "report.pdf")
put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf")
put(MediaStore.MediaColumns.RELATIVE_PATH, "Documents/Reports")
}
val uri = contentResolver.insert(
MediaStore.Files.getContentUri("external"),
contentValues
)
uri?.let {
contentResolver.openOutputStream(it)?.use { stream ->
stream.write(pdfBytes)
}
}
SAF는 런타임 권한 없이 파일을 선택하고 생성하기 위한 통합 인터페이스를 제공합니다. Intent ACTION_OPEN_DOCUMENT는 Android에서 시스템 파일 관리자를 엽니다. 선택 후 앱은 FLAG_GRANT_READ_URI_PERMISSION을 통한 임시 액세스 권한이 있는 content:// Uri를 받습니다. ACTION_CREATE_DOCUMENT를 사용하면 사용자가 선택한 모든 외부 스토리지 위치에 파일을 저장할 수 있습니다. SAF는 Android 5+에서 작동하며 DocumentsProvider를 통해 연결된 클라우드 제공자의 파일에 대한 액세스를 제공합니다.
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
"application/pdf",
"text/plain"
))
}
startActivityForResult(intent, REQUEST_CODE)
두 플랫폼 모두 사용자가 파일을 선택할 수 있는 내장 메커니즘을 제공합니다. 모바일 애플리케이션의 문서는 영구 권한 없이 파일에 대한 임시 액세스를 제공하는 시스템 피커를 통해 전달됩니다. iOS에서는 UIDocumentPickerViewController, Android에서는 ACTION_OPEN_DOCUMENT입니다. 모바일 애플리케이션의 문서는 로컬 스토리지와 클라우드 서비스 모두에서 선택할 수 있습니다. 사용자가 명시적으로 파일을 지정하면 앱이 제한된 유효 기간의 Uri 또는 URL을 받습니다.
UIDocumentPickerViewController는 Files App을 열고 하나 이상의 문서를 선택할 수 있습니다. 모드: 가져오기(샌드박스에 복사) 및 열기(보안 범위 URL을 통한 액세스). 파일 필터링을 위해 UTType 유형의 배열이 전달됩니다 — 예: .pdf 및 .plainText. URL을 받은 후 앱은 읽기 전에 startAccessingSecurityScopedResource()를 호출하고 완료 후 stopAccessingSecurityScopedResource()를 호출해야 합니다. stopAccessing을 호출하지 않으면 시스템 리소스 누수가 발생합니다. iOS의 모바일 애플리케이션에서 문서는 파일 작업 완료 후 임시 권한을 반드시 해제해야 합니다.
let picker = UIDocumentPickerViewController(
forOpeningContentTypes: [.pdf, .plainText]
)
picker.allowsMultipleSelection = true
picker.delegate = self
present(picker, animated: true)
// 델리게이트에서 액세스 해제
func documentPicker(
_ controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]
) {
guard let url = urls.first else { return }
url.startAccessingSecurityScopedResource()
defer { url.stopAccessingSecurityScopedResource() }
}
FileProvider는 앱 간에 파일을 안전하게 공유하기 위한 ContentProvider의 서브클래스입니다. 지정된 XML 디렉토리의 파일을 기반으로 임시 content:// Uri를 생성합니다. 다른 앱은 FLAG_GRANT_READ_URI_PERMISSION과 함께 Intent를 통해 액세스 권한을 얻습니다. DocumentProvider는 FileProvider와 달리 SAF에 파일을 게시하고 다른 앱이 파일 시스템의 일부로 앱의 콘텐츠를 탐색할 수 있도록 합니다. DocumentsProvider를 구현하려면 queryRoots(), queryChildDocuments() 및 openDocument()를 재정의한 다음 AndroidManifest.xml에 등록해야 합니다.
클라우드 동기화는 사용자가 모든 기기에서 문서에 액세스할 수 있게 합니다. 모바일 애플리케이션의 파일 시스템은 클라우드 계층으로 확장됩니다. iOS의 UIDocument는 변경 사항을 자동으로 추적하고 iCloud를 통해 동기화합니다. Android에서는 Google Drive API 또는 클라우드 루트가 있는 DocumentsProvider를 통해 유사한 기능이 구축됩니다. 안정적인 기기 간 동기화를 구축하려면 모바일 개발의 파일 시스템을 이해하는 것이 중요합니다.
UIDocument는 iCloud 문서 작업을 위한 추상 클래스입니다. 변경 사항을 자동으로 저장하고, 데이터를 읽고, 델리게이트에 업데이트를 알립니다. 쓰기 충돌 시 NSFileVersion이 사용 가능한 버전 목록을 제공합니다 — 개발자는 최신 버전을 선택하거나 사용자에게 충돌 해결 옵션을 표시할 수 있습니다. iCloud Drive를 사용하려면 프로젝트 Capabilities에서 Ubiquity Container를 구성해야 합니다. NSFileCoordinator와 NSFilePresenter는 여러 스레드 또는 기기에서 동시 액세스 시 데이터 경합을 방지합니다.
iOS는 자동으로 Documents 디렉토리를 iCloud Backup에 포함시킵니다. Android는 Auto Backup for Apps로 작동합니다 — 시스템이 getFilesDir(), SharedPreferences 및 SQLite 데이터베이스의 데이터를 Google Drive에 저장합니다. 캐시 및 외부 파일은 백업에 포함되지 않습니다. 두 플랫폼 모두 예외 구성을 허용합니다. iOS는 NSURLIsExcludedFromBackupKey, Android는 XML 백업 규칙 구성을 통해 설정합니다. 개인 데이터가 포함된 파일의 암호화는 필수입니다 — iOS에서는 NSDataWritingFileProtectionComplete를, Android에서는 security-crypto 라이브러리의 EncryptedFile을 사용하십시오.
| 매개변수 | iOS | Android |
|---|---|---|
| 기본 백업 | Documents 및 Library | getFilesDir(), SharedPreferences, DB |
| 파일 제외 | isExcludedFromBackupKey | XML 백업 규칙 (fullBackupContent) |
| 암호화 | NSDataWritingFileProtectionComplete | EncryptedFile (security-crypto) |
| 클라우드 동기화 | UIDocument + iCloud | Google Drive API + SAF |
| 자동 복원 | 설치 후 iCloud Restore | 재설치 시 Auto Backup |
자주 묻는 질문
Sandbox는 iOS에서 각 앱을 위한 격리된 환경입니다. UIDocumentPickerViewController와 같은 시스템 피커를 사용하지 않으면 다른 앱의 파일에 접근할 수 없습니다.
Scoped Storage는 Android 10+의 제한된 파일 시스템 액세스 모델입니다. 앱은 자체 파일만 직접 읽고, 미디어에는 MediaStore API, 문서에는 Storage Access Framework를 사용합니다.
UIDocumentPickerViewController — Files App 또는 iCloud Drive에서 문서를 선택하기 위한 시스템 피커를 사용합니다. 선택 후 임시 액세스 권한이 있는 보안 범위 URL을 받습니다.
미디어 파일의 경우 MIME 유형을 지정하여 ContentResolver를 통해 MediaStore API를 사용합니다. 임의 문서의 경우 Intent ACTION_OPEN_DOCUMENT와 함께 Storage Access Framework를 사용합니다.
FileProvider는 FLAG_GRANT_READ_URI_PERMISSION과 함께 임시 content:// Uri를 통해 앱 간에 파일을 안전하게 공유하기 위한 ContentProvider의 서브클래스입니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.