Braze Android Integration

Table of Contents

  • Getting Started
  • Integrate Bluedot Point SDK in your Project
  • Interaction between Braze SDK and Bluedot Point SDK

Getting Started

1. Modify your build.gradle to include Braze SDK.

repositories {
...
    maven { 
        url "https://appboy.github.io/appboy-android-sdk/sdk" 
    }
}

Braze supports a few push providers: FCM, GCM, ADM. We recommend using Firebase. However, you can choose other.

2. In the app gradle add

implementation "com.appboy:android-sdk-ui:+"

3. Create appboy.xml under the res folder and add the following code. Create a Braze Android App and get the API key and replace it in the “REPLACE_WITH_YOUR_API_KEY”. Also, replace the “YOUR_CUSTOM_ENDPOINT_OR_CLUSTER” with the custom endpoint from Braze.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="com_appboy_api_key">REPLACE_WITH_YOUR_API_KEY</string>
    <string translatable="false" name="com_appboy_custom_endpoint">YOUR_CUSTOM_ENDPOINT_OR_CLUSTER</string>
    <bool translatable="false" name="com_appboy_firebase_cloud_messaging_registration_enabled">true</bool>
    <string translatable="false" name="com_appboy_firebase_cloud_messaging_sender_id">your_fcm_sender_id_here</string>
    <integer name="com_appboy_default_notification_accent_color">0xFFf33e3e</integer>
    <bool name="com_appboy_handle_push_deep_links_automatically">true</bool>
</resources>

4. In the AndroidManifest.xml add the following:
a. The following permissions are required.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

b. The following braze service should be included to handle push receipt and open intents.

<service android:name="com.appboy.AppboyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Integrate Bluedot Point SDK in your Project

To integrate Bluedot Point SDK in your project, please click here

Interaction between Braze SDK and Bluedot Point SDK

1. We need to ask the user to give permission to use the location services. To do that, create a RequestPermissionActivity.kt and then add the below code.

internal val PERMISSION_REQUEST_CODE = 1
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    //Request permission required for location
    ActivityCompat.requestPermissions(
        this,
        arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
        PERMISSION_REQUEST_CODE
    )
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        PERMISSION_REQUEST_CODE -> if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            (application as MainApplication).initPointSDK()

        } else {
            //Permissions denied

        }
    }
    finish()
}

2. We then create another class which will make use of all the Bluedot SDK callbacks and then sends them to Braze. To do that create MainApplication.kt class and add the below code.

internal lateinit var mServiceManager: ServiceManager

    private val apiKey = Bluedot API key for the App

    internal var restartMode = true


    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(AppboyLifecycleCallbackListener())

        // initialize Bluedot point sdk
        initPointSDK()
    }

    fun initPointSDK() {

        val checkPermissionCoarse =
            ActivityCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION)
        val checkPermissionFine =
            ActivityCompat.checkSelfPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)

        if (checkPermissionCoarse == PackageManager.PERMISSION_GRANTED && checkPermissionFine == PackageManager.PERMISSION_GRANTED) {
            mServiceManager = ServiceManager.getInstance(this)

            if (!mServiceManager.isBlueDotPointServiceRunning()) {
                mServiceManager.setForegroundServiceNotification(createNotification(), false)
                mServiceManager.sendAuthenticationRequest(apiKey, this, restartMode)
            }
        } else {
            requestPermissions()
        }

    }

    private fun requestPermissions() {
        val intent = Intent(applicationContext, RequestPermissionActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        startActivity(intent)
    }

This method is called when BlueDotPointService started successfully, your app logic code using the Bluedot service could start from here. Replace “YOUR_BRAZE_USER_ACCOUNT” with the Braze user account.

    override fun onBlueDotPointServiceStartedSuccess() {
        mServiceManager.subscribeForApplicationNotification(this)
        Appboy.getInstance(this).changeUser(YOUR_BRAZE_USER_ACCOUNT)
    }

This method notifies the client application that BlueDotPointService is stopped. Your app could release the resources related to Bluedot service from here.

    override fun onBlueDotPointServiceStop() {
        mServiceManager.unsubscribeForApplicationNotification(this)
    }
    /**
     *
     * The method delivers the error from BlueDotPointService by a generic BDError. There are several types of error such as
     * - BDAuthenticationError (fatal)
     * - BDNetworkError (fatal / non fatal)
     * - LocationServiceNotEnabledError (fatal / non fatal)
     * - RuleDownloadError (non fatal)
     * - BLENotAvailableError (non fatal)
     * - BluetoothNotEnabledError (non fatal)
     *
     *  The BDError.isFatal() indicates if error is fatal and service is not operable.
     * Followed by onBlueDotPointServiceStop() indicating service is stopped.
     *
     *  The BDError.getReason() is useful to analyse error cause.
     * @param bdError
     */
    override fun onBlueDotPointServiceError(bdError: BDError) {
        println("onBlueDotPointServiceError = $bdError")
    }

    /**
     *
     * The method deliveries the ZoneInfo list when the rules are updated. Your app is able to get the latest ZoneInfo when the rules are updated.
     * @param list
     */
    override fun onRuleUpdate(list: List) {

    }

Call the below callbacks when a check-in/check-out happens for a Fence/Beacon. Replace “YOUR_EVENT_NAME” with an event name created in Braze account.

    override fun onCheckIntoFence(
        fenceInfo: FenceInfo,
        zoneInfo: ZoneInfo,
        location: LocationInfo,
        customData: Map,
        isCheckOut: Boolean
    ) {
        val eventProperties = AppboyProperties()
        eventProperties.addProperty("zone_id", zoneInfo.zoneId)
        eventProperties.addProperty("zone_name", zoneInfo.zoneName)
        eventProperties.addProperty("latitude", location.latitude)
        eventProperties.addProperty("longitude", location.longitude)
        eventProperties.addProperty("fence_id", fenceInfo.id)
        eventProperties.addProperty("fence_name", fenceInfo.name)

        for (data in customData) {
            eventProperties.addProperty(data.key, data.value)
        }

        Appboy.getInstance(this).logCustomEvent(YOUR_EVENT_NAME, eventProperties)
    }

    override fun onCheckedOutFromFence(
        fenceInfo: FenceInfo,
        zoneInfo: ZoneInfo,
        dwellTime: Int,
        customData: Map
    ) {
        val eventProperties = AppboyProperties()
        eventProperties.addProperty("zone_id", zoneInfo.zoneId)
        eventProperties.addProperty("zone_name", zoneInfo.zoneName)
        eventProperties.addProperty("dwellTime", dwellTime)
        eventProperties.addProperty("fence_id", fenceInfo.id)
        eventProperties.addProperty("fence_name", fenceInfo.name)

        for (data in customData) {
            eventProperties.addProperty(data.key, data.value)
        }

        Appboy.getInstance(this).logCustomEvent(YOUR_EVENT_NAME, eventProperties)
    }

    override fun onCheckIntoBeacon(
        beaconInfo: BeaconInfo,
        zoneInfo: ZoneInfo,
        location: LocationInfo,
        proximity: Proximity,
        customData: Map,
        isCheckOut: Boolean
    ) {
        val eventProperties = AppboyProperties()
        eventProperties.addProperty("zone_id", zoneInfo.zoneId)
        eventProperties.addProperty("zone_name", zoneInfo.zoneName)
        eventProperties.addProperty("beacon_id", beaconInfo.id)
        eventProperties.addProperty("latitude", location.latitude)
        eventProperties.addProperty("longitude", location.longitude)

        for (data in customData) {
            eventProperties.addProperty(data.key, data.value)
        }

        Appboy.getInstance(this).logCustomEvent(YOUR_EVENT_NAME, eventProperties)
    }

    override fun onCheckedOutFromBeacon(
        beaconInfo: BeaconInfo,
        zoneInfo: ZoneInfo,
        dwellTime: Int,
        customData: Map
    ) {
        val eventProperties = AppboyProperties()
        eventProperties.addProperty("zone_id", zoneInfo.zoneId)
        eventProperties.addProperty("zone_name", zoneInfo.zoneName)
        eventProperties.addProperty("beacon_id", beaconInfo.id)
        eventProperties.addProperty("dwellTime", dwellTime)

        for (data in customData) {
            eventProperties.addProperty(data.key, data.value)
        }

        Appboy.getInstance(this).logCustomEvent(YOUR_EVENT_NAME, eventProperties)
    }

This method creates notification channel and notification, required for foreground service notification.

    private fun createNotification(): Notification {
        val channelId: String
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            channelId = "Bluedot" + getString(R.string.app_name)
            val channelName = "Bluedot Service" + getString(R.string.app_name)
            val notificationChannel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
            notificationChannel.enableLights(false)
            notificationChannel.lightColor = Color.RED
            notificationChannel.enableVibration(false)
            val notificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(notificationChannel)

            val notification = Notification.Builder(applicationContext, channelId)
                .setContentTitle(getString(R.string.foreground_notification_title))
                .setContentText(getString(R.string.foreground_notification_text))
                .setStyle(Notification.BigTextStyle().bigText(getString(R.string.foreground_notification_text)))
                .setOngoing(true)
                .setCategory(Notification.CATEGORY_SERVICE)
                .setSmallIcon(R.mipmap.ic_launcher)

            return notification.build()
        } else {

            val notification = NotificationCompat.Builder(applicationContext)
                .setContentTitle(getString(R.string.foreground_notification_title))
                .setContentText(getString(R.string.foreground_notification_text))
                .setStyle(NotificationCompat.BigTextStyle().bigText(getString(R.string.foreground_notification_text)))
                .setOngoing(true)
                .setCategory(Notification.CATEGORY_SERVICE)
                .setPriority(PRIORITY_MAX)
                .setSmallIcon(R.mipmap.ic_launcher)

            return notification.build()
        }
    }

    companion object {
        private val TAG = "BDApp"
    }

Created by Ram Akunuru on August 6, 2019

Start the discussion