Laravel y Android: Cómo subir imágenes

El día de hoy vamos a ver cómo subir una imagen desde Android a nuestro servidor web a través de nuestra API.

Obtener una imagen como Bitmap

Vamos a asumir que ya tenemos la imagen de nuestro interés en un objeto Bitmap.

La imagen la puedes obtener de múltiples formas. Por ejemplo:

  • Permitir al usuario seleccionar una imagen desde galería.
  • Permitir al usuario tomar una foto.
  • Permitir al usuario dibujar, y capturar el resultado.

Si no sabes cómo lograr esto, asegúrate de suscribirte al canal de YouTube, que pronto agregaré tutoriales para cada uno de estos casos.

Preparar el backend (API)

En nuestro proyecto Laravel debemos crear una ruta para subir la imagen. Sobre esta ruta haremos una petición POST, enviando la imagen en formato Base64.

Para este ejemplo vamos a subir una imagen de perfil.

Es por eso que:

  • Empezamos obteniendo la información del usuario en $user.
  • Obtenemos un nombre de imagen aleatorio.
  • Definimos dónde queremos que se guarde nuestra imagen.
  • Obtenemos la imagen desde el campo image presente en nuestro request.
  • Decodificamos el formato Base 64 para obtener el contenido de nuestra imagen.
  • Creamos un archivo con el $imageContent, en la ruta $fullPath que definimos previamente.
  • Guardamos el nombre de la imagen en la columna photo (tabla users), para el usuario que está actualizando su imagen de perfil.
  • Finalmente, devolvemos la información del usuario en formato JSON.
public function updateImage(Request $request)
{
    $user = Auth::guard('api')->user();

    $imageName = $this->randomImageName();
    $fullPath = public_path('/uploaded/' . $imageName);

    $image = $request->image;  // base64 encoded
    $imageContent = $this->imageBase64Content($image);

    File::put($fullPath, $imageContent);

    $user->photo = $imageName;
    $user->save();

    return $user;
}

Ten en cuenta que esto es un ejemplo. En tu caso:

  • Debes definir qué nombre de imagen quieres usar, y dónde quieres que se guarde.
  • Puedes usar un nombre distinto a image para el campo que viene en la petición POST.
  • Así como guardar el nombre de la imagen en otra columna u otra tabla.
  • También puedes devolver un tipo de respuesta diferente.

Del código anterior, aquí tienes los 2 métodos que hacen falta:

private function imageBase64Content($image) {
    $image = str_replace('data:image/png;base64,', '', $image);
    $image = str_replace(' ', '+', $image);
    return base64_decode($image);
}

private function randomImageName() {
    return Str::random(10) . '.' . 'png';
}

Ten en cuenta que guardamos la imagen en nuestro servidor, y luego en la base de datos solo guardamos el nombre del archivo.

Si bien no es necesario definir un mecanismo de autenticación para tu API, es lo más recomendable. Aquí puedes ver cómo agregar un sistema de autenticación para tu API en Laravel usando Passport.

Subir la imagen desde Android

Una vez que tenemos lista nuestra API, sólo nos queda hacer una petición POST desde Android, para subir nuestra imagen.

private fun postUserImage(bitmap: Bitmap) {
    val call = apiService.postUserImage(
        authHeader, bitmap.toBase64()
    )

    call.enqueue(object: Callback<User> {
        override fun onFailure(call: Call<User>, t: Throwable) {
            context?.toast(t.localizedMessage)
        }

        override fun onResponse(call: Call<User>, response: Response<User>) {
            if (response.isSuccessful) {
                context?.toast(getString(R.string.successful_avatar_updated))
                val user = response.body()
                user?.let {
                    Picasso.get()
                        .load(user.photoUrl)
                        .transform(CircleTransform())
                        .into(ivProfileImage)
                }
            } else {
                context?.toast(getString(R.string.error_server_response))
            }
        }
    })
}

En este ejemplo, para hacer la petición POST usamos Retrofit.

Puedes leer este artículo sobre cómo consumir una API desde Android con Retrofit. Allí vemos cómo definir un API Service.

@POST("user/image")
@Headers("Accept: application/json")
@FormUrlEncoded
fun postUserImage(
    @Header("Authorization") authHeader: String,
    @Field("image") base64Image: String
): Call<User>

Básicamente estamos haciendo una petición a través del método postUserImage de nuestro API Service y enviando 2 argumentos:

  • Un Bearer token (usado para la autenticación con la API), y
  • La imagen codificada en formato Base 64.

Te preguntarás cómo es posible ejecutar: bitmap.toBase64().

Lo que ocurre es que en Kotlin tenemos extension functions. Es decir, podemos extender clases y agregar métodos adicionales.

En este caso, a la clase Bitmap, le agregué un método toBase64:

fun Bitmap.toBase64(): String {
    val stream = ByteArrayOutputStream()
    compress(Bitmap.CompressFormat.JPEG, 70, stream)
    return Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP)
}

Una vez hecha la petición, en cuanto el servidor responda, vamos a ejecutar onResponse o bien onFailure, dependiendo de si el request se pudo llevar a cabo.

Si la respuesta es exitosa, mostramos un Toast (un mensaje flotante) al usuario y así mismo le mostramos en pantalla la imagen que ha subido.

Esto último, haciendo uso de Picasso. Adicionalmente, en mi caso también definí un CircleTransform() para mostrar la imagen en formato circular.

Conclusión

Como ves, subir una imagen y mostrarla finalmente al usuario no es nada de otro mundo.

Si quieres aprender más sobre Android y Kotlin, y cómo organizar tus proyectos, te invito a inscribirte al curso de Android y Laravel que tengo publicado 🙂

# laravel # android # retrofit

Cursos recomendados

Curso de Laravel desde Cero

Aprende Laravel

Aprende Laravel desde cero y desarrolla aplicaciones web reales, en tiempo récord, de la mano de Laravel.

Ingresar al curso
Curso de Actualización Laravel

Curso de Laravel Upgrade

Actualiza tus proyectos desde cualquier versión hasta la última versión estable de Laravel.

Ingresar al curso
Curso de Laravel, Vue.js y Pusher

Aprende Vue.js

Desarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.

Ingresar al curso
Logo de Programación y más

¿Tienes alguna duda?

Si algo no te quedó claro o tienes alguna sugerencia, escribe un comentario aquí debajo.

Además recuerda compartir el post si te resultó de ayuda! 🙂

Cargando comentarios ...

Antes que te vayas

Inscríbete en nuestro curso gratuito de Laravel