Skip to main content

Quick Start

Lura Android SDK is a powerful and versatile android media playback library designed to simplify the process of incorporating audio and video playback into your android applications. With Lura, developers can easily integrate media playback into their applications, providing users with a seamless, immersive playback experience. The library is packed with every feature a developer might need, from fine-tuned playback controls, playlist management, HLS & DASH support to advanced playback features such as Content Protection (DRM), Advertisement Integration and more. Lura also provides extensive documentation and support, making it an ideal choice for developers of all levels of expertise.

info

Android documentation targets Android / Android TV / Fire TV.

Environment Setup

1. Install Android Studio

Follow the guide on Installing Android Studio

2. Create a sample app

In order to create a sample app, follow the following steps.

  • Launch the Android Studio.
  • File > New > New Project
  • Select Empty Views Activity template and click 'Next' button
  • Fill the following fields and click 'Finish' button:
    • Name: LuraPlayerTest
    • Package Name: com.akta.luraplayertest
    • Minimum SDK: 21 or higher
info

LuraPlayer is supporting minimum SDK level 21

Import the SDK & Add Dependencies

  • Download the latest version of Lura Player .aar files from the developer portal.
  • Contact with the support team to get the Open Measurement SDK as .aar.
  • Move the .aar files to project/app/libs/ folder in your Android Studio project.
build.gradle
android {
...

defaultConfig {
...
minSdk = 21 // Or higher
}
}

dependencies {

// Import all .aar files from 'libs' folder
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))

// Kotlin
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.23")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.20")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")

// ExoPlayer dependency
implementation("androidx.media3:media3-exoplayer:1.3.1")
implementation("androidx.media3:media3-ui:1.3.1")

// DASH dependency
implementation("androidx.media3:media3-exoplayer-dash:1.3.1")

// HLS dependency
implementation("androidx.media3:media3-exoplayer-hls:1.3.1")

// SmoothStreaming dependency (Optional)
implementation("androidx.media3:media3-exoplayer-smoothstreaming:1.3.1")

// IMA dependency (Optional)
implementation("androidx.media3:media3-exoplayer-ima:1.3.1")

// Other dependencies
implementation("androidx.mediarouter:mediarouter:1.7.0")

...
}

Create LuraPlayer

In order to use the LuraPlayer and LuraPlayerControls, include LuraPlayerView and LuraPlayerControls in your layout:

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<!--
Base view for LuraPlayer. This must be implemented in order to get a playback
Available in 'LuraPlayer.aar'
-->
<com.akta.luraplayer.api.ui.LuraPlayerView
android:id="@+id/lura_player_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<!--
Optional controls view for LuraPlayer.
Available in 'LuraPlayerControls.aar'
-->
<com.akta.luraplayercontrols.ui.LuraPlayerControls
android:id="@+id/lura_player_controls_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/lura_player_view"
app:layout_constraintEnd_toEndOf="@id/lura_player_view"
app:layout_constraintStart_toStartOf="@id/lura_player_view"
app:layout_constraintTop_toTopOf="@id/lura_player_view" />

</androidx.constraintlayout.widget.ConstraintLayout>

Prepare MainActivity:

MainActivity.kt
package com.akta.luraplayertest

import android.annotation.SuppressLint
import android.app.PictureInPictureParams
import android.content.pm.ActivityInfo
import android.graphics.Rect
import android.os.Build
import android.os.Bundle
import android.util.Rational
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.akta.luraplayer.api.LuraEventListener
import com.akta.luraplayer.api.LuraPlayer
import com.akta.luraplayer.api.configs.Lura
import com.akta.luraplayer.api.configs.LuraConfiguration
import com.akta.luraplayer.api.enums.LuraScreenState
import com.akta.luraplayer.api.event.LuraEventData
import com.akta.luraplayer.api.ui.LuraPlayerView
import com.akta.luraplayercontrols.ui.LuraPlayerControls
import kotlinx.coroutines.Dispatchers

