Development record of developer who study hard everyday.

, , , , ,

How to use UnityPlayer in Android Compose

How to use UnityPlayer in Android Compose

Android Development blog

In my company, I have to use 3D avatar animation using UnityPlayer derived from Unity module.

The base code I will use is consist of Android Compose.

So, I want to use UnityPlayer with Android Compose.

However, There were no information about using UnityPlayer with Compose.

This is why I write this post.


☝I introduce this post on the condition that you add UnityModule.

If you not, read this post first!!

https://antwhale94.blogspot.com/2024/03/AddingUnityModuleToAndroid.html


1. Add dependency

android {
...
buildFeatures {
viewBinding true
}     ...
}

dependencies {

implementation 'androidx.compose.ui:ui-viewbinding:1.6.0'

}

You should add viewBinding dependency.

And you should add "androidx.compose.ui:ui-viewbinding" to take xml into Compose.


2.  MainActivity.kt

class MainActivity : ComponentActivity() {
val TAG = MainActivity::class.java.simpleName
lateinit var mUnityPlayer: UnityPlayer

@ExperimentalMaterial3Api
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

mUnityPlayer = UnityPlayer(this)
val glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1)
val trueColor8888 = false
mUnityPlayer.init(glesMode, trueColor8888)

setContent {
Surface(
modifier = Modifier
.fillMaxSize()
) {
MLCChatTheme {
NavView()
}
}
}


}

override fun onDestroy() {
Log.d(TAG, "onDestroy: ")
super.onDestroy()

mUnityPlayer.quit()
}

override fun onPause() {
Log.d(TAG, "onPause: ")
super.onPause()
mUnityPlayer.pause()
}

override fun onResume() {
Log.d(TAG, "onResume: ")
super.onResume()
mUnityPlayer.resume()
}

override fun onLowMemory() {
Log.d(TAG, "onLowMemory: ")
super.onLowMemory()
mUnityPlayer.lowMemory()
}

override fun onTrimMemory(level: Int) {
Log.d(TAG, "onTrimMemory: ")
super.onTrimMemory(level)
if(level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL)
mUnityPlayer.lowMemory()
}

override fun onConfigurationChanged(newConfig: Configuration) {
Log.d(TAG, "onConfigurationChanged: ")
super.onConfigurationChanged(newConfig)
mUnityPlayer.configurationChanged(newConfig)
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
Log.d(TAG, "onWindowFocusChanged: $hasFocus")
super.onWindowFocusChanged(hasFocus)
mUnityPlayer.windowFocusChanged(hasFocus)
}

}

fun Context.getActivity(): ComponentActivity? = when (this) {
is ComponentActivity -> this
is ContextWrapper -> baseContext.getActivity()
else -> null
}

In my experience, The UnityPlayer derived from activity only can play animation.

I don't know why, so I make UnityPlayer object in MainActivity using MainActivity context.

The lowest function getActivity is used to get MainActivity from Composable function.


3. xml layout to put UnityPlayer

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frameLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

</FrameLayout>

This layout file's name is "avatar_view_layout.xml"

Obviously, you can change this file name if you want.


4. Composable function to show UnityPlayer

@Composable
fun AvatarView() {
val TAG = "AvatarView"
val localContext = LocalContext.current

Log.d(TAG, "AvatarView composition")

val unityPlayer = (localContext.getActivity() as MainActivity).mUnityPlayer    //1
AndroidViewBinding(AvatarViewLayoutBinding::inflate) {     //2
if(unityPlayer.parent == null) {
Log.d(TAG,
"AvatarView added")
frameLayout.addView(unityPlayer.view)        //3
unityPlayer.resume()
}
}

DisposableEffect(key1 = localContext) {
onDispose {        //4
Log.d(TAG, "remove AvatarView")
(unityPlayer.
parent as FrameLayout).removeView(unityPlayer.view)

unityPlayer.pause()

}
}
}

1 => Get UnityPlayer object using local context

2 => AndroidViewBinding to use xml in Compose

3 => Add UnityPlayer to FrameLayout and resume UnityPlayer

4 => DisposableEffect to notice when AvatarView composable leave.

You should remove UnityPlayer from framelayout and pause it to restart when recomposing.


I don't know this is good way to use UnityPlayer with Compose, but This is only way I got this.




Share:

댓글 없음:

댓글 쓰기