ChangelogEdit pageSTAFFOpen dashboard

Testing and diagnostics

Approve a test phone, send it a test push and a test geofence, read where Bubbl stands on the device, and find its logs.

A first test run#

  1. Start the app with your Sandbox key and address, and approve the phone under Configuration › Test Devices. See Sandbox and Production.
  2. Check Bubbl.diagnostics(): active and registered true.
  3. Send a test push from the Active users card on the dashboard's home page, or from Configuration › Test Devices. See Send a test push.
  4. For a guided run, open Set up the SDK from Configuration › Developers. Its Test checklist ticks six checks as your phone reports them, and can place a temporary 100 m test geofence at your approved test phone for 30 minutes: walk into it, or open the app inside it, and its notification should show. See SDK setup.

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: search for it under Active users in the dashboard.
environment, testDevice"sandbox" or "production"; in a Sandbox, the test device's status and, while pending, its code.
permissionsWhat the user allowed.
hasPushTokenTrue once the phone has a push token.
geofencesHow many are watched.
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.sandbox.bubbl.tech", logLevel = BubblOptions.LogLevel.DEBUG)
SWIFT
BubblOptions(baseUrl: "https://api.sandbox.bubbl.tech", logLevel: .debug)
DART
const BubblOptions(baseUrl: 'https://api.sandbox.bubbl.tech', logLevel: BubblLogLevel.debug)
TS
{ baseUrl: 'https://api.sandbox.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), Bubbl sandbox: approve this device with code …, and Bubbl.… before Bubbl.start: ignored when a call comes too early.

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'));