Files
App/packages/miniapp-example/BUILD_GUIDE.md

8.1 KiB

Mini-App Example: Building for Production

This guide shows how to build and deploy the Payment Demo mini-app.

Prerequisites

  • Flutter SDK installed
  • flutter_eval package installed
  • Access to the PluginRegistry in your main app

Development

Running the Example

Run the example app directly:

cd packages/miniapp-example
flutter run

Running Tests

Run the test suite:

flutter test

Building for Production

Step 1: Compile to Bytecode

Use flutter_eval to compile the mini-app to bytecode (.evc file):

cd packages/miniapp-example
flutter pub get
dart run flutter_eval:compile -i lib/main.dart -o payment_demo.evc

This will create payment_demo.evc in the current directory.

Step 2: Upload to Server

Upload the .evc file to your server:

# Example: Upload to your mini-apps server
curl -X POST https://your-server.com/api/mini-apps/upload \
  -F "file=@payment_demo.evc" \
  -F "metadata={\"name\":\"Payment Demo\",\"version\":\"1.0.0\",\"description\":\"Example payment mini-app\"}"

Step 3: Configure Server Metadata

Ensure your server returns the mini-app metadata in the correct format:

{
  "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": 12345,
  "min_host_version": "1.0.0"
}

Integration with Main App

Load the Mini-App

Use the PluginRegistry to load and run the mini-app:

import 'package:island/modular/registry.dart';
import 'package:island/pods/plugin_registry.dart';

// Get the registry
final registry = ref.read(pluginRegistryProvider.notifier);

// Load the mini-app from server
final miniApp = await registry.loadMiniApp(
  'https://your-server.com/mini-apps/payment-demo.evc',
);

// Enable the mini-app
await registry.enablePlugin(miniApp.id);

// Launch the mini-app
await registry.launchMiniApp(context, miniApp.id);

Provide PaymentAPI to Mini-App

Ensure the PaymentAPI is available to the mini-app through the eval bridge:

import 'package:island/modular/api/payment.dart';

// When loading the mini-app, register the PaymentAPI
final registry = PluginRegistry();

// Register PaymentAPI with the eval bridge
registry.registerBridge('PaymentAPI', PaymentAPI.instance);

Mini-App Development Guide

Project Structure

packages/miniapp-example/
├── lib/
│   ├── main.dart              # Main mini-app entry point
│   └── payment_api.dart       # PaymentAPI interface (for reference)
├── test/
│   └── main_test.dart         # Widget tests
├── pubspec.yaml               # Package configuration
└── README.md                  # This file

Key Files

lib/main.dart

  • Contains the main mini-app widget
  • Implements the UI for testing PaymentAPI
  • Can be run standalone or compiled to bytecode

lib/payment_api.dart

  • Shows the PaymentAPI interface
  • Used as a reference for API usage
  • Not compiled into the final .evc file

Writing Your Own Mini-App

  1. Create a new Flutter package:
mkdir packages/my-miniapp
cd packages/my-miniapp
flutter create --org com.example my_miniapp
  1. Add flutter_eval to pubspec.yaml:
dependencies:
  flutter:
    sdk: flutter
  flutter_eval: ^0.8.2
  1. Write your mini-app in lib/main.dart
  2. Test with flutter test
  3. Compile to .evc:
dart run flutter_eval:compile -i lib/main.dart -o my_miniapp.evc

API Usage Examples

Creating an Order

final paymentApi = PaymentAPI.instance;

final order = await paymentApi.createOrder(
  CreateOrderRequest(
    amount: 19.99,
    currency: 'USD',
    description: 'Premium subscription',
    metadata: {'plan': 'premium', 'duration': '1m'},
  ),
);

print('Order created: ${order.orderId}');

Processing Payment with Overlay

final result = await paymentApi.processPaymentWithOverlay(
  orderId: order.orderId,
);

if (result.success) {
  print('Payment successful: ${result.transactionId}');
  // Navigate to success screen
} else {
  print('Payment failed: ${result.errorMessage}');
  // Show error to user
}

Processing Direct Payment

final result = await paymentApi.processDirectPayment(
  orderId: order.orderId,
  paymentMethod: 'credit_card',
  paymentToken: 'tok_abc123',
);

if (result.success) {
  print('Payment successful: ${result.transactionId}');
} else {
  print('Payment failed: ${result.errorMessage}');
}

Testing Strategy

Unit Tests

Test business logic and API interactions:

test('should create order with correct amount', () {
  final request = CreateOrderRequest(
    amount: 19.99,
    currency: 'USD',
    description: 'Test order',
  );
  
  expect(request.amount, 19.99);
  expect(request.currency, 'USD');
});

Widget Tests

Test UI components:

flutter test test/main_test.dart

Integration Tests

Test the mini-app with the eval bridge:

testWidgets('should process payment through eval bridge', (tester) async {
  // Setup eval bridge
  final eval = EvalCompiler();
  eval.addPlugin(PaymentAPIPlugin());
  
  // Load mini-app
  final program = eval.compile(await File('main.dart').readAsString());
  
  // Run mini-app
  await tester.pumpWidget(program.build());
  
  // Test payment flow
  await tester.tap(find.text('Pay with Overlay'));
  await tester.pumpAndSettle();
  
  expect(find.text('Payment successful!'), findsOneWidget);
});

Troubleshooting

Compilation Errors

Error: Method not found in eval bridge Solution: Ensure PaymentAPI is registered with the eval bridge before loading the mini-app.

Error: Permission denied when accessing storage Solution: Add the following to AndroidManifest.xml (Android):

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

And Info.plist (iOS):

<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to save payment receipts</string>

Runtime Errors

Error: PaymentAPI.instance is null Solution: Ensure PaymentAPI is initialized before the mini-app starts.

Error: Network timeout Solution: Increase timeout in PaymentAPI configuration or check network connectivity.

Testing Errors

Error: Widget not found Solution: Ensure you're pumping the widget tree with await tester.pump() after state changes.

Error: Multiple widgets found Solution: Use more specific finders or add keys to widgets.

Best Practices

  1. Keep Mini-Apps Small: Mini-apps should be focused and lightweight
  2. Handle Errors Gracefully: Always wrap API calls in try-catch blocks
  3. Show Loading States: Provide feedback for long-running operations
  4. Test Thoroughly: Write comprehensive tests for all user flows
  5. Version Management: Include version information in metadata
  6. Security: Never store sensitive data in the mini-app
  7. Network Handling: Implement retry logic for network failures
  8. User Feedback: Always show success/error messages to users

Performance Tips

  1. Lazy Loading: Load resources only when needed
  2. Image Optimization: Compress images before including in mini-app
  3. Code Splitting: Split large mini-apps into smaller modules
  4. Caching: Cache API responses to reduce network calls
  5. Debouncing: Debounce user inputs to reduce API calls

Security Considerations

  1. Input Validation: Always validate user inputs
  2. API Keys: Never include API keys in the mini-app code
  3. HTTPS Only: Always use HTTPS for API calls
  4. Data Encryption: Encrypt sensitive data stored locally
  5. Permissions: Request minimum necessary permissions
  6. Updates: Always update to the latest version of dependencies

Support

For issues or questions:

  1. Check the main README in lib/modular/README.md
  2. Review PaymentAPI documentation in lib/modular/api/README.md
  3. Check test examples in test/main_test.dart
  4. Review the PaymentAPI interface in lib/payment_api.dart