class MainActivity : AppCompatActivity() {

private lateinit var rootLayout: ConstraintLayout
private lateinit var playerView: LuraPlayerView
private lateinit var playerControlsView: LuraPlayerControls

private var player: LuraPlayer? = null
private val listener: LuraEventListener = LuraEventListener { event ->
when (val data = event.data) {

// Listen the ScreenState event from player to set UI mode
is LuraEventData.ScreenState -> {
setPlayerState(data.state)
}

else -> {}
}
}

private var isInPictureInPicture: Boolean = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Get view references
rootLayout = findViewById(R.id.root_layout)
playerView = findViewById(R.id.lura_player_view)
playerControlsView = findViewById(R.id.lura_player_controls_view)

// Initialize LuraPlayer
player = LuraPlayer(context = this, playerView = playerView)

// Connect the control with the Lura Player
playerControlsView.addPlayer(player)
player?.friendlyViews = listOf(playerControlsView)

// This is for adding listener to the main thread.
// If you want to listen the events on IO thread, change the dispatcher to `Dispatchers.IO`
player?.addListener(dispatcher = Dispatchers.Main, listener = listener)

addOnPictureInPictureModeChangedListener {
it?.let {
isInPictureInPicture = it.isInPictureInPictureMode

// Show-Hide controls
playerControlsView.useControls(!isInPictureInPicture)
}
}

// Simplified LuraConfiguration
val luraConfiguration = LuraConfiguration(
lura = Lura(
appKey = "PqSpQb9pFu1A_v4qrMnRNwcXJGoFMO0B02BwGBQ4Zwa0_uMdXPXrqjnlSbJbkv8duDNk2-c3JbOXq2auBscWP1GyvlWlgFcIzaO6QFG74nY",
assetId = "5179678"
)
)

// Entry point for core SDK
player?.setConfig(luraConfiguration)
}

@SuppressLint("SourceLockedOrientationActivity")
private fun setPlayerState(state: LuraScreenState) {
if (state == LuraScreenState.PICTURE_IN_PICTURE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
enterPictureInPicture()
}
return
}

ConstraintSet().apply {
clone(rootLayout)

if (state == LuraScreenState.WINDOWED) {
clear(playerView.id, ConstraintSet.BOTTOM)
setDimensionRatio(playerView.id, "16:9")
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setActionAndSystemBars(true)
} else if (state == LuraScreenState.FULLSCREEN) {
setDimensionRatio(playerView.id, null)
connect(
playerView.id,
ConstraintSet.BOTTOM,
rootLayout.id,
ConstraintSet.BOTTOM
)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
setActionAndSystemBars(false)
}

applyTo(rootLayout)
}
}

@RequiresApi(Build.VERSION_CODES.O)
private fun enterPictureInPicture() {
isInPictureInPicture = enterPictureInPictureMode(getPictureInPictureParams())
}

@RequiresApi(Build.VERSION_CODES.O)
private fun getPictureInPictureParams(): PictureInPictureParams {
val visibleRect = Rect()
playerView.getGlobalVisibleRect(visibleRect)
var rational = Rational(playerView.width, playerView.height)
// Maximum allowed aspect ratio is 2.39, (239 / 100 = 2.39)
if (rational.numerator.toFloat() / rational.denominator > 2.39) {
rational = Rational(16, 9)
}
val params = PictureInPictureParams.Builder()
.setAspectRatio(rational)
.setSourceRectHint(visibleRect)
.build()
return params
}

// Lifecycle method
override fun onResume() {
super.onResume()
player?.onResume()
}

// Lifecycle method
override fun onPause() {
if (!isInPictureInPicture)
player?.onPause()
super.onPause()
}

// Lifecycle method
override fun onStop() {
if (isInPictureInPicture)
player?.onPause()
super.onStop()
}

// Lifecycle method
override fun onDestroy() {
player?.removeListener(listener = listener)
player?.destroy()
super.onDestroy()
}

// Fullscreen helper method
private fun setActionAndSystemBars(show: Boolean) {
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

if (show) {
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
supportActionBar?.show()
} else {
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
supportActionBar?.hide()
}
}
}

Prepare Manifest:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LuraPlayerTest"
tools:targetApi="34">
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
android:supportsPictureInPicture="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

You are ready to go!