Skip to content

usabilla/usabilla-u4a-android-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Download

Usabilla for Apps - Android SDK

Usabilla for Apps allows you to collect feedback from your users with great ease and flexibility.



Requirements

  • Android API: Minimum 19 - Target 30
  • Use of AndroidX support libraries
  • Use of TLS1.2 protocol for network connections (automatically enabled for Android API >= 21)
  • Project targeting Java8 in the build.gradle compileOptions

TLS1.2

If your app supports Android API 19, in order to enable TLS1.2 on those devices you need to update your security provider as follows

Include the following dependency in your build.gradle file

implementation `com.google.android.gms:play-services-safetynet:17.0.0`

Call the following function in your app before any action with the Usabilla SDK

fun upgradeSecurityProvider(context: Context) {
    ProviderInstaller.installIfNeededAsync(context, object : ProviderInstallListener {
        override fun onProviderInstalled() {
            // You are good to go
        }

        override fun onProviderInstallFailed(errorCode: Int, recoveryIntent: Intent) {
            // Something went wrong. For more details please refer to https://developer.android.com/training/articles/security-gms-provider
        }
    })
}

Java 8

Our SDK targets Java8 and uses components available from Android API 26, therefore if your app targets previous Android versions please do enable desugaring support as explained in the official Google guidelines

Android API limitations

The following functionalities will only be available on phones running Android API >= 21

  • The cursor on text fields is tinted with the accent color
  • The progress bar at the top of the form is tinted with the accent color
  • The star component allow custom drawables to be applied to it

Installation

Grab the latest version using

implementation 'com.usabilla.sdk:ubform:8.0.2'

If you have obfuscation enabled (ProGuard/R8) and you use a version of our SDK <= 6.4.0 you need to add this line to your obfuscation configuration

-keep public class com.usabilla.sdk.ubform.eventengine.TargetingOptionsModel

Public properties

Custom variables

Custom variables are represented by a non mutable Map of objects and are attached to each feedback sent

 Usabilla.customVariables = mapOf(
    Pair("tier", "premium"),
    Pair("loggedIn", true)
  )

There are a few limitations to the kind of objects you can add to the custom variables

  • Custom objects need to override the toString() function.
  • Arrays are not allowed.
  • The name (key) of each custom variable must not be blank and it must not contain . or $.

⚠️ Custom variables can be used as targeting options for campaigns, as long as their value is a String.

Debug mode

Local logging (disabled by default) can be enabled using

Usabilla.debugEnabled = true

External navigation (passive feedback only)

It is possible to hide the default navigation buttons our forms use and provide your own (e.g. in the Toolbar).

To do so a couple of steps are required:

  • Set the standard navigation buttons invisible

    Usabilla.setDefaultNavigationButtonsVisibility(false)
  • From your custom trigger call the function navigationButtonPushed on the form fragment to continue.

    myButton.setOnClickListener { formFragment.navigationButtonPushed() }

Telemetry data submission

Telemetry data submission (enabled by default) can be disabled using

Usabilla.submitTelemetryData = false

Theme

A custom theme can be applied to both passive forms and campaign forms using

Usabilla.theme = UsabillaTheme(UbFonts(), UbImages())

Public functions

Initialize

The first function called on the Usabilla SDK should be initialize. Failure to call initialize before any other public function in the SDK can cause erratic behaviour.

Usabilla.initialize(context: Context, appId: String?, httpClient: UsabillaHttpClient?, callback: UsabillaReadyCallback?)

Load a passive form

Passive feedback form are loaded using

Usabilla.loadFeedbackForm(formId: String, screenshot: Bitmap?, theme: UsabillaTheme? , callback: UsabillaFormCallback?)

Preload a passive form

Preloading the form will fetch and store it locally. It can be then shown by calling loadFeedbackForm with the preloaded formId.

Usabilla.preloadFeedbackForms(formIds: List<String>)

Remove cached forms

Preloaded forms can be removed from cache using

Usabilla.removeCachedForms()

Capture a screenshot

We offer two utility functions to capture a screenshot that can then be added to the passive form load request

val myScreenshot = Usabilla.takeScreenshot(view: View)
val myScreenshot = Usabilla.takeScreenshot(activity: Activity)

Send events

Campaigns are triggered by events sent using

Usabilla.sendEvent(context: Context, event: String)

⚠️ A campaign will only be triggered once for the same user.

Update fragment manager

To show campaigns it's necessary to provide a reference to the FragmentManager using

Usabilla.updateFragmentManager(fragmentManager: FragmentManager)

⚠️ When the fragmentManager is updated from inside a child-fragment the right instance to pass is requireActivity().supportFragmentManager.

