Skip to content

Android Integration

The Android integration is a WebView-based implementation that loads Hubble’s gift card store. This guide shows you how to integrate Hubble into your Android app using a standard WebView.

Basic Setup

At its core, integrating Hubble is straightforward - it’s a WebView loading a URL with your credentials:

val webView = WebView(context).apply {
settings.javaScriptEnabled = true
}
val clientId = "your_client_id" // provided by Hubble team
val clientSecret = "your_client_secret" // provided by Hubble team
val token = "your_user_token" // unique identifier for your user
val env = "dev" // "dev" or "prod"
val baseUrl = if (env == "prod") "vouchers.myhubble.money" else "vouchers.dev.myhubble.money"
webView.loadUrl("https://$baseUrl/classic?clientId=$clientId&clientSecret=$clientSecret&token=$token&wrap-plt=an")

This basic setup will display the Hubble store. For a production-ready integration, you’ll want to add the following features:

Additional Setup

1. Back Navigation

Handle back button presses to navigate within the WebView:

fun goBack(): Boolean {
return if (webView.canGoBack()) {
webView.goBack()
true
} else {
false
}
}
// In your Activity
override fun onBackPressed() {
if (!goBack()) {
super.onBackPressed()
}
}

2. Analytics Events

Receive analytics events from the WebView using JavaScript interface:

import android.util.Log
import android.webkit.JavascriptInterface
import org.json.JSONException
import org.json.JSONObject
class HubbleJavaScriptInterface {
@JavascriptInterface
fun onAnalyticsEvent(eventName: String, properties: String?) {
val propertiesMap = if (properties != null) {
parseJsonProperties(properties)
} else {
null
}
// Send to your analytics provider
Log.d("HubbleAnalytics", "Event: $eventName, Properties: $propertiesMap")
}
private fun parseJsonProperties(properties: String): Map<String, Any> {
return try {
val jsonObject = JSONObject(properties)
val map: MutableMap<String, Any> = HashMap()
val iterator = jsonObject.keys()
while (iterator.hasNext()) {
val key = iterator.next()
map[key] = jsonObject[key]
}
map
} catch (e: JSONException) {
Log.e("HubbleAnalytics", "Failed to parse: ${e.message}")
emptyMap()
}
}
}
// Add to WebView
webView.addJavascriptInterface(HubbleJavaScriptInterface(), "AndroidHost")

3. URL Handling

Control which URLs open within the WebView vs external browser:

import android.content.Intent
import android.webkit.WebViewClient
import android.webkit.WebResourceRequest
class HubbleWebViewClient : WebViewClient() {
private val baseUrl = "vouchers.dev.myhubble.money" // or "vouchers.myhubble.money" for prod
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
val url = request?.url?.toString()
return if (url?.contains(baseUrl) == true) {
false // Allow navigation within Hubble
} else {
// Open external URLs in browser
try {
val intent = Intent(Intent.ACTION_VIEW, request?.url)
view?.context?.startActivity(intent)
true
} catch (e: Exception) {
false
}
}
}
}
// Set the WebViewClient
webView.webViewClient = HubbleWebViewClient()

4. Additional WebView Settings

For optimal performance, configure these settings:

webView.apply {
settings.javaScriptEnabled = true
settings.javaScriptCanOpenWindowsAutomatically = true
settings.databaseEnabled = true
settings.domStorageEnabled = true
settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
settings.setSupportZoom(false)
settings.builtInZoomControls = false
settings.displayZoomControls = false
}

Complete Example

Here’s a complete fragment implementation combining all the above features:

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.fragment.app.Fragment
import org.json.JSONException
import org.json.JSONObject
class HubbleWebViewFragment : Fragment() {
private lateinit var webView: WebView
private val clientId = "your_client_id"
private val clientSecret = "your_client_secret"
private val token = "your_user_token"
private val env = "dev" // "dev" or "prod"
private val baseUrl: String
get() = if (env == "prod") "vouchers.myhubble.money" else "vouchers.dev.myhubble.money"
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
webView = WebView(requireContext()).apply {
id = View.generateViewId()
settings.apply {
javaScriptEnabled = true
javaScriptCanOpenWindowsAutomatically = true
databaseEnabled = true
domStorageEnabled = true
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
setSupportZoom(false)
builtInZoomControls = false
displayZoomControls = false
}
addJavascriptInterface(HubbleJavaScriptInterface(this@HubbleWebViewFragment), "AndroidHost")
webViewClient = HubbleWebViewClient(baseUrl, requireContext())
val url = "https://$baseUrl/classic?clientId=$clientId&clientSecret=$clientSecret&token=$token&wrap-plt=an"
loadUrl(url)
}
return webView
}
fun goBack(): Boolean {
return if (webView.canGoBack()) {
webView.goBack()
true
} else {
false
}
}
fun reload() {
webView.reload()
}
}
class HubbleJavaScriptInterface(private val fragment: HubbleWebViewFragment) {
@JavascriptInterface
fun close() {
fragment.activity?.finish()
}
@JavascriptInterface
fun reload() {
fragment.reload()
}
@JavascriptInterface
fun onAnalyticsEvent(eventName: String, properties: String?) {
val propertiesMap = properties?.let { parseJsonProperties(it) }
Log.d("HubbleAnalytics", "Event: $eventName, Properties: $propertiesMap")
// Send to your analytics provider here
}
private fun parseJsonProperties(properties: String): Map<String, Any> {
return try {
val jsonObject = JSONObject(properties)
val map: MutableMap<String, Any> = HashMap()
jsonObject.keys().forEach { key ->
map[key] = jsonObject[key]
}
map
} catch (e: JSONException) {
Log.e("HubbleAnalytics", "Failed to parse: ${e.message}")
emptyMap()
}
}
}
class HubbleWebViewClient(
private val baseUrl: String,
private val context: Context
) : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
val url = request?.url?.toString()
return if (url?.contains(baseUrl) == true) {
false // Allow navigation within Hubble
} else {
try {
val intent = Intent(Intent.ACTION_VIEW, request?.url)
context.startActivity(intent)
true
} catch (e: Exception) {
false
}
}
}
}

Example Usage in Activity

import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private lateinit var hubbleFragment: HubbleWebViewFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
hubbleFragment = HubbleWebViewFragment()
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, hubbleFragment)
.commit()
}
override fun onBackPressed() {
if (!hubbleFragment.goBack()) {
super.onBackPressed()
}
}
}

Configuration Options

You can customize the integration by modifying the URL parameters:

  • Environment: Set env to "prod" for production or "dev" for development
  • Initial Page: Add &page=<page_name> to open a specific page

For detailed information about supported pages and parameters, refer to our Deeplinks documentation.


Legacy: Android SDK (Deprecated)

⚠️ Deprecation Notice: The Hubble Android SDK is deprecated and no longer recommended for new integrations. Please use the WebView integration documented above. Existing integrations using the SDK will continue to work, but we recommend migrating to the WebView approach for better control and maintainability.

The Android SDK was a lightweight Android library around our web application. If you’re currently using it, here’s the reference documentation:

Setup

  1. Add Jitpack repository to your project’s Gradle file:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
  1. Add the dependency:
dependencies {
implementation ("money.myhubble:storesdk:0.0.3")
}
  1. Initialize the SDK:
Hubble.init(
env="dev", // If not given, will default to 'prod'
token="GOpBKIQ0xj", // Some token or ID that uniquely identifies your user
clientId= "clientA", // will be provided by Hubble team
clientSecret= "clientSecretA", // will be provided by Hubble team
)
  1. Open the store:
Hubble.open(context = context)

SDK Features

Fragments:

hubbleFragment = Hubble.getFragment()
hubbleFragment.goBack() // returns true/false

Events:

Hubble.init(
...
onAnalyticsEvent = { eventName: String, props: Map<String, Any> ->
Log.i(tag, "Received event $eventName from Hubble SDK. ${props}")
}
)

Deeplinks:

Hubble.init(
...
page = HubblePage(
page = "brand",
params = mapOf("brandId" to "uber")
)
)

For migration assistance, please contact the Hubble team.