Upgrading to 1.12
AFCore 1.12 adds the locations(), content() and activePerks() modules and has a handful of breaking changes. An app that builds its config with AFCoreConfig.Builder, runs on the Bismuth realm and does not use Movement Health upgrades by changing only the version: reads keep their 1.11 behavior unless you opt in. Work through the checklist below; the full list of changes is in the changelog.
1. Update the dependency
- Android (Gradle)
- iOS (Swift Package Manager)
implementation("com.advantahealth:core-android:1.12.1")
.package(url: "https://github.com/AdvantaHealth/AFCore.git", from: "1.12.1")
- Android: exclude AFCore from backups (required). Unless your app sets
android:allowBackup="false", reference AFCore's backup rule files or copy their entries into yours -- see Install on Android. - Android dependencies moved forward with no code change: Kotlin stdlib 2.4.21, Ktor 3.5.2, Kermit 2.2.0, WorkManager 2.12.0, Fragment 1.9.1 (kotlinx-coroutines stays at 1.11.0).
compileSdk37 andminSdk26 are unchanged.
2. Breaking changes
-
AFException.messageis member-safe. For system failures it is now a short sentence you can show as is. LogtechnicalMessageinstead ofmessage, and branch onkind(AFErrorKind) instead of parsing the text. Backend refusals can also carry a machine-readableerrorCode. See Error Handling. -
registerMovrProfile()returns the Movr external id (String?) instead ofBoolean, and throws on failure. Configure the MOVR SDK with that id;nullmeans no usable profile was registered. - Virtual Fitness status.
isMemberRegisteredToNeou()/isMemberRegisteredToLifetimeDigital()are deprecated (their result was inverted). UsegetNEOUStatus()/getLifetimeDigitalStatus()and handleCONNECTED,NOT_ENROLLEDandACCOUNT_DISABLED. - New enum values
AFHeartbeatTrigger.SIGNIFICANT_LOCATION_CHANGEandDeviceType.GOOGLE_HEALTH: add a branch (orelse) to exhaustive Kotlinwhenexpressions. - New interface members on
Activities,Authentication,ApplicationSettings,VirtualFitnessandMyCarePath: only code that implements these interfaces (typically test fakes) must add them. Prebuilt libraries that constructMenuItem,BottomNavItemorAFActivitiesSummarymust be recompiled. -
androidx.security:security-cryptois no longer included. If your app usesEncryptedSharedPreferencesorMasterKey, declareandroidx.security:security-crypto:1.1.0yourself.
3. Set the realm (Horizon apps) and decide on read failures
Apps whose members are on Horizon must set the realm; without it requests are routed to Bismuth, the 1.11 behavior. See Initialization.
throwOnReadFailure defaults to false, so reads that existed in 1.11 still return an empty result when they fail. Setting it to true (recommended, and the only behavior in 2.0) makes them throw AFException, so an empty result always means "no data". Before you turn it on, wrap every such read in try/catch / do/catch: on Android the compiler does not force you to, and on iOS watch for try? and force-unwraps. Reads added in 1.12 always throw.
- Android (Kotlin)
- iOS (Swift)
val config = AFCoreConfig.builder()
.baseUrl("https://api.example.com")
.realm(AFRealm.HORIZON) // Horizon apps only
.throwOnReadFailure(true) // optional, recommended
.build()
let config = AFCoreConfig.Builder()
.baseUrl(value: "https://api.example.com")
.realm(value: .horizon) // Horizon apps only
.throwOnReadFailure(value: true)
.build()
4. Deprecations at a glance
Everything below still works in 1.12 and produces a warning that names its replacement, so you can migrate screen by screen. A build with allWarningsAsErrors / -Werror must migrate or suppress them.
| Deprecated | Use instead |
|---|---|
AFCoreConfig public constructor | AFCoreConfig.builder() / AFCoreConfig.Builder() |
AFCore.sessionState, AFCore.isLoggedIn() | AFCore.authentication().sessionState, .isLoggedIn() |
facilities().get() | locations().getFavorites(), keeping FAVORITE and MUTED (it also returns EXCLUDED) |
locations().getFavorites(type) (1.12.1) | locations().getFavorites(), then filter by favoriteType |
facilities().update(id, verified = true) / delete(id) | locations().addFavorite(locationId) / removeFavorite(locationId) |
facilities().nominateFacility(...) / getNominatedFacilities() | locations().nominateLocation(...) / getMySubmissions(...) |
facilities().startMonitoring() / stopMonitoring() / isMonitoringActive() | locations().startVisitDetection() / stopVisitDetection() / isVisitDetectionActive() |
facilities().geofenceEvents, subscribeToEvents / subscribeToStatus | locations().visitEvents, subscribeToVisitEvents / subscribeToVisitDetectionStatus |
map().getNearbyFacilities(...) / getFacilitiesByViewPort(...) | locations().getLocationsByRadius(...) / getLocationsByViewPort(...) |
heartbeatEnabled(value) (builder), AFCore.setHeartbeatEnabled(...) | locationSharingEnabled(value) in the config (reconfigure to change it) |
AFCore.heartbeat, AFCore.heartbeatEnabled, AFCore.fireDebugHeartbeat() | locations().locationSharing, locations().locationSharingEnabled, locations().shareLocationNow() |
Swift subscribeToHeartbeat / subscribeToHeartbeatEnabled | locations().subscribeToLocationSharing / subscribeToLocationSharingEnabled |
When you switch to locations():
- Keep calling
facilities().update(id, verified = false)to exclude a location; Locations has no replacement yet (muting a favorite only pauses it). - Visit detection monitors fitness favorites only (
FavoriteLocation.isFitness); stores never earn gym visits. Automatic visits are credited exactly as before. - Background location sharing is new and only available through
locationSharingEnabled(true)with "Always" location permission. See Locations.
5. userInterface() changes
userInterface() keeps its signatures. Route keys are now normalized (SMARTWALKING → MY_DASHBOARD, HOME_WORKOUTS → FIT_HOME, MOVEMENT_HEALTH → MOVR), so you can remove your own mapping for the AIDE names. MenuItem gains section fields and BottomNavItem a webUrl, both with null defaults. For new code, consider content().
6. Other behavior to check
- Sign-out.
logout()now also stops SmartWalking auto-sync (callenableAutoSync()again after the next sign-in) and removes this install's push registration. If you callmessaging().deleteToken(), call it beforelogout(). - Session boundaries. A different member signing in, or re-initializing for another base URL or realm, clears the previous member's cached data, queued submissions and monitoring.
- Sessions survive temporary failures. Only a rejected refresh token ends a session; timeouts and server errors keep the member signed in.
- New writes are never queued.
locations()andactivePerks()writes reach the backend or throw. - Device storage (iOS). Keychain items move to device-only storage on first launch without signing the member out. No action needed.
- Rolling back. Prefer a forward fix: a 1.11 build still starts after 1.12, but signs members out once.
AFCoreInternalApiwarnings mark declarations that were public only for technical reasons. Stop using them.
7. New modules
Adopt them when you are ready: locations() (favorites, place search, visit detection, location sharing), content() (toolbar, banners, Explore menu), activePerks() (rewards; your client needs the ActivePerks capability). If one of them is not available in your environment, contact your Advanta representative.
Learn more
See the API Reference and the changelog. Complete integration guides are in AIDE Docs.