Android Mobile Browser Plugin

Android Browser Plugin SDK Documentation

VersionDetailsDateAuthor
1.0.11Initial version22/07/2022SB
1.2.0Introduced show Earnings feature flag10/08/2022SB
1.3.0Introduced earthmark feature flag06/09/2022SB
1.4.0Updates to include:

- Custom logo

- Logic improvements
07/10/2022CPI
1.5.0Fixed an issue causing crash on Android 711/10/2022SB
1.6.0Updates to include:

- Fixed an issue when sharing a web page
- Fixed an issue for deal activation in the wrong brand
- Fixed an issue when the deal popup is shown in domains with no deals
- Fixed an issue that was removing the deal popup when scrolling
17/10/2022CPI
1.7.0Fixed an issue on Android 719/10/2022CPI
1.8.0Added cashback configuration28/10/2022CPI
1.9.0Added charity configuration07/11/2022CPI
2.0.0Updates to include:

- Bug fixes
- Added new service status check function
07/12/2022CPI
2.2.0Updates to include:

- Settings activation flow more user-friendly
15/12/2022CPI
2.3.0Updates to include:

- Spanish, French, German & Korean language support
- Network requests bug-fixes
- Coupons view bug-fixes
19/01/2023CPI
2.4.0 Added Kindred Wallet Sign in24/01/2023CPI
2.5.0Updates to include:

- Added logic improvements
21/01/2023CPI
2.6.0Updates to include:

- Added UTM parameters for analytics
- Comeback activity bug-fix
02/03/2023CPI
2.7.1Updates to include:

- Improved error tracking
- Country/currency re-configuration after service starts is now possible
-
22/03/2023CPI
2.7.2Updates to include:

- Addition of Kindred License Agreement
02/06/2023EL
3.1.0Updates to include:

- New implementation (Maven)
- Logic improvements
- Minor bug-fixes
- Customizable texts of the popups
28/06/2023CPI
28/06/2023Updates to include:

- Memory use optimization
- Arabic , Chinese simplified , Chinese traditional , French, German, Hindi, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, Thai, Turkish & Vietnamese language support
- New back button to after deal activation
21/07/2023CPI
3.4.0Updates to Include:

- Setting Custom Log Prefix
8/08/2023DR
3.7.1Updates to Include:

- Popup Redesign/ K-Menu
- Custom Popups
- Popup Customisations
- Coupons on-Demand via K-Menu
- Auto Coupons
- Continue Browsing Rule
- Post Purchase Rules with analytics
- Translation updates for all supported languages
- Optional feature flag for capturing user device ID as the user ID
17/11/2023DR
3.7.24- Handle deals for brands with multiple domains

- Optimize Auto Coupon Templates
- Bug Fixes & Improvements
- Support for more Browsers
7/2/2024DR/CJ
3.7.25Bug Fixes & Improvements23/2/2024DR/CJ
3.7.28- Fixed an issue with popups when navigating back to the app

- Fixed issue with popup alignment on certain devices
8/3/2024DR
3.7.30- Web URL support for web custom images

- Custom color support for toggle switches
- Translations update
- Bug fixes and improvements
4/4/2024DR/CJ
3.7.32- Fixed Auto coupon issue on(Edge, DuckDuckGo & Firefox)

- Logic Improvements
24/4/2024DR
3.7.34- Bug Fixes & Logic improvements 30/4/2024CJ/DR
3.7.40Bug fixes includes;

- K-menu pin bugs
- Templates failing to load
- Fix broken remote config key and ui related bugs
20/5/2024CJ
3.8.0Bug fixes and improvements.03/6/2024CJ

Getting Started

Follow these instructions to add the Kindred Browser Plugin SDK to an existing application.

For any questions or support with your integration, or to receive your API details, please email [email protected]

Note:

The Android Mobile Browser SDK functions seamlessly across a variety of Android browsers that are supported. Below is the current list of compatible browsers. Additionally, we are committed to continually expanding compatibility by adding support for additional browsers.

  • Google Chrome
  • Microsoft Edge
  • Mozilla Firefox
  • Opera Browser
  • Duck Duck Go
  • Brave

  • Instructions contained by "[]" need to be adapted for each application.
    
  • Instructions contained by "{}" might change on each SDK revision.
    

Maven Implementation

  1. Edit the app’s module build.gradle file, and add dependencies with the latest version.
// app/build.gradle
...
implementation("io.github.kindred-app:browser-sdk:{X.X.X}")
...
  1. Add the kindred.properties file in the root of your project. This will include authentication for Maven repositories and authentication for the Kindred SDK.
    // kindred.properties
    ext {
        AUTH_CLIENT_ID="[AUTH_CLIENT_ID]"
        AUTH_CLIENT_SECRET="[AUTH_CLIENT_SECRET]"
        AUTH_SHARED_KEY="[AUTH_SHARED_KEY]"
    }
    

