ChangelogEdit pageSTAFFOpen dashboard

Appearance and text

Match Bubbl's notification screen and privacy view to your app with your own colours, sizes and words, in light and dark mode.

Bubbl's notification screen (the card, the survey wizard and media) and its privacy view take their look and words from your app. The defaults follow the system's light and dark appearance. You change them the way each platform expects: Android resources, and on iOS colour sets and a strings table. Nothing is set in code.

In Flutter and React Native apps, put the Android resources in your app module (android/app/src/main/res) and the iOS colour sets and strings table in your iOS app target (the Runner target in Flutter).

Expo apps regenerate those folders at prebuild, so they add the files another way: see Expo apps.

Some of the privacy view comes from the dashboard instead, on every platform and with no app change: see Set in the dashboard.

Colours#

The same nine names on both platforms:

NameUsed for
bubbl_accentButtons, links and highlights
bubbl_on_accentText on accent-coloured buttons
bubbl_surfaceThe card
bubbl_on_surfaceHeadline and body text
bubbl_on_surface_mutedSecondary text
bubbl_outlineBorders and dividers
bubbl_scrimThe dimmed backdrop behind the card
bubbl_media_surfaceThe area behind media
bubbl_errorError text, such as a required answer missing

Android: declare a colour with the same name in your app's res/values/colors.xml, and in res/values-night/colors.xml for dark mode. Yours wins over Bubbl's.

COLORS.XML
<resources>
    <color name="bubbl_accent">#FF0A7A6E</color>
    <color name="bubbl_on_accent">#FFFFFFFF</color>
</resources>

iOS: add a colour set with the same name to your app's asset catalogue, with light and dark variants. Bubbl looks each one up in your app's main bundle and falls back to its own.

Sizes (Android)#

On Android you can also override these dimensions in res/values/dimens.xml. On iOS they're fixed at the same values.

NameDefault
bubbl_card_max_width480dp
bubbl_card_radius20dp
bubbl_card_padding20dp
bubbl_media_max_height240dp

Text#

Every piece of text Bubbl shows can be reworded or translated. On Android each is a bubbl_ string resource: override it in res/values/strings.xml and translate it in res/values-<language>/ as usual. On iOS, add a strings table named Bubbl (Bubbl.strings) to your app with the same keys, and localise it as usual.

KeyDefault
bubbl_closeClose
bubbl_nextNext
bubbl_backBack
bubbl_doneDone
bubbl_submitSend answers
bubbl_thanksThanks for your answers
bubbl_answer_requiredPlease answer this question to carry on
bubbl_question_progressQuestion %1$d of %2$d
bubbl_yesYes
bubbl_noNo
bubbl_answer_hintYour answer
bubbl_number_hintA number
bubbl_slider_unansweredDrag to answer
bubbl_rating_star%1$d of 5
bubbl_play_mediaPlay
bubbl_pause_mediaPause
bubbl_open_mediaOpen
bubbl_media_descriptionImage for (headline)
bubbl_permission_notifications_titleStay in the loop
bubbl_permission_notifications_bodyAllow notifications to hear about offers and updates as they happen.
bubbl_permission_location_titleOffers near you
bubbl_permission_location_bodyAllow your location to get offers and messages when you're near the places they're for.
bubbl_permission_background_titleOffers even when the app is closed
bubbl_permission_background_bodyTells the user which option to choose for "all the time" location. The default names Android's and iOS's own button.
bubbl_privacy_policyPrivacy policy
bubbl_continueContinue
bubbl_not_nowNot now

bubbl_media_description takes the headline as its one argument: %1$s on Android, %1$@ on iOS. The privacy view's text in the dashboard (Configuration › Plugin › Callbacks & privacy › Privacy text), when set, is used in place of the built-in body text. See Permissions and privacy.

Android only#

  • bubbl_channel_name ("Offers and updates") and bubbl_channel_description ("Messages and surveys from this app"): the notification channel users see in system settings.
  • bubbl_background_channel_name ("Background updates") and bubbl_background_working ("Checking for updates"): shown only on Android 11 and older, briefly and silently, while an update runs in the background.
  • bubbl_media_position ("%1$s / %2$s"): an audio clip's position and length.

Status bar icon#

