6.0 KiB
6.0 KiB
Plugin Registry and Loader System
Overview
This module provides a plugin system for the Island app with two types of plugins:
- Raw Plugins: Extend app abilities (services, hooks, utilities)
- Mini-Apps: Full-screen applications loaded from network with caching
File Structure
lib/
modular/
interface.dart # Plugin interfaces and metadata models
registry.dart # PluginRegistry class for managing plugins
pods/
plugin_registry.dart # Riverpod providers for plugin management
Core Components
1. Plugin Interface (lib/modular/interface.dart)
Defines the base types for plugins:
Plugin: Base interface for all pluginsRawPlugin: For plugins that extend app functionalityMiniApp: For full-screen apps with entry widgetsPluginMetadata: Common metadata structureMiniAppMetadata: Metadata for mini-apps including download URL, cache pathMiniAppServerInfo: Server response format for mini-app listingsPluginLoadResult: Enum for load operation results
2. Plugin Registry (lib/modular/registry.dart)
PluginRegistry class manages plugin lifecycle:
Raw Plugins:
registerRawPlugin(RawPlugin plugin)unregisterRawPlugin(String id)getRawPlugin(String id)
Mini-Apps:
loadMiniApp(MiniAppMetadata metadata, {ProgressCallback? onProgress}): Loads .evc bytecodeunloadMiniApp(String id): Unloads and cleans upgetMiniApp(String id): Get loaded mini-appgetMiniAppCacheDirectory(): Get cache directory pathclearMiniAppCache(): Clear all cached mini-appsdispose(): Cleanup all resources
3. Riverpod Providers (lib/pods/plugin_registry.dart)
Providers:
pluginRegistryProvider: Main registry provider withkeepAlive: trueminiAppsProvider: List of loaded mini-appsrawPluginsProvider: Map of raw plugins
Methods (via ref.read(pluginRegistryProvider.notifier):
syncMiniAppsFromServer(apiEndpoint): Sync with server, returnsMiniAppSyncResultdownloadMiniApp(id, downloadUrl, {ProgressCallback? onProgress}): Download and cacheupdateMiniApp(id, {ProgressCallback? onProgress}): Update to latest versionenableMiniApp(id, enabled): Enable/disable mini-appdeleteMiniApp(id, {deleteCache}): Remove mini-appclearMiniAppCache(): Clear cachegetMiniApp(id): Get specific mini-appgetLastSyncTime(): Get last sync timestamp
Storage
SharedPreferences Keys:
kMiniAppsRegistryKey: JSON array of MiniAppMetadatakMiniAppsLastSyncKey: ISO8601 timestamp of last sync
Cache Structure:
{applicationDocuments}/mini_apps/
├── {app_id}.evc # Compiled bytecode
└── {app_id}_metadata.json # Metadata backup (optional)
Usage Examples
Registering a Raw Plugin
class MyRawPlugin extends RawPlugin {
@override
PluginMetadata get metadata => PluginMetadata(
id: 'my_plugin',
name: 'My Plugin',
version: '1.0.0',
description: 'Extends app with new features',
);
}
final container = ProviderContainer();
container.read(pluginRegistryProvider.notifier).registerRawPlugin(MyRawPlugin());
Syncing Mini-Apps from Server
final syncResult = await ref.read(pluginRegistryProvider.notifier).syncMiniAppsFromServer(
'https://api.example.com/mini-apps',
);
if (syncResult.success) {
print('Added: ${syncResult.added}');
print('Updated: ${syncResult.updated}');
}
Downloading and Loading a Mini-App
await ref.read(pluginRegistryProvider.notifier).downloadMiniApp(
'com.example.miniapp',
'https://cdn.example.com/mini-apps/v1/app.evc',
onProgress: (progress, message) {
print('$progress: $message');
},
);
Using a Loaded Mini-App Entry
class MiniAppScreen extends ConsumerWidget {
final String appId;
const MiniAppScreen({required this.appId, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final miniApp = await ref.read(pluginRegistryProvider.notifier).getMiniApp(appId);
if (miniApp == null) {
return const Center(child: Text('Mini-app not loaded'));
}
return Scaffold(
body: miniApp.buildEntry(),
);
}
}
Server API Response Format
{
"mini_apps": [
{
"id": "com.example.miniapp",
"name": "Example Mini-App",
"version": "1.2.0",
"description": "An example mini-application",
"author": "Example Corp",
"iconUrl": "https://cdn.example.com/icons/miniapp.png",
"downloadUrl": "https://cdn.example.com/mini-apps/v1/app.evc",
"updatedAt": "2026-01-18T00:00:00Z",
"sizeBytes": 524288
}
]
}
Mini-App Development
A mini-app should export a buildEntry() function:
// mini_app/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Widget buildEntry() {
return MaterialApp(
title: 'My Mini-App',
home: Scaffold(
appBar: AppBar(title: const Text('My Mini-App')),
body: const Center(
child: Text('Hello from Mini-App!'),
),
),
);
}
Compile to .evc using flutter_eval toolchain before uploading to server.
FlutterEval Integration
Currently, a stub Runtime class is provided in lib/modular/registry.dart for compilation. To enable full flutter_eval functionality:
- Resolve dependency conflicts with analyzer package
- Replace stub
Runtimeclass with actual flutter_eval import - Test with actual .evc bytecode files
Notes
- Registry uses
keepAlive: trueto persist across app lifecycle - All operations are async and return appropriate results
- Progress callbacks provide real-time feedback for download/load operations
- Error handling includes talker logging for debugging
- SharedPreferences persistence survives app restarts
Future Enhancements
- Full flutter_eval integration
- Mini-app permissions and security model
- Version comparison and auto-update
- Dependency resolution for mini-apps
- Mini-app marketplace UI
- Hot-swapping without app restart