southgames_flutter 0.6.9
southgames_flutter: ^0.6.9 copied to clipboard
Flutter SDK for SouthGames — integrate gamification and loyalty features (spin wheel, scratch cards, trivia, slot machine, promo codes, in-app notifications) into your Flutter app with a single package.
SouthGames Flutter SDK #
Flutter SDK para integrar gamificación y loyalty de SouthGames en tu app.
Funcionalidades #
- Registro de clientes — upsert por
externalIdcon custom params y device tokens. - Idioma automático — detecta el locale del dispositivo (ej:
es-CL) y lo envía al registrar. - Identificación automatica — envía y refresca el device token en cada inicio de app.
- Campañas activas — listado de campañas con configuración de juego.
- 4 tipos de juego — spin wheel, scratch card, trivia y slot machine.
- Juegos del marketplace — carga juegos HTML5 en WebView con
SouthGamesGameView. - Códigos promocionales — generación automatica al ganar + canje.
- Sistema de puntos — consultar saldo, historial, gastar y ganar puntos canjeables.
- Notificaciónes in-app — filtradas por segment rules del cliente.
- Push notifications — registro de device tokens con cualquier proveedor (FCM, APNs, etc.).
- Eventos personalizados — trackeo de eventos con propiedades y notificaciones triggered.
Instalación #
Agrega southgames_flutter a tu pubspec.yaml:
dependencies:
southgames_flutter: ^0.6.3
Luego ejecuta:
flutter pub get
Inicio rápido #
import 'package:southgames_flutter/southgames_flutter.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@pragma('vm:entry-point')
Future<void> _firebaseBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
await SouthGamesSDK.handleBackgroundMessage(message);
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseBackgroundHandler);
// 1. Inicializar el SDK (una sola vez)
await SouthGamesSDK.init(
apiKey: 'sg_live_xxxxxxxxxxxxxxxx',
orgId: 'tu-org-slug',
);
runApp(const MyApp());
}
// 2. Desde cualquier parte de la app, usar SouthGamesSDK.instance
final sdk = SouthGamesSDK.instance;
// Identificar al usuario
final res = await sdk.identify(
externalId: 'user_123',
email: 'usuario@app.com',
customParams: {'plan': 'premium'},
);
print('Client ID: ${res.clientId}');
// Obtener campañas activas
final campaigns = await sdk.getCampaigns();
// Jugar
final play = await sdk.play(
campaignId: campaigns.first.id,
externalUserId: 'user_123',
);
if (play.won && play.prizeCode != null) {
print('Ganaste! Código: ${play.prizeCode}');
}
// Canjear un código
final redeem = await sdk.redeem(code: play.prizeCode!);
print('Descuento: ${redeem.discountValue}%');
Uso #
Inicialización #
Llama a SouthGamesSDK.init() una vez antes de usar cualquier otro método. Generalmente en main().
await SouthGamesSDK.init(
apiKey: 'sg_live_xxxxxxxxxxxxxxxx',
orgId: 'tu-org-slug',
pushConfig: PushConfig(
requestPermissionOnInit: true,
showForegroundNotifications: true,
onNotificationTap: (message) {
debugPrint('Notification tapped: ${message.data}');
},
),
onCtaTap: (action) {
debugPrint('CTA tapped: $action');
},
);
Después de init(), accede al SDK desde cualquier parte de la app:
final sdk = SouthGamesSDK.instance;
O verifica si fue inicializado:
if (SouthGamesSDK.isInitialized) {
// usar sdk
}
Nota: Si usas el SDK sin llamar a
init(), se lanzaSouthGamesNotInitializedException.
Identificación de usuario #
identify() registra o actualiza al usuario y envía el device token automáticamente. El idioma del dispositivo (ej: es-CL) se detecta y envía automáticamente. Llámalo en cada inicio de app una vez que conozcas la identidad del usuario.
final sdk = SouthGamesSDK.instance;
final res = await sdk.identify(
externalId: 'user_123', // ID del usuario en tu plataforma
email: 'user@example.com', // opciónal
firstName: 'Juan', // opciónal
lastName: 'Perez', // opciónal
phone: '+56912345678', // opciónal
latitude: -33.45, // opciónal
longitude: -70.66, // opciónal
customParams: {'tier': 'gold'}, // opciónal
);
print(res.clientId); // ID único del cliente en SouthGames
print(res.created); // true si es nuevo, false si se actualizó
print(res.deviceTokenSent); // true si el device token fue envíado
Debug: El SDK imprime logs con el prefijo
[SouthGames]en la consola de debug.
Registro manual de cliente #
Si necesitas más control, puedes usar registerClient() directamente:
final res = await SouthGamesSDK.instance.registerClient(
externalId: 'user_123',
email: 'user@example.com',
deviceToken: 'fcm_or_apns_token', // opciónal
);
Heartbeat #
Actualiza lastSeenAt del cliente. Útil para trackear actividad.
await SouthGamesSDK.instance.heartbeat(clientId: 'client_id');
Campañas activas #
Retorna las campañas con status == "active" dentro de su rango de fechas.
final campaigns = await SouthGamesSDK.instance.getCampaigns();
for (final c in campaigns) {
print('${c.name} (${c.gameType})');
}
Jugar un juego #
final sdk = SouthGamesSDK.instance;
// Spin wheel / scratch card / slot machine
final play = await sdk.play(
campaignId: 'campaign_id',
externalUserId: 'user_123',
);
// Trivia (requiere respuestas)
final triviaPlay = await sdk.play(
campaignId: 'trivia_campaign_id',
externalUserId: 'user_123',
answers: [0, 2, 1, 3], // índice de la opción elegida por pregunta
);
print(play.won); // true si ganó
print(play.prizeCode); // código promo si ganó, null si no
print(play.result); // descripción del resultado
print(play.metadata); // metadata especifica del juego
Juegos del marketplace (WebView) #
Para campañas con juegos del marketplace, usa SouthGamesGameView:
if (campaign.isMarketplaceGame) {
Navigator.push(context, MaterialPageRoute(
builder: (_) => SouthGamesGameView(
campaign: campaign,
externalUserId: 'user_123',
onResult: (result) {
print(result.won ? 'Ganaste!' : 'No ganaste');
Navigator.pop(context);
},
onClose: () => Navigator.pop(context),
onError: (error) => print('Error: $error'),
),
));
}
Eventos personalizados #
Trackea eventos y recibe notificaciones triggered automáticamente.
final result = await SouthGamesSDK.instance.trackEvent(
eventName: 'purchase_completed',
properties: {'amount': 9990, 'product': 'premium'},
);
print('Evento: ${result.eventName}');
if (result.triggeredNotifications.isNotEmpty) {
print('${result.triggeredNotifications.length} notificación(es) triggered');
}
Canjear código promocional #
final redeem = await SouthGamesSDK.instance.redeem(
code: 'SG-AB2C-XY9Z',
externalUserId: 'user_123', // opciónal
);
print(redeem.success); // true
print(redeem.discountType); // 'percentage' | 'fixed'
print(redeem.discountValue); // ej: 20
print(redeem.remainingUses); // usos restantes
Notificaciónes in-app #
Las notificaciones in-app se muestran automáticamente después de init(). No necesitas agregar ningún widget.
Para obtener las notificaciones manualmente:
final notifications = await SouthGamesSDK.instance.getInAppNotifications();
for (final n in notifications) {
print('${n.title} — ${n.body}');
if (n.cta != null) {
print('CTA: ${n.cta!.label} -> ${n.cta!.action}');
}
}
Si prefieres controlar el rendering con un widget:
MaterialApp(
builder: (context, child) => SouthGamesNotificationOverlay(
child: child!,
onCtaTap: (action) => print('CTA: $action'),
),
)
Puntos #
Consulta el saldo, historial, gasta y gana puntos canjeables.
final sdk = SouthGamesSDK.instance;
// Consultar saldo
final balance = await sdk.getPointsBalance(
externalUserId: 'user_123',
);
print('${balance.pointsName}: ${balance.pointsBalance}');
print('Ganados: ${balance.pointsEarned}');
print('Gastados: ${balance.pointsSpent}');
// Historial de puntos
final history = await sdk.getPointsHistory(
externalUserId: 'user_123',
limit: 10,
);
for (final entry in history) {
print('${entry.type}: ${entry.amount} — ${entry.reason}');
}
// Gastar puntos
try {
final spend = await sdk.spendPoints(
externalUserId: 'user_123',
amount: 100,
reason: 'Canje por descuento',
);
print('Gastaste ${spend.pointsSpent} puntos. Saldo: ${spend.newBalance}');
} on SouthGamesException catch (e) {
if (e.code == 'INSUFFICIENT_BALANCE') {
print('Saldo insuficiente');
}
}
// Ganar puntos manualmente
final earn = await sdk.earnPoints(
externalUserId: 'user_123',
action: 'custom',
eventName: 'purchase_completed',
);
print('Ganaste ${earn.pointsAwarded} puntos. Saldo: ${earn.newBalance}');
Nota: Los puntos también se ganan automáticamente al jugar, ganar juegos y canjear códigos, si hay reglas de ganancia configuradas en el dashboard.
Atribución #
Captura datos de atribución para medir de dónde vienen tus usuarios.
// Opción 1: Pasar directamente en identify()
final attr = Attribution(
utmSource: 'meta',
utmMedium: 'cpc',
utmCampaign: 'black-friday-2026',
);
await SouthGamesSDK.instance.identify(
externalId: 'user_123',
attribution: attr,
);
// Opción 2: Parsear desde un deep link
final attr = Attribution.fromUri(deepLinkUri);
await SouthGamesSDK.instance.identify(
externalId: 'user_123',
attribution: attr,
);
// Opción 3: Guardar antes del identify (ej: desde Install Referrer)
SouthGamesSDK.instance.setAttribution(
Attribution.fromMap(installReferrerParams),
);
// Se envía automáticamente en el próximo identify()
Nota: La atribución se limpia automáticamente después de enviarse.
Push notifications (manual) #
Si necesitas registrar tokens manualmente:
await SouthGamesSDK.instance.push.registerDeviceToken(
externalId: 'user_123',
token: 'fcm_or_apns_token',
);
Logout #
Desregistra el dispositivo y limpia todo el estado local.
await SouthGamesSDK.instance.logout(externalId: 'user_123');
// Después de logout, debes llamar init() e identify() de nuevo.
Limpieza #
Libera los recursos del HTTP client cuando ya no necesites el SDK.
SouthGamesSDK.dispose();
Manejo de errores #
Todas las llamadas pueden lanzar SouthGamesException:
try {
await SouthGamesSDK.instance.redeem(code: 'INVALID');
} on SouthGamesException catch (e) {
print(e.message); // "Código no encontrado"
print(e.code); // "CODE_NOT_FOUND"
print(e.statusCode); // 404
}
Códigos de error comunes #
| Código | HTTP | Descripción |
|---|---|---|
MISSING_API_KEY |
401 | Falta API key |
MISSING_ORG_ID |
401 | Falta org ID |
INVALID_API_KEY |
401 | API key inválida o inactiva |
API_KEY_EXPIRED |
401 | API key expirada |
VALIDATION_ERROR |
400 | Datos de entrada inválidos |
NOT_FOUND |
404 | Recurso no encontrado |
CAMPAIGN_INACTIVE |
400 | Campaña no activa |
CODE_NOT_FOUND |
404 | Código promo no existe |
CODE_INACTIVE |
400 | Código desactivado |
CODE_EXPIRED |
400 | Código expirado |
CODE_MAX_USES_REACHED |
400 | Código sin usos restantes |
INSUFFICIENT_BALANCE |
400 | Saldo de puntos insuficiente |
POINTS_NOT_ENABLED |
400 | Sistema de puntos no habilitado |
Modelos #
| Clase | Descripción |
|---|---|
RegisterResponse |
Resultado del registro (clientId, created, deviceTokenSent) |
Campaign |
Campaña activa (id, name, gameType, config, fechas) |
PlayResponse |
Resultado de jugar (sessionId, won, prizeCode, metadata) |
RedeemResult |
Resultado de canje (discountType, discountValue, remainingUses) |
InAppNotification |
Notificación in-app (title, body, type, position, cta, colores) |
CtaButton |
Botón CTA de notificación (label, action) |
TrackEventResult |
Resultado de trackear evento (eventName, triggeredNotifications) |
PointsBalance |
Saldo de puntos (pointsBalance, pointsEarned, pointsSpent, pointsName) |
PointsLedgerEntry |
Entrada del historial de puntos (type, amount, balance, reason) |
SpendPointsResponse |
Resultado de gastar puntos (pointsSpent, newBalance) |
EarnPointsResponse |
Resultado de ganar puntos (pointsAwarded, newBalance, totalEarned) |
Attribution |
Datos de atribución (utmSource, utmMedium, utmCampaign, utmContent, utmTerm, linkId) |
Requisitos #
- Dart SDK
>=3.0.0 <4.0.0 - Flutter
>=3.10.0 - Una cuenta en SouthGames con API key activa
Licencia #
MIT — ver LICENSE.