southgames_flutter 0.19.0
southgames_flutter: ^0.19.0 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.
0.19.0 #
getRankingPrizes()— qué reparte el ranking de una campaña, por período, para mostrarle al jugador qué está compitiendo. Solo vienen los períodos habilitados y con premios: una tabla apagada llega vacía, porque mostrarla prometería algo que no va a pasar.- Un premio de proveedor externo llega como
CodePrizeRewardsin monto: lo emite un tercero y cuánto vale es parte del acuerdo con él. El jugador ve que gana un código; el valor lo dice el código al canjearse. - El parseo es tolerante: una recompensa de un tipo que esta versión todavía no conoce se ignora, en vez de romper la tabla entera.
0.18.2 #
- One close button, not two —
SouthGamesGameViewnow hides its native top-right X when the game announcessouthgames:capabilities {selfClose: true}after the bridge handshake (Doggis Delivery >= 1.2.5 does). Such games render their own in-game X — with a proper abandon screen and a safe close that flushes any pendingsubmitResult. Older games that never announce the capability keep the native X: nobody is left without an exit. - The native X no longer kills games silently — while it is visible,
tapping it first routes a
southgames:requestClosemessage into the game. A game that understands it acknowledges withsouthgames:requestCloseAckand opens its own abandon / safe-close flow (so an in-flight result is never lost). If no acknowledgement arrives within ~600 ms (older games), the SDK falls back to callingonClosedirectly, exactly as before.
0.18.1 #
- Game campaigns now render truly full screen —
SouthGamesGameViewno longer constrains the WebView to 70% of the screen height (which produced black bars above and below the game). The game page handles its own safe areas viaviewport-fit=cover. kSdkVersionnow reports the real package version (0.18.0 introduced itself as "0.17.0" in thesdkVersionheader).
0.18.0 #
- Rankings (
getRankings/getMyRanking) — dos métodos nuevos sobre/api/v1/rankingsque exponen la tabla de posiciones que el servidor ya venía alimentando con cada partida.getRankingstrae el top del período (RankingPeriod.daily/weekly/monthly/allTime), acotado porRankingScope.campaign/gameType/org, ordenable porRankingSortBy.rankingScore(la fórmula compuesta que configura la organización, default del servidor),highScore,totalScoreototalWins.getMyRankingdevuelve la fila y la posición de UN jugador en una sola llamada aunque esté fuera del top — pensado para fijar "tu posición" al pie de la tabla — y exponeentry == null/hasPlayed == falsecuando todavía no jugó en ese período, para que el host muestre su estado vacío en vez de un cero. SinexternalUserIdexplícito usa el que persistió el últimoidentify(). Los cortes de día, semana y mes los resuelve el servidor en la ZONA HORARIA DE LA ORGANIZACIÓN (nunca UTC), así que "hoy" es el día del jugador.limitse recorta al rango 1..100 que acepta el servidor, y pedircampaign/gameTypesinscopeIdlanzaArgumentErroren el cliente en vez de gastar un round-trip para recibir un 400. Parseo tolerante en todos los modelos: un campo ausente, nulo o de un tipo inesperado cae a su neutro y jamás lanza — un servidor más nuevo que agregue campos, o uno más viejo que no los mande, no rompen al cliente.
0.17.0 #
prizeenSouthGamesGameResult— campo aditivoSouthGamesPrize?con el código de premio emitido por la PLATAFORMA cuando el gajo ganador tiene "Código del premio" configurado en el editor (estudio de mini-juegos, F1).prize.codetrae el código canjeable yprize.fulfillmentes"fulfilled"o"pending"(emisión transitoria fallida: la plantilla reintenta sola y el código queda recuperable en el award). Llega con el mismo payload enonGameResultyonGameFinished. Parseo tolerante: ausente,nullo con shape raro →null, jamás lanza — servers y plantillas viejas siguen funcionando igual.
0.16.0 #
externalIdenSouthGamesGameResult— campo aditivoString?con el identificador que el operador declaró para el gajo ganador en el editor del portal, pensado para mapear el resultado contra TU plataforma (un SKU, un id de cupón, etc.) sin depender delsegmentIdinterno. Llega con el mismo payload enonGameResultyonGameFinished. Parseo fail-closed: si el campo viene ausente,null, vacío o con un tipo inesperado, el modelo exponenully jamás lanza — así una notificación compilada con un HTML viejo (que no emite el campo) o un gajo sin identificador declarado siguen funcionando exactamente igual que antes. Requiere portal actualizado y notificación recompilada para que el valor viaje; con configs anteriores el campo simplemente esnull.
0.15.0 #
onGameFinishedcallback (fin de la animación del mini-juego) —SouthGamesNotificationOverlayganaonGameFinished: void Function(SouthGamesGameResult)?, espejo exacto deonGameResult. La plantilla de la ruleta ahora emite DOS eventos por giro con el MISMO payload JSON:result:apenas el servidor confirma el giro (usalo para precargar datos conawardIden paralelo a la animación, como hasta hoy) yfinished:(nuevo) cuando la rueda se detiene y el resultado quedó a la vista — el momento correcto para navegar a tu propia pantalla o reaccionar en la UI.finished:es solo señal: nunca cierra el overlay, nunca marca impresiones ni eventos, y un payload malformado se ignora con log sin lanzar jamás (mismo contrato fail-closed queresult:). Requiere una notificación recompilada con la plantilla vigente para que el evento exista; con un HTML viejo el callback simplemente no se dispara, y un SDK anterior a 0.15.0 ignorafinished:sin errores. Ojo: si el usuario cierra la in-app a mitad del giro (el botón de cerrar sigue activo durante la animación),finished:ya no llega para ese giro — no difieras aonGameFinishednada crítico: acredita/decide cononGameResulty usaonGameFinishedsolo para UI/navegación.
0.14.0 #
- Mini-juegos sin caps de impresiones/cooldown: las in-apps de mini-juego
(
isGameen el wire, servido por el portal) ya no se regulan pormaxImpressionsnicooldownMinutes— su unica regulacion es la cadencia de giro del servidor (frecuencia de giro + replay idempotente). Las in-apps normales conservan sus caps sin cambios. Requiere portal actualizado (el flag es aditivo: con un portal viejo, los juegos siguen con caps como antes).
0.13.1 #
- Fix: in-apps mostradas DOS veces cuando
SouthGamesNotificationOverlayse suscribia mientrasinit()seguia corriendo (o tras un re-init de logout): el stream es broadcast y el auto-overlay interno quedaba escuchando junto al widget. El deshabilitado del auto-overlay ahora es persistente (sobrevive a init/re-init) y ademas se re-chequea en cada emision. El widget tambien gana el guard de "misma in-app ya visible" que el auto-overlay siempre tuvo (el re-emit del poll ya no recarga el WebView ni infla impresiones).
0.13.0 #
shouldShowNotification— la app decide si se muestra la in-app. Antes de mostrar CADA in-app (poll normal o abierta desde un push vinculado — mismo choke point, el callback no distingue la fuente hoy), el SDK deja que la app host la vete con su propia lógica (pantalla actual, estado del usuario, reglas de negocio):SouthGamesNotificationOverlay(shouldShowNotification: (notification) async => !estoyEnCheckout()). TambiénSouthGamesSDK.instance.shouldShowInApp = ...para apps que usan el auto-overlay (sin widget) — si ambos están definidos, gana el del widget (es el path activo mientras el widget está montado). Semántica completa:- Corre ANTES del preload (
_onNotification, justo después del check deisDismissed): un "no" no gasta red ni crea WebViews. - Es por intento, no permanente: un "no" no descarta la notificación — la próxima vez que se reemita (p. ej. el siguiente poll) se vuelve a preguntar, así que lógica de la app que cambia con el tiempo ("no durante el checkout") se respeta en vivo.
- REQUISITO DURO — cero rastro con un "no": jamás se emite el evento
shownal servidor (trackInAppEvent), jamás se incrementa el contador local de impresiones ni el frequency cap, jamás se persiste nada. Para el sistema, esa entrega no existió. - Fail-open estricto: si el callback lanza o no resuelve en 3s, la in-app SE MUESTRA igual (+
debugPrint) — un bug del integrador no puede apagar las campañas de una org en silencio. - Sin callback definido (ni widget ni SDK), comportamiento idéntico al de antes: el gate ni se evalúa — cero cambio para las apps que no usan esta feature.
- Corre ANTES del preload (
0.12.0 #
- Fondo transparente en mini-juegos HTML (
transparentBackground) — cuando el servidor mandatransparentBackground: truepara una notificación in-app HTML (hoy, la ruleta de premios con el switch "Fondo transparente" activado en el editor), el SDK deja de pintar cualquier fondo propio detrás del mini-juego: el WebView carga consetBackgroundColor(Colors.transparent)en vez del color/opacidad configurados, y su contenedor pierde tanto el color como la sombra que normalmente dibuja. Lo que queda visible detrás es la app del cliente, atenuada por el velo del modal de siempre (backdropOpacity, sin cambios). Fail-closed: cualquier valor que no sea exactamentetrue(ausente,false, string, número) se comporta exactamente como hoy — cero cambio de color, cero cambio de decoración. Aplica por igual a los dos caminos de despliegue del SDK (el widgetSouthGamesNotificationOverlayy el overlay automático), porque ambos renderizan el mismoNotificationOverlayWidget. La tarjeta de resultado del mini-juego nunca se transparenta — esto solo afecta el fondo detrás del WebView. - Caveat: requiere una notificación recompilada con manifiesto de plantilla 1.4.0+. El HTML compilado nunca se recompila solo (ver la guía "Mini-juegos in-app" del dashboard) — una ruleta guardada antes de este flag sigue sirviendo el HTML viejo, sin
transparentBackgrounden absoluto, así que activar el switch en el editor no tiene ningún efecto hasta volver a abrirla y guardarla (eso dispara la recompilación contra la plantilla vigente). - Caveat: SDKs anteriores a 0.12.0 ignoran el flag sin errores. Un SDK más viejo no sabe interpretar
transparentBackground— el campo simplemente no existe en su modelo — así que el mini-juego se sigue mostrando dentro de su contenedor opaco de siempre, sin ningún error ni degradación visible más allá de perder el efecto transparente.
0.11.2 #
- La recuperación de clientId obsoleto ahora es compartida entre llamadas
concurrentes: si el polling y una apertura de push chocan con el 404 a la
vez, ambas esperan la MISMA re-registración y reintentan con el id
recuperado. Antes, la segunda rebotaba en el guard de reentrada y logueaba
un
Notification poll errorespurio (se auto-corregía al siguiente tick, pero ensuciaba el log).
0.11.1 #
- Auto-sanación de clientId obsoleto: si el servidor responde
404 NOT_FOUND(el clientId guardado apunta a un cliente que ya no existe — p. ej. la respuesta de unidentifyse perdió a mitad de un merge), el SDK descarta el id muerto, se re-registra con la identidad persistida (o el deviceToken) y reintenta la llamada una vez. Aplica aheartbeat,getInAppNotifications(incluido el polling) ygetInAppNotificationById(apertura de in-apps vinculadas a push, que antes podía quedar crasheando en loop). - El sync de arranque adopta y persiste el
clientIdque resuelva el servidor (con las lápidas de merge server-side, un id viejo en prefs se corrige solo).
0.11.0 #
onGameResultcallback (mini-game results) —SouthGamesNotificationOverlaygains a newonGameResult: void Function(SouthGamesGameResult)?callback, same pattern as the existingonCtaTap/onNotificationShown. It fires the moment a mini-game running inside an HTML in-app (e.g. the roulette) posts its result over theSouthGamesNotifchannel — as soon as the server confirms the spin, before the in-notification result card even animates in — so your app can call your own platform (points, wallet, coupons) in parallel with the ~4s spin animation instead of waiting for it to finish. The newSouthGamesGameResultmodel exposesnotificationId,segmentId,label,isPrize(fail-closed: onlytruewhen the server confirms it),awardId(nullable — use it as your idempotency key before crediting anything), andalreadyPlayed(trueon a replayed/idempotent delivery). A malformed or unexpected channel message is ignored with a debug log — it never throws and never affects the overlay's owndismissbehavior; the callback simply isn't called for that message.- Caveat: only roulette notifications compiled with template 1.3.1+ send the full payload. Compiled HTML never auto-recompiles (see the dashboard's "Mini-juegos in-app" guide), so a roulette saved before 1.3.1 still emits the old, late-only
result:message — after the spin animation, and also for local-fallback and replayed draws. Against 0.11.0 that arrives asisPrize: false,awardId: null,notificationId: '',alreadyPlayed: false(fail-safe — never over-credits, but gives nothing to act on). Re-save the notification in the editor to recompile it against the current template and get real values.
0.10.0 #
- In-apps now preload all assets before showing — the SDK precaches every image the notification will render (legacy
imageUrl,imageblocks, YouTube video thumbnails) and, for HTML in-apps, pre-creates the WebView and waits for the page to finish loading, BEFORE inserting the overlay. The card appears fully rendered in one shot instead of popping in images progressively. A single global budget of 4 s (configurable viaSouthGamesNotificationOverlay(preloadTimeout: ...)) caps the wait: on timeout the in-app is shown anyway with whatever loaded (already-cached images appear instantly; slow ones pop in as they arrive), so a campaign is never lost to a slow network. A notification that never got shown never counts an impression. Applies to both display paths (theSouthGamesNotificationOverlaywidget and the automatic overlay). If a newer notification arrives while an older one is still preloading, the newer one wins and the stale preload is discarded silently.
0.9.1 #
- Dismiss is now session-scoped, not permanent — closing an in-app (or tapping its CTA) hides it only for the current session; on the next app launch it's eligible again. Re-display is governed by
maxImpressionsandcooldownMinutesas intended. Previously the dismiss flag was persisted and permanently suppressed the notification, so analwaysin-app with no caps (or its CTA tapped once) would show only once ever — ignoring the frequency config. SetmaxImpressions: 1for genuine show-once, or acooldownMinutesto space repeats.
0.9.0 #
- Launch a game campaign from a notification (
onLaunchCampaign) — when an in-app or push references a game campaign with the canonical formsouthgames://campaign/{id}(what the dashboard writes with the new "game campaign" selector), the SDK routes thecampaignIdto a typedonLaunchCampaign(campaignId)handler instead of the genericonDeeplink. The SDK still never opens the game itself — you decide WHERE to mount it, typicallygetCampaignById(id)+SouthGamesGameView. Shares the cold-start buffer withonDeeplink. Register viaSouthGamesSDK.init(onLaunchCampaign: ...)or theonLaunchCampaignsetter. Only thesouthgames://scheme is treated as a campaign launch, so your own app schemes (myapp://campaign/x) are never hijacked; ifonLaunchCampaignisn't registered, these links fall back toonDeeplinkwhere you can handle them withlink.match('campaign/:id'). getCampaignById(id)— fetches a single campaign by id (with its signedembedUrland mergedgameConfig), without audience filtering, so a recipient can open a campaign they were explicitly sent even if they're not in its segment. ThrowsSouthGamesExceptionif the campaign is missing or unavailable (paused/expired). Also exposed:SgDeeplink.campaignIdgetter andSgLaunchCampaignHandlertypedef.- Registering
onDeeplinkandonLaunchCampaignback-to-back via setters (the recommended cold-start pattern) is now safe: router installation is coalesced to a microtask, so a pending cold-start deeplink is delivered once, with both handlers in place, instead of being routed against a half-registered set. - In-app background & backdrop opacity — in-app notifications now honor
bgOpacity(card background, 0–100) andbackdropOpacity(the dim veil behind modal/center/full, 0–100;0= no veil) from the dashboard. Defaults preserve the previous look (opaque card, 54% veil). Banners/toasts (top/bottom) never show a veil.
0.8.0 #
- Unified deeplink pipeline (
onDeeplink) — a single handler now receives ALL deeplinks:data.deeplinkfrom tapped pushes and CTA/button actions from in-app notifications. The SDK never opens or interprets the link — it delivers a parsedSgDeeplink(raw string,uri,params,pathSegments,source,match('promo/:id')route helper) so the app routes it with its own navigation/config system. Register viaSouthGamesSDK.init(onDeeplink: ...)(delivered after the first frame, so your navigator/router exists) or theonDeeplinksetter (delivered immediately, register it when your router is ready). Legacy callbacks (PushConfig.onDeeplinkReceived,onCtaTap) keep working unchanged. - Cold-start deeplinks no longer get lost — previously, a push tapped while the app was terminated fired the deeplink callback during
init(), before the app's navigator existed, silently dropping it. Deeplinks that arrive before a handler is registered are now buffered and delivered on registration (or retrievable viaconsumePendingDeeplink()). - Push-linked in-app auto-open — tapping a push sent with the dashboard's "also show as in-app" option (
data.inAppId) automatically fetches the linked in-app notification and shows it via the overlay, bypassing local dismiss/frequency state (explicit open). Disable withPushConfig(autoOpenLinkedInApp: false). New APIs:getInAppNotificationById(id),SouthGamesPush.getInAppId(message),SouthGamesNotificationManager.forceEmit(...).
0.7.4 #
getCampaigns()now sends identity — the request toGET /api/v1/campaignsincludes aclientIdquery param when the SDK has one (set byinit()/identify()), or falls back to theexternalUserIdpersisted by the lastidentify()call. The server uses it to filter campaigns by segment strictly for the current user. Calls without any identity are unchanged (no query params).
0.7.3 #
- Auto re-identify on app boot — the SDK now persists the identify payload (
externalId,email,firstName,lastName,phone) toSharedPreferencesafter every successfulidentify()call. On every subsequentinit(),_syncClientre-sends that payload to/api/v1/clients/registerso the server keeps the client identified even when the integrator app has a persistent session and doesn't re-callidentify()on each launch. Fixes the case where users who logged in once stayed anonymous in SouthGames because their session outlived the original identify trigger. Idempotent — the server merges into the same client doc. logout()clears the persisted identify payload alongside the existing clientId reset.
0.7.2 #
createPromoCode(...)method — New SDK method to create a single promo code for an end user on a campaign. UsesPOST /api/v1/codes; params (discount, expiry, prefix, length, maxDiscountAmount) come from the campaign'sdefaultCodeConfig, enforced server-side. Returns aCreateCodeResultwithcode,discountType,discountValue,maxDiscountAmount,maxUses,expiresAt,remainingGenerations,limitPeriod, andidempotentfields.- Automatic idempotency — Each call auto-generates a UUID v4
Idempotency-Keyheader so HTTP-layer retries never produce duplicates. Override by passingidempotencyKey. - Webhook — Server dispatches
code.createdevent on successful generation (not on idempotent replays).
0.7.1 #
- Rankings endpoint — New
GET /api/v1/rankingssupport for leaderboard queries by campaign, game type, or organization scope, with all-time, weekly, and monthly periods.
0.7.0 #
- Fix API paths — All SDK endpoints now use
/api/v1/(previously/api/sdk/). Resolves 404 errors on all API calls.
0.6.9 #
- Campaign imageUrl —
Campaignmodel now exposesimageUrl(nullable). Gaming campaigns return the marketplace game icon; traditional campaigns return their optional campaign image.
0.6.8 #
- Unit tests — Added 163 unit tests covering all model
fromJson()deserialization (Attribution, Campaign, ClientInfo, CtaButton, GameResult, InAppNotification, Points, PromoCodeResult, TrackEventResult), exceptions, HTTP client (headers, errors, timeouts), SDK config (URL construction, defaults), and notification manager (trigger evaluation, frequency capping, impression tracking).
0.6.7 #
- Push & in-app event tracking with clientId —
trackInAppEventand push event tracking now includeclientIdin the request body, enabling per-user engagement analytics on the server.
0.6.6 #
- first_open event — Tracks
first_opencustom event on first device registration, with automatic retry on next launch if the initial attempt fails. - Offline event queue — Failed
trackEventcalls (network errors, 5xx) are persisted and retried on next app start. Events expire after 24 hours. Max queue size: 50. - HTTP timeouts — All API requests now timeout after 30 seconds instead of hanging indefinitely.
- Concurrent push dismiss flush — Pending push dismiss events are now sent concurrently instead of sequentially on app start.
- Cleanup — Removed redundant debug logging loop in notification fetching, deduplicated OS detection helper.
0.6.5 #
- Game view height cap — The game WebView container now uses a maximum of 70% of the screen height, keeping movement buttons and surrounding UI visible.
0.6.4 #
- Responsive font sizes — Text sizes in in-app notification blocks now scale proportionally to the device screen width (reference: 375pt), clamped between 0.85x–1.3x to avoid extremes on very small or very large screens.
- Full-width buttons — Single buttons in block-based notifications now stretch to fill the available width.
- Button text scaling — Button labels use
FittedBoxto stay on a single line and scale down proportionally when space is limited, ensuring consistent appearance between single and grouped buttons.
0.6.3 #
- Singleton pattern —
SouthGamesSDKis now a true singleton. CallSouthGamesSDK.init()once, then access the instance from anywhere viaSouthGamesSDK.instance. This fixes issues where methods liketrackEvent()threwSouthGamesNotInitializedExceptiondespiteinit()having been called. - Instance methods —
identify(),trackEvent(),getCampaigns(),play(),redeem(),heartbeat(),registerClient(),getInAppNotifications(),trackInAppEvent(),getPointsBalance(),getPointsHistory(),spendPoints(),earnPoints(),requestPushPermission(),logout(),disableAutoOverlay()are now instance methods accessed viaSouthGamesSDK.instance. - Static methods —
init(),handleBackgroundMessage(),dispose(), andisInitializedremain static.
0.6.2 #
- Fix — Fixed State class name mismatch in
NotificationOverlayWidgetthat caused compilation errors.
0.6.1 #
- Fix — Made
NotificationOverlayWidgetpublic so auto-overlay can reference it correctly.
0.6.0 #
- Auto in-app notifications — In-app notifications now render automatically without requiring
SouthGamesNotificationOverlaywidget. Just callSouthGamesSDK.init()and notifications appear on top of all routes. - Optional callbacks in
init()—onCtaTapandonNotificationShowncan now be passed directly toinit()instead of requiring the widget. - Static callback setters —
SouthGamesSDK.onCtaTapandSouthGamesSDK.onNotificationShownsetters for apps that configure callbacks after init. - Backward compatible —
SouthGamesNotificationOverlaywidget still works. When used, it automatically disables the auto-overlay to prevent duplicates.
0.5.20 #
- Global notification overlay —
SouthGamesNotificationOverlaynow uses a globalOverlayEntryso notifications always render on top of all routes and dialogs, even when placed inside a specific view instead ofMaterialApp.builder. - HTTP debug logging — logs status code and response body (first 200 chars) when server returns non-JSON responses, making it easier to diagnose API issues.
0.5.19 #
- Fix duplicate client creation — SDK now sends persisted
clientIdon every/registercall so the server finds the existing client instead of creating a new one. - Sync on every app start —
init()now calls the server on each launch to updatedeviceToken, location, and metadata for existing clients. externalIdis now optional inidentify()andregisterClient()— clients can be registered/updated with justdeviceTokenorclientId.- Server:
clientIdlookup —/api/sdk/clients/registernow acceptsclientIdas a lookup field, with fallback chain:clientId→externalId→email→deviceToken.
0.5.18 #
- Fix 301 redirect on API calls — server-side fix (
skipTrailingSlashRedirect) eliminates unnecessary 301 redirects on SDK HTTP requests, reducing latency.
0.5.17 #
- Server-side in-app notification analytics — the overlay now reports
shown,dismissed, andcta_clickevents to the server viaPOST /api/sdk/notifications/in-app/events. - New
SouthGamesSDK.trackInAppEvent()static method for custom event tracking on in-app notifications.
0.5.16 #
- Disable scroll in HTML notification overlay — set
overflow: hiddenandheight: 100%on bothhtmlandbodyto prevent scrolling inside the WebView modal.
0.5.15 #
- Fix
isHtmldetection — notifications withhtmlContentpresent are now treated as HTML even ifcontentTypefield is missing from Firestore (backward compatibility for notifications created before thecontentTypefield existed).
0.5.14 #
- Debug logging for HTML notifications — logs raw server response fields (
contentType,htmlContentlength,modalSize) and overlay state (isHtml, parsed values) to help diagnose rendering issues.
0.5.13 #
- Fix HTML notification WebView — replaced
Uri.dataFromString(fails on Android with large content) withloadHtmlStringfor reliable HTML rendering. - Auto-detect full HTML documents — if
htmlContentalready contains<!DOCTYPE>or<html>, it's loaded as-is without wrapping in another HTML shell. - WebView controller lifecycle — controller is now stored as state and properly cleaned up on dismiss, preventing stale WebView instances.
- WebView error logging — added
NavigationDelegatewithonPageFinishedandonWebResourceErrorfor debugging.
0.5.12 #
- Fix HTML notification rendering — HTML in-app notifications now display correctly with proper width/height constraints using screen-relative sizing (40%/65%/85%/full).
- Fix
modalSizemapping — handles both portal values (small,medium,large) and shorthand (sm,md,lg). - Fix
Expandedin non-flex parent — replaced withPositioned.fillinside Stack for the WebView widget.
0.5.11 #
- HTML in-app notifications — notifications with
contentType: "html"now render in a WebView instead of native text widgets. Supports custom HTML/CSS content with full viewport control. - JS bridge for HTML notifications — HTML content can call
SouthGamesNotif.postMessage('dismiss')to dismiss orSouthGamesNotif.postMessage('cta:action')to trigger CTA actions. - Modal size support — HTML notifications respect
modalSize(sm,md,lg,full) for height control. - Auto-polling for in-app notifications — notifications are fetched automatically after
init()andidentify(), no manual call needed. - Overlay subscription retry —
SouthGamesNotificationOverlayretries subscription indidChangeDependenciesif SDK wasn't ready at init. - Fixed double evaluation — polling no longer calls
evaluateAndEmittwice per fetch cycle.
0.5.10 #
- WebView bridge fix — games now work correctly in Flutter WebView (fake
window.parentinjection so SDK methods likeclose(),getConfig(),submitResult()no longer fail with "Not running inside an iframe"). - Deduplicated message forwarding — prevent duplicate postMessage handling that caused renderer crashes.
- Navigator safety —
onClosecallback is deferred viaaddPostFrameCallbackto avoidNavigator._debugLockedassertion. - Mounted guard —
_respondToGamechecksmountedbefore using the WebView controller, preventing "Bad state" errors on dispose. - Removed client-side
submitResultthrottle — the bridge no longer blocks repeat submissions (backend handles dedup); fixes "Resultado ya enviado" errors on replay. trackEventauto-resolvesclientId— uses the internally stored client ID when no explicitclientIdorexternalIdis passed.
0.5.9 #
- Fixed synchronization between
init()andidentify()functions.
0.5.8 #
- Anonymous device registration —
init()now auto-registers the device as an anonymous client, enabling push notifications from app install without requiring user login. - New
SouthGamesSDK.clientIdgetter — exposes the current client ID (anonymous or identified). - Automatic client merge — when
identify()is called after anonymous registration, the anonymous client's tokens are transferred to the identified client and the anonymous record is deleted. - New
SouthGamesSDK.logout()method — unregisters the device token from the server, deletes the local FCM token, clears all local state (SharedPreferences), and disposes the SDK. - Client ID persistence via SharedPreferences (
sg_client_id,sg_anon_client_id) — survives app restarts. - Token refresh now works for anonymous clients (re-registers via
/api/sdk/clients/register-device).
0.5.7 #
- Auto-detect and send app version (
appVersion) on client registration viapackage_info_plus. - Send SDK version (
sdkVersion) on every registration for version tracking. - Auto-detect geolocation passively on
identify()— uses existing permissions only, never requests. - Push notification click and dismiss tracking — clicks tracked on tap, dismisses inferred via SharedPreferences and flushed on next app launch.
- New dependency:
package_info_plus(>=4.0.0),geolocator(>=6.0.0).
0.5.6 #
- New Points System — spendable currency alongside XP progression.
getPointsBalance()— get the current points balance for a user.getPointsHistory()— get the points ledger (earn/spend history).spendPoints()— spend points from a user's balance.earnPoints()— manually trigger a points earn action.- New models:
PointsBalance,PointsLedgerEntry,SpendPointsResponse,EarnPointsResponse. - Game play and code redemption now automatically award points when configured.
- Webhook dispatch on all major events (game.played, game.won, code.redeemed, client.registered, client.level_up, points.earned, points.spent).
0.5.5 #
- Auto-detect device locale (e.g.
es-CL) and send it on client registration. - Fix: add debug logging for device token resolution — prints warnings when tokenProvider is missing, returns null, or throws.
RegisterResponsenow includesdeviceTokenSentfield so devs can verify if the token was included.- Token refresh re-registration now logs success/failure instead of silently ignoring errors.
- Guard against empty string tokens being sent to the backend.
0.5.4 #
- Update README with complete documentation for
identify(),tokenProvider,onTokenRefresh,SouthGamesGameView, and manual push registration. - Fix class name references from
SouthGamestoSouthGamesSDKin all docs and examples.
0.5.3 #
- New
identify()method: registers the user and automatically sends the device token on every app start. init()now accepts optionaltokenProviderandonTokenRefreshparameters for automatic token management.- Automatic re-registration when the device token is refreshed (via
onTokenRefreshstream).
0.5.2 #
- Rename
SouthGamesclass toSouthGamesSDK. - Add
firstName,lastName,phone,latitude,longitudeparameters toregisterClient. - Add
embedUrlandisMarketplaceGametoCampaignmodel. - New
SouthGamesGameViewwidget for running marketplace games in a WebView with full postMessage bridge support. - New dependency:
webview_flutter: ^4.10.0.
0.5.1 #
- Fix default base URL to
https://southgames.ai.
0.5.0 #
- Breaking: Remove
firebase_messagingas a required dependency — Firebase is no longer needed. registerClientnow accepts an optionaldeviceTokenparameter. Pass your own token from any push provider (FCM, APNs, OneSignal, etc.).- Removed
enablePushandvapidKeyparameters fromregisterClient. SouthGamesPushis now a lightweight base class withregisterDeviceToken()for manual token registration.- For FCM integration, use the separate
southgames_flutter_fcmpackage (coming soon) or callSouthGames.push.registerDeviceToken()with your own FCM token.
0.4.4 #
- Upgrade
firebase_messagingto^16.0.0for compatibility withfirebase_core ^4.0.0.
0.4.3 #
- Restore
firebase_messagingto^15.0.0for compatibility withfirebase_core ^4.0.0.
0.4.2 #
- Downgrade
firebase_messagingdependency from^14.0.0to^13.0.0for broader compatibility.
0.4.1 #
- Downgrade
firebase_messagingdependency from^15.0.0to^14.0.0for broader compatibility.
0.4.0 #
- Breaking:
registerClientnow requiresexternalId(your platform's user ID) instead ofemailas primary identifier. - Device token is now obtained internally via FCM — no need to call
initPushseparately. - Server creates and returns
clientId— the developer only providesexternalId. - New
enablePushparameter (defaulttrue) to opt out of push registration. - New
vapidKeyparameter for Flutter web push token support. - Automatic token refresh listener re-registers with
externalIdon FCM token change. - Removed
SouthGames.initPush()— push is now handled insideregisterClient. - Improved OS detection using
dart:io Platformwith proper web fallback.
0.3.0 #
baseUrlis now optional inSouthGames.init()— defaults tohttps://portal.southgames.ai.orgIdnow accepts the organization slug (e.g.mi-empresa) in addition to the UUID.
0.2.0 #
- Add push notification support via Firebase Cloud Messaging.
- New
SouthGamesPushclass (lib/src/push.dart). SouthGames.initPush(clientId:, vapidKey:)— request permission, obtain FCM token, and register it automatically.SouthGames.push.onMessage— stream of foreground notifications.SouthGames.push.onMessageOpenedApp— stream of notification taps from background/terminated state.SouthGames.push.getInitialMessage()— check if app was launched from a notification tap.- Automatic token re-registration on
onTokenRefresh. - New dependency:
firebase_messaging: ^15.0.0.
0.1.0 #
- Initial release.
- Client registration and heartbeat.
- List active campaigns (spin wheel, scratch card, trivia, slot machine).
- Play games and receive promo codes on win.
- Redeem promo codes.
- Fetch segment-targeted in-app notifications.