Durante bastante tiempo, la única forma sencilla de dejar que un usuario eligiera una foto de su galería desde una app Android era pedir el permiso de acceso a todo el almacenamiento multimedia del dispositivo. Eso significaba que, para dejar que alguien subiera una única foto de un punto de pesca en Caladero, la app tenía que declarar y solicitar acceso a la totalidad de las fotos guardadas en el teléfono, incluidas las que no tenían nada que ver con la app. El Photo Picker de Android resuelve exactamente ese desajuste, y quiero explicar cómo lo integré y qué limitaciones tiene en la práctica.
Qué es el Photo Picker
El Photo Picker es un selector de imágenes y vídeos proporcionado por el propio sistema operativo Android, que se ejecuta en un proceso separado de la app que lo invoca. La app lanza el selector, el usuario elige una o varias imágenes desde una interfaz controlada por el sistema, y la app recibe únicamente las referencias a los archivos que el usuario eligió explícitamente. En ningún momento la app obtiene acceso de lectura al resto de la galería del dispositivo.
Esto es una diferencia de fondo, no solo de interfaz. Con el enfoque anterior, conceder el permiso significaba dar acceso permanente a toda la colección de fotos, aunque la intención real del usuario fuera compartir una sola imagen. Con el Photo Picker, el acceso se limita exactamente a lo que el usuario seleccionó, y la app nunca puede enumerar ni leer nada más allá de eso.
Por qué me importaba para Caladero
En Caladero, la funcionalidad de añadir una foto a un punto guardado es opcional y puntual: el usuario puede querer ilustrar un punto de pesca con una imagen del lugar, pero eso no significa que la app deba tener, ni necesite, visibilidad sobre el resto de fotos personales del usuario, que podrían incluir cualquier cosa sin relación alguna con la pesca. Pedir acceso a toda la galería para una funcionalidad tan acotada habría sido pedir más de lo que la funcionalidad justifica, algo que trato como principio general en el artículo sobre permisos Android: pedir solo lo necesario.
Además, el Photo Picker no requiere declarar ningún permiso de tiempo de ejecución para esta funcionalidad. Al usuario no se le muestra ningún diálogo de "Caladero quiere acceder a tus fotos", porque técnicamente la app no está pidiendo ese acceso: es el propio sistema quien gestiona la selección y solo entrega el resultado final.
Cómo lo integré en la práctica
La integración usa el contrato de actividad PickVisualMedia, parte de las librerías de Activity de Jetpack:
val seleccionarImagen = registerForActivityResult(
ActivityResultContracts.PickVisualMedia()
) { uri: Uri? ->
if (uri != null) {
viewModel.onImagenSeleccionada(uri)
}
}
// Al pulsar el botón de añadir foto:
seleccionarImagen.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
El Uri que se recibe es válido temporalmente para que la app lea el contenido de esa imagen concreta (por ejemplo, para copiarla al almacenamiento propio de la app o subirla si el usuario lo decide explícitamente), pero no otorga ningún acceso más allá de ese archivo puntual. No hace falta declarar READ_MEDIA_IMAGES ni ningún permiso equivalente en el manifiesto para esta funcionalidad concreta.
Qué pasa en dispositivos con versiones antiguas de Android
El Photo Picker está disponible de forma nativa a partir de ciertas versiones de Android, pero gracias a una implementación retrocompatible distribuida a través de Google Play Services, funciona también en versiones anteriores del sistema en la mayoría de dispositivos con esos servicios instalados. Esto significa que, en la práctica, no hace falta mantener dos caminos de código distintos según la versión de Android: el mismo contrato PickVisualMedia funciona de forma consistente en el rango de versiones que cubre la inmensa mayoría de dispositivos activos. Los detalles técnicos exactos de compatibilidad están documentados en la página oficial sobre el selector de fotos en developer.android.com.
Un límite real: selección múltiple con cuota máxima
Cuando permito selección múltiple de imágenes, por ejemplo si en el futuro Caladero permitiera varias fotos por punto, el contrato acepta un parámetro de número máximo de elementos seleccionables:
seleccionarImagen.launch(
PickVisualMediaRequest(
mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly
)
)
Para selección múltiple con límite se usa PickMultipleVisualMedia(maxItems), y hay que tener en cuenta que ese máximo tiene un límite técnico impuesto por el propio sistema, no arbitrario por parte de la app. Si se necesita más flexibilidad que la que ofrece el selector estándar, la alternativa sigue siendo pedir el permiso completo de medios, pero eso implica volver al modelo de acceso amplio que el Photo Picker está pensado precisamente para evitar.
Errores que cometí al integrarlo
El primer error fue asumir que el Uri devuelto por el Photo Picker se podía guardar indefinidamente y volver a leer más adelante sin restricciones. En la práctica, ese Uri tiene una validez limitada en el tiempo dentro del ciclo de vida de la app, así que si necesito conservar la imagen de forma permanente (por ejemplo, asociada a un punto guardado que persiste en la base de datos local), tengo que copiar el contenido a almacenamiento propio de la app inmediatamente después de la selección, no confiar en que el Uri original siga siendo válido más adelante.
El segundo error fue no gestionar bien el caso de que el usuario cierre el selector sin elegir nada, que en el contrato se traduce en recibir null como resultado. Al principio esto provocaba un cierre inesperado del flujo sin ningún mensaje; ahora simplemente no hago nada visible cuando el resultado es nulo, tratándolo como una cancelación normal y no como un error.
Conclusión
El Photo Picker es uno de esos cambios que no se nota en un titular de marketing pero que mejora de forma concreta la relación entre lo que una app pide y lo que realmente necesita. Para una funcionalidad tan puntual como añadir una foto a un punto guardado, tiene mucho más sentido pedir exactamente esa foto que pedir acceso permanente a toda la galería del usuario. Es una integración sencilla desde el punto de vista técnico, y el beneficio en términos de privacidad y de confianza del usuario es desproporcionadamente mayor que el esfuerzo que cuesta implementarla.
