Skip to main content

Jetpack Compose

Intro

OBComposeViewWidget and OBComposeColumnWidget are a new solution provided by Outbrain to integrate our Web-based solution for SmartLogic / Smartfeed in a native Android app built with Jetpack Compose.

The general concept for integrating Outbrain Web-based solution in Android Compose app - is to include AndroidView with a OBComposeWidget/OBComposeColumnWidget which encapsulates the WebView which in turn loads the SmartLogic feed in a Web format with a native bridge to pass messages from\to native code.

SFWebViewWidget is a sub-class of RelativeLayout.

Integration instructions

You will need to register your app's Outbrain configuration once during the initialization of your app, before calling any other Outbrain method. You can do this by calling Outbrain's register() method.

info

Please make sure to follow the Getting Started guidelines before moving forward. Specifically make sure to call Outbrain.register() method.

Compose Plugin Dependency

info

Starting Android SDK v4.32.0, the compose plugin is included in the SDK. Before this version, developers needed to include the plugin as a separate dependency.

Optional - for tracking events

See more details at the bottom of this page.

implementation "com.squareup:otto:1.3.8"

LazyColumn Integration

1. Import the OBComposeWidget class:

import com.outbrain.OBSDK.Compose.OBComposeWidget

2. Create lazy list state and local context variables:

val context = LocalContext.current
val listState = rememberLazyListState()

3. Use the OBComposeWidget class with remember method to make sure no recomposition would occur on scroll:

val widget = remember {
OBComposeWidget(
context = context,
url = "http://mobile-demo.outbrain.com", // article url
widgetID = "MB_2",
widgetIndex = 0, // (default is 0) - should be set only if there are 2 widgets on the same page)
installationKey = "NANOWDGT01",
sfWebViewClickListener = null,
darkMode = false, // (default is "false")
listState = listState,
itemIndex = 7
)
}

4. Create NestedScrollConnection object to pass scroll events to the widget:

val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
widget.onScroll()
return Offset.Zero
}
}
}

5. Create the LazyColumn with the defined listState and add the nestedScroll() modifier:

LazyColumn(
state = listState,
modifier = Modifier
.fillMaxHeight()
.nestedScroll(nestedScrollConnection)
.padding(top = 8.dp)
)

6. Add an AndroidView with the widget as item:

item { // Outbrain widget
AndroidView(
factory = { widget },
modifier = Modifier.fillMaxWidth()
)
}

Optional – Tracking events

In your Activity onCreate() – register to Outbrain OttoBus event via:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
OutbrainBusProvider.getInstance().register(this)
.....
}

In the Activity implement the @subscribe for the following 2 methods:

@Subscribe
fun onOutbrainRecReceived(event: OutbrainBusProvider.BridgeRecsReceivedEvent) {
println("Received event onOutbrainRecReceived: ${event.widgetID}")
}

@Subscribe
fun receivedHeightChangeEvent(event: OutbrainBusProvider.HeightChangeEvent) {
println("Received event HeightChange: ${event.height}")
}

Column Integration

1. Import the OBComposeColumnWidget class:

import com.outbrain.OBSDK.Compose.OBComposeColumnWidget

2. Create scroll state and local context variables:

val context = LocalContext.current
val scrollState = rememberScrollState()

3. Use the OBComposeColumnWidget class with remember method to make sure no recomposition would occur on scroll:

val widget = remember {
OBComposeColumnWidget(
context = context,
url = "http://mobile-demo.outbrain.com", // article url
widgetID = "MB_1",
widgetIndex = 0, // (default is 0) - should be set only if there are 2 widgets on the same page)
installationKey = "NANOWDGT01",
sfWebViewClickListener = {
onRecClick() // Implement organic recommendation click or pass an `SFWebViewClickListener`
},
darkMode = false, // (default is "false")
scrollState = scrollState,
)
}

4. Add scroll state to the Column:

Column(
modifier = Modifier
.verticalScroll(scrollState)
.fillMaxHeight()
) {
...
}

5. Add an AndroidView with the widget and add the onGloballyPositioned modifier in order to track scroll events:

    AndroidView(
factory = { widget },
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
widget.onScroll(coordinates.size, coordinates.positionInParent().y)
})

Full example:

    val context = LocalContext.current
val scrollState = rememberScrollState()

val widget = remember {
OBComposeColumnWidget(
context = context,
url = "http://mobile-demo.outbrain.com", // article url
widgetID = "MB_1",
widgetIndex = 0, // (default is 0) - should be set only if there are 2 widgets on the same page)
installationKey = "NANOWDGT01",
sfWebViewClickListener = {
onRecClick() // Implement organic recommendation click or pass an `SFWebViewClickListener`
},
darkMode = false, // (default is "false")
scrollState = scrollState,
)
}

Column(
modifier = modifier
.verticalScroll(scrollState)
.fillMaxHeight()
) {
ArticleHeader()

ArticleContent(
text = stringResource(id = R.string.article_txt_1),
modifier = Modifier
.fillMaxHeight()
.padding(top = 24.dp)
.padding(horizontal = 10.dp)
)

AndroidView(
factory = { widget },
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
widget.onScroll(coordinates.size, coordinates.positionInParent().y)
})
}