Reset campaigns data

Campaign data stored locally can be removed (and fetched again, effectively losing any trace whether they already triggered or not) using

Usabilla.resetCampaignData(context: Context, callback: UsabillaReadyCallback?)

Dismiss form

Forms showing on screen can be programmatically dismissed using

Usabilla.dismiss(context: Context)

Campaigns are dismissed directly by the SDK, whereas passive forms assume the proper broadcast receiver is implemented.

Mask PII

PII (Personally Identifiable Information) present in all input text fields can be masked (on submission) using

Usabilla.setDataMasking(masks: List<String>, maskCharacter: Char)

⚠️ The email field does not apply masking since it explicitly asks for a sensitive data.

Set footer logo clickable

Setting whether the footer logo is clickable or not can be done using

Usabilla.setFooterLogoClickable(clickable: Boolean)

Miscellaneous

⚠️ LocalBroadcastManager is deprecated from v8.0.0 onwards.

Back button intercept

Our forms (campaign banner included) intercepts the phone's back button clicks and remove themselves from the screen

Access form data

You can optionally register receivers with any of the following filters

In Kotlin

private val uiScope = CoroutineScope(Dispatchers.Main) // you can use your scope of component

private fun collectClosingFormSharedFlow() {
  uiScope.launch {
    Usabilla.sharedFlowClosingForm.collectLatest {
      if (it.formType == com.usabilla.sdk.ubform.sdk.form.FormType.PASSIVE_FEEDBACK) {
        // The passive feedback form needs to be closed and the feedback result is returned
        val res: FeedbackResult = it.feedbackResult
      } else if (it.formType == com.usabilla.sdk.ubform.sdk.form.FormType.CAMPAIGN) {
        // The campaign feedback form has been closed and the feedback result is returned
        val res: FeedbackResult = it.feedbackResult
      }
    }
  }
}

override fun onStart() {
    super.onStart()
    collectClosingFormSharedFlow()
}

override fun onStop() {
    super.onStop()
  uiScope.coroutineContext.cancelChildren()
}

In Java

private final Observer<ClosingFormData> closingObserver = closingFormData -> {
        if (closingFormData.getFormType().equals(FormType.PASSIVE_FEEDBACK)) {
          // The passive feedback form needs to be closed and the feedback result is returned
          FeedbackResult feedbackResult = closingFormData.getFeedbackResult();
        } else if (closingFormData.getFormType().equals(FormType.CAMPAIGN)) {
          // The campaign feedback form has been closed and the feedback result is returned
          FeedbackResult feedbackResult = closingFormData.getFeedbackResult();
        }
  };


@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Usabilla.INSTANCE.getClosingData().observe(this, closingObserver);
        }

Additionally, in order to receive user entries when a form or campaign has been closed, you need to implement another collector :

In Kotlin

private fun collectEntriesSharedFlow() {
    scope.launch {
       Usabilla.sharedFlowEntries.collectLatest {
         // The campaign or feedback form has been closed
         // `entries` is the `string` implementation of `fieldId` -> `fieldValue` map
       val entries : String = it
       }
    }
}

override fun onStart() {
    super.onStart()
    collectEntriesSharedFlow()
}

override fun onStop() {
    super.onStop()
    uiScope.coroutineContext.cancelChildren()
}

In Java

private final Observer<String> entriesObserver = _entries -> {
        String entries = _entries
        };

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Usabilla.INSTANCE.getEntriesData().observe(this, entriesObserver);
        }

Before show a campaign

To apply any logic before presenting any campaign, you must construct a collector that listens for the campaign's before show event. You will be notified of this event prior to displaying the campaign.

Inside the collectLatest method it's possible to obtain a FormType object.

In Kotlin

 uiScope.launch {
            Usabilla.sharedFlowBeforeShowCampaign.collectLatest {
                if (it == FormType.CAMPAIGN_BEFORE_SHOW) {
                  // Campaign will be displayed.
                }
            }
        }

In Java

private final Observer<FormType> beforeShowCampaignObserver = formType -> {
        if (formType.equals(FormType.CAMPAIGN_BEFORE_SHOW)) {
            // Campaign will be displayed.
        }
    };

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Usabilla.INSTANCE.getBeforeShowCampaign().observe(this, beforeShowCampaignObserver);
        }

App review on the PlayStore

When a form is given a 4 or 5 rating in the mood/star component, once closed the official In-App review API prompt to rate the app on the PlayStore will be presented.

This will show only on devices that have the Play Store installed.

For information regarding testing/checking this feature, please refer to the official guidelines.

Custom http client

