- 📦 Android storage volumes use internal UUID-style paths, not friendly names like "SD Card".
- 🔄 Flutter uses platform channels to access native Android APIs like StorageManager.
- 🧭 The getDescription() method returns localized, easy-to-read volume labels (e.g., "Internal Storage").
- ⚙️ Android 7.0+ supports the StorageManager.getStorageVolumes API, older versions do not.
- 🛑 Apps must handle permissions and null path values when working with storage volumes.
Getting drive names users understand is hard in Android, especially with Flutter. Android shows storage paths using names like /storage/0123-4567. These aren't easy for people to understand. But you can use Flutter's platform channels with Android's StorageVolume.getDescription() API. This gets you names like "Internal Shared Storage" or "SD Card". And this guide shows how to use Kotlin code in your Flutter app through platform channels. You'll learn how to get and show storage names people can understand.
Understanding Android Storage Volumes
Android devices handle storage through "volumes." And these volumes are parts of internal storage, SD cards, or USB drives. They get connected to specific paths in the Android system. Here are some paths you might see:
/storage/emulated/0: Usually the main internal shared storage./storage/1234-5678: A removable SD card or USB OTG device./mnt/media_rw: Mount points that go with the/storagepaths.
Also, each volume gets a name like 1234-4567. This makes it hard to give them clear names right from the system. What's more, to make apps easy to use when dealing with files, you should show good names for storage. Android has StorageVolume and StorageManager. Furthermore, these let you get more info than just the path, like names people can read.
Why Easy-to-Read Volume Names Matter
If you're making a file picker or anything using storage, your app should show names people know, like “SD Card” or “USB Drive”. Don't show paths like /storage/ABCDE-1234. Showing clear names:
- Helps users feel sure when they pick where to save something.
- Stops people from picking the wrong place and losing files.
- Makes the app look good and work like other apps.
Moreover, using Android’s getDescription(Context) method, which gives names in the user's language (like "Almacenamiento interno" for Spanish), makes it much easier to find storage in your app.
Flutter and Native Android Integration using Platform Channels
Flutter apps are built with Dart, which doesn't work directly with Android's Java/Kotlin APIs. So, when you need to do things like ask for drive names, you need to use Android platform channels.
What Are Platform Channels?
Platform channels are how you call native code (like Kotlin on Android, Swift on iOS) from Flutter. With a MethodChannel, Dart code can call a function in Kotlin. It can send info and get answers back. And this is good for things Dart can't do on its own, like using Android’s StorageManager.
Basic Steps:
- Dart (Flutter) makes a
MethodChannel. - Dart sends a request (a method name and maybe some info).
- And then Android native code hears the request and answers using a method handler on the same channel name.
- Next, the answer comes back to Dart later.
Native Android: Getting Storage Names
The main Kotlin parts we will use are:
StorageManager.getStorageVolumes(): Returns all volumes.StorageVolume.getDescription(Context): Gives volume names in the user's language.StorageVolume.getDirectory(): Gives the path for the volume.
Here is how to use these:
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
for (volume in storageVolumes) {
val label = volume.getDescription(context)
val path = volume.directory?.absolutePath
}
Notes:
getDescription()gives different text based on the Android system language.directorymight benullfor volumes that aren't connected or you can't get to.- On API level < 24 (Android 7), the
getStorageVolumes()method isn’t there.
Always check if volume.directory is null. Do something else when values are missing.
Implementing Android Platform Channel in Kotlin
Let’s make an Android platform channel. It will send a list of volumes to Flutter.
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.devsolus/volume_info"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method == "getVolumes") {
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageVolumes = storageManager.storageVolumes
val volumeData = storageVolumes.map { volume ->
val label = volume.getDescription(applicationContext) ?: "Unknown"
val path = volume.directory?.absolutePath ?: "Unavailable"
mapOf("label" to label, "path" to path)
}
result.success(volumeData)
} else {
result.notImplemented()
}
}
}
}
Calling Native Code from Flutter
On the Dart side, use a MethodChannel to ask Android for the info and get it back:
import 'package:flutter/services.dart';
class VolumeInfo {
static const platform = MethodChannel('com.devsolus/volume_info');
static Future<List<Map<String, String>>> fetchVolumes() async {
final List<dynamic> result = await platform.invokeMethod('getVolumes');
return result.cast<Map<String, String>>();
}
}
What's more, this lets your Dart code get a list of all storage volumes. It will have names people can understand and the paths.
Creating a Storage Volume Model in Dart
You can make your Flutter code easier to read. Put the info into a simple model object:
class DriveVolume {
final String label;
final String path;
DriveVolume({required this.label, required this.path});
factory DriveVolume.fromMap(Map<String, dynamic> map) {
return DriveVolume(
label: map['label'] ?? 'Unknown',
path: map['path'] ?? 'Unavailable',
);
}
}
Future<List<DriveVolume>> getDriveVolumes() async {
final volumes = await VolumeInfo.fetchVolumes();
return volumes.map((volume) => DriveVolume.fromMap(volume)).toList();
}
Displaying Volumes in Flutter UI
Here’s a simple ListView.builder that shows the volumes:
FutureBuilder<List<DriveVolume>>(
future: getDriveVolumes(),
builder: (context, snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
final volumes = snapshot.data!;
return ListView.builder(
itemCount: volumes.length,
itemBuilder: (context, index) {
final volume = volumes[index];
return ListTile(
title: Text(volume.label),
subtitle: Text(volume.path),
);
},
);
},
)
In addition, this makes a good way for users to pick storage inside your app.
Dealing with Permissions and Versions
Permissions Needed
To get to most outside storage, like SD cards, you'll need permissions while the app is running:
READ_EXTERNAL_STORAGEMANAGE_EXTERNAL_STORAGE(for Android 11+)
And use the permission_handler package in Flutter to make handling permissions simpler.
Directory or Description Can Be Null
Be ready for:
nulldirectory: Volume not connected or you can't get to it.nullgetDescription(): This can happen sometimes or if storage isn't set up right.
You can show "Unknown" or just not show the volume.
Works on Different Android Versions
Android 7.0 (API 24)+: Has getStorageVolumes().
Older versions: Might need special code or won't work as well.
And test on many different devices to make sure it works right.
More: Show Names in Other Languages and Keep Them the Same
In apps with different languages, you might want storage names to be the same no matter the phone's language. Because getDescription() uses the user's language, think about this:
-
Make names the same in Kotlin:
val normalizedLabel = when (label.lowercase(Locale.getDefault())) { "almacenamiento interno", "internal shared storage" -> "Internal Storage" else -> label } -
Or send the original names and translate them in Dart using
Intl. -
Or let the UI show the name in the user's language using the description.
Finally, pick based on what's more important for users—having names always look the same or having them in their language.
Where to Show Volume Names in Flutter Apps
- File Pickers: Help users find where files are—SD card or internal.
- Backup Tools: Let users pick a clear place to save backups.
- Media Managers: Keep media organized by volume.
- Custom Explorers: Make file explorers that are easy to understand.
And making the volume names clear makes your app easier to use and trust.
How to Debug and Test Flutter Android Storage Access
- Use real phones, not just emulators. Emulators might not show fake SD cards.
- And test with SD cards, USB OTG, and internal volumes.
- Also, put logs in both Dart and Kotlin. This helps you see if the calls work right.
- And use Android Studio’s device file explorer and logcat to check things closely.
To Finish Up
With platform channels, Flutter developers can use Android's storage tools. They can show names like "Internal Storage" or "SD Card" instead of hard-to-read paths. And this needs you to know the basics of MethodChannels, Android tools like StorageManager, and how Dart talks to native code. Furthermore, when you add this to your file pickers or storage screens, you make your app better and easier to use. Lastly, for things like file managers or backup tools, showing clear names makes things easy for your users.
Citations:
Android Developers. (n.d.). StorageManager.getStorageVolumes(). Found at https://developer.android.com/reference/android/os/storage/StorageManager
Android Developers. (n.d.). StorageVolume.getDescription(Context). Found at https://developer.android.com/reference/android/os/storage/StorageVolume#getDescription(android.content.Context)