Service Configuraiton

  1. Add the Auth Settings to the defaultConfig in the module build.gradle. This is later passed down to the Kindred SDK during configuration. Make sure you apply the "kindred.properties":
// app/build.gradle
apply from: "../kindred.properties"
...
android {
    ...
      defaultConfig {
      ...
        buildConfigField("String", "AUTH_CLIENT_ID", "\"" + AUTH_CLIENT_ID + "\"")
        buildConfigField("String", "AUTH_CLIENT_SECRET", "\"" + AUTH_CLIENT_SECRET + "\"")
        buildConfigField("String", "AUTH_SHARED_KEY", "\"" + AUTH_SHARED_KEY + "\"")
      }
 		 ...
    }
    ...
}
  1. Create the Deals Accessibility service class in the app module

Note: find out more about the configuration flags below, in the section Kindred feature configuration

Note: KindredUserConfiguration is deprecated and will be removed in future versions. We suggest the use of the new functions "setUserCountry" & "setUserCurrency" from KidnredFramework.

// DealAccessibilityService.kt

import com.kindred.browser_sdk.KindredAbstractAccessibilityService
import com.kindred.browser_sdk.configuration.*

class DealsAccessibilityService : KindredAbstractAccessibilityService() {

    companion object {
        val kindredApiConfiguration = KindredApiConfiguration(
            clientID = BuildConfig.AUTH_CLIENT_ID,
            clientSecret = BuildConfig.AUTH_CLIENT_SECRET,
            sharedKey = BuildConfig.AUTH_SHARED_KEY
        )
    }

    override fun configureService() = KindredAccessibilityServiceConfiguration(
        api = kindredApiConfiguration,
        user = KindredUserConfiguration(
            userCurrency = "CURRENCY_CODE",
            userCountry = "COUNTRY_CODE"
        ),
        features = KindredFeaturesConfiguration(
          showEarningsConfirmationMessage = true,
        	earthMarkScoring = true,
          showCashbackLabel = true
        ),
        charity = KindredCharityConfiguration(
            charityId = "CHARITY_ID",
            charityShare = CHARITY_SHARE
        )
    )

    override fun onCreate() {
        setUserId("UNIQUE_USER_ID")
        setAppIcon(R.drawable."[logo]")

        super.onCreate()
    }
}
  1. Setting the user ID (optional)

The default configuration gives each user a unique user ID. If you wish to provide your own user ID or a unique identifier for the user for analytic purposes, you can provide the SDK with you own unique ID as follows:

// DealAccessibilityService.kt
...
    override fun onCreate() {
        setUserId("UNIQUE_USER_ID")

        super.onCreate()
    }
...
  1. Setting a custom icon (optional)

By default, the service will use a Kindred logo but it's possible to set a custom icon by providing the drawable Int in this function:

// DealAccessibilityService.kt
...
    override fun onCreate() {
        setAppIcon(R.drawable."[logo]")
                
        super.onCreate()
    }
...
  1. Setting an activity to return to after service activation (optional) (Min Android 7)

You can use this function to set a comeback intent. After the service is activated by the user, they will get returned to the activity if the set intent automatically:

// DealAccessibilityService.kt
...
    override fun onCreate() {
        setComebackActivity(Intent(this, YOUR_ACTIVITY_NAME::class.java))
                
        super.onCreate()
    }
...
  1. Add the accessibility service XML file in the res/xml folder.
// accessibilityservice.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
    android:accessibilityFlags="flagDefault|flagReportViewIds|flagRetrieveInteractiveWindows"
    android:accessibilityFeedbackType="feedbackVisual"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
    />
  1. Add permissions to the AndroidManifest.xml file
// AndroidManifest.xml
...
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
...
  1. Add accessibility service to the AndroidManifest.xml file
// AndroidManifest.xml
...
<application
...
        <service
            android:name="com.kindred.browsersdk.DealsAccessibilityService"
            android:canRetrieveWindowContent="true"
            android:exported="true"
            android:label="@string/accessibility_service_label"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibilityservice" />
        </service>
...
</application>
...
  1. Add string values to the res/values/strings.xml (Note, you can change these values as applicable)
// strings.xml
...
    <string name="accessibility_service_description">By allowing the Accessibility Permission, you permit “App Name” to access data about your URLs. We do this to enable you to save money when you are shopping on your favourite brands, coupon codes will pop up at checkout, helping you to save!</string>
    <string name="accessibility_service_label">Kindred</string>
...
  1. Setting a custom Log prefix (optional)

By default the log message tag in the Logcat will be "kk", you can change this by providing your own custom prefix:

// DealAccessibilityService.kt
...
    override fun onCreate() {
        setLogTag("[YOUR-CUSTOM-PREFIX]")
        super.onCreate()
    }

Kindred Framework

KindredFramework is an object class we expose to facilitate some functionalities related to the service.

isAccessibilityServiceEnabled

This function will return the current status of the service, a boolean indicating if the service is currently running or not.

val serviceStatus = KindredFramework.isAccessibilityServiceEnabled(context)

openAccessibilityServiceSettings

This function will open the accessibility settings of the service for its activation and will display a toast message with the received text.

KindredFramework.openAccessibilityServiceSettings(context, "INCLUDE YOUR TEXT HERE")

This toast message is a tiny popup at the bottom of the screen and it's centered. It will disappear after a fraction of a second.

openKindredWallet

This function will receive the context, the kindredApiConfiguration companion object that was created in the service, and a callback. It will open the wallet sign-in web page in the default browser.
The callback will receive one of three states: _SUCCEED, NO_AUTH (No authentication was detected during the process), ERROR (Something else went wrong)

 KindredFramework.openKindredWallet(this, DealsAccessibilityService.kindredApiConfiguration) {
	Log.d("kk", "$it")
}

setUserCountry

This function allows you to override the country code of the initial service configuration or add one if none was specified at the service start.

KindredFramework.setUserCountry("COUNTRY_CODE", context)

setUserCurrency

This function allows you to override the currency code of the initial service configuration or add one if none was specified at the service start.

KindredFramework.setUserCurrency("CURRENCY_CODE", context)

Helper Functions

setLogTag

This function allows you to set a prefix for log messages, defaults to "kk"

 setLogTag("Kindred")

setLogLevel

This function allows you to control the log message output, you can also completely disable the log messages using this method. the level is set to NONE by default, meaning no log messages would be displayed.
DEBUG, INFO, ERROR & NONE

setLogLevel(KLogLevel.DEBUG)

optOutFromDeviceIdCapture

The kindred framework automatically sends the device-id as part of the request header when making network calls, you can disable this by calling the method below.

optOutFromDeviceIdCapture()

Kindred TRANSLATIONS

TRANSLATIONS is an object class we expose to facilitate the customization of the strings of the popups shown by the service.
The translations can be customized from anywhere but we suggest to do it in the onCreate of the AccessibilityService class to ensure the new strings set will be used when needed.

How to use it?

class DealsAccessibilityService : KindredAbstractAccessibilityService() {
  override fun onCreate() {
    val stringMap = mapOf<String, String>(
        TRANSLATIONS.ACTIVATE_ALL_DEALS_TEXT_BUTTON to "Sample Text 1",
        TRANSLATIONS.ACTIVATE_DEAL_TEXT_BUTTON to "Sample Text 2",
        etc...
    )
    TRANSLATIONS.setCustomTranslations(context, stringMap)
  }
}

Customizable strings

COPY_DISCOUNT_CODES_TEXT_BODY -> Default: Copy discount codes below
COPY_TEXT -> Default: Copy
DEAL_ACTIVATED_TEXT_TITLE -> Default: Woohoo!
DEAL_ACTIVATED_TEXT_TITLE_WITH_COUPON -> Default: Coupons available at checkout!
DEAL_ACTIVATED_TEXT_BODY -> Default: We will plant trees with your purchase
DEAL_ACTIVATED_TEXT_BODY_WITH_COUPONS -> Default: We will plant trees with your purchase
AUTO_CHECK_COUPON_TEXT_TITLE -> Default: Auto Check Coupons
AUTO_CHECK_COUPON_TEXT_DESC -> Default: Automatically check for coupons and plant trees as I shop
ALLOW_PINNED_ICON_TEXT_TITLE -> Default: Allow Pinned Icon
ALLOW_PINNED_ICON_TEXT_DESC -> Default: Get Coupons at the touch of a button while you browse
ACTIVATING_DEAL_TEXT_BODY -> Default: Searching for coupons
ACTIVATE_ALL_DEALS_TEXT_BUTTON -> Default: Always plant trees when I make a purchase
ACTIVATE_DEAL_TEXT_BUTTON -> Default: I'd rather you only plant with this purchase
COPIED_TEXT -> Default: Copied!
POST_PURCHASE_CTA_TEXT -> Default: Go to app/ Learn more
POST_PURCHASE_TITLE -> Default: Woohoo!
POST_PURCHASE_BODY -> Default: Your Recent Purchase has contributed to planting trees
COUPONS_MESSAGE_DESC -> Default: If codes don't pop up automatically at checkout 
SETTINGS_TITLE_DESC  -> Default: Settings
COUPONS_TITLE_DESC -> Default: Coupon Codes

