Uploading images to Firebase Storage from Android

A mobile app that accepts profile photos, receipts or marketplace listings needs a dependable way to transfer image files to cloud storage. Firebase Storage is a practical choice for Android because it works with Firebase Authentication, supports resumable uploads and can return a public or protected download URL for later use.

The usual flow is straightforward: let someone choose an image, obtain its Uri, upload that Uri to a deliberate path in a Firebase Storage bucket, then save the resulting URL in Firestore or Realtime Database. Keeping the binary image in Storage and the descriptive data in a database makes searches, permissions and screen loading easier to manage.

For Australian users, image handling also deserves attention beyond the code. A customer in Sydney may be uploading over busy café Wi-Fi, while someone in regional Queensland could be relying on a slower mobile connection. Resizing large photos before transfer can reduce waiting time, mobile data usage and storage costs.

Privacy should be designed into the feature from the beginning. If an app collects identifiable photographs, its data practices may fall under the Australian Privacy Act 1988 and the Australian Privacy Principles. Explain why an image is collected, restrict access to authorised users and avoid making sensitive files publicly readable by default.

Configure Firebase and the Android project

Create or select a Firebase project, register the Android application with its exact package name, and download google-services.json into the app module. In Firebase Console, enable Storage and choose a region that suits your users and compliance requirements. Australian teams should consider latency to cities such as Melbourne, Brisbane and Perth, along with where their organisation expects customer data to be stored.

Add the Google services plugin and Firebase Storage dependency using the current versions recommended by Firebase. With Kotlin and the modern Android setup, the important library is typically com.google.firebase:firebase-storage-ktx or the current Firebase Storage module specified in the official dependency guidance. Use the Firebase BoM so related Firebase libraries remain compatible.

Authentication should usually be enabled before uploads. An anonymous account can provide a quick start for a prototype, while email, Google or another sign-in method gives the security rules a durable user identity. Avoid relying on a device-only identifier, as it can change when a person reinstalls the app or switches phones.

Let the user select a suitable image

The Android Photo Picker is a strong default for modern devices because it gives the app access to selected media without requesting broad storage permissions. With an ActivityResultContracts.PickVisualMedia launcher, request an image and receive a content Uri. For older Android versions, GetContent is a useful fallback.

Keep the selected Uri rather than trying to convert the entire image into a bitmap immediately. A ContentResolver can provide the MIME type and open an input stream when Firebase begins the transfer. This approach reduces memory pressure, which matters on budget phones commonly used across Australia and avoids crashes caused by decoding a high-resolution camera image at full size.

Before uploading, check that the content is an accepted type such as JPEG, PNG or WebP. You can also inspect the file size and reject an unreasonable upload with a clear message. A five-megapixel camera photo may be perfectly suitable for a listing, but an uncompressed image or a 4K video accidentally selected as a photo can consume unnecessary bandwidth.

Upload the Uri with progress feedback

Create a predictable storage reference, such as users/{uid}/profiles/{imageId}.jpg or listings/{uid}/{listingId}/cover.jpg. Use a generated identifier rather than the original filename to prevent collisions and reduce the chance of exposing personal information in a path. Include a correct content type through StorageMetadata, especially when the file extension is unavailable.

A Kotlin coroutine makes the asynchronous process easier to read. The essential operation is reference.putFile(imageUri, metadata).await(), followed by reference.downloadUrl.await(). Store the returned URL with the relevant Firestore document only after the upload has completed successfully. If the database write fails, retain enough information to retry or remove the orphaned Storage object.

Expose progress through a ViewModel and a state object containing idle, uploading, successful and failed states. Firebase upload tasks provide byte counts that can be converted into a percentage. Disable repeated submission while an upload is active, show a cancel option where appropriate and preserve the selected Uri across a configuration change.

Network quality varies widely between an NBN connection in Canberra and a congested mobile connection on a commuter train in Sydney. Handle temporary failures with retry logic and an explanatory message rather than treating every interruption as a permanent error. When diagnosing a device that cannot reach Firebase, first check its connection and local network; a guide to router setup steps can help when a home or office Wi-Fi configuration is interfering with testing.

Resize images before sending them

A reliable upload feature often performs client-side preparation. Decode the image with bounds first, calculate a sensible target size and compress a copy into the app cache. For a profile image, a maximum dimension around 1,200 to 1,600 pixels is usually sufficient; a product catalogue may need a larger version, while a thumbnail should be much smaller.

Use lossless rotation correction based on the image’s EXIF orientation, then apply a chosen JPEG quality. Do not overwrite the user’s original photo in the gallery. Save the prepared file privately, upload it, and delete the temporary copy after success or a final failure. HEIC support requires a considered approach because some older Android devices, browsers and downstream image tools may not handle it consistently.

Compression should be measured rather than assumed. Log the original and final byte sizes during development, test on low-memory phones and check that text in receipts remains readable. For an Australian retail or trades app, clear images can be important evidence, so aggressive compression should never make invoices, serial numbers or damage details impossible to inspect.

Protect files with Storage Rules

Storage Rules are the main boundary between a working demo and a safe production app. A common policy allows an authenticated user to write only beneath their own user ID, limits the content type to images and sets a maximum size. For example, a rule can compare request.auth.uid with the UID in the path and reject files above a chosen limit.

Do not treat an obscured download URL as authorisation. Anyone who obtains a broadly accessible URL may be able to use it, and URLs can be copied into logs or shared messages. Private customer documents should remain protected by rules, with access granted to authenticated users who have a legitimate relationship to the record. Public catalogue images can use a separate, carefully limited path.

Rules should match the database permissions. If a user may edit a listing but not another seller’s listing, the Storage path and Firestore document should enforce the same ownership model. Test these cases in the Firebase Emulator Suite: signed-out access, a second authenticated account, oversized files, invalid MIME types and attempts to guess another user’s path.

Record consent and retention decisions in the app’s privacy documentation. Give people a way to replace or delete images, and remove the associated Storage object when a record is deleted where retention is not legally or operationally required. Australian businesses should also consider breach response procedures and whether a service provider arrangement needs review under their privacy obligations.

Choose a clear naming convention, validate every upload, and test on Wi-Fi and mobile data before release. Then connect the successful download URL to the screen that needs it, monitor failed transfers in production and review Storage usage regularly. Build the feature around secure rules and modest file sizes now, so adding galleries, receipts or listing photos later does not require a major rewrite.