
Uploading images to Azure Blob Storage can be an essential feature in modern apps, whether for storing user photos, application assets, or other multimedia. In this article, we’ll walk through how to build a Flutter app that enables users to select an image, upload it to Azure Blob Storage, and retrieve a public URL for access.
Prerequisites
Before diving into the code, ensure you have:
- Azure Blob Storage account: Set up an Azure Storage Account and create a Blob container. Follow Microsoft’s guide if you’re new to Azure.
- SAS Token: Generate a Shared Access Signature (SAS) token for secure access to the blob container.
- Flutter development environment: Install Flutter on your machine and create a new project using flutter create.
Setting Up the Flutter Project
Step 1: Add Dependencies
Update your pubspec.yaml file with the required packages:
dependencies:
flutter:
sdk: flutter
azure_blob_flutter: ^1.0.0
image_picker: ^0.8.7+3
path: ^1.8.3
http: ^0.15.0
Run flutter pub get to install these packages.
Code Walkthrough
Step 2: Initialize the App
Start by creating the basic Flutter app structure with a main() function and a StatefulWidget for managing the upload process. The app contains:
- An image picker for selecting images from the device.
- Functions for uploading the selected image to Azure Blob Storage.
- A display for the upload status and the retrieved public URL.
Here’s the complete code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:io';
import 'package:azure_blob_flutter/azure_blob_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
// App entry point
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String uploadStatus = 'No image selected';
final ImagePicker _picker = ImagePicker();
XFile? _imageFile;
String? uploadedImageUrl;
// Azure Configuration
static const String storageAccount = "YOUR_STORAGE_ACCOUNT_NAME";
static const String containerName = "YOUR_CONTAINER_NAME";
static const String sasToken = "YOUR_SAS_TOKEN";
late final String blobUrl;
late final AzureBlobFlutter azureBlobFlutter;
@override
void initState() {
super.initState();
blobUrl = "https://$storageAccount.blob.core.windows.net";
}
Future<void> uploadToBlob(String filePath, String fileName) async {
try {
final bytes = await File(filePath).readAsBytes();
final blobName = Uri.encodeComponent(fileName);
final uploadUrl = '$blobUrl/$containerName/$blobName$sasToken';
final publicUrl = '$blobUrl/$containerName/$blobName$sasToken';
final request = http.Request('PUT', Uri.parse(uploadUrl));
request.bodyBytes = bytes;
request.headers.addAll({
'x-ms-blob-type': 'BlockBlob',
'Content-Type': 'image/jpeg',
});
final response = await request.send();
if (response.statusCode == 201) {
setState(() {
uploadStatus = 'Upload successful!\nFile: $fileName';
uploadedImageUrl = publicUrl;
});
} else {
final responseBody = await response.stream.bytesToString();
setState(() {
uploadStatus = 'Upload failed: ${response.statusCode}\n$responseBody';
uploadedImageUrl = null;
});
}
} catch (e) {
setState(() {
uploadStatus = 'Upload error: $e';
uploadedImageUrl = null;
});
}
}
Future<void> pickAndUploadImage() async {
try {
setState(() {
uploadStatus = 'Selecting image...';
uploadedImageUrl = null;
});
final XFile? image = await _picker.pickImage(
source: ImageSource.gallery,
maxWidth: 1024,
maxHeight: 1024,
imageQuality: 85
);
if (image == null) {
setState(() {
uploadStatus = 'No image selected';
});
return;
}
final fileName = 'image_${DateTime.now().millisecondsSinceEpoch}.jpg';
await uploadToBlob(image.path, fileName);
} catch (e) {
setState(() {
uploadStatus = 'Error: $e';
uploadedImageUrl = null;
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Azure Blob Upload'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_imageFile != null)
Image.file(File(_imageFile!.path), height: 200, width: 200),
ElevatedButton(
onPressed: pickAndUploadImage,
child: const Text('Select and Upload Image'),
),
const SizedBox(height: 20),
Text(uploadStatus, textAlign: TextAlign.center),
if (uploadedImageUrl != null) ...[
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Clipboard.setData(ClipboardData(text: uploadedImageUrl!));
},
child: const Text('Copy URL'),
),
Text('URL: $uploadedImageUrl', maxLines: 2),
],
],
),
),
),
),
);
}
}
Key Features Explained
- Image Selection: Using the image_picker package, the app allows users to select images from their gallery.
- Azure Blob Upload: The http package sends a PUT request to Azure Blob Storage with the image bytes and appropriate headers.
- Public URL Generation: The public URL is generated using the blob container and the file name.
- Error Handling: Informative messages help users understand the upload status or errors.
Running the App
- Replace YOUR_STORAGE_ACCOUNT_NAME, YOUR_CONTAINER_NAME, and YOUR_SAS_TOKEN with your Azure credentials.
- Run the app on a connected device or emulator using:
- flutter run
Final Thoughts
This app demonstrates the basics of integrating Azure Blob Storage with Flutter for uploading images. Extending this, you can handle advanced use cases such as user authentication, uploading multiple files, or managing larger media assets.