Kindred feature configuration

What is "Show Earnings" feature flag?

If you would like us to popup to the user whenever they've made any cash back or donated to a cause, you can set this feature flag on when setting up the configuration on the DealsAccessibilityService.

What is "EarthMark" feature flag?

Earthmark have developed a rating system to show how "green" retailers really are. Earthmark's rating system will now be highlighted within the Kindred technology so partners can help their users make more informed choices to shop sustainably.

Kindred Popup Customisation

you can modify the look and feel of our popups to suit your brand needs

Button Customisations

to change the color and radius of buttons

  setPopupImplementation(
            popupAsset = PopupAsset(
                primaryColor = R.color."[color_name]",
                buttonRadius = 25
            )
        )

Image Resource

you can provide your own image resource to the framework for certain popups

Coupons Found
        val popupAsset = PopupAsset(
            couponFoundImage = R.drawable."[image]"
        )

Applying Coupons

  val popupAsset = PopupAsset(
                couponFoundImage = R.drawable."[iamge]",
                applyingCouponsImage = R.drawable."[iamge]"
            )

Best Price

val popupAsset = PopupAsset(
                couponFoundImage = R.drawable."[iamge]",
                applyingCouponsImage = R.drawable."[iamge]",
                bestPricesImage = R.drawable."[iamge]"
            )

finally, you pass your custom image(s) to the setPopupImplementation method


            val popupAsset = PopupAsset(
                couponFoundImage = R.drawable."[iamge]",
                applyingCouponsImage = R.drawable."[iamge]",
                bestPricesImage = R.drawable."[iamge]"
            )

            setPopupImplementation(popupAsset = popupAsset)

Alternatively, You can set custom images using web URLs, similar to the way you set image assets, call the settPopupImplementation method and then pass in a PopupAsset. Example below.

  setPopupImplementation(
            popupAsset = PopupAsset(
                couponFoundImageUrl = "https://cdn.euroflorist.com/Products/600x700/PS14BQTSF01M_1.ebp",
                bestPricesImageUrl = "[your-image-url]",
                applyingCouponsImageUrl = "[your-image-url]"
            )
        )

Custom popup implementation

if the customization options above doesn't satisfy your needs, you can provide a different implementation for each popup. you can do this by extending the popup class for each popup you'd like to customize and then pass your implementation to the setPopupImplementation method.

class CustomDealFoundPopup(private val context: Context) :
    DealFoundPopup(context) {
   
      
       override fun getView(
        coreSettings: CoreSettings,
        id: String?,
        cashbackMessage: String?,
        onActivate: () -> Unit,
        onActivateAll: () -> Unit,
        showEarthMarkScore: Boolean,
        earthmarkScore: Float?,
        onClose: () -> Unit
    ): View {
         //initialize your custom view
				val layoutInflater =
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
				val mCustomView: View = layoutInflater.inflate(R.layout."[layout_name]", null)

				return mCustomView
			}

         override fun getWindowConfig(): WindowManager.LayoutParams {
        val windowParam = WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT
        )

        windowParam.gravity = Gravity.CENTER
        windowParam.y = windowYAxisPosition

        return windowParam
    }



    }

to configure your own layout parameter for the WindowManager, override the getWindowConfig method and then return an instance of WindowManager.LayoutParams as done above.

Finally pass the custom implementation as a map to the setPopupImplementation method.

val customPopups = mapOf(PopupType.DEAL_FOUND to CustomDealFoundPopup(this))

 val popupAsset = PopupAsset(
                couponFoundImage = R.drawable."[iamge]",
                applyingCouponsImage = R.drawable."[iamge]",
                bestPricesImage = R.drawable."[iamge]"
            )

setPopupImplementation(customPopups, popupAsset = popupAsset)

below is the list of customizable popups, each implementation must be passed with a valid map key and a popup class that extends the default kindred implementation.

Map KeyPopup Class
PopupType.DEAL_FOUNDDealFoundPopup
PopupType.ACTIVATINGDealActivatingPopUp
PopupType.ACTIVATEDDealActivatedPopup
PopupType.BALANCE_CHANGEBalanceChangePopup

Kindred SDK Size

What's the size of our SDK in your project and APK?

Adding the Kindred SDK to a sample project adds an extra 0.71 MB to the total APK size

Before SDK:

  • Project size: 35.4 MB
  • APK size: 5.25 MB

After SDK:

  • Project size: 46.1 MB
  • APK size: 5.96 MB

License Agreement: https://event.kindred.co/licensing-terms-and-conditions