Intereting Posts
Различные макеты для разных групп ExpandableListView Заполняется ли в viewviewport пользователя horizontalscrollview прокрутка? Android StackOverflowError в ViewGroup.resetResolvedTextDirection при добавлении ListView в LinearLayout Левое внешнее соединение с предложением Select в Android Как удалить белое подчеркивание в виджет SearchView на панели инструментов Android MultipartEntityBuilder и setCharset для UTF-8 отправляют пустой контент Минимальные пакеты, необходимые для начала работы, Android SDK Где и зачем добавлять репозитории на build.gradle Ошибка: тип «JNIENV» не может быть разрешен Создание мастера установки на Android Автоматическое обновление приложения для Android никогда не происходит Как установить высоту элемента WearableListView Аутентификация с App Engine из приложения Android с Federated Login (OpenID) Пейджер с автопрокруткой вызывает падение кадров Использование холста и растрового изображения в Android, как получить это изображение?

Android: securityException: «назначение должно быть на внешнем хранилище»

Я тщательно искал сеть, чтобы найти ответ, но без результата.

Я реализовал некоторые «настройки» в своем приложении для Android, в том числе возможность сохранять файлы в любом месте, которое вы хотите.

Если я выберу путь на так называемой «интегрированной SD-карте», все будет в порядке. Но у меня также есть «реальная» внешняя SD-карта, которая монтируется (в моем случае) в /storage/sdcard1 привязанная к /extSdCard и /mnt/extSdCard (хотя «внутренняя» SD-карта – /storage/sdcard0 с символическими /sdcard на /sdcard И /mnt/sdcard ).

На ICS у меня был внешний at /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(); } }); 

    Согласно ЭТОЙ СТАТЬЕ Джереми Мейсом ( jerdog ) и ЭТОЙ ЛИНКОМ Chainfire , это поведение должно быть «нормальным», как сейчас. Необходимо разрешение 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 я извлекаю boolean extra как:

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

    А затем внутри приемника:

     if (doCopy) copyFileToExtSdCard(); 

    Надеюсь, это прояснит и поможет.