Testing and diagnostics

Check a first run, check that pushes arrive, read where Bubbl stands on the device, and find its logs.

A first test run#

There's no test workspace on production: what you create in the dashboard is live. See Plans and going live for suggestions on working safely.

  1. Start the app with your pk_live_… key and https://api.bubbl.tech, on a paid plan.
  2. Check Bubbl.diagnostics(): active and registered true.
  3. Once hasPushToken is true, check that a push arrives: see Check that pushes arrive.
  4. In the dashboard, Configuration › Developers shows the devices registered and the last check-in.

Diagnostics#

Bubbl.diagnostics() says where Bubbl stands on the device, for your support or debug screen. It's suspend (or takes a callback) on Android, async (or takes a completion handler) on iOS, and returns a Future or Promise in Flutter and React Native.

KOTLIN
Bubbl.diagnostics { d ->
    Log.i("App", "active=${d.active} registered=${d.registered} push=${d.hasPushToken} " +
        "geofences=${d.geofences} background=${d.backgroundLocation} lastError=${d.lastError}")
}
SWIFT
let d = await Bubbl.diagnostics()
print(d.active, d.registered, d.hasPushToken, d.geofences, d.backgroundLocation, d.osWatchesGeofences, d.lastError ?? "none")
DART
final d = await Bubbl.diagnostics();
debugPrint('installId=${d.installId} active=${d.active} registered=${d.registered} push=${d.hasPushToken} '
    'geofences=${d.geofences} background=${d.backgroundLocation} lastError=${d.lastError}');
TS
const d = await Bubbl.diagnostics();
console.log(d.installId, d.active, d.registered, d.hasPushToken, d.geofences, d.backgroundLocation, d.lastError);
FieldWhat you want to see
started, activeTrue. If active is false, check consentRequired and consent, pausedUntil, sdkSupported and supported.
supportedTrue: the device meets the runtime minimum (Android 8.1, iOS 17).
sdkSupportedTrue. False means your workspace requires a newer SDK.
registeredTrue after the first successful call to Bubbl, straight away with a device credential.
installIdThis install's ID, for your own support screen and your records.
environment, testDevice"production" on production. Sandbox workspaces aren't open on production yet: in one, "sandbox" and the test device's status and, while pending, its code.
permissionsWhat the user allowed.
hasPushTokenTrue once the phone has a push token.
geofencesHow many geofences Bubbl got from its last fetch (not how many the OS is watching). 0 before the first fetch: see geofences is 0.
backgroundLocationTrue with "Always" or "Allow all the time"; otherwise geofences work only while the app is open.
locationEnabledFalse after setLocationEnabled(false).
queuedEventsEvents waiting to be sent.
lastErrorThe last error Bubbl logged.
pausedUntilSet when the server has paused Bubbl, in Unix seconds.
credentialRejectedFalse. True means the server refused the device credential Bubbl was started with.
transitionsDroppedWhileLockedGeofence events lost before the first unlock after a reboot (iOS; always 0 on Android).
sdkVersionThe SDK version running.

Each platform adds its own fields. In Flutter and React Native they're null on the other platform:

  • Android: backgroundRestricted (the user restricted the app's background activity, so Bubbl can't run with the app closed) and batteryOptimized (battery optimisation applies, the default, so background work may be delayed in Doze).
  • iOS: osWatchesGeofences (iOS watches the geofences itself: "Always", precise location, and a device that can), backgroundRefreshAvailable (Background App Refresh is on for the app) and lowPowerMode (Low Power Mode holds background work back).

See Diagnostics for the full types.

Logs#

Bubbl logs natively. Set how much with logLevel in BubblOptions: none, error, warning (the default), info or debug.

KOTLIN
BubblOptions(baseUrl = "https://api.bubbl.tech", logLevel = BubblOptions.LogLevel.DEBUG)
SWIFT
BubblOptions(baseUrl: "https://api.bubbl.tech", logLevel: .debug)
DART
const BubblOptions(baseUrl: 'https://api.bubbl.tech', logLevel: BubblLogLevel.debug)
TS
{ baseUrl: 'https://api.bubbl.tech', logLevel: 'debug' }
  • Android: Logcat, tag BubblSDK.
  • iOS: the unified log, subsystem tech.bubbl.sdk: the Xcode console, or Console.app filtered on the subsystem.
  • Flutter and React Native: the same native logs, in Logcat or the iOS unified log, not the Dart or JavaScript console.

Useful lines to look for: Bubbl … started with the SDK version (at info level), and Bubbl.… before Bubbl.start: ignored when a call comes too early.

Positions on emulators and simulators#

Bubbl uses the device's own position. There's no Bubbl call or API to set one, so on an emulator or simulator, set it through the operating system. Put it within 5 km of your campaign locations, or Bubbl gets no geofences.

Android emulator. On emulator images with Google Play, adb emu geo fix and the emulator's Location panel don't reach the fused location provider, so Bubbl never sees the position. Use a test location provider instead:

  1. On the emulator, turn on Settings › Location › Location services › Location Accuracy.
  2. Allow test locations, add test providers and turn them on:
TERMINAL
adb shell appops set 2000 android:mock_location allow
adb shell cmd location providers add-test-provider gps
adb shell cmd location providers add-test-provider network
adb shell cmd location providers set-test-provider-enabled gps true
adb shell cmd location providers set-test-provider-enabled network true
  1. Set the position, and set it again to move the device:
TERMINAL
adb shell cmd location providers set-test-provider-location gps --location 51.5074,-0.1278 --accuracy 10
adb shell cmd location providers set-test-provider-location network --location 51.5074,-0.1278 --accuracy 10

iOS Simulator. Use Features › Location › Custom Location… in the Simulator, or Debug › Simulate Location in Xcode while the app runs.

Local development over http#

The API address must be https://. For a local server, http:// is allowed only for localhost, 127.0.0.1, 10.0.2.2 (the Android emulator's host) and *.test hosts. Your app must also allow cleartext traffic to that host:

  • Android: a network security config that permits cleartext to that host.
  • iOS: App Transport Security blocks it unless Info.plist sets NSAppTransportSecurity › NSAllowsLocalNetworking to YES. Bubbl logs a warning if it's missing. Add it to development builds only.
  • Expo: Bubbl's config plugin options android.cleartextHosts (a network security config allowing only those hosts) and ios.allowLocalNetworking. If your app already sets android:networkSecurityConfig, the plugin refuses cleartextHosts with an error: add the hosts to your own config instead. Keep both out of release builds, for example from app.config.js with an environment variable.

Tests and places without Bubbl#

Where there's no native module (Jest, Expo Go, your app's web build, or a build from before you installed the package), Bubbl's calls do nothing and log one error saying why. Bubbl.diagnostics() still resolves, with started and active false and the reason in lastError. Rebuild the app after installing.

In Jest, use the package's mock, whose functions are jest.fns:

JEST
jest.mock('@bubblsdk/react-native-sdk', () => require('@bubblsdk/react-native-sdk/jest'));