Advanced Topics¶
Introduction¶
This section covers advanced Bond concepts for experienced developers who want to extend the framework, optimize performance, implement complex patterns, or integrate with existing systems. These topics assume familiarity with Bond's core concepts and are designed for production applications with specific requirements.
Extending Bond Packages¶
Custom Cache Drivers¶
Create custom cache drivers for specialized storage needs:
// lib/core/cache/redis_cache_driver.dart
class RedisCacheDriver extends CacheDriver {
final RedisConnection _redis;
RedisCacheDriver(this._redis);
@override
bool has(String key) {
try {
return _redis.exists([key]).first > 0;
} catch (e) {
return false;
}
}
@override
Json? retrieve(String key) {
try {
final value = _redis.get(key);
return value != null ? json.decode(value) : null;
} catch (e) {
return null;
}
}
@override
Future<bool> store(String key, Json data) async {
try {
await _redis.set(key, json.encode(data));
return true;
} catch (e) {
return false;
}
}
@override
Future<bool> forget(String key) async {
try {
await _redis.del([key]);
return true;
} catch (e) {
return false;
}
}
@override
Future<bool> flush() async {
try {
await _redis.flushdb();
return true;
} catch (e) {
return false;
}
}
}
// Register in Service Provider
class CacheServiceProvider extends ServiceProvider {
@override
Future<void> register(GetIt it) async {
if (AppConfig.useRedisCache) {
final redis = await RedisConnection.connect('localhost', 6379);
it.registerLazySingleton<CacheDriver>(
() => RedisCacheDriver(redis),
instanceName: 'redis',
);
}
}
}
Custom Notification Providers¶
Implement custom notification providers for third-party services:
// lib/core/notifications/onesignal_provider.dart
class OneSignalNotificationProvider extends PushNotificationProvider {
final OneSignal _oneSignal;
OneSignalNotificationProvider(this._oneSignal);
@override
Future<void> initialize() async {
await _oneSignal.setAppId(NotificationConfig.oneSignalAppId);
_oneSignal.setNotificationWillShowInForegroundHandler((event) {
onNotificationReceived(NotificationData.fromOneSignal(event.notification));
});
_oneSignal.setNotificationOpenedHandler((event) {
onNotificationTapped(NotificationData.fromOneSignal(event.notification));
});
}
@override
Future<String?> getToken() async {
final deviceState = await _oneSignal.getDeviceState();
return deviceState?.userId;
}
@override
Future<void> subscribeToTopic(String topic) async {
await _oneSignal.sendTag('topic_$topic', 'true');
}
}
Custom Analytics Providers¶
Integrate with analytics services beyond Firebase:
// lib/core/analytics/mixpanel_provider.dart
class MixpanelAnalyticsProvider implements AnalyticsProvider {
final Mixpanel _mixpanel;
MixpanelAnalyticsProvider(this._mixpanel);
@override
void log(AnalyticsEvent event) {
if (event is UserLoggedIn) {
_mixpanel.identify(event.id.toString());
_mixpanel.getPeople().set('login_method', event.loginMethod);
} else if (event is UserSignedUp) {
_mixpanel.identify(event.id.toString());
_mixpanel.getPeople().set({
'signup_date': DateTime.now().toIso8601String(),
'signup_method': event.signupMethod,
});
}
_mixpanel.track(event.key, event.params);
}
@override
void setUserId(String userId) {
_mixpanel.identify(userId);
}
@override
void setUserAttributes(Map<String, dynamic> attributes) {
_mixpanel.getPeople().set(attributes);
}
}
Performance Optimization¶
Lazy Loading Strategies¶
Implement lazy loading for better app startup performance:
class LazyServiceProvider extends ServiceProvider {
@override
Future<void> register(GetIt it) async {
// Register factories that create instances only when needed
it.registerLazySingleton<ExpensiveService>(() {
print('Creating ExpensiveService instance...');
return ExpensiveService();
});
// Use async factories for services that require async initialization
it.registerSingletonAsync<DatabaseService>(() async {
final db = DatabaseService();
await db.initialize();
return db;
});
}
}
Memory Management¶
Implement proper memory management for large datasets:
class MemoryManagedController extends StateNotifier<DataState> {
static const int _maxCachedItems = 1000;
final Map<String, dynamic> _memoryCache = {};
final Queue<String> _accessOrder = Queue<String>();
void cacheItem(String key, dynamic item) {
// Remove oldest items if cache is full
while (_memoryCache.length >= _maxCachedItems) {
final oldestKey = _accessOrder.removeFirst();
_memoryCache.remove(oldestKey);
}
_memoryCache[key] = item;
_accessOrder.add(key);
}
dynamic getCachedItem(String key) {
if (_memoryCache.containsKey(key)) {
// Move to end of access order (LRU)
_accessOrder.remove(key);
_accessOrder.add(key);
return _memoryCache[key];
}
return null;
}
@override
void dispose() {
_memoryCache.clear();
_accessOrder.clear();
super.dispose();
}
}
Background Processing¶
Handle background tasks efficiently:
class BackgroundTaskService {
static const String _taskQueueKey = 'background_tasks';
Future<void> scheduleTask(BackgroundTask task) async {
final tasks = await _getQueuedTasks();
tasks.add(task);
await Cache.put(_taskQueueKey, tasks);
// Process immediately if app is active
if (WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) {
await _processTasks();
}
}
Future<void> _processTasks() async {
final tasks = await _getQueuedTasks();
final completedTasks = <BackgroundTask>[];
for (final task in tasks) {
try {
await task.execute();
completedTasks.add(task);
} catch (e) {
// Log error but continue with other tasks
print('Background task failed: $e');
}
}
// Remove completed tasks
tasks.removeWhere((task) => completedTasks.contains(task));
await Cache.put(_taskQueueKey, tasks);
}
Future<List<BackgroundTask>> _getQueuedTasks() async {
final cached = await Cache.get<List<dynamic>>(_taskQueueKey);
return cached?.map((json) => BackgroundTask.fromJson(json)).toList() ?? [];
}
}
Security Best Practices¶
Certificate Pinning¶
Implement certificate pinning for API security:
class SecureApiServiceProvider extends ServiceProvider {
@override
Future<void> register(GetIt it) async {
final dio = Dio();
// Add certificate pinning
(dio.httpClientAdapter as IOHttpClientAdapter).onHttpClientCreate = (client) {
client.badCertificateCallback = (cert, host, port) {
// Verify certificate fingerprint
final fingerprint = _getCertificateFingerprint(cert);
return _trustedFingerprints.contains(fingerprint);
};
return client;
};
it.registerSingleton<Dio>(dio);
}
static const List<String> _trustedFingerprints = [
'AA:BB:CC:DD:EE:FF:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE',
// Add your API server's certificate fingerprint
];
String _getCertificateFingerprint(X509Certificate cert) {
final bytes = cert.der;
final digest = sha256.convert(bytes);
return digest.bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(':').toUpperCase();
}
}
Data Encryption¶
Encrypt sensitive data before storage:
class EncryptedStorage {
final FlutterSecureStorage _secureStorage;
final Encrypter _encrypter;
EncryptedStorage(this._secureStorage, this._encrypter);
Future<void> store(String key, String value) async {
final encrypted = _encrypter.encrypt(value);
await _secureStorage.write(key: key, value: encrypted.base64);
}
Future<String?> retrieve(String key) async {
final encryptedValue = await _secureStorage.read(key: key);
if (encryptedValue == null) return null;
try {
final encrypted = Encrypted.fromBase64(encryptedValue);
return _encrypter.decrypt(encrypted);
} catch (e) {
return null;
}
}
Future<void> delete(String key) async {
await _secureStorage.delete(key: key);
}
}
Next Steps¶
Continue exploring Bond's advanced capabilities:
- Performance Optimization - Detailed performance tuning
- Security Hardening - Comprehensive security guide
- Testing Strategies - Advanced testing patterns
- Deployment - Production deployment strategies