:drunk: Werid miniapp runtime
This commit is contained in:
617
packages/miniapp-example/INTEGRATION.md
Normal file
617
packages/miniapp-example/INTEGRATION.md
Normal file
@@ -0,0 +1,617 @@
|
||||
# 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```dart
|
||||
// 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
|
||||
|
||||
```dart
|
||||
// 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
|
||||
|
||||
```dart
|
||||
// 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
|
||||
|
||||
```dart
|
||||
// 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
|
||||
|
||||
```dart
|
||||
// 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`
|
||||
|
||||
```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
|
||||
|
||||
```dart
|
||||
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
|
||||
|
||||
```dart
|
||||
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
|
||||
|
||||
```dart
|
||||
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
|
||||
|
||||
1. **Add to pubspec.yaml**:
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter_eval: ^0.8.2
|
||||
```
|
||||
|
||||
2. **Initialize PluginRegistry**:
|
||||
```dart
|
||||
final registry = ref.read(pluginRegistryProvider.notifier);
|
||||
await registry.initialize();
|
||||
registry.registerBridge('PaymentAPI', PaymentAPI.instance);
|
||||
```
|
||||
|
||||
3. **Set up server**:
|
||||
```dart
|
||||
final serverInfo = MiniAppServerInfo(
|
||||
baseUrl: 'https://your-server.com/api',
|
||||
miniAppsPath: '/mini-apps',
|
||||
);
|
||||
registry.setServerInfo(serverInfo);
|
||||
```
|
||||
|
||||
### Mini-App Setup
|
||||
|
||||
1. **Create package**:
|
||||
```bash
|
||||
mkdir packages/my-miniapp
|
||||
cd packages/my-miniapp
|
||||
flutter create --org com.example my_miniapp
|
||||
```
|
||||
|
||||
2. **Add flutter_eval**:
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter_eval: ^0.8.2
|
||||
```
|
||||
|
||||
3. **Write mini-app**:
|
||||
```dart
|
||||
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());
|
||||
```
|
||||
|
||||
4. **Test and build**:
|
||||
```bash
|
||||
flutter test
|
||||
dart run flutter_eval:compile -i lib/main.dart -o my_miniapp.evc
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
|
||||
Test business logic in isolation:
|
||||
|
||||
```dart
|
||||
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:
|
||||
|
||||
```bash
|
||||
cd packages/miniapp-example
|
||||
flutter test
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
Test full flow:
|
||||
|
||||
```dart
|
||||
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**:
|
||||
```dart
|
||||
// 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**:
|
||||
```dart
|
||||
// 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**:
|
||||
```dart
|
||||
// Add Dio interceptors for logging
|
||||
dio.interceptors.add(LogInterceptor(
|
||||
request: true,
|
||||
response: true,
|
||||
error: true,
|
||||
));
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Mini-App Developers
|
||||
|
||||
1. **Keep it Small**: Mini-apps should be focused and lightweight
|
||||
2. **Test Thoroughly**: Write comprehensive tests for all user flows
|
||||
3. **Handle Errors**: Always wrap API calls in try-catch
|
||||
4. **Show Feedback**: Provide loading states and user feedback
|
||||
5. **Use Official APIs**: Only use PaymentAPI and other provided APIs
|
||||
6. **Version Control**: Include version information in metadata
|
||||
7. **Security**: Never store sensitive data or API keys
|
||||
|
||||
### For Main App Developers
|
||||
|
||||
1. **Register APIs Early**: Register all bridge APIs before loading mini-apps
|
||||
2. **Handle Failures**: Gracefully handle mini-app load failures
|
||||
3. **Cache Wisely**: Implement proper caching for .evc files
|
||||
4. **Validate Metadata**: Verify server metadata before loading
|
||||
5. **Secure Bridge**: Only expose necessary APIs to mini-apps
|
||||
6. **Monitor Usage**: Track mini-app usage and performance
|
||||
7. **Update System**: Keep flutter_eval and dependencies updated
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Load Time Optimization
|
||||
|
||||
1. **Compress .evc files**: Use gzip compression for download
|
||||
2. **Lazy Loading**: Only load bytecode when needed
|
||||
3. **Prefetch**: Download popular mini-apps in background
|
||||
4. **Cache Validation**: Use ETags for cache validation
|
||||
|
||||
### Memory Optimization
|
||||
|
||||
1. **Unload When Done**: Release mini-app resources when closed
|
||||
2. **Limit Concurrent Apps**: Only load one mini-app at a time
|
||||
3. **Clean Up Runtime**: Dispose runtime after mini-app exits
|
||||
4. **Monitor Memory**: Track memory usage during operation
|
||||
|
||||
### Network Optimization
|
||||
|
||||
1. **Batch Requests**: Combine multiple requests when possible
|
||||
2. **Retry Logic**: Implement exponential backoff for retries
|
||||
3. **Offline Support**: Cache responses for offline use
|
||||
4. **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
|
||||
|
||||
1. **Validate Inputs**: Always validate user inputs
|
||||
2. **Encrypt Data**: Encrypt sensitive data at rest
|
||||
3. **Use HTTPS**: Always use HTTPS for API calls
|
||||
4. **Minimize Permissions**: Request minimum necessary permissions
|
||||
5. **Regular Updates**: Keep dependencies updated
|
||||
6. **Audit Logs**: Review audit logs regularly
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
|
||||
1. **Hot Reload**: Support live reloading during development
|
||||
2. **Plugin System**: Allow mini-apps to use plugins
|
||||
3. **Version Management**: Automatic version checking and updates
|
||||
4. **Analytics**: Built-in analytics for mini-app usage
|
||||
5. **Marketplace**: Mini-app marketplace UI
|
||||
6. **Permissions System**: Fine-grained permissions for mini-apps
|
||||
|
||||
### Potential Improvements
|
||||
|
||||
1. **Smaller Bytecode**: Reduce .evc file size
|
||||
2. **Faster Compilation**: Improve compilation speed
|
||||
3. **Better Debugging**: Enhanced debugging tools
|
||||
4. **Offline Support**: Better offline functionality
|
||||
5. **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:
|
||||
|
||||
1. Check documentation files
|
||||
2. Review code examples
|
||||
3. Check test cases
|
||||
4. Review PaymentAPI interface
|
||||
5. 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.
|
||||
Reference in New Issue
Block a user