Flutter Microsoft Azure

Integrate Azure cloud services with Flutter apps

โ˜๏ธ What is Microsoft Azure?

Microsoft Azure is a comprehensive cloud computing platform offering authentication, databases, storage, AI services, and more. Integrate Azure services into your Flutter apps for enterprise-grade security, scalability, and powerful cloud capabilities.


// Azure authentication example
import 'package:aad_oauth/aad_oauth.dart';

final config = Config(
  tenant: 'YOUR_TENANT_ID',
  clientId: 'YOUR_CLIENT_ID',
  redirectUri: 'YOUR_REDIRECT_URI',
);
final oauth = AadOAuth(config);
await oauth.login();
                                    

Key Azure Services

๐Ÿ”

Azure AD Authentication

Enterprise identity and access management with Azure Active Directory. Secure single sign-on, multi-factor authentication, and integration with Microsoft 365 for corporate app development.

final oauth = AadOAuth(config);
await oauth.login();
๐Ÿ—„๏ธ

Cosmos DB

Globally distributed NoSQL database with multiple APIs. Store and query data with low latency worldwide, supporting MongoDB, SQL, Cassandra, and Gremlin APIs for flexible data models.

final response = await http.post(
  Uri.parse(cosmosEndpoint),
  headers: {'Authorization': token},
);
๐Ÿ’พ

Blob Storage

Scalable object storage for unstructured data. Store images, videos, backups, and documents with high availability, automatic tiering, and built-in CDN for fast global access.

await azureStorage.uploadBlob(
  containerName: 'images',
  blobName: 'photo.jpg',
);
๐Ÿค–

Cognitive Services

AI-powered APIs for vision, speech, and language. Add image recognition, text translation, sentiment analysis, and speech-to-text capabilities to your Flutter apps with pre-trained models.

final result = await cognitiveServices
  .analyzeImage(imageUrl);

๐Ÿ”น Azure AD Authentication Setup

Implement Microsoft authentication in your Flutter app:

# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  aad_oauth: ^0.4.0
  http: ^1.1.0
// auth_service.dart
import 'package:aad_oauth/aad_oauth.dart';
import 'package:aad_oauth/model/config.dart';

class AzureAuthService {
  static final Config config = Config(
    tenant: 'YOUR_TENANT_ID',
    clientId: 'YOUR_CLIENT_ID',
    scope: 'openid profile offline_access',
    redirectUri: 'msauth://com.example.app/callback',
    navigatorKey: navigatorKey,
  );

  final AadOAuth oauth = AadOAuth(config);

  Future<bool> login() async {
    try {
      await oauth.login();
      final accessToken = await oauth.getAccessToken();
      return accessToken != null;
    } catch (e) {
      print('Login error: $e');
      return false;
    }
  }

  Future<void> logout() async {
    try {
      await oauth.logout();
    } catch (e) {
      print('Logout error: $e');
    }
  }

  Future<String?> getAccessToken() async {
    try {
      return await oauth.getAccessToken();
    } catch (e) {
      print('Get token error: $e');
      return null;
    }
  }

  Future<bool> isLoggedIn() async {
    final token = await getAccessToken();
    return token != null;
  }
}

// Usage in a widget
class AzureLoginScreen extends StatefulWidget {
  @override
  _AzureLoginScreenState createState() => _AzureLoginScreenState();
}

class _AzureLoginScreenState extends State<AzureLoginScreen> {
  final authService = AzureAuthService();
  bool isLoading = false;

  Future<void> handleLogin() async {
    setState(() => isLoading = true);
    
    final success = await authService.login();
    
    setState(() => isLoading = false);
    
    if (success) {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(builder: (context) => HomeScreen()),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Login failed')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Azure Login')),
      body: Center(
        child: isLoading
            ? CircularProgressIndicator()
            : ElevatedButton.icon(
                onPressed: handleLogin,
                icon: Icon(Icons.login),
                label: Text('Sign in with Microsoft'),
              ),
      ),
    );
  }
}

Setup requirements:

1. Create Azure AD app registration

2. Configure redirect URIs

3. Get tenant ID and client ID

4. Add authentication to Flutter app

๐Ÿ”น Azure Blob Storage

Upload and download files to Azure Blob Storage:

# pubspec.yaml
dependencies:
  azure_storage_blobs: ^0.1.0
  http: ^1.1.0
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'dart:convert';

class AzureBlobService {
  final String accountName;
  final String accountKey;
  final String containerName;

  AzureBlobService({
    required this.accountName,
    required this.accountKey,
    required this.containerName,
  });

  String get baseUrl => 'https://$accountName.blob.core.windows.net';

  // Upload blob
  Future<bool> uploadBlob(String blobName, File file) async {
    try {
      final bytes = await file.readAsBytes();
      final url = '$baseUrl/$containerName/$blobName';
      
      final response = await http.put(
        Uri.parse(url),
        headers: {
          'x-ms-blob-type': 'BlockBlob',
          'x-ms-version': '2021-08-06',
          'Content-Type': 'application/octet-stream',
          'Authorization': _generateAuthHeader('PUT', blobName),
        },
        body: bytes,
      );

      return response.statusCode == 201;
    } catch (e) {
      print('Upload error: $e');
      return false;
    }
  }