Bubbl's status bar icon is your app's tech.bubbl.sdk.notification_icon meta-data in AndroidManifest.xml. Without it, Bubbl uses Firebase's default notification icon, then your app icon.

ANDROIDMANIFEST.XML
<application ...>
    <meta-data
        android:name="tech.bubbl.sdk.notification_icon"
        android:resource="@drawable/ic_notification" />
</application>

Set in the dashboard#

Three things about the privacy view come from Bubbl's server with the SDK's configuration, so they apply to every app, Expo included, without a new build: whether it shows (automatically, always or never), its body text, and its privacy-policy link. They're set under Configuration › Plugin › Callbacks & privacy. Colours, sizes and every other piece of text stay in the app. See Permissions and privacy.

Expo apps#

Expo writes android/ and ios/ afresh at every npx expo prebuild (EAS Build runs it too), so files you add there by hand are lost. Bubbl's config plugin has no colour or text options: the only words it sets are iOS's location permission prompts, with ios.locationWhenInUse and ios.locationAlways. BubblOptions takes no appearance settings either. To ship overrides from an Expo app, do one of these:

  • Add a small config plugin of your own that writes the files at prebuild, like the one below.
  • Stop regenerating the native folders (keep android/ and ios/ in your repository) and add the files as a React Native app does.

This plugin sets colours on both platforms. Colours are written #AARRGGBB, as on Android.

WITHBUBBLAPPEARANCE.JS
const { withDangerousMod } = require('expo/config-plugins');
const fs = require('fs');
const path = require('path');

const colors = { bubbl_accent: '#FF0A7A6E', bubbl_on_accent: '#FFFFFFFF' };

const withAndroidColors = (config) =>
  withDangerousMod(config, ['android', (config) => {
    const dir = path.join(config.modRequest.platformProjectRoot, 'app/src/main/res/values');
    fs.mkdirSync(dir, { recursive: true });
    const items = Object.entries(colors).map(([name, value]) => `    <color name="${name}">${value}</color>`);
    fs.writeFileSync(path.join(dir, 'bubbl_colors.xml'), `<?xml version="1.0" encoding="utf-8"?>\n<resources>\n${items.join('\n')}\n</resources>\n`);
    return config;
  }]);

const withIosColors = (config) =>
  withDangerousMod(config, ['ios', (config) => {
    const catalog = path.join(config.modRequest.platformProjectRoot, config.modRequest.projectName, 'Images.xcassets');
    for (const [name, value] of Object.entries(colors)) {
      const [a, r, g, b] = value.slice(1).match(/../g);
      const dir = path.join(catalog, `${name}.colorset`);
      fs.mkdirSync(dir, { recursive: true });
      const components = { alpha: (parseInt(a, 16) / 255).toFixed(3), red: `0x${r}`, green: `0x${g}`, blue: `0x${b}` };
      fs.writeFileSync(path.join(dir, 'Contents.json'), JSON.stringify({
        colors: [{ idiom: 'universal', color: { 'color-space': 'srgb', components } }],
        info: { author: 'xcode', version: 1 },
      }, null, 2));
    }
    return config;
  }]);

module.exports = (config) => withIosColors(withAndroidColors(config));

Then list it after Bubbl's plugin in app.json, and run npx expo prebuild --clean:

APP.JSON
{
  "expo": {
    "plugins": ["@bubblsdk/react-native-sdk", "./plugins/withBubblAppearance"]
  }
}
  • Dark mode: on Android, write a second file to res/values-night. On iOS, add a dark entry to the colour set's colors (with appearances: [{ appearance: 'luminosity', value: 'dark' }]).
  • Text on Android: write bubbl_ strings to a file in res/values the same way, and translations to res/values-<language>.
  • Text on iOS: a Bubbl.strings file must be part of the app target, not just in ios/: write it with withDangerousMod, then add it to the project's resources in a withXcodeProject step (for example with IOSConfig.XcodeUtils.addResourceFileToGroup). The colour sets above need no such step, because the asset catalogue is already in the target.

What you can't change#

The screen's layout is Bubbl's: the close button in the card's top-right corner, one survey question per step, and the SANDBOX ribbon on Sandbox notifications. For a completely different design, draw notifications yourself: see Drawing notifications yourself.