Preference Center
Preference Center allows users to opt in and out of subscription lists configured via the Airship Dashboard.
Airship preference centers are widgets that can be embedded in a page in an app or website. Please verify with your legal team that your full preference center page, including any web page for email preference centers, is compliant with local privacy regulations.
Installation
Preference Center requires adding the urbanairship-preference-center
module:
dependencies {
def airshipVersion = "16.4.0"
implementation "com.urbanairship.android:urbanairship-preference-center:$airshipVersion"
}
Displaying a Preference Center
A Preference Center can be displayed with a simple method call on the PreferenceCenter
instance.
By wiring this method call to a button in your app, you can quickly produce a user-initiated
Preference Center with no additional effort.
PreferenceCenter.shared().open(preferenceCenterId = "my-first-pref-center")
PreferenceCenter.shared().open("my-first-pref-center");
Adding a Custom Look and Feel
By default, Preference Centers are displayed with basic styling for elements, similar in appearance to Android’s PreferenceFragment
.
Most developers will want to customize the look and feel to match their app’s existing style and layout. If your app is using a theme that extends from a MaterialComponents
theme, Preference Centers can be easily customized to use your app colors by overriding the top-level preference center style:
<!-- Use colors from MyAppTheme instead of the default pref center colors. -->
<style name="UrbanAirship.PreferenceCenter" parent="MyAppTheme">
<!-- Specific attributes may also be overriden here, as needed. For example,
the following overrides the background color used by PreferenceCenterFragment. -->
<item name="android:colorBackground">@color/my_background_color</item>
</style>
If your app doesn’t use a MaterialComponents
theme or you need the ability to further customize preference center styles, The Android resource merging feature can be used to override the default styles that the SDK provides. Copy the style sheet
into the application’s resource directory, then change any of the styles.
Overriding the Preference Center
If the provided Activity does not work for your application, you can either embed the PreferenceCenterFragment
directly into your application, or you can provide your own UI.
Embedding the PreferenceCenterFragment
When embedding the PreferenceCenterFragment, either use a FragmentContainerView
or create the fragment directly. You must specify the ID of the Preference center
to be displayed when creating the fragment. The static create
on PreferenceCenter
will
handle passing the given id to the fragment as an argument:
val fragment = PreferenceCenterFragment.create(preferenceCenterId = "my-first-pref-center")
PreferenceCenterFragment fragment = PreferenceCenterFragment.create("my-first-pref-center");
Building your own Preference Center UI
If the provided fragment is insufficient for your app, you can build your own UI by accessing the PreferenceCenterConfig
directly:
val configPendingResult = PreferenceCenter.shared().getConfig("my-first-pref-center")
PendingResult<PreferenceCenterConfig> configPendingResult = PreferenceCenter.shared().getConfig("my-first-pref-center");
The PreferenceCenterConfig
object includes the name and (optional) description for the Preference Center and a list of sections containing preference items:
fun displayPreferenceCenter(config: PreferenceCenterConfig) {
val prefCenterName = config.display.name
val prefCenterDescription = config.display.description
for (section in config.sections) {
val sectionName = section.display.name
val sectionDescription = section.display.description
for (item in section.items) {
val itemId = item.id
val itemName = item.display.name
val itemDescription = item.display.description
// Create item and add it to an adapter, etc...
}
}
}
void displayPreferenceCenter(PreferenceCenterConfig config) {
String prefCenterName = config.display.name;
String prefCenterDescription = config.display.description;
// Set pref center name and description on Activity, Fragment, etc...
for (Section section : config.sections) {
String sectionName = section.display.name;
String sectionDescription = section.display.description;
for (Item item : section.items) {
String itemId = item.id;
String itemName = item.display.name;
String itemDescription = item.display.description;
// Create item and add it to an adapter, wire up click listener, etc...
}
}
}
The getSubscriptionLists
method on AirshipChannel
can be used to fetch the set of subscriptions
that the channel is currently subscribed to. The IDs returned in the set correspond to Item IDs in the
PreferenceCenterConfig object. An empty set indicates that the current channel is not
subscribed to any lists.
// Include subscription list changes that have been requested via SubscriptionListEditor
// and will be applied during the next channel update.
val includePendingUpdates = true
val subscriptionsPendingResult = UAirship.shared().channel.getSubscriptionLists(includePendingUpdates)
// Include subscription list changes that have been requested via SubscriptionListEditor
// and will be applied during the next channel update.
boolean includePendingUpdates = true;
PendingResult<Set<String>> subscriptionsPendingResult = UAirship.shared().getChannel().getSubscriptionLists(includePendingUpdates);
The getSubscriptionLists
method on AirshipContact
can be used to fetch the set of subscriptions that the contact is currently subscribed to. An empty set indicates that the current contact is not subscribed to any lists.
// Include subscription list changes that have been requested via SubscriptionListEditor
// and will be applied during the next contact update.
val includePendingUpdates = true
val subscriptionsPendingResult = UAirship.shared().contact.getSubscriptionLists(includePendingUpdates)
// Include subscription list changes that have been requested via SubscriptionListEditor
// and will be applied during the next contact update.
boolean includePendingUpdates = true;
PendingResult<Map<String, Set<Scope>>> subscriptionsPendingResult = UAirship.shared().getContact().getSubscriptionLists(includePendingUpdates);
To update subscriptions when a preference item is updated, use the
editSubscriptionLists()
method on AirshipChannel
:
fun onPreferenceChannelItemToggled(subscriptionItem: ChannelSubscription, isSubscribed: Boolean) {
val editor = UAirship.shared().channel.editSubscriptionLists()
if (isSubscribed) {
editor.subscribe(subscriptionItem.subscriptionId)
} else {
editor.unsubscribe(subscriptionItem.subscriptionId)
}
editor.apply()
}
void onPreferenceChannelItemToggled(Item.ChannelSubscription subscriptionItem, boolean isSubscribed) {
SubscriptionListEditor editor = UAirship.shared().getChannel().editSubscriptionLists();
if (isSubscribed) {
editor.subscribe(subscriptionItem.getSubscriptionId());
} else {
editor.unsubscribe(subscriptionItem.getSubscriptionId());
}
editor.apply();
}
To update contact subscription lists when a contact preference item is updated, use the
editSubscriptionLists
method on AirshipContact
:
fun onPreferenceContactSubscriptionItemToggled(subscriptionItem: ContactSubscription, scope: Scope?, isSubscribed: Boolean) {
val editor = UAirship.shared().contact.editSubscriptionLists()
if (isSubscribed) {
editor.subscribe(subscriptionItem.subscriptionId, scope!!)
} else {
editor.unsubscribe(subscriptionItem.subscriptionId, scope!!)
}
editor.apply()
}
void onPreferenceContactSubscriptionItemToggled(Item.ContactSubscription subscriptionItem, Scope scope, boolean isSubscribed) {
ScopedSubscriptionListEditor editor = UAirship.shared().getContact().editSubscriptionLists();
if (isSubscribed) {
editor.subscribe(subscriptionItem.getSubscriptionId(), scope);
} else {
editor.unsubscribe(subscriptionItem.getSubscriptionId(), scope);
}
editor.apply();
}
Override open behavior
If you provide your own UI or embed the fragment directly, you need to override the open
behavior to navigate to your custom UI. Set the listener during takeOff
.
PreferenceCenter.shared().openListener = object : PreferenceCenter.OnOpenListener {
override fun onOpenPreferenceCenter(preferenceCenterId: String): Boolean {
// Navigate to custom preference center UI
return true
}
}
PreferenceCenter.shared().setOpenListener(preferenceCenterId -> {
// Navigate to custom preference center UI
return true;
});
Deep linking
Deeplinking to a Preference Center is supported automatically within the SDK with URLs with
uairship://
scheme. Preference Center deep links must include the ID of the Preference Center to be opened, in the form of uairship://preferences/pref-center-id
.
To expose deep linking to a preference center externally, setup a deep link that calls through to PreferenceCenter.shared().open("pref-center-id")
.
fun onDeepLink(deepLink: String) {
if (deepLink.startsWith("my-app://deeplink/preferences/")) {
val prefCenterId = deepLink.toUri().lastPathSegment
PreferenceCenter.shared().open(prefCenterId)
}
}
public void onDeepLink(String deepLink) {
if (deepLink.startsWith("my-app://deeplink/preferences/")) {
Uri uri = Uri.parse(deepLink);
String prefCenterId = uri.getLastPathSegment();
PreferenceCenter.shared().open(prefCenterId);
}
}
Categories