  // Download blob
  Future<List<int>?> downloadBlob(String blobName) async {
    try {
      final url = '$baseUrl/$containerName/$blobName';
      
      final response = await http.get(
        Uri.parse(url),
        headers: {
          'x-ms-version': '2021-08-06',
          'Authorization': _generateAuthHeader('GET', blobName),
        },
      );

      if (response.statusCode == 200) {
        return response.bodyBytes;
      }
      return null;
    } catch (e) {
      print('Download error: $e');
      return null;
    }
  }

  // List blobs
  Future<List<String>> listBlobs() async {
    try {
      final url = '$baseUrl/$containerName?restype=containerโˆ=list';
      
      final response = await http.get(
        Uri.parse(url),
        headers: {
          'x-ms-version': '2021-08-06',
          'Authorization': _generateAuthHeader('GET', ''),
        },
      );

      if (response.statusCode == 200) {
        // Parse XML response to get blob names
        // Simplified - actual implementation needs XML parsing
        return [];
      }
      return [];
    } catch (e) {
      print('List error: $e');
      return [];
    }
  }

  // Delete blob
  Future<bool> deleteBlob(String blobName) async {
    try {
      final url = '$baseUrl/$containerName/$blobName';
      
      final response = await http.delete(
        Uri.parse(url),
        headers: {
          'x-ms-version': '2021-08-06',
          'Authorization': _generateAuthHeader('DELETE', blobName),
        },
      );

      return response.statusCode == 202;
    } catch (e) {
      print('Delete error: $e');
      return false;
    }
  }

  String _generateAuthHeader(String method, String blobName) {
    // Simplified - actual implementation needs proper signature
    return 'SharedKey $accountName:$accountKey';
  }
}

// Usage example
class BlobUploadScreen extends StatelessWidget {
  final blobService = AzureBlobService(
    accountName: 'YOUR_ACCOUNT_NAME',
    accountKey: 'YOUR_ACCOUNT_KEY',
    containerName: 'images',
  );

  Future<void> uploadImage() async {
    final picker = ImagePicker();
    final image = await picker.pickImage(source: ImageSource.gallery);
    
    if (image != null) {
      final file = File(image.path);
      final blobName = 'image_${DateTime.now().millisecondsSinceEpoch}.jpg';
      
      final success = await blobService.uploadBlob(blobName, file);
      
      if (success) {
        print('Upload successful!');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Azure Blob Storage')),
      body: Center(
        child: ElevatedButton(
          onPressed: uploadImage,
          child: Text('Upload Image'),
        ),
      ),
    );
  }
}

๐Ÿ”น Azure Cosmos DB Integration

Connect to Cosmos DB for NoSQL data storage:

import 'package:http/http.dart' as http;
import 'dart:convert';

class CosmosDBService {
  final String endpoint;
  final String masterKey;
  final String databaseId;
  final String containerId;

  CosmosDBService({
    required this.endpoint,
    required this.masterKey,
    required this.databaseId,
    required this.containerId,
  });

  // Create document
  Future<Map<String, dynamic>?> createDocument(
    Map<String, dynamic> document,
  ) async {
    try {
      final url = '$endpoint/dbs/$databaseId/colls/$containerId/docs';
      
      final response = await http.post(
        Uri.parse(url),
        headers: {
          'Content-Type': 'application/json',
          'x-ms-version': '2018-12-31',
          'x-ms-documentdb-partitionkey': '["${document['id']}"]',
          'Authorization': _generateAuthToken('POST', 'docs', containerId),
        },
        body: jsonEncode(document),
      );

      if (response.statusCode == 201) {
        return jsonDecode(response.body);
      }
      return null;
    } catch (e) {
      print('Create error: $e');
      return null;
    }
  }

  // Query documents
  Future<List<Map<String, dynamic>>> queryDocuments(String query) async {
    try {
      final url = '$endpoint/dbs/$databaseId/colls/$containerId/docs';
      
      final response = await http.post(
        Uri.parse(url),
        headers: {
          'Content-Type': 'application/query+json',
          'x-ms-version': '2018-12-31',
          'x-ms-documentdb-isquery': 'true',
          'Authorization': _generateAuthToken('POST', 'docs', containerId),
        },
        body: jsonEncode({
          'query': query,
        }),
      );

      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        return List<Map<String, dynamic>>.from(data['Documents']);
      }
      return [];
    } catch (e) {
      print('Query error: $e');
      return [];
    }
  }

