Flutter Integration
Integrate Loyalteez into your Flutter app (iOS & Android).
Prerequisites
- Flutter SDK installed
- Dart 3.0+
- Your Loyalteez Brand ID
Quick Start
1. Add Dependencies
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
http: ^1.1.0
shared_preferences: ^2.2.2
Run:
flutter pub get
2. Create Loyalteez Service
// lib/services/loyalteez_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class LoyalteezService {
static const String _apiUrl = 'https://api.loyalteez.app';
static const String _gasRelayerUrl = 'https://relayer.loyalteez.app';
static const String _brandId = 'YOUR_BRAND_ID';
Future<EventResponse?> trackEvent({
required String event,
required String email,
Map<String, dynamic>? metadata,
}) async {
try {
final response = await http.post(
Uri.parse('$_apiUrl/loyalteez-api/manual-event'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'event': event,
'email': email,
'metadata': {
...?metadata,
'platform': 'mobile',
'os': 'Flutter',
'brandId': _brandId,
},
}),
);
if (response.statusCode == 200) {
return EventResponse.fromJson(jsonDecode(response.body));
}
return null;
} catch (e) {
print('Error tracking event: $e');
return null;
}
}
Future<String?> executeTransaction({
required String privyToken,
required String to,
required String data,
required String userAddress,
}) async {
try {
final response = await http.post(
Uri.parse('$_gasRelayerUrl/relay'),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $privyToken',
},
body: jsonEncode({
'to': to,
'data': data,
'userAddress': userAddress,
'value': '0',
'gasLimit': 500000,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['transactionHash'];
}
return null;
} catch (e) {
print('Error executing transaction: $e');
return null;
}
}
Future<bool> checkHealth() async {
try {
final response = await http.get(
Uri.parse('$_apiUrl/loyalteez-api/debug'),
);
return response.statusCode == 200;
} catch (e) {
return false;
}
}
}
class EventResponse {
final bool success;
final int? ltzDistributed;
final String? transactionHash;
final String? walletAddress;
EventResponse({
required this.success,
this.ltzDistributed,
this.transactionHash,
this.walletAddress,
});
factory EventResponse.fromJson(Map<String, dynamic> json) {
return EventResponse(
success: json['success'] ?? false,
ltzDistributed: json['ltzDistributed'],
transactionHash: json['transactionHash'],
walletAddress: json['walletAddress'],
);
}
}
3. Create UI
// lib/main.dart
import 'package:flutter/material.dart';
import 'services/loyalteez_service.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Loyalteez Demo',
theme: ThemeData(primarySwatch: Colors.green),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _service = LoyalteezService();
bool _isLoading = false;
bool _isAuthenticated = false;
String _userEmail = '';
int _rewardAmount = 0;
bool _showReward = false;
Future<void> _handleLogin() async {
setState(() => _isLoading = true);
// Implement Privy login here
await Future.delayed(const Duration(seconds: 1));
setState(() {
_isLoading = false;
_isAuthenticated = true;
_userEmail = '[email protected]';
});
_trackLoginEvent();
}
Future<void> _trackLoginEvent() async {
final response = await _service.trackEvent(
event: 'mobile_login',
email: _userEmail,
metadata: {'source': 'flutter_app'},
);
if (response?.ltzDistributed != null) {
setState(() {
_rewardAmount = response!.ltzDistributed!;
_showReward = true;
});
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() => _showReward = false);
}
});
}
}
Future<void> _completeAction() async {
setState(() => _isLoading = true);
final response = await _service.trackEvent(
event: 'action_completed',
email: _userEmail,
metadata: {'actionType': 'button_click', 'screen': 'home'},
);
setState(() => _isLoading = false);
if (response?.ltzDistributed != null) {
setState(() {
_rewardAmount = response!.ltzDistributed!;
_showReward = true;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('You earned ${response.ltzDistributed} LTZ!')),
);
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() => _showReward = false);
}
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Column(
children: [
// Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
color: const Color(0xFF8CBC99),
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Loyalteez Demo',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 8),
Text(
'Earn rewards for your actions',
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
),
),
),
// Content
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
if (!_isAuthenticated) _buildLoginCard() else ...[
_buildAccountCard(),
const SizedBox(height: 16),
_buildActionsCard(),
],
],
),
),
),
],
),
// Reward Notification
if (_showReward)
Positioned(
top: 100,
left: 20,
right: 20,
child: _buildRewardNotification(),
),
// Loading Overlay
if (_isLoading)
Container(
color: Colors.black.withOpacity(0.5),
child: const Center(
child: CircularProgressIndicator(color: Colors.white),
),
),
],
),
);
}
Widget _buildLoginCard() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Get Started', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
const Text('Login to start earning LTZ rewards'),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleLogin,
child: Text(_isLoading ? 'Loading...' : 'Login with Email'),
),
),
],
),
),
);
}
Widget _buildAccountCard() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Your Account', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 12),
const Text('Email:', style: TextStyle(fontSize: 12, color: Colors.grey)),
Text(_userEmail, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
setState(() {
_isAuthenticated = false;
_userEmail = '';
});
},
child: const Text('Logout'),
),
),
],
),
),
);
}
Widget _buildActionsCard() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Earn Rewards', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
const Text('Complete actions to earn LTZ'),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isLoading ? null : _completeAction,
child: Text(_isLoading ? 'Processing...' : 'Complete Action'),
),
),
],
),
),
);
}
Widget _buildRewardNotification() {
return Card(
color: const Color(0xFF8CBC99),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
const Text('🎉', style: TextStyle(fontSize: 40)),
const SizedBox(height: 8),
Text(
'You earned $_rewardAmount LTZ!',
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white),
),
const SizedBox(height: 4),
const Text(
'Keep up the great work',
style: TextStyle(fontSize: 14, color: Colors.white),
),
],
),
),
);
}
}
4. Add Permissions
iOS (ios/Runner/Info.plist):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
</dict>
Android (android/app/src/main/AndroidManifest.xml):
<uses-permission android:name="android.permission.INTERNET" />
Running
# iOS
flutter run -d ios
# Android
flutter run -d android
# Both
flutter run
Testing
- Run the app on simulator/emulator
- Test login and event tracking
- Check Partner Portal analytics
Next Steps
- Add Privy Flutter integration
- Implement wallet view
- Add deep linking
- Add push notifications
Support
- Flutter: Flutter.dev
- Loyalteez API: API Reference
- Email: [email protected]