Scoped Storage एक फ़ाइल सिस्टम एक्सेस मॉडल है जो Android 10 (API 29) में पेश किया गया था, जो डिवाइस के साझा स्टोरेज तक ऐप्स की मनमानी पहुंच को प्रतिबंधित करता है। Google Android Developer Documentation (2024) के अनुसार, Scoped Storage READ_EXTERNAL_STORAGE और WRITE_EXTERNAL_STORAGE की पुरानी अनुमति मॉडल को बदलता है, जो ऐप्स को केवल उनकी अपनी फ़ाइलों तक एक पृथक सैंडबॉक्स में और MediaStore के माध्यम से साझा संग्रह तक पहुंच प्रदान करता है। यह मॉडल उपयोगकर्ता डेटा गोपनीयता को बढ़ाता है और ऐप्स द्वारा जानकारी के अनधिकृत संग्रह को रोकता है।
मुख्य बिंदु
Scoped Storage Android 10 (API 29) में एक आर्किटेक्चरल बदलाव है जो मौलिक रूप से डिवाइस के फ़ाइल सिस्टम तक ऐप्स की पहुंच के तरीके को बदलता है। साझा स्टोरेज तक पूर्ण पहुंच के बजाय, ऐप को केवल अपने सैंडबॉक्स और MediaStore के माध्यम से विशिष्ट मीडिया संग्रह तक पहुंच मिलती है।
Scoped Storage से पहले, READ_EXTERNAL_STORAGE अनुमति वाला कोई भी ऐप साझा स्टोरेज में सभी फ़ाइलों को पढ़ सकता था — फ़ोटो, दस्तावेज़, डाउनलोड, अन्य ऐप्स का डेटा। इससे गोपनीयता जोखिम पैदा होते थे: अविश्वसनीय ऐप्स उपयोगकर्ता की जानकारी उसकी जानकारी के बिना एकत्र कर सकते थे।
Google I/O 2019 के अनुसार, 65% से अधिक Android उपयोगकर्ता ऐप चुनते समय डेटा गोपनीयता को एक महत्वपूर्ण कारक मानते हैं। Scoped Storage इस मांग का सीधा जवाब है: प्रत्येक ऐप एक पृथक वातावरण में काम करता है और उपयोगकर्ता की स्पष्ट सहमति पर ही अन्य ऐप्स के डेटा तक पहुंच प्राप्त करता है।
महत्वपूर्ण: Android 10 में Scoped Storage वैकल्पिक था (ऐप इसे requestLegacyExternalStorage के माध्यम से बंद कर सकता था)। Android 11 (API 30) से शुरू होकर, Scoped Storage सभी ऐप्स के लिए अनिवार्य हो गया, चाहे target SDK कुछ भी हो।
Google ने फ़ाइलों तक पहुंच के पुराने मॉडल की तीन मूलभूत समस्याओं को हल करने के लिए Scoped Storage पेश किया: गोपनीयता, अनुमति प्रबंधन और अवशिष्ट फ़ाइलों की सफाई।
पुराने मॉडल में, READ_EXTERNAL_STORAGE वाला ऐप पूरे साझा स्टोरेज को स्कैन कर सकता था और उपयोगकर्ता की फ़ाइलों के मेटाडेटा एकत्र कर सकता था — फ़ोटो के भौगोलिक निर्देशांक, दस्तावेज़ों के नाम, निर्देशिकाओं की संरचना। Scoped Storage इस संभावना को समाप्त करता है: अनुमति होने पर भी, ऐप केवल अपने द्वारा बनाई गई फ़ाइलों और SAF के माध्यम से उपयोगकर्ता द्वारा स्पष्ट रूप से चुनी गई फ़ाइलों को देखता है।
Scoped Storage से पहले, ऐप अनइंस्टॉल करने के बाद साझा स्टोरेज में फ़ाइलें छोड़ सकते थे। समय के साथ, जंक निर्देशिकाएं जमा हो जाती थीं। Scoped Storage इसे हल करता है: ऐप के सैंडबॉक्स में सभी फ़ाइलें ऐप के साथ हटा दी जाती हैं, और MediaStore के माध्यम से फ़ाइलों का एक मालिक होता है और सिस्टम द्वारा साफ किया जा सकता है।
| पहलू | पुराना मॉडल (Legacy) | Scoped Storage |
|---|---|---|
| साझा स्टोरेज तक पहुंच | पूर्ण (अनुमति के साथ) | केवल अपना सैंडबॉक्स |
| मीडिया फ़ाइलें | सीधा फ़ाइल पथ | MediaStore URI के माध्यम से |
| अन्य ऐप्स की फ़ाइलें | हमेशा सुलभ | केवल SAF के माध्यम से |
| अनइंस्टॉल पर सफाई | फ़ाइलें रह जाती हैं | सैंडबॉक्स हटा दिया जाता है |
| उपयोगकर्ता नियंत्रण | न्यूनतम | प्रति फ़ाइल स्पष्ट सहमति |
Scoped Storage Android में Google की समग्र गोपनीयता रणनीति का हिस्सा है, जिसमें "केवल उपयोग के दौरान" अनुमतियां, कैमरा और माइक्रोफ़ोन एक्सेस संकेतक और प्राइवेसी डैशबोर्ड भी शामिल हैं।
प्रत्येक Android ऐप को अपनी निजी निर्देशिका मिलती है, जो Context.getFilesDir() और context.getCacheDir() के माध्यम से सुलभ होती है। बाहरी (साझा) निजी निर्देशिका तक पहुंच के लिए Context.getExternalFilesDir() का उपयोग किया जाता है।
Scoped Storage में, ऐप को बिना किसी अनुमति के अपनी बाहरी निजी निर्देशिका तक पूर्ण पहुंच होती है। यह उन फ़ाइलों को संग्रहीत करने के लिए प्राथमिक स्थान है जो अन्य ऐप्स के लिए सुलभ नहीं होनी चाहिए या जो ऐप अपने उपयोग के लिए बनाता है।
import android.os.Environment
import java.io.File
import java.io.IOException
class FileManager {
fun saveToAppStorage(context: Context, fileName: String, data: ByteArray) {
val appDir = context.getExternalFilesDir(null)
?: return
val file = File(appDir, fileName)
file.writeBytes(data)
}
fun readFromAppStorage(context: Context, fileName: String): ByteArray? {
val appDir = context.getExternalFilesDir(null)
?: return null
val file = File(appDir, fileName)
return file.takeIf { it.exists() }?.readBytes()
}
}
बाहरी निजी निर्देशिका का पथ: /storage/emulated/0/Android/data/{packageName}/files/। Android 11 से शुरू होकर, सीधा फ़ाइल पथ उपलब्ध नहीं है — केवल API के माध्यम से। यह Scoped Storage की एक और सुरक्षा वृद्धि है।
MediaStore Scoped Storage में साझा मीडिया फ़ाइलों (चित्र, वीडियो, ऑडियो) तक पहुंच के लिए प्राथमिक API है। ऐप फ़ाइल पथों के साथ नहीं, बल्कि MediaStore प्रदाता द्वारा प्रदान किए गए content URIs के साथ काम करता है।
MediaStore तीन मुख्य संग्रहों में विभाजित है: Images, Video और Audio। प्रत्येक संग्रह ContentResolver के माध्यम से CRUD संचालन का समर्थन करता है। Images संग्रह में एक नई फ़ाइल डालने के लिए MediaStore.Images.Media का उपयोग किया जाता है; मौजूदा फ़ाइलों को क्वेरी करने के लिए — संबंधित URI के साथ query का उपयोग किया जाता है।
import android.content.ContentValues
import android.provider.MediaStore
import android.os.Environment
import java.io.OutputStream
fun saveImageToGallery(context: Context, bitmap: Bitmap, title: String) {
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "$title.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(
MediaStore.Images.Media.RELATIVE_PATH,
"${Environment.DIRECTORY_PICTURES}/MyApp"
)
}
val uri = context.contentResolver
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
?: return
context.contentResolver.openOutputStream(uri)?.use { output: OutputStream ->
bitmap.compress(
Bitmap.CompressFormat.JPEG,
95,
output
)
}
}
महत्वपूर्ण: MediaStore मनमानी फ़ाइल पथों का समर्थन नहीं करता — केवल content URIs। MediaStore.Files.getContentUri() के माध्यम से URI से फ़ाइल पथ प्राप्त करने का प्रयास Android 11+ पर फ़ाइल तक सीधा पथ नहीं देगा। इसके बजाय, सामग्री के साथ काम करने के लिए ContentResolver.openInputStream() और openOutputStream() का उपयोग करें।
Storage Access Framework (SAF) ऐप के सैंडबॉक्स के बाहर मनमानी फ़ाइलों और निर्देशिकाओं तक पहुंच के लिए एक API है। SAF उपयोगकर्ता को फ़ाइल या निर्देशिका चयन इंटरफ़ेस प्रदान करता है, जिसके बाद ऐप को अस्थायी पहुंच के साथ एक content URI प्राप्त होता है।
SAF का उपयोग उन परिदृश्यों के लिए किया जाता है जो MediaStore द्वारा कवर नहीं किए जाते हैं: मनमाने दस्तावेज़ों (PDF, ZIP, APK) के साथ काम करना, SD कार्ड पर निर्देशिकाओं तक पहुंच, अन्य ऐप्स से फ़ाइलों का आयात और निर्यात। उपयोगकर्ता सिस्टम फ़ाइल पिकर के माध्यम से स्पष्ट रूप से एक फ़ाइल का चयन करता है — यह पहुंच के लिए उनकी सहमति की गारंटी देता है।
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.DocumentsContract
const val REQUEST_CODE_PICK_DIR = 1001
fun pickDirectory(activity: Activity) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
activity.startActivityForResult(intent, REQUEST_CODE_PICK_DIR)
}
fun handlePickResult(requestCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_PICK_DIR && data != null) {
val treeUri: Uri = data.data ?: return
// Take persistent URI permission
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
contentResolver.takePersistableUriPermission(treeUri, flags)
}
}
SAF ऐप को उपयोगकर्ता द्वारा चुनी गई निर्देशिका तक डिवाइस रीबूट तक पहुंच प्रदान करता है (takePersistableUriPermission का उपयोग करते समय)। Android 11+ पर साझा स्टोरेज में मनमानी फ़ाइलों तक पहुंच प्राप्त करने का यह एकमात्र तरीका है।
मौजूदा Android ऐप को Scoped Storage में माइग्रेट करने के लिए कई प्रमुख क्षेत्रों में बदलाव की आवश्यकता होती है। Google Android 11+ पर परीक्षण के साथ चरणबद्ध दृष्टिकोण की सिफारिश करता है।
साझा स्टोरेज में सभी सीधे File संचालन को ContentResolver.openInputStream / openOutputStream से बदलें। ऐप के सैंडबॉक्स (getExternalFilesDir) में फ़ाइलों के लिए, फ़ाइल पथ काम करते रहते हैं।
READ_EXTERNAL_STORAGE और WRITE_EXTERNAL_STORAGE हटाएं यदि वे विशिष्ट परिदृश्यों के लिए आवश्यक नहीं हैं (उदाहरण के लिए, फ़ाइल प्रबंधन — इसके लिए विशेष अनुमति MANAGE_EXTERNAL_STORAGE है)।
| परिदृश्य | पुराना दृष्टिकोण | Scoped Storage दृष्टिकोण |
|---|---|---|
| फ़ोटो सहेजना | File(path).writeBytes() | MediaStore + ContentResolver |
| PDF पढ़ना | File(path).inputStream() | SAF ACTION_OPEN_DOCUMENT |
| अपनी फ़ाइलें | Environment.getExternalStorageDirectory() | context.getExternalFilesDir() |
| कैश | File(cacheDir).writeBytes() | context.cacheDir (कोई बदलाव नहीं) |
माइग्रेशन के बाद, build.gradle में targetSdk = 30 या उच्चतर सेट करके ऐप को Android 11+ (API 30) पर परीक्षण करें। सुनिश्चित करें कि साझा स्टोरेज में सभी फ़ाइल संचालन MediaStore या SAF के माध्यम से काम करते हैं, न कि सीधे फ़ाइल पथों के माध्यम से।
import android.os.Build
fun isScopedStorage(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
}
fun compatReadFile(context: Context, uri: Uri): ByteArray? {
return if (isScopedStorage()) {
context.contentResolver
.openInputStream(uri)?.readBytes()
} else {
File(uri.path ?: return null)
.takeIf { it.exists() }
?.readBytes()
}
}
Google Play Console (2024) के अनुसार, 78% से अधिक सक्रिय Android डिवाइस Scoped Storage के साथ Android 10+ पर चलते हैं। Google Play पर अपडेट प्रकाशित करने के लिए माइग्रेशन एक अनिवार्य कदम है: नए ऐप्स को API 31+, अपडेट को API 30+ लक्षित करना चाहिए।
अक्सर पूछे जाने वाले प्रश्न
नहीं, Android 11 (API 30) से शुरू होकर Scoped Storage सभी ऐप्स के लिए अनिवार्य है। requestLegacyExternalStorage फ़्लैग, जो Android 10 में उपलब्ध था, API 30+ पर काम नहीं करता। फ़ाइल सिस्टम तक व्यापक पहुंच प्राप्त करने का एकमात्र तरीका MANAGE_EXTERNAL_STORAGE अनुमति है, लेकिन यह केवल फ़ाइल प्रबंधकों और एंटीवायरस के लिए है।
MANAGE_EXTERNAL_STORAGE उन ऐप्स के लिए एक विशेष अनुमति है जिन्हें पूर्ण फ़ाइल सिस्टम पहुंच की आवश्यकता होती है (फ़ाइल प्रबंधक, बैकअप टूल)। अनुमति का अनुरोध करने पर उपयोगकर्ता के लिए चेतावनी के साथ एक सिस्टम स्क्रीन खुलती है। Google Play पर प्रकाशित करते समय, इस अनुमति की आवश्यकता के बारे में घोषणा फॉर्म भरना आवश्यक है।
Android 11+ पर Scoped Storage में content URI से सीधा फ़ाइल पथ प्राप्त नहीं किया जा सकता। इसके बजाय, पढ़ने के लिए ContentResolver.openInputStream() और लिखने के लिए openOutputStream() का उपयोग करें। यदि आपको तृतीय-पक्ष लाइब्रेरी के साथ संगतता के लिए फ़ाइल पथ की आवश्यकता है, तो getCacheDir() में फ़ाइल की एक प्रति बनाएं और प्रति के साथ काम करें।
FileProvider बिना किसी बदलाव के काम करना जारी रखता है — इसका उपयोग ऐप के सैंडबॉक्स से फ़ाइलों तक अन्य ऐप्स को content URIs के माध्यम से पहुंच प्रदान करने के लिए किया जाता है। Scoped Storage FileProvider को प्रभावित नहीं करता, क्योंकि FileProvider content URIs के स्तर पर काम करता है, न कि सीधे फ़ाइल पथों पर।
Build.VERSION.SDK_INT जांचें: यदि >= Build.VERSION_CODES.Q (29) है, तो डिवाइस Scoped Storage का समर्थन करता है। हालांकि, Android 10 पर, Scoped Storage को requestLegacyExternalStorage के माध्यम से बंद किया जा सकता है। Android 11+ पर, जांचें कि क्या मेनिफेस्ट फ़्लैग requestLegacyExternalStorage सेट है — यदि नहीं, तो Scoped Storage सक्रिय है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें