Android Setup

Hub

Requires SDK 4.13.0 or later

The Hub (previously known as the Communication Hub) is an embeddable app area that includes an inbox of posts and other features. It is intended to be embedded within a tab bar item in the app, and includes support for badging the tab bar item when new content is available.

Hub

This feature is distinct from the legacy "Inbox" feature. The legacy Inbox (InboxActivity et al) is deprecated and will be removed in a future release.

Configuration Change

The title and accentColor parameters were previously documented here. These are now configured server-side, so remove them from your client code.


Jetpack Compose

To embed the Hub composable as a new tab in a typical Jetpack Compose Navigation Bar, use a NavigationBarItem:

import io.rover.sdk.notifications.communicationhub.ui.Hub

enum class SelectedTab {
    /* ... other tab definitions ... */
    RoverHub,
}

@Composable
fun MyApp() {
    var selectedTab: SelectedTab by remember { mutableStateOf(SelectedTab.RoverHub) }

    MaterialTheme(
        // ... ensure a Material 3 theme is configured in your app ...
    ) {
        Scaffold(
            modifier = Modifier.fillMaxSize(),
            bottomBar = {
                NavigationBar() {
                    /* ... other tab button items ... */
                    NavigationBarItem(
                        selected = selectedTab == SelectedTab.RoverHub,
                        icon = {
                            // observe the Rover badge count
                            val badgeText by Rover.shared.roverBadge.newBadge.collectAsState()

                            // use a BadgedBox to display the badge if it is non-null
                            BadgedBox(
                                badge = {
                                    badgeText?.let { text ->
                                        Badge { Text(text) }
                                    }
                                }
                            ) {
                                // Use an "Inbox" filled icon from Google's Material Icons. You will need to do the standard Google procedure for adding the Material icon to your app. https://fonts.google.com/
                                Icon(painter = painterResource(id = R.drawable.inboxfilled48), contentDescription = "For You", modifier = Modifier.size(24.dp))
                            }
                        },
                        label = {
                            Text("For You", maxLines = 1)
                        },
                        onClick = {
                            selectedTab = SelectedTab.RoverHub
                        }
                    )
                }
            }
        ) {
            when (selectedTab) {
                /* ... other tab content ... */
                SelectedTab.RoverHub -> {
                    Hub(
                        // any custom jetpack compose modifiers:
                        modifier = Modifier
                    )
                }
        }
    }
}

Theme configuration for WebView in Dark Mode

Even though the Rover Hub uses Jetpack Compose, Android WebView will only honour dark mode if you have a values-night theme (as used by classic Android views) configured with the isLight property set to false. If you don't do this, posts in the Hub will not be displayed in dark mode.

Ensure you have a values-night/themes.xml file in your app with the following content:

<item name="android:isLightTheme">false</item>

App Icon Badging

Unlike iOS, Android does not support automatic app icon badging due to platform limitations and the way Android app badges work. The badge count functionality shown in the examples above only applies to in-app UI elements like tab bars and navigation items, not the app icon itself.

Compose Theme & Accent Color Configuration

When embedded in a tab, the Hub composable will adopt whatever Material 3 theme it is wrapped in (particularly for tinting controls like hyperlinks with the primary/accent color), just as other composables do. By wrapping a Material 3 Jetpack Compose theme around your Compose UI content, this will happen automatically for an embedded Hub.

However, when the Hub is launched from a deep link, this theme provided by UI context is not available. Therefore, in order for the Hub UI to be properly styled, Material 3 color schemes need to be supplied globally to Rover for it to use when it launches a standalone activity with the Hub composable.

Typically, as part of your Material 3 Theme, you will have defined a lightScheme and darkScheme in your app.

You can set these to Rover's global lightColorScheme and darkColorScheme properties to ensure that the Hub is presented in the correct theme when launched from a deep link:

Rover.shared.lightColorScheme = lightScheme
Rover.shared.darkColorScheme = darkScheme

Classic Android Views

To use the Hub in a classic Android Views app with an MDC BottomNavigationView, and display a badge count on the Hub tab, perform the following steps.

  1. Create a Fragment to host the Hub composable:
import io.rover.sdk.notifications.communicationhub.ui.Hub

class HubFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Use ComposeView to host the Hub composable
        return ComposeView(requireContext()).apply {
            setContent {
                // configure a Material 3 theme as you would normally do here. Rover's Hub will adopt it, particularly for the primary (or accent) color.
                MaterialTheme {
                    Hub(
                        // any custom jetpack compose modifiers:
                        modifier = Modifier
                    )
                }
            }
        }
    }
}
  1. In your Activity, set up the BottomNavigationView and observe the badge count:
class MainActivity : AppCompatActivity() {

    private var badgeJob: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main) // Your layout with a FrameLayout and BottomNavigationView

        // Set initial fragment
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
            // where "HomeFragment" is the view for your default tab
                .replace(R.id.fragment_container, HomeFragment())
                .commit()
        }

        val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)

        // Set up badge for Hub tab
        val hubMenuItemId = R.id.tab_hub

        // Observe badge count using a coroutine
        badgeJob = lifecycleScope.launch {
            // Import kotlinx.coroutines.flow.collectLatest
            io.rover.sdk.core.Rover.shared.roverBadge.newBadge.collect { badgeText ->
                val badge = bottomNav.getOrCreateBadge(hubMenuItemId)
                if (badgeText.isNullOrEmpty() || badgeText == "0") {
                    // Remove badge if no unread
                    bottomNav.removeBadge(hubMenuItemId)
                } else {
                    badge.isVisible = true
                    badge.number = badgeText.toIntOrNull() ?: 0
                }
            }
        }

        bottomNav.setOnItemSelectedListener { item ->
            when (item.itemId) {
                /* ... other tab views ... */
                R.id.tab_hub -> {
                    supportFragmentManager.beginTransaction()
                        .replace(R.id.fragment_container, HubFragment())
                        .commit()
                    true
                }
                // ... handle other tabs ...
                else -> false
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        badgeJob?.cancel()
    }
}
  1. In your res/layout/activity_main.xml, you should have something like:
<LinearLayout ... >
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        ... />
</LinearLayout>
  1. In your res/menu/bottom_nav_menu.xml, define the menu items:
<menu>
    <item
        android:id="@+id/tab_home"
        android:icon="@drawable/ic_home"
        android:title="Home"/>
    <item
        android:id="@+id/tab_hub"
        android:icon="@drawable/ic_inbox"
        android:title="For You"/>
    <!-- ... other tabs ... -->
</menu>

This approach allows you to use the Hub composable in a classic Android Views app with a BottomNavigationView, and display a badge count on the Hub tab that updates automatically.

Previous
Push Notifications