Before you add the BV Garner SDK to your own app, use the BV Garner test app to confirm that your Firebase project, sender profile, and Play Integrity setup work together. After the test passes, integrate the SDK into your app.
This topic is for your Android developers. It is part of the setup described in Set up push notifications in Portal.
Before you begin
- You need a real Android phone (Android 11 or later) with Google Play or an emulator with a Google Play system image (Firebase Cloud Messaging needs Google Play services).
- Git, Android Studio, or IntelliJ IDEA with the Android plugin, JDK 17.
-
Get the following from your Account Administrator or Technical Administrator:
- The App ID from the sender profile. See the Create a sender profile article, step 9.
- The package name registered on the sender profile.
-
The
google-services.jsonfile from the same Firebase project as the uploaded key. - The Google Cloud project number linked for Play Integrity. See the Prepare for Android article, step 3.
Verify your setup with the BV Garner test app
The BV Garner test app runs the SDK with your Firebase project and your sender profile. Its tester screen shows the result of each step, so you can fix configuration issues before you write any integration code.
Setup overview
To set up the BV Garner test app for push notifications, complete these steps:
Step 1: Set up a test identity
Use a separate package name for the sample, for example com.yourcompany.shop.bvpushtest. Using your production package name would mean uploading the sample to your production app's Google Play listing.
Step 2: Get the code
Code |
git clone https://github.com/bazaarvoice/garner.git cd garner/test-app/android cp client.properties.example client.properties |
The app builds the SDK from source in the same repository. An SDK change appears the next time you run the app. Your own app takes the same artifact from Maven Central.
Step 3: Configure the app
XML |
|
Edit client.properties:
| Key | Value |
|---|---|
appName |
The name shown under the app icon (optional). The default is BV Garner.
|
packageName |
The package name of your Firebase Android app and your sender profile. The default is bv.garner.test.app.
|
appId |
The App ID from your sender profile. |
baseUrl |
The production endpoint (the default, https://push.prod.bazaarvoice.com), or the QA endpoint your Bazaarvoice contact gives you.
|
googleServicesJson |
Path to your google-services.json.
|
cloudProjectNumber |
Optional. The Google Cloud project number linked to your app in Google Play Console (App integrity > Play Integrity API), digits only. Without it, the SDK asks Play Integrity with no project number. |
Git ignores client.properties and the copied app/google-services.json. The build fails without a google-services.json.
Step 4: Run the app
-
Open
test-app/androidin Android Studio or IntelliJ IDEA and run theappconfiguration. Alternatively, run./gradlew :app:installDebugfrom a terminal. - Allow notifications when the app asks.
The app has four tabs:
| Tabs | What it shows |
|---|---|
| Home | Whether the device is ready. A banner (for example, "3 of 5 checks pass") and a checklist: device registered, push token sent, user signed in, notifications allowed, and quiet hours. Each problem has a button that fixes it or takes you to the fix. |
| Account | Sign in with a user ID and a customer email (both required). After you sign in, it shows the user and the session, plus Sign out. It always shows Receive pushes (opt in or opt out) and Quiet hours (Off, Default, or Set hours). |
| Inbox | Every push the SDK reported on this device, newest first, with its title, text, time, and outcome (shown, held, hidden and why, or tapped). Filter by All, Shown, Held, or Hidden. The device keeps the newest 500 until you select Clear. Select a push to copy its notification ID. |
| Details | Device ID, FCM token, App ID, package, endpoint, user ID, session, opt-out, quiet hours, and last error, each with Copy. It also has Copy all (JSON), Share, recent SDK events, and the raw inspector text. |
Step 5: Send a test notification
- Send a test push from the Portal: On Home, select Copy device ID and paste it into the Portal's Send test notification dialog. The push appears on the device and in Inbox. Selecting it opens the review page. A test push appears even when no user is signed in.
- Send a real push: On Account, enter a user ID and the customer email the push is addressed to, and then select Sign in. When Home shows a green check for User signed in, pushes for that email reach this device.
- Test at night: By default, pushes are held from 20:00 to 08:00 device time. On Account, set Quiet hours to Off, or use Set hours for your own window.
You can also read the device ID in logcat: adb logcat -s BVPushDriver:I | grep DEVICEID.

ATTESTATION_REJECTED. To test, either use an endpoint that has attestation turned off, or install the app from a Google Play Console testing track on a real device.
When every step on the tester screen passes, continue to Add the BV Garner SDK to your own app.
Add the BV Garner SDK to your own app (Android)
Setup overview
To add the BV Garner SDK to your Android app, complete these steps:
- Add the dependency
- Check Firebase
- Initialize the SDK
- Add Play Integrity token
- Forward messages (if your app has its own messaging service)
- Link the signed-in customer
- Ask for notification permission (Android 13 and later)
- Respect customer preferences (optional)
- Exclude the SDK's files from Android Auto Backup
- Add a way to see the Device ID (internal builds)
What you need
minSdk24 or higher.- Firebase set up in the app.
- Kotlin 2.4.
- The SDK uses HTTPS only and connects to the production endpoint by default, so you don't need to set a URL.
Step 1: Add the dependency
In app/build.gradle.kts:
Code |
|
The artifact is on Maven Central (mavenCentral()).
The SDK brings its own dependencies: Firebase Messaging, Play Integrity, OkHttp, and AndroidX Core, Browser, WorkManager, Lifecycle, and Startup. It's designed to add no more than 1.5 MB to a release build that uses R8.
The SDK's manifest already declares its messaging service, the notification tap handler, the INTERNET, ACCESS_NETWORK_STATE, POST_NOTIFICATIONS, and RECEIVE_BOOT_COMPLETED permissions, and the browser queries. You don't need to add them.
Step 2: Check Firebase
-
Put the
google-services.jsonfrom your production Firebase project inapp/, and apply the Google services Gradle plugin (id("com.google.gms.google-services")). Most apps that already use Firebase have both. -
The
package_nameingoogle-services.jsonmust equal yourapplicationId, including any suffixes. - The SDK fetches the FCM token itself. You don't need to pass it.
Step 3: Initialize the SDK
Call init once in Application.onCreate, with your App ID:
Code |
|
initis lightweight on the main thread. Everything else runs in the background.initnever throws. If the App ID is invalid, the SDK stays inactive and emits anINVALID_APP_IDerror event.-
If you don't already have an
Applicationclass, register it in your manifest withandroid:name=".ShopApplication".
If your app has no Application class, or it's a React Native or Expo app, let the SDK start itself from manifest metadata instead:
XML |
<application> <meta-data android:name="com.bazaarvoice.push.APP_ID" android:value="10000001" /> </application> |
Use one approach. If you use both, make sure the App ID is the same in each.
Step 4: Add Play Integrity token
Device registration carries a Play Integrity token. Give the SDK the Google Cloud project number linked to your app in Play Console (Test and release → App integrity → Play Integrity API) as a string resource: a plain 12-digit android:value is stored as a float and loses digits.
XML |
<!-- res/values/strings.xml: <string name="bv_cloud_project_number">123456789012</string> --> <meta-data android:name="com.bazaarvoice.push.CLOUD_PROJECT_NUMBER" android:value="@string/bv_cloud_project_number" /> |
Without it the SDK sends the request with no project number. A value that is not digits is ignored with a warning. Failures are written to logcat with Play's error code: adb logcat -s BVPush shows BVPush attestation failed code=\.
Step 5: Forward messages if your app has its own messaging service
If your app already extends FirebaseMessagingService, Android delivers each message to only one service. Forward Bazaarvoice messages and new tokens to the SDK:
Code |
|
handleRemoteMessage returns true only for Bazaarvoice messages, so your other notifications keep working. If BVPush.diagnostics() reports fcmConflict=true, messages aren't reaching the SDK. Check this forwarding.
Step 6: Link the signed-in customer
Code |
// After the customer signs in. Calling it again for the same user is free (no network call). BVPush.linkIdentity(userId = customer.id, email = customer.email) // When the customer signs out BVPush.unlinkIdentity(customer.id) |
- Use the same email address that you send to Bazaarvoice in your purchase (transaction) data. Matching uses a hash of the normalized address, so a different address means the device never receives that customer's review requests.
userIdis sent as is. Use your internal customer ID, not an email address or name.-
Without a linked user, the SDK hides review requests on that device. Call
linkIdentityon every sign-in, and on app start if the customer is already signed in.
Step 7: Ask for notification permission (Android 13 and later)
Code |
|
If the customer denies permission or turns off the app's notifications, the SDK quietly suppresses review requests on that device and doesn't show an error.
Step 8: Respect customer preferences (optional)
Code |
BVPush.optOut() // Customer turned off review requests in your app's settings BVPush.optIn() // Customer turned them back on BVPush.setQuietHours(22, 0, 7, 0) // Hold pushes from 22:00 to 07:00 device time BVPush.disableQuietHours() // Show pushes at any time BVPush.resetQuietHours() // Back to the default, 20:00 to 08:00 |
Quiet hours use the device's local time. A push that arrives during quiet hours is held on the device and shown when quiet hours end. The default is 20:00–08:00.
Step 9: Exclude the SDK's files from Android Auto Backup
If your app allows backup, exclude the SDK's files. After a restore, the SDK discards restored credentials and registers again with a new Device ID, so excluding the files keeps backups clean. The file names include your App ID. The following example is for Android 12 and later (android:dataExtractionRules):
XML |
<data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="bv_push_secure_10000001.xml" /> <exclude domain="sharedpref" path="bv_push_settings_10000001.xml" /> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="bv_push_secure_10000001.xml" /> <exclude domain="sharedpref" path="bv_push_settings_10000001.xml" /> </device-transfer> </data-extraction-rules> |
Step 10: Add a way to see the Device ID (internal builds)
Testers need the Device ID to verify the sender profile. Show it on an internal or debug screen, or log it:
Code |
|
For more SDK detail in logcat, turn on debug logging in internal test builds only. The SDK redacts its logs.
Code |
import com.bazaarvoice.push.log.Level import com.bazaarvoice.push.log.Logger Logger.level = Level.DEBUG |
You can also observe BVPush.state (a StateFlow with initialized, deviceId, and lastError) and BVPush.events, which reports each push as received, displayed, held, or suppressed with a reason. These events stay on the device and are never uploaded.
Next step
Verify your sender profile by sending a test notification, create a notification template in Review Channels, test it, and publish it to your site. For detailed instructions, refer to Verify and publish notification template.