Quickstart in Android Kotlin

Integrate the ARwayKit SDK with Android Kotlin

In this quickstart guide, we will be integrating the ARwayKit SDK with Android Kotlin. This example will be using Unity as a Library to integrate into an Android app.

Installed Versions

In this guide, we will be using the following versions:

  • Android Studio: 2022.1.1

  • Unity: 2022.3.17f1 LST

  • Android Min API Level 24

Download the ARwayKit SDK

Steps

  1. Download the ARwayKit SDK project from GitHub as a ZIP. You can contact us for access to the ARwayKit SDK.

Create a Basic Project in Android Studio

Create a new sample Android Project, for this example a new project using the Empty Activity template will be used with the language set to Kotlin and the minimum SDK set to API 24.

Generate the Gradle Project for the Android Platform

Make sure to add the Account ID and Secret Key variables to the Unity project. Follow the guide for Building from the Source Code for instructions.

Steps

  1. In Unity select File -> Build Settings.

  2. Switch the Platform to Android.

  3. Select option "Export Project".

  4. Export the ARwayKit Unity SDK to a new folder and name it "androidBuild" and place it in the base directory for the Android Kotlin project.

Updating the Addressables Groups

When opening the project in Unity for the first time, you will need to build the Addressables Groups.

  1. Switch the build platform to either iOS or Android

    • "File-> Build Settings..." then select the Android or iOS as the Platform.

  2. Click "Switch Platform" on the bottom right.

  3. Navigate to "Window -> Asset Management -> Addressable -> Groups".

  4. In the Addressables Groups window, click on "Build -> New Build -> Default Build Script".

  5. In the Console window, you should see the success message "Addressable content successfully built".

When making any changes that affect localization strings, you will need to update the Addressables Groups.

Add the Unity Android Build to the Android App

Steps

  1. Open the Android sample app in Android Studio.

  2. Open the settings.gradle file and make the following changes to the code as shown below. Ensure that the line 'androidBuild\\unityLibrary' matches the path to the ARwayKit Unity SDK export.

    + include ':unityLibrary'
    + project(':unityLibrary').projectDir=new File('androidBuild\\unityLibrary')
    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
    +       flatDir {
    +            dirs "${project(':unityLibrary').projectDir}/libs"
    +       }
        }
    }
  3. Open build.gradle(Module: app) file, then add the following in the dependencies block.

    dependencies {
    ...
    +    implementation project(':unityLibrary')
    +    implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])
    }
  4. Open gradle.properties and add the code below to the end of the file.

    + unityStreamingAssets=.unity3d
  5. Add the ndk.dir to the end of the local.properties file, this should match the location of the Unity Editor.

    + ndk.dir=C\:\\Program Files\\Unity\\Hub\\Editor\\2022.3.17f1\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\NDK
  6. You will be notified that changes have been made to the grade files, click the 'Sync Now' button to continue.

  7. If everything succeeds you should be able to see the unityLibrary module added in the Android view.

Preparing the Sample Project

To run the ARwayKit Unity SDK on Android, we need to integrate Unity as a library in our Android project. This will allow us to use the Unity engine within our app and run Unity scenes alongside native Android activities. In this section, we will go through the steps to set up Unity as a library and add the ARwayKit Unity SDK to the project.

  1. For this we will be creating a new blank Activity in the project called MainUnityActiviy.kt. You do not need to generate a new layout file.

MainUnityActiviy
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.FrameLayout
import com.unity3d.player.UnityPlayerActivity;

open class MainUnityActivity : UnityPlayerActivity() {
    private var instance: MainUnityActivity? = null

    // Setup activity layout
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        instance = this;
        addControlsToUnityFrame()
        val intent: Intent = intent
        handleIntent(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
        instance = null
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        handleIntent(intent)
        setIntent(intent)
    }

    private fun handleIntent(intent: Intent?) {
        if (intent == null || intent.extras == null) return
        if (intent.extras!!.containsKey("doQuit")) if (mUnityPlayer != null) {
            finish()
        }
    }

    private fun showMainActivity() {
        val intent: Intent = Intent(this, MainActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP
        startActivity(intent)
    }

    override fun onUnityPlayerUnloaded() {
        showMainActivity()
    }

    private fun addControlsToUnityFrame() {
        val layout: FrameLayout = mUnityPlayer
        run {
            val myButton = Button(this)
            myButton.text = "Show Main"
            myButton.x = 10f
            myButton.y = 500f
            myButton.setOnClickListener { showMainActivity() }
            layout.addView(myButton, 300, 200)
        }

        run {
            val myButton = Button(this)
            myButton.text = "Unload"
            myButton.x = 630f
            myButton.y = 500f
            myButton.setOnClickListener { mUnityPlayer.unload() }
            layout.addView(myButton, 300, 200)
        }
    }
}

In the above file, the addControlsToUnityFrame() method sets the positions of the buttons added to the layout. These buttons are not required but showcase the methods to unload the Unity player.

To pass data to Unity, you can call the following method:

mUnityPlayer.UnitySendMessage("<GameObject>", "<Method>",<string value>);
  1. The MainActivity.kt file will be modified to add a button to load the activity above. The code below shows the end result.

MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {
    private var isUnityLoaded = false

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

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        handleIntent(intent)
        setIntent(intent)
    }

    private fun handleIntent(intent: Intent?) {
        if (intent?.extras == null) return
    }

    fun btnLoadUnity(v: View?) {
        isUnityLoaded = true
        val intent = Intent(this, MainUnityActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
        startActivityForResult(intent, 1)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1) isUnityLoaded = false
    }

    private fun unloadUnity(doShowToast: Boolean) {
        if (isUnityLoaded) {
            val intent = Intent(this, MainUnityActivity::class.java)
            intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
            intent.putExtra("doQuit", true)
            startActivity(intent)
            isUnityLoaded = false
        } else if (doShowToast) showToast("Show Unity First")
    }

    fun btnUnloadUnity(v: View?) {
        unloadUnity(true)
    }

    private fun showToast(message: String) {
        val text: CharSequence = message
        val duration = Toast.LENGTH_SHORT
        val toast = Toast.makeText(applicationContext, text, duration)
        toast.show()
    }

    override fun onBackPressed() {
        finishAffinity()
    }
}
  1. Next, create a new layout resource file under src/main/res/layout called content_main.xml. This adds the buttons to open the Unity activity and close the app.

content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="36dp"
        android:onClick="btnLoadUnity"
        android:text="Show Unity"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:onClick="btnUnloadUnity"
        android:text="Finish"
        app:layout_constraintStart_toEndOf="@+id/button"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Modify the layout code of the default file activity_main.xml to load the content_main.xml file from above.

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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <include layout="@layout/content_main" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. Then add a new string resource with the name game_view_content_descriptionand the content Game view in the strings.xml file.

<resources>
+    <string name="game_view_content_description">Game view</string>
</resources>

Once you have completed all the necessary steps to integrate the ARwayKit Unity SDK into your Android Kotlin project, you are ready to build, run, and debug your app. If everything has been properly configured, you should be able to run the app seamlessly with the ARwayKit Unity SDK.

Unity will run in another process android:process=":Unity" (AndroidManifest.xml at app module).

Additional information about integrating Unity as a library into a standard Android app can be found in the following links:

https://github.com/Unity-Technologies/uaal-example/blob/uaal-example/19LTS-21LTS/docs/android.md

https://docs.unity3d.com/2019.3/Documentation/Manual/UnityasaLibrary.html

Last updated