page.title=Acceso a directorios determinados page.keywords=preview,sdk,scoped directory access page.tags=androidn @jd:body <div id="qv-wrapper"> <div id="qv"> <h2>En este documento</h2> <ol> <li><a href="#accessing">Acceder a un directorio de almacenamiento externo</a></li> <li><a href="#removable">Acceder a un directorio de un medio extraíble</a></li> <li><a href="#best">Prácticas recomendadas</a></li> </ol> </div> </div> <p>Las aplicaciones como las aplicaciones de fotografía generalmente solo necesitan acceso a directorios de almacenamiento externo, como el directorio <code>Pictures</code>. Los métodos existentes para acceder a almacenamiento externo no están diseñados para brindar un acceso fácil a determinados directorios para estos tipos de aplicaciones. Por ejemplo:</p> <ul> <li>Solicitar {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} o {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} en tu manifiesto permite el acceso a todos los directorios públicos de un almacenamiento externo, lo cual podría ser un acceso mayor que el que necesita tu aplicación.</li> <li>Usar el <a href="{@docRoot}guide/topics/providers/document-provider.html">framework de acceso al almacenamiento</a> generalmente implica que el usuario seleccione directorios mediante un sistema de IU, lo cual no es necesario si tu aplicación siempre accede al mismo directorio externo.</li> </ul> <p>Android N brinda una API nueva y simplificada para acceder a directorios de almacenamiento externo comunes. </p> <h2 id="accessing">Acceder a un directorio de almacenamiento externo</h2> <p>Usa la clase <code>StorageManager</code> para obtener la instancia de <code>StorageVolume</code> correcta. Luego, crea una intent llamando al método <code>StorageVolume.createAccessIntent()</code> de esa instancia. Usa esta intención para acceder a directorios de almacenamiento externo. Para obtener una lista de todos los volúmenes disponibles, incluidos los volúmenes de medios extraíbles, usa <code>StorageManager.getVolumesList()</code>.</p> <p>Si tienes información sobre un archivo específico, usa <code>StorageManager.getStorageVolume(File)</code> para obtener el <code>StorageVolume</code> que contiene el archivo. Llama a <code>createAccessIntent()</code> en este <code>StorageVolume</code> para acceder al directorio de almacenamiento externo del archivo.</p> <p> En el caso de los volúmenes secundarios, como las tarjetas SD externas, pasa un valor nulo cuando llames a <code>StorageVolume.createAccessIntent()</code> para solicitar acceso al volumen completo, en lugar de un directorio específico. <code>StorageVolume.createAccessIntent()</code> regresa un valor nulo si pasas un valor nulo para el volumen principal o si pasas un nombre de directorio no válido. </p> <p>El siguiente fragmento de código es un ejemplo de cómo abrir el directorio <code>Pictures</code> en el almacenamiento compartido principal:</p> <pre> StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE); StorageVolume volume = sm.getPrimaryVolume(); Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code); </pre> <p>El sistema intenta otorgar acceso al directorio externo y, si es necesario, confirma el acceso con el usuario usando una IU simplificada:</p> <img src="{@docRoot}preview/images/scoped-folder-access-framed.png" srcset="{@docRoot}preview/images/scoped-folder-access-framed.png 1x, {@docRoot}preview/images/scoped-folder-access-framed_2x.png 2x" /> <p class="img-caption"><strong>Imagen 1.</strong> Una aplicación solicitando acceso al directorio Pictures.</p> <p>Si el usuario otorga el acceso, el sistema llama a tu anulación de <code>onActivityResult()</code> con un código resultante de <code>Activity.RESULT_OK</code> y datos de intents que contienen el URI. Usa el URI brindado para acceder a la información del directorio. Es similar a usar URI generados por el <a href="{@docRoot}guide/topics/providers/document-provider.html">framework de acceso al almacenamiento</a>.</p> <p>Si el usuario no otorga el acceso, el sistema llama a tu anulación de <code>onActivityResult()</code> con un código resultante de <code>Activity.RESULT_CANCELED</code> y datos de intents nulos.</p> <p class="note"><b>Nota</b>: Obtener acceso a un directorio externo específico también otorga el acceso a los subdirectorios de ese directorio.</p> <h2 id="removable">Acceder a un directorio de un medio extraíble</h2> <p>Para usar el acceso a directorios determinados para acceder a directorios de medios extraíbles, primero debes agregar un {@link android.content.BroadcastReceiver} que escuche la notificación{@link android.os.Environment#MEDIA_MOUNTED}, por ejemplo:</p> <pre> <receiver android:name=".MediaMountedReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.MEDIA_MOUNTED" /> <data android:scheme="file" /> </intent-filter> </receiver> </pre> <p>Cuando el usuario conecta un medio extraíble, como una tarjeta SD, el sistema envía una notificación{@link android.os.Environment#MEDIA_MOUNTED}. Esta notificación brinda un objeto <code>StorageVolume</code> en los datos de intents que puedes usar para acceder a directorios del medio extraíble. El siguiente ejemplo accede al directorio <code>Pictures</code> de medios extraíbles:</p> <pre> // BroadcastReceiver has already cached the MEDIA_MOUNTED // notification Intent in mediaMountedIntent StorageVolume volume = (StorageVolume) mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME); volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code); </pre> <h2 id="best">Prácticas recomendadas</h2> <p>Cuando sea posible, sigue usando el URI de acceso a directorios externos de modo que no tengas que solicitarle acceso al usuario continuamente. Una vez que el usuario haya otorgado el acceso, llama a <code>getContentResolver().takePersistableUriPermssion()</code> con el URI de acceso a directorios. El sistema continuará el URI, y las siguientes solicitudes de acceso generarán <code>RESULT_OK</code> y no le mostrarán una IU de confirmación al usuario.</p> <p>Si el usuario deniega el acceso a un directorio externo, no vuelvas a solicitar el acceso inmediatamente. Hacer esto provocaría una mala experiencia de usuario. Si el usuario deniega una solicitud y la aplicación solicita acceso nuevamente, aparece la casilla de verificación <b>Don't ask again</b> en la IU:</p> <img src="{@docRoot}preview/images/scoped-folder-access-dont-ask.png" srcset="{@docRoot}preview/images/scoped-folder-access-dont-ask.png 1x, {@docRoot}preview/images/scoped-folder-access-dont-ask_2x.png 2x" /> <p class="img-caption"><strong>Figura 1.</strong> Una aplicación que presenta una segunda solicitud para obtener acceso a medios extraíbles.</p> <p>Si el usuario selecciona <b>Don't ask again</b> y deniega la solicitud, todas las solicitudes futuras que presente la aplicación para el directorio determinado se denegarán automáticamente, y el usuario no recibirá ninguna IU de solicitud.</p>