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 کے مطابق، Android کے 65% سے زیادہ صارفین ایپ کا انتخاب کرتے وقت ڈیٹا کی رازداری کو ایک اہم عنصر سمجھتے ہیں۔ 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 ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں