Android:securityException:“目标必须在外部存储上”

时间:2012-11-30 13:57:15

标签: android mobile securityexception

我已经彻底搜索了网络以找到答案,但没有结果。

我在Android应用中实现了一些“偏好设置”,包括在任何您想要的位置保存文件的功能。

如果我在所谓的“集成SD卡”上选择路径,一切都OK。但我也有一个“真正的”外部SD卡,在/storage/sdcard1符号链接到/extSdCard/mnt/extSdCard时挂载(在我的情况下)(而“内部”sdcard是/storage/sdcard0带符号链接到/sdcard/mnt/sdcard)。

在ICS上我有/emmc的外部加上一些我不记得的链接。

问题是,如果我选择指向此extSdCard的路径,应用程序将创建文件夹结构,但不会写入下载的文件,以“SecurityException”结尾,“目标必须位于外部存储上”

但这条路径在外部存储上!更多:如果存在写入权限的问题,为什么要创建文件夹? (android.permission.WRITE_EXTERNAL_STORAGE出现在清单中。

我很可能做错了什么;或者也许是一些错误?

Eclipse日志:

11-30 11:58:29.143: D/ShareActivity(24752): doInBackground...
11-30 11:58:33.813: D/ShareActivity(24752): The response is: 200
11-30 11:58:50.283: D/ShareActivity(24752): location: Downloads
11-30 11:58:50.443: D/ShareActivity(24752): User defined folders created
11-30 11:58:50.443: D/ShareActivity(24752): path: /storage/sdcard1/temp
11-30 11:59:07.053: D/ShareActivity(24752): downloadUri: file:/storage/sdcard1/temp/test.3gpp
11-30 11:59:07.313: D/AndroidRuntime(24752): Shutting down VM
11-30 11:59:07.318: W/dalvikvm(24752): threadid=1: thread exiting with uncaught exception (group=0x41ce3300)
11-30 11:59:07.318: E/AndroidRuntime(24752): FATAL EXCEPTION: main
11-30 11:59:07.318: E/AndroidRuntime(24752): java.lang.SecurityException: Destination must be on external storage: file:/storage/sdcard1/temp/test.3gpp
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.os.Parcel.readException(Parcel.java:1425)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:188)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.content.ContentProviderProxy.insert(ContentProviderNative.java:420)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.content.ContentResolver.insert(ContentResolver.java:864)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.app.DownloadManager.enqueue(DownloadManager.java:904)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at dentex.youtube.downloader.ShareActivity$AsyncDownload$1$1.onClick(ShareActivity.java:269)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.os.Handler.dispatchMessage(Handler.java:99)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.os.Looper.loop(Looper.java:137)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at android.app.ActivityThread.main(ActivityThread.java:4931)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at java.lang.reflect.Method.invokeNative(Native Method)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at java.lang.reflect.Method.invoke(Method.java:511)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
11-30 11:59:07.318: E/AndroidRuntime(24752):    at dalvik.system.NativeStart.main(Native Method)
11-30 11:59:09.248: I/Process(24752): Sending signal. PID: 24752 SIG: 9

相关代码:

lv.setOnItemClickListener(new OnItemClickListener() {

            private File userFolder;

                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                String location = settings.getString("download_locations", "Downloads");
                Log.d(DEBUG_TAG, "location: " + location);

                boolean userLocationEnabled = settings.getBoolean("enable_user_location", false);

                if (userLocationEnabled == false) {
                    if (location.equals("DCIM") == true) {
                        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
                    }
                    if (location.equals("Movies") == true) {
                        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
                    } 
                    if (location.equals("Downloads") == true) {
                        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
                    }
                    Log.d(DEBUG_TAG, "path: " + path);
                } else {
                        userFolder = new File(settings.getString("user_location", ""));
                        path = userFolder;
                }

                Log.d(DEBUG_TAG, "path: " + path.toString());

                pos = position;
                AlertDialog.Builder helpBuilder = new AlertDialog.Builder(ShareActivity.this);

                helpBuilder.setIcon(android.R.drawable.ic_dialog_info);
                helpBuilder.setTitle("Confirm Download for:");
                helpBuilder.setMessage(" *** msg *** ");

                helpBuilder.setPositiveButton("Download here", new DialogInterface.OnClickListener() {

                    @TargetApi(11)
                    public void onClick(DialogInterface dialog, int which) {
                        mLink = links[pos];
                        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

                        Request request = new Request(Uri.parse(mLink));
                        uri = Uri.parse(path.toURI() + title + "." + mExt);
                        Log.d(DEBUG_TAG, "downloadUri: " + uri);
                        request.setDestinationUri(uri);
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                            request.allowScanningByMediaScanner();
                            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                        }

                        if (isExternalStorageWritable() == true) {
                            enqueue = downloadManager.enqueue(request);
                        }
                    }
                });

                helpBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                   //...
                });

                AlertDialog helpDialog = helpBuilder.create();
                helpDialog.show();

            }
});

1 个答案:

答案 0 :(得分:8)

Jeremy Meiss( jerdog )的THIS ARTICLE Chainfire THIS LINK,这种行为应该是“正常的”,因为时间存在。应该需要WRITE_MEDIA_STORAGE权限,但这仅授予系统应用程序。

作为一种解决方法,在我的活动中,我像这样处理SecurityException(伪代码):

Intent intent = new Intent(MyActivity.this, DownloadsService.class);

try {
    intent.putExtra("COPY", false);
    enqueue = dm.enqueue(request);
    Log.d(DEBUG_TAG, "_ID " + enqueue + " enqueued");
} catch (SecurityException e) {
    Log.w(DEBUG_TAG, e.getMessage());

    // handle the path on etxSdCard here:
    showSomeInfo();
    intent.putExtra("COPY", true);
    tempDownloadToSdcard(request);
}

startService(intent);

DownloadsService我有一个BroadcastReceiver,我处理完成的下载; 在onStartCommand中,我将布尔额外检索为:

doCopy = intent.getBooleanExtra("COPY", false);

然后在接收器内:

if (doCopy) copyFileToExtSdCard();

希望这能澄清并帮助。