14 KiB
14 KiB
Mini-App Example - Integration Overview
This document explains how the miniapp-example package integrates with the main Island application and the plugin registry system.
Architecture Overview
Island Main App
│
├── PluginRegistry (lib/modular/registry.dart)
│ ├── loadMiniApp() # Downloads and caches .evc files
│ ├── enablePlugin() # Activates mini-app
│ └── launchMiniApp() # Runs mini-app in full-screen
│
├── PaymentAPI (lib/modular/api/payment.dart)
│ └── Singleton with internal Dio client
│
└── Eval Bridge
├── PaymentAPI instance registered
└── Available to mini-apps at runtime
Integration Flow
1. Mini-App Development
Developer creates mini-app in packages/miniapp-example
↓
Tests with `flutter test` (17 tests passing)
↓
Runs with `flutter run` (debug mode)
↓
Compiles with `dart run flutter_eval:compile -i lib/main.dart -o payment_demo.evc`
↓
Uploads payment_demo.evc to server
2. Server Setup
Server provides mini-app metadata:
{
"id": "payment-demo",
"name": "Payment Demo",
"version": "1.0.0",
"description": "Example payment mini-app",
"download_url": "https://your-server.com/mini-apps/payment_demo.evc",
"checksum": "sha256:abc123...",
"size": 3456,
"min_host_version": "1.0.0"
}
3. Main App Discovery
// In main app startup
final registry = ref.read(pluginRegistryProvider.notifier);
// Register PaymentAPI with eval bridge
registry.registerBridge('PaymentAPI', PaymentAPI.instance);
// Sync with server to discover mini-apps
await registry.syncMiniApps();
4. User Downloads Mini-App
// User selects mini-app from list
final miniApp = await registry.loadMiniApp(
'https://your-server.com/mini-apps/payment_demo.evc',
);
// PluginRegistry handles:
// 1. Download from server
// 2. Save to {appDocuments}/mini_apps/{id}/payment_demo.evc
// 3. Validate checksum
// 4. Cache locally
// 5. Save to SharedPreferences (enabled apps list)
5. Enable Mini-App
// User enables mini-app
await registry.enablePlugin('payment-demo');
// PluginRegistry:
// 1. Adds to enabled apps in SharedPreferences
// 2. Prepares for launch
6. Launch Mini-App
// User launches mini-app
await registry.launchMiniApp(context, 'payment-demo');
// PluginRegistry:
// 1. Loads .evc bytecode
// 2. Creates Runtime with flutter_eval
// 3. Provides PaymentAPI through eval bridge
// 4. Runs mini-app main() function
// 5. Displays full-screen
7. Mini-App Uses PaymentAPI
// Inside mini-app (payment_demo.evc)
// Access PaymentAPI through eval bridge
final paymentApi = PaymentAPI.instance;
// Create order
final order = await paymentApi.createOrder(
CreateOrderRequest(
amount: 19.99,
currency: 'USD',
description: 'Premium subscription',
),
);
// Process payment
final result = await paymentApi.processPaymentWithOverlay(
orderId: order.orderId,
);
// Show result
if (result.success) {
print('Payment successful!');
} else {
print('Payment failed: ${result.errorMessage}');
}
Key Integration Points
1. PaymentAPI Registration
Location: lib/modular/registry.dart
class PluginRegistry {
final Map<String, dynamic> _bridge = {};
void registerBridge(String name, dynamic api) {
_bridge[name] = api;
}
// Called when loading mini-app
Runtime _createRuntime() {
return Runtime(
bridge: _bridge, // Pass PaymentAPI to mini-app
// ... other config
);
}
}
Usage: In main app startup
void main() async {
final registry = ref.read(pluginRegistryProvider.notifier);
// Register PaymentAPI
registry.registerBridge('PaymentAPI', PaymentAPI.instance);
runApp(MyApp());
}
2. Mini-App Loading
Location: lib/modular/registry.dart - loadMiniApp() method
Future<MiniApp> loadMiniApp(String url) async {
// 1. Download .evc file
final bytes = await _downloadFile(url);
// 2. Save to cache
final path = await _saveToCache(url, bytes);
// 3. Create MiniApp object
final miniApp = MiniApp(
id: _extractId(url),
bytecodePath: path,
// ... metadata
);
return miniApp;
}
3. Mini-App Launch
Location: lib/modular/registry.dart - launchMiniApp() method
Future<void> launchMiniApp(BuildContext context, String id) async {
// 1. Get mini-app
final miniApp = _getMiniApp(id);
// 2. Load bytecode
final bytecode = await File(miniApp.bytecodePath).readAsBytes();
// 3. Create runtime with PaymentAPI bridge
final runtime = _createRuntime();
// 4. Execute mini-app
final program = runtime.loadProgram(bytecode);
program.execute();
// 5. Navigate to mini-app screen
Navigator.push(
context,
MaterialPageRoute(builder: (_) => MiniAppScreen(program)),
);
}
Data Flow
Mini-App Request Flow
Mini-App (payment_demo.evc)
↓
PaymentAPI instance (from eval bridge)
↓
PaymentAPI class (lib/modular/api/payment.dart)
↓
Dio client (internal)
↓
Server API (your payment server)
↓
Response back to mini-app
State Management
SharedPreferences (Persistent)
├── enabled_mini_apps: ['payment-demo', ...]
└── last_sync: '2025-01-18T00:00:00Z'
File System (Cached .evc files)
└── {appDocuments}/mini_apps/
├── payment-demo/
│ └── payment_demo.evc
└── other-miniapp/
└── app.evc
Runtime (Memory)
├── Loaded mini-apps
└── Bridge APIs (PaymentAPI, etc.)
File Locations
Main App Files
lib/
├── modular/
│ ├── interface.dart # Plugin interfaces
│ ├── registry.dart # PluginRegistry class
│ ├── api/
│ │ └── payment.dart # PaymentAPI implementation
│ └── README.md # Plugin system docs
└── pods/
└── plugin_registry.dart # Riverpod providers
Mini-App Example Files
packages/miniapp-example/
├── lib/
│ ├── main.dart # Mini-app code
│ └── payment_api.dart # API reference
├── test/
│ └── main_test.dart # Widget tests
├── README.md # API usage docs
├── BUILD_GUIDE.md # Build instructions
├── SUMMARY.md # This document
├── build.sh # Build script
└── pubspec.yaml # Package config
Generated Files
build/ # Build artifacts (ignored)
*.evc # Compiled bytecode (optional)
*.freezed.dart # Generated code
*.g.dart # Generated code
Configuration
Main App Setup
- Add to pubspec.yaml:
dependencies:
flutter_eval: ^0.8.2
- Initialize PluginRegistry:
final registry = ref.read(pluginRegistryProvider.notifier);
await registry.initialize();
registry.registerBridge('PaymentAPI', PaymentAPI.instance);
- Set up server:
final serverInfo = MiniAppServerInfo(
baseUrl: 'https://your-server.com/api',
miniAppsPath: '/mini-apps',
);
registry.setServerInfo(serverInfo);
Mini-App Setup
- Create package:
mkdir packages/my-miniapp
cd packages/my-miniapp
flutter create --org com.example my_miniapp
- Add flutter_eval:
dependencies:
flutter_eval: ^0.8.2
- Write mini-app:
import 'package:flutter/material.dart';
class MyMiniApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(child: Text('Hello from Mini-App!')),
),
);
}
}
void main() => runApp(MyMiniApp());
- Test and build:
flutter test
dart run flutter_eval:compile -i lib/main.dart -o my_miniapp.evc
Testing Strategy
Unit Tests
Test business logic in isolation:
test('PaymentAPI should create order', () async {
final api = PaymentAPI.instance;
final order = await api.createOrder(
CreateOrderRequest(
amount: 19.99,
currency: 'USD',
description: 'Test',
),
);
expect(order.orderId, isNotEmpty);
});
Widget Tests
Test UI components:
cd packages/miniapp-example
flutter test
Integration Tests
Test full flow:
testWidgets('mini-app should process payment', (tester) async {
// Setup registry
final registry = PluginRegistry();
registry.registerBridge('PaymentAPI', PaymentAPI.instance);
// Load mini-app
final miniApp = await registry.loadMiniApp('test.evc');
// Launch
await registry.launchMiniApp(tester.element(miniApp), miniApp.id);
// Test payment flow
await tester.tap(find.text('Pay with Overlay'));
await tester.pumpAndSettle();
expect(find.text('Payment successful!'), findsOneWidget);
});
Troubleshooting
Mini-App Won't Load
Checklist:
- .evc file exists at expected path
- File is not corrupted (verify checksum)
- PaymentAPI is registered with bridge
- flutter_eval is properly initialized
- Mini-app main() function exists
Debug:
// Add logging in registry.dart
print('Loading mini-app from: $path');
print('Bytecode size: ${bytecode.length}');
print('Bridge APIs: ${_bridge.keys}');
PaymentAPI Not Available
Checklist:
- PaymentAPI is registered before mini-app loads
- Bridge name matches ('PaymentAPI')
- Singleton instance is not null
- Dio client is configured
Debug:
// Check bridge
print('Bridge has PaymentAPI: ${_bridge.containsKey('PaymentAPI')}');
// Check instance
print('PaymentAPI.instance: ${PaymentAPI.instance}');
Network Errors
Checklist:
- Server URL is accessible
- API endpoints are correct
- Authentication token exists
- Network permissions granted
Debug:
// Add Dio interceptors for logging
dio.interceptors.add(LogInterceptor(
request: true,
response: true,
error: true,
));
Best Practices
For Mini-App Developers
- Keep it Small: Mini-apps should be focused and lightweight
- Test Thoroughly: Write comprehensive tests for all user flows
- Handle Errors: Always wrap API calls in try-catch
- Show Feedback: Provide loading states and user feedback
- Use Official APIs: Only use PaymentAPI and other provided APIs
- Version Control: Include version information in metadata
- Security: Never store sensitive data or API keys
For Main App Developers
- Register APIs Early: Register all bridge APIs before loading mini-apps
- Handle Failures: Gracefully handle mini-app load failures
- Cache Wisely: Implement proper caching for .evc files
- Validate Metadata: Verify server metadata before loading
- Secure Bridge: Only expose necessary APIs to mini-apps
- Monitor Usage: Track mini-app usage and performance
- Update System: Keep flutter_eval and dependencies updated
Performance Considerations
Load Time Optimization
- Compress .evc files: Use gzip compression for download
- Lazy Loading: Only load bytecode when needed
- Prefetch: Download popular mini-apps in background
- Cache Validation: Use ETags for cache validation
Memory Optimization
- Unload When Done: Release mini-app resources when closed
- Limit Concurrent Apps: Only load one mini-app at a time
- Clean Up Runtime: Dispose runtime after mini-app exits
- Monitor Memory: Track memory usage during operation
Network Optimization
- Batch Requests: Combine multiple requests when possible
- Retry Logic: Implement exponential backoff for retries
- Offline Support: Cache responses for offline use
- Compression: Enable compression for API responses
Security Considerations
Mini-App Sandbox
Mini-apps run in a sandboxed environment:
- Limited file system access
- No direct network access (through bridge APIs only)
- No access to other mini-apps
- Limited device permissions
PaymentAPI Security
- Internal Dio client (no external dependencies)
- Token management via SharedPreferences
- HTTPS-only connections
- Automatic error logging
- No sensitive data in logs
Best Practices
- Validate Inputs: Always validate user inputs
- Encrypt Data: Encrypt sensitive data at rest
- Use HTTPS: Always use HTTPS for API calls
- Minimize Permissions: Request minimum necessary permissions
- Regular Updates: Keep dependencies updated
- Audit Logs: Review audit logs regularly
Future Enhancements
Planned Features
- Hot Reload: Support live reloading during development
- Plugin System: Allow mini-apps to use plugins
- Version Management: Automatic version checking and updates
- Analytics: Built-in analytics for mini-app usage
- Marketplace: Mini-app marketplace UI
- Permissions System: Fine-grained permissions for mini-apps
Potential Improvements
- Smaller Bytecode: Reduce .evc file size
- Faster Compilation: Improve compilation speed
- Better Debugging: Enhanced debugging tools
- Offline Support: Better offline functionality
- Background Tasks: Support for background operations
Resources
Documentation
- Plugin System:
lib/modular/README.md - Payment API:
lib/modular/api/README.md - Build Guide:
packages/miniapp-example/BUILD_GUIDE.md - API Reference:
packages/miniapp-example/lib/payment_api.dart
Code Examples
- Mini-App Example:
packages/miniapp-example/lib/main.dart - Widget Tests:
packages/miniapp-example/test/main_test.dart - Plugin Registry:
lib/modular/registry.dart - Payment API:
lib/modular/api/payment.dart
Tools
- Build Script:
packages/miniapp-example/build.sh - Flutter Eval: https://pub.dev/packages/flutter_eval
- Flutter Docs: https://flutter.dev/docs
Support
For issues or questions:
- Check documentation files
- Review code examples
- Check test cases
- Review PaymentAPI interface
- Consult build guide
Conclusion
The mini-app example demonstrates a complete integration between:
- Main app with PluginRegistry
- PaymentAPI with internal Dio client
- Mini-app compiled to .evc bytecode
- Eval bridge providing API access
This architecture enables:
- Dynamic loading of mini-apps
- Secure API access through bridge
- Full-screen mini-app experience
- Version management and updates
- Caching and offline support
For more details, see the documentation files listed above.