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-এ, requestLegacyExternalStorage-এর মাধ্যমে Scoped Storage বন্ধ করা যেতে পারে। Android 11+-এ, পরীক্ষা করুন যে ম্যানিফেস্ট ফ্ল্যাগ requestLegacyExternalStorage সেট করা আছে কিনা — যদি না থাকে, তাহলে Scoped Storage সক্রিয়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন