0

我已经阅读了很多关于这个主题的帖子,但我还没有找到解决方案。在我的应用程序中,我需要在将文件从 USB 驱动器复制到平板电脑后卸载 USB 驱动器,这样我就可以在不使用设置菜单的情况下安全地删除它。

现在我正在使用这种方法:

Utility.copyDirectory(file,new File(_CURR_FOLDER));
Process su;
su = Runtime.getRuntime().exec("/system/bin/su");
String cmd = "umount" +
             " " + SDPath + "\n" + "exit\n";
             su.getOutputStream().write(cmd.getBytes());

我在存储设置中得到的是:

总空间 0.0 可用空间 0.0

但仍然安装了 SD。

预先感谢您的帮助。

第一次编辑:

有人知道如何使用 IMountService 吗?我读过它,也许是解决USB DRIVE卸载的正确方法,但是添加后classes-full-debug.jar我的项目不再编译

4

3 回答 3

2

这是做不到的。许多用户在那里存储他们所有的内容,如歌曲、视频、照片。不允许应用程序卸载 SD 卡,而是使用它们来存储数据,这是一个很好的安全决定。

但是您可以将用户发送到设置并由用户执行,而不是通过代码

Intent i = new Intent(android.provider.Settings.ACTION_MEMORY_CARD_SETTINGS);
startActivity(i);

这带来了那个屏幕......

在此处输入图像描述

我认为这会奏效

于 2014-07-16T14:42:15.797 回答
0

这是我在Android 6.0.1上必须做的,希望 4.2 也一样。

编译 android 后,我必须将库SDK/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes-full-debug.jar 添加到我的应用程序中。(我刚刚从这里下载了棒棒糖版本,幸运的是它也适用于棉花糖)

Android Studio 会抱怨内存不足错误,通过将以下代码添加到 android 部分内的 build.gradle 来解决此问题。

dexOptions {
    javaMaxHeapSize "4g"
}

您还需要通过在 defaultConfig 部分的 build.gradle 中添加以下行来添加 multidex 支持。

multiDexEnabled true

并在依赖项部分添加以下行。

compile 'com.android.support:multidex:1.0.0'

并在清单内的应用程序部分添加以下行。

android:name="android.support.multidex.MultiDexApplication"

并且您的 apk 必须在/system/priv-app目录中并具有以下权限。

<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />

然后下面的代码应该可以工作。

private void unmount() {
    IMountService mountService = getMountService();
    try {
        if (mountService != null) {
            mountService.unmountVolume("/mnt/media_rw/8842-89A4", true, false);
            Log.e(TAG,"Unmounted");
        } else {
            Log.e(TAG, "Mount service is null, can't unmount");
        }
    } catch (RemoteException ex) {
        // Not much can be done
    }
}

private synchronized IMountService getMountService() {
    if (mMountService == null) {
        IBinder service = ServiceManager.getService("mount");
        if (service != null) {
            mMountService = IMountService.Stub.asInterface(service);
        } else {
            Log.e(TAG, "Can't get mount service");
        }
    }
    return mMountService;
}
于 2016-09-30T13:32:06.943 回答
0

我在有权做任何事情的系统应用程序中使用了这些代码片段。我不确定这是否适用于常规应用程序,即使它具有所有存储权限。

我知道这已经晚了 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是我编写的一个简单的数据类,用于将相关信息保存在一起。

祝你好运!

于 2022-01-27T19:46:40.747 回答