21.0.0
SDK 21.0 raises the minimum SDK to 26, moves public timestamps and durations to java.time.Instant and kotlin.time.Duration, brings on-device AI to Scenes and in-app experiences, adds Compose banner and embedded carousel hosts, and tightens the public API surface across every module. See the Migration Guide for details.
Changes
minSdkis now 26 (Android 8.0), and the SDK builds againstcompileSdk36 with Kotlin 2.2.20 and JDK 17.- Migrated public timestamps from
Long/Datetojava.time.Instantand durations fromLongtokotlin.time.Duration. EveryDuration-typed member ships a Java-friendly counterpart. JSON, wire formats, and persisted values are unchanged. - Tightened the public API surface across all modules with
@RestrictTo, which now also covers nested types and overrides. The layout module in particular went from 235 accidentally-public declarations to 9. A few APIs that were always meant to be public —AirshipInputValidation.Request,ChannelType,InAppMessageColor, and the custom view APIs — are no longer flagged as restricted. - Added binary compatibility validation, so the public API of every module is now dumped to
api/and checked in CI. - Changed
PushProvider.getRegistrationTokenandPushManager.performPushRegistrationto suspend functions. CustomPushProviderimplementations must update their overrides. - Removed the deprecated
PushManagerExtensions. Both extensions are now members onPushManager. - Renamed the layout event types on
EventTypeandEventAutomationTriggerTypefromIN_APP_*toLAYOUT_*, since they are emitted by Scenes rather than only by in-app messages.IN_APP_DISPLAYandIN_APP_RESOLUTIONkeep their names. Reporting values sent to Airship are unchanged. - Enabled
-Xconsistent-data-class-copy-visibility, socopy()onAutomationSchedule.ScheduleData.DeferredandEmbeddedViewItemis no longer public.
On-Device AI
- Added on-device AI support for three usages, reached through
Airship.ai: in-app message suppression, embedded view selection, and Scene text-input inference. Apps supply their own model by implementingModelAdapter; prompts and context stay on the device, and app-supplied context is never sent to Airship. - Added the
PrivacyManager.Feature.ON_DEVICE_AIprivacy manager feature gating on-device AI. It is included inFeature.ALL, but apps that enable an explicit set of features must add it orAirship.aiwill behave as though no model were configured.
Scenes
- Added six
Permissionvalues —APP_TRACKING_TRANSPARENCY,CAMERA,MICROPHONE,BLUETOOTH,PHOTO_LIBRARY, andCONTACTS— for the Composer's new system-permission action. - Added the
stack_image_viewview type andredact_inputsupport for text input form fields. - Let a modal's or banner's entrance and exit use different transition effects, matching web.
- Fixed a broad set of layout and sizing issues, including percent- and ratio-sized children under auto-sized parents, media sizing, pager indicator dot sizing, scroll viewport handling, banner placement parsing, and label text clipping and truncation. Verify your live Scenes after upgrading.
- Fixed label icon placement and gaps to resolve from the layout's start/end and the locale's direction, so
icon_startis correct in RTL. - Fixed score items and animated icon drawables not always starting.
Embedded Views
- Added
AirshipEmbeddedCarousel, a Compose carousel container for embedded content. - Added
filterInstancestoAirshipEmbeddedViewandAirshipEmbeddedViewGroup, a predicate that decides which pending instances are eligible.selectionstill decides order. - Added
AirshipEmbeddedSelection.ByAi, which ranks pending content with an on-device model and falls back to priority, a comparator, or an instance list. - Changed
AirshipEmbeddedSelection.ByInstanceIdto take an ordered list of instance IDs rather than one. It is now an allow-list — pending content that isn't named is excluded rather than ordered last. - Fixed
AirshipEmbeddedInfo.priorityalways reporting0, which made comparators that sort on it a no-op and made observer filters that test it match everything.AirshipEmbeddedInfoalso gainscontentDescription.
In-App Automation
- Added
InAppMessagingInterface.onCheckSuppression, an app-side callback that can suppress a message before it displays and choose how the miss is reported. - Added
AirshipBannerHost, a Compose host for in-app message banners, withrememberAirshipBannerHostState. - Changed display limit calculation to use a display ledger, with retention and compaction, and fixed limit enforcement gaps for shared display groups and penalized attempts. Shared-group pooling is behind an explicit opt-in.
- Added Experiment Groups variant control and miss resolution, and
audience_subset_overridessupport in audience hashing. - Let a deferred response specify its audience miss behavior.
- Improved parse error handling, so a malformed schedule or payload from one source no longer prevents the rest from being parsed.
Message Center
- Added localized accessibility strings.
- Fixed message date formatting.
Preference Center
- Added support for embedding the Compose Preference Center in wrap content parents.
- Fixed XML Preference Center edge-to-edge insets.
Feature Flags
- Added a public
FeatureFlagManager.waitRefresh, with awaitRefreshPendingResultcounterpart for Java callers.
Other Fixes
- Fixed remote data status not always updating as expected after a refresh.
- Hardened Live Update notification
PendingIntents. - Fixed
PushMessage.isExpiredthrowing on an out-of-range expiration. - Fixed an inverted delay comparison in
EventManager.scheduleEventUpload. - Fixed
info.isCheckednot being set in accessibility delegates.