我在有权做任何事情的系统应用程序中使用了这些代码片段。我不确定这是否适用于常规应用程序,即使它具有所有存储权限。
我知道这已经晚了 7 年,但也许对其他人有帮助。StorageManager类有一个名为unmount的隐藏函数。因为它不是公共的并且阻塞了调用者线程,所以使用反射来访问它并把它放在一个 AsyncTask 中:
public static void unmountStorage(Context context, String volId) {
new AsyncTask<Void, Void, Exception>() {
@Override
protected void onPostExecute(Exception e) {
if (e == null) {
Log.i("storageman", "unmounting " + volId + " success!");
}
else {
Log.e("storageman", "unmounting", e);
}
}
@Override
protected Exception doInBackground(Void... params) {
try {
StorageManager storageManager = context.getSystemService(StorageManager.class);
Method unmountMethod = StorageManager.class.getMethod("unmount", String.class);
unmountMethod.setAccessible(true);
unmountMethod.invoke(storageManager, volId);
return null;
}
catch (Exception ex) {
return ex;
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
volId
获取参数有点棘手。首先,列出可用的卷。StorageManager也有一个隐藏的方法来执行此操作,称为getVolumes。然后您可以遍历它们并获取它们的属性,例如卷 ID。此方法为您提供了第一个“外部”存储:
public static ExternalStorage getExternalStorage(Context context) {
try {
StorageManager storageManager = context.getSystemService(StorageManager.class);
Method getVolumes = StorageManager.class.getMethod("getVolumes");
getVolumes.setAccessible(true);
List<Object> volumes = (List<Object>) getVolumes.invoke(storageManager);
for (Object volume : volumes) {
Class<?> volumeInfoClass = Class.forName("android.os.storage.VolumeInfo");
Field idField = volumeInfoClass.getField("id");
idField.setAccessible(true);
String volumeId = (String) idField.get(volume);
Field nameField = volumeInfoClass.getField("fsLabel");
nameField.setAccessible(true);
String volumeName = (String) nameField.get(volume);
Field stateField = volumeInfoClass.getField("state");
stateField.setAccessible(true);
Integer volumeState = (Integer) stateField.get(volume);
Field pathField = volumeInfoClass.getField("path");
pathField.setAccessible(true);
String volumePath = (String) pathField.get(volume);
if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
return new ExternalStorage(volumeId, volumeName, new File(volumePath));
}
}
}
catch (Exception ex) {
Log.e("storagehelper", "getExternalStorage(Context context)", ex);
}
return null;
}
我认为这条线需要进一步解释:
if (volumeId.startsWith("public") && (volumeState == 2 || volumeState == 3 || volumeState == 5)) {
正如我在测试过程中所经历的那样,外部驱动器的卷 ID 以“公共”开头,这就是我为它过滤卷的原因。常量 2、3 和 5 表示已安装卷。在这里查看常量。
ExternalStorage是我编写的一个简单的数据类,用于将相关信息保存在一起。
祝你好运!