  // Update document
  Future<bool> updateDocument(
    String documentId,
    Map<String, dynamic> document,
  ) async {
    try {
      final url = '$endpoint/dbs/$databaseId/colls/$containerId/docs/$documentId';
      
      final response = await http.put(
        Uri.parse(url),
        headers: {
          'Content-Type': 'application/json',
          'x-ms-version': '2018-12-31',
          'x-ms-documentdb-partitionkey': '["$documentId"]',
          'Authorization': _generateAuthToken('PUT', 'docs', containerId),
        },
        body: jsonEncode(document),
      );

      return response.statusCode == 200;
    } catch (e) {
      print('Update error: $e');
      return false;
    }
  }

  // Delete document
  Future<bool> deleteDocument(String documentId) async {
    try {
      final url = '$endpoint/dbs/$databaseId/colls/$containerId/docs/$documentId';
      
      final response = await http.delete(
        Uri.parse(url),
        headers: {
          'x-ms-version': '2018-12-31',
          'x-ms-documentdb-partitionkey': '["$documentId"]',
          'Authorization': _generateAuthToken('DELETE', 'docs', containerId),
        },
      );

      return response.statusCode == 204;
    } catch (e) {
      print('Delete error: $e');
      return false;
    }
  }

  String _generateAuthToken(String verb, String resourceType, String resourceId) {
    // Simplified - actual implementation needs proper HMAC signature
    return 'type=master&ver=1.0&sig=$masterKey';
  }
}

// Usage example
final cosmosDB = CosmosDBService(
  endpoint: 'https://YOUR_ACCOUNT.documents.azure.com:443',
  masterKey: 'YOUR_MASTER_KEY',
  databaseId: 'myDatabase',
  containerId: 'myContainer',
);

// Create a user
await cosmosDB.createDocument({
  'id': '1',
  'name': 'John Doe',
  'email': '[email protected]',
});

// Query users
final users = await cosmosDB.queryDocuments(
  'SELECT * FROM c WHERE c.name = "John Doe"',
);

๐Ÿ”น Azure Cognitive Services

Add AI capabilities with Computer Vision API:

import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:io';

class AzureCognitiveServices {
  final String endpoint;
  final String subscriptionKey;

  AzureCognitiveServices({
    required this.endpoint,
    required this.subscriptionKey,
  });

  // Analyze image
  Future<Map<String, dynamic>?> analyzeImage(File imageFile) async {
    try {
      final url = '$endpoint/vision/v3.2/analyze?visualFeatures=Categories,Description,Tags,Objects';
      final bytes = await imageFile.readAsBytes();
      
      final response = await http.post(
        Uri.parse(url),
        headers: {
          'Content-Type': 'application/octet-stream',
          'Ocp-Apim-Subscription-Key': subscriptionKey,
        },
        body: bytes,
      );

      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      }
      return null;
    } catch (e) {
      print('Analysis error: $e');
      return null;
    }
  }

  // Detect text in image (OCR)
  Future<String?> detectText(File imageFile) async {
    try {
      final url = '$endpoint/vision/v3.2/ocr';
      final bytes = await imageFile.readAsBytes();
      
      final response = await http.post(
        Uri.parse(url),
        headers: {
          'Content-Type': 'application/octet-stream',
          'Ocp-Apim-Subscription-Key': subscriptionKey,
        },
        body: bytes,
      );

      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        // Extract text from regions
        return _extractTextFromOCR(data);
      }
      return null;
    } catch (e) {
      print('OCR error: $e');
      return null;
    }
  }

  String _extractTextFromOCR(Map<String, dynamic> data) {
    final regions = data['regions'] as List;
    final textLines = <String>[];
    
    for (var region in regions) {
      final lines = region['lines'] as List;
      for (var line in lines) {
        final words = line['words'] as List;
        final lineText = words.map((w) => w['text']).join(' ');
        textLines.add(lineText);
      }
    }
    
    return textLines.join('\n');
  }
}

// Usage example
class ImageAnalysisScreen extends StatefulWidget {
  @override
  _ImageAnalysisScreenState createState() => _ImageAnalysisScreenState();
}

class _ImageAnalysisScreenState extends State<ImageAnalysisScreen> {
  final cognitiveServices = AzureCognitiveServices(
    endpoint: 'https://YOUR_REGION.api.cognitive.microsoft.com',
    subscriptionKey: 'YOUR_SUBSCRIPTION_KEY',
  );

  String result = '';

  Future<void> analyzeImage() async {
    final picker = ImagePicker();
    final image = await picker.pickImage(source: ImageSource.gallery);
    
    if (image != null) {
      final file = File(image.path);
      final analysis = await cognitiveServices.analyzeImage(file);
      
      if (analysis != null) {
        setState(() {
          result = 'Description: ${analysis['description']['captions'][0]['text']}\n';
          result += 'Tags: ${analysis['tags'].map((t) => t['name']).join(', ')}';
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Image Analysis')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            ElevatedButton(
              onPressed: analyzeImage,
              child: Text('Analyze Image'),
            ),
            SizedBox(height: 24),
            Text(result),
          ],
        ),
      ),
    );
  }
}

๐Ÿง  Test Your Knowledge

What is Azure AD used for?