We enable the injection of a custom http client in the initialize function to handle all the network connections in our SDK.

A sample http client implementation can be seen in the classes CustomHttpClient.java or CustomHttpClient.kt

Telemetry

The SDK collects diagnostic data to improve the performance and optimise usage on the variety of devices it can be run on.

⚠️ The information collected is not used to identify users, does not contain PII and it's not shared with external parties

Adding the SDK to your project will not send us any information; information is sent only in the following cases:

  • Call to initialise() completes
  • Call to loadFeedbackForm() completes
  • Call to sendEvent() completes
  • Exiting a feedback form

The data collected content is as follows:

{
  "appVersion": "1.0.0",
  "appName": "AppName",
  "device": "Android SDK built for x86",
  "freeMemory": "831172",
  "freeSpace": "582800",
  "orientation": "Portrait",
  "osVersion": "8.1.0",
  "reachability": "WiFi",
  "rooted": false,
  "screenSize": "1440x2392",
  "sdkVersion": "8.0.2",
  "system": "android",
  "totalMemory": "1530604",
  "totalSpace": "793488",
  "id": "ms since Unix Epoch",
  "timestamp": "human readable date",
  "originClass": "com.usabilla.Usabilla",
  "action": {
    "duration": "102",
    "errorCode": "0",
    "errorMessage": "",
    "name": "function or property invoked on our public interface"
    ...
    function parameters are also collected here
    ...
  }
}

Localization

To provide your own translation of some of the strings our SDK uses just overwrite them in your strings.xml file

<string name="ub_field_error">Please check this field</string>
<string name="ub_element_screenshot_title">Screenshot (optional)</string>
<string name="ub_element_screenshot_message">Add an image</string>
<string name="ub_button_close_default">Close</string>
<string name="ub_button_continue_default">Continue</string>
<string name="ub_button_playStore_default">Rate on the play store</string>
<string name="ub_button_submit_default">Submit</string>
<string name="ub_dialog_playStore_title">Rate</string>
<string name="ub_dialog_playStore_message">Thank you for your feedback! Would you like to leave a review?</string>
<string name="ub_dialog_playStore_negative">No, thanks</string>
<string name="ub_dialog_playStore_positive">Rate now</string>
<string name="ub_sdk_permission_disabled_label">Permission disabled!\nEnable it from Settings -> app info</string>

// Accessibility labels
<string name="ub_element_mood_select_rating">Select a rating out of %1$d</string>
<string name="ub_element_mood_adjust_instructions">Swipe up or swipe down to adjust</string>
<string name="ub_element_slider_select_rating">Select a rating from %1$d (%2$s) to %3$d (%4$s)</string>
<string name="ub_element_required">This field is required</string>
<string name="ub_element_screenshot_delete">Delete Screenshot</string>
<string name="ub_element_screenshot_edit">Change Screenshot</string>
<string name="ub_element_mood_hate">I really don\'t like it!</string>
<string name="ub_element_mood_dislike">I don\'t like it</string>
<string name="ub_element_mood_neutral">I feel neutral</string>
<string name="ub_element_mood_like">I like it!</string>
<string name="ub_element_mood_love">I love it!</string>
<string name="ub_element_mood_one_star">One star</string>
<string name="ub_element_mood_two_star">Two stars</string>
<string name="ub_element_mood_three_star">Three stars</string>
<string name="ub_element_mood_four_star">Four stars</string>
<string name="ub_element_mood_five_star">Five stars</string>
<string name="ub_usabilla_logo">Powered by Usabilla</string>

<string name="ub_take_picture">Take Picture</string>
<string name="ub_screenshot_preview">Screenshot Preview</string>
<string name="ub_menu_add">Add</string>
<string name="ub_menu_undo">Undo</string>
<string name="ub_menu_done">Done</string>

<string name="ub_camera_access_denied">No access to camera</string>
<string name="ub_camera_access_denied_details">Allowing access lets you take photos to add to your feedback.</string>
<string name="ub_camera_access_allow">Allow access to camera</string>

<string name="ub_edit_title">Edit</string>

Accessibility

For Android TalkBack to work properly with our passive feedback form you have to make sure that the Activity (or Fragment) holding it is not considered for TalkBack.

This can be achieved using

view.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS

where view is the ViewGroup you want to exclude from the TalkBack.

When the form is dismissed then you can set it back using

view.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES

Devices with notch

There might be some display issues in devices with a notch, especially if no action bar theme is used.

This can be handled for devices running Android 9 (API Level 28) and above following google guidelines.

Support

If you need help, want to report an issue, or have a question please reach out to the support team via our Help Center or email [email protected]