SocialHub.AIFlash
OverviewAPI ReferenceMCP GuideSocodePortal EmbedMobile SDKApp PushWalletLocation (LBS)Quick Start

Mobile SDK

Put Flash loyalty inside your own native iOS / Android app — member center, app push, Apple/Google Wallet, and store-proximity. A thin native SDK wraps the Flash server endpoints, so you ship portal changes without an app release.

The SDK ships as source (iOS Swift Package + Android Kotlin library) — clone it, compile it into your app, and debug the integration on your own devices. Build steps and full snippets are in the repo README.

What you can build

Member center in your app

Render the real Flash member portal (points, coupons, tier) inside a native WebView with single sign-on. No second login, no re-build to ship portal changes.

App push as a send channel

Register device tokens with Flash; push joins the automation/send stack alongside email.

Wallet membership card (Apple + Google)

Issue server-side from one endpoint: Apple returns a signed .pkpass that auto-updates on balance change; Google returns a save link. Requires your wallet credentials configured.

Location / store-visit (LBS)

Background geofence → near-store events via the FlashLocation package (CoreLocation / Play Services, no Radar dependency).

Get the SDK & integrate

Download from https://github.com/huangchunbo2025/flash-sdk. Three packages: an iOS Swift Package and an Android Kotlin library wrapping the endpoints below. It's source you compile & debug in your app — see the README for build steps and required Gradle/Xcode setup.

FlashCore

Identity / Bearer + device-token (push) registration.

FlashPortal

WKWebView / WebView member center + SSO bridge — no native UI rebuild.

FlashLocation

Store geofence monitoring (CoreLocation / Play Services) → near_store / dwell events. No Radar dependency required.

iOS (Swift Package)

// 1. Add the package in Xcode: File ▸ Add Package Dependencies…
//    URL:  https://github.com/huangchunbo2025/flash-sdk   (path: ios)
//    or in Package.swift:
.package(url: "https://github.com/huangchunbo2025/flash-sdk", branch: "main")
// link the products you need: FlashCore, FlashPortal, FlashLocation

// 2. Configure once at app start + set the member Bearer your backend mints:
FlashClient.shared.configure(.init(baseURL: URL(string: "https://flash.socialhub.ai")!))
FlashClient.shared.setMemberToken(memberBearerFromYourBackend)

// 3. Use it:
FlashClient.shared.registerPushToken(fcmToken) { _ in }      // push
let portal = FlashPortalViewController()                      // member center
portal.load(token: embedJwtFromYourBackend)
FlashLocation.shared.requestAuthorization(); FlashLocation.shared.start()  // LBS

// Info.plist: NSLocationAlwaysAndWhenInUseUsageDescription + NSLocationWhenInUseUsageDescription

Android (Kotlin library)

// 1. Pull the android/ library (clone the repo, or publish it to your Maven).
//    Transitive deps it uses: okhttp, kotlinx-coroutines, play-services-location.

// 2. Configure once + set the member Bearer your backend mints:
FlashClient.configure(FlashConfig("https://flash.socialhub.ai"))
FlashClient.setMemberToken(memberBearerFromYourBackend)

// 3. Use it:
FlashClient.registerPushToken(fcmToken) { /* result */ }     // push
val portal = FlashPortalView(context); portal.load(embedJwtFromYourBackend)  // member center
FlashLocation.start(context)                                  // LBS

// Manifest declares GeofenceBroadcastReceiver; request ACCESS_FINE_LOCATION +
// ACCESS_BACKGROUND_LOCATION at runtime before FlashLocation.start().

Deep links use Universal Links / App Links — host your apple-app-site-association and assetlinks.json on your own domain (templates ship with the SDK).

Server endpoints the SDK calls

The packages above wrap these endpoints — you can also call them directly. Reuse the same per-client embed JWT you already sign for the web Member Portal Embed (see the Portal Embed guide); the native flow just opens it in a WebView instead of an iframe.

1. Member center via WebView SSO

// Your app backend signs the SAME per-client HS256 JWT used by the web embed
// (iss = your client_id, ≤5-min expiry), then the app opens a WebView at:
GET https://flash.socialhub.ai/embed/member/native?token=<JWT>

// Flash verifies the JWT, sets an HttpOnly + Secure + SameSite=Lax cookie
// (member_token), and renders the portal. Because a native WebView is first-party
// to its own origin, the cookie survives in-app navigations — the member is never
// bounced to login (unlike a third-party iframe, which must stay cookieless).

2. Register a push device token

// Register the device's FCM token. teamId + memberId come from the session — never the body.
POST /api/consumer/push/register
Content-Type: application/json

{
  "platform": "ios",            // "ios" | "android"
  "provider": "fcm",            // "fcm" (default) | "apns"
  "token": "<FCM registration token>",
  "appBundleId": "com.yourbrand.app"
}
// → { "ok": true }   (idempotent UPSERT; re-registering re-assigns the device)

3. Issue a Wallet card (Apple / Google)

// Issue the member's Wallet card. The body selects the platform.
POST /api/consumer/wallet/issue     { "platform": "apple" }   // "apple" | "google"
// Apple  → 200  application/vnd.apple.pkpass        (Add to Apple Wallet)
// Google → 200  { "saveUrl": "…" }                  (Save to Google Wallet)

// Apple cards push a silent update on points/tier change automatically — no app code.

4. JS bridge (native chrome)

// The WebView posts a small, versioned set of intents to your native host.
// It NEVER carries auth (auth is the HttpOnly cookie). Listen via WKWebView
// messageHandlers "flashBridge" (iOS) or a JS interface "FlashNativeBridge" (Android).

{ "v": 1, "type": "ready" }                  // portal mounted
{ "v": 1, "type": "resize", "height": 812 }  // size the WebView to content
{ "v": 1, "type": "navigate", "href": "…" }  // an in-portal link was activated
{ "v": 1, "type": "tokenExpiring" }          // a call 401'd → re-mint JWT, reload /native
{ "v": 1, "type": "close" }                  // member asked to leave

5. Store-proximity (near-store) events

// Store-proximity ("near a store") events. The device SDK monitors the member's
// nearest stores on-device; the server gates consent + GPC (fail-closed) + a cooldown.

// 1. Get the ≤20 nearest store geofences for the device to monitor (server-curated
//    to beat iOS's 20-region limit). Device lat/lng is used transiently, never stored.
POST /api/v2/lbs/nearby-stores      { "lat": 40.71, "lng": -74.00, "limit": 20 }
// → { "geofences": [ { "storeId": "…", "name": "…", "lat": …, "lng": …, "distanceMeters": … } ] }

// 2. Report an on-device geofence transition → near_store / store_dwell triggers.
POST /api/v2/lbs/geofence-event     { "storeId": "…", "eventType": "enter" }  // or "dwell"
// → { "recorded": true }   (no precise_location_consent or GPC present → { recorded:false })

Integration acceptance checklist

Member center (Embed)

Tapping links inside the WebView does NOT bounce to login; works offline with a graceful state.

Push

An opted-in member receives a push; the waterfall falls back to email when there is no token/consent.

Wallet

A real .pkpass installs on a device; a points change refreshes the card within seconds; a removed member's serial returns 410, not 500.

Location

A real device crossing a store geofence fires enter/dwell → POST /api/v2/lbs/geofence-event; with no consent / GPC present, nothing records.

Configure your Apple Pass Type ID / APNs / FCM credentials with your Flash team before going live. Wallet + push require those to be set.