개요
유니티 강의를 준비하다보니 겪어왔던 모든 유니티 지식들을 쥐어짜는 중인데,
어쩌면 깊으면서도 현시대에 유니티개발자라면 필수적으로 알아야할 안드로이드 AAR에 대해서 알아보고자 한다.
C++이나 C#등 dll 파일을 만드는 것과 비슷한데, 안드로이드스튜디오에서 만드는 패키지라고 할 수 있고
그 목적성은 유니티가 안드로이드 네이티브 기능을 호출하는 것에 있다고 할 수 있다...
물론 유니티에서 기본적으로 지원해주는 것들도 있다.
유니티에서는 AndroidJava 객체를 가지고 있으므로 간단한 토스트 메시지나 더 간단한 진동알림 같은 것은
굳이 AAR이 필요가 없다...지만 권한을 얻어야 하는 것들은 필요하다고 말할 수 있겠다.
일단 구현전에 Toast 메시지의 경우 AAR이 아니더라도 구현할 수 있다.
기본 코드는 다음과 같다.
using UnityEngine;
public class Toast : MonoBehaviour
{
public void ShowToast(string message)
{
#if UNITY_ANDROID && !UNITY_EDITOR
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
// Toast.LENGTH_SHORT = 0
AndroidJavaClass toastClass = new AndroidJavaClass("android.widget.Toast");
activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{
AndroidJavaObject toast = toastClass.CallStatic<AndroidJavaObject>(
"makeText", activity, message, 0);
toast.Call("show");
}));
}
#endif
}
// 버튼용으로 쓸 함수
public void OnClickToastButton()
{
ShowToast("안드로이드 Toast 메시지!");
}
}
위 코드를 쓰면 그냥 안드로이드스튜디오 없이 안드로이드 os 에서 토스트 메시지를 호출 할 수 있다.
하지만 우리는 AAR을 통하여 토스트메시지를 구현하고 나아가서.. 알림메시지를 구현해보고자 한다.
알림메시지는 뭐 간단히 말하면 카톡이 온다던지 문자메시지가 올 때 상단에 뜨는 알림이다.
구현
당연하게도 안드로이드로 일단 플랫폼을 변경해주자.
Player 세팅에 가서 Minimum API Level을 외우고
Scripting Backend를 무엇으로 설정했는지도 필요하다.
난 IL2CPP로 했지만 MONO여도 상관은 없다..
자 그럼 이제 .jar 파일을 찾으러 가야한다.
보통 해당 유니티 버젼을 안드로이드 support으로 같이 설치했다면 JDK 설치된 경로가 있을텐데..
C:\Program Files\Unity\Hub\Editor\6000.0.44f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Development\Classes
나의 경우 위와 같다.
Mono인 사람은 il2CPP 폴더 분기점에서 Mono로 들어가면 된다.
그러면 이렇게 classes.jar 파일이 덩그러니 있다..
일단 이 창을 열어두고 안드로이드 스튜디오를 켠다.
new project로 아무거나 만들어준다. 어차피 모듈로 만들것이기 때문에..
난 Empty Activity로 만들었다.
minimum SDK는 유니티와 같게 맞추어준다.
그러면 이런 프로젝트가 열린다.
루트 프로젝트 클릭한 상태로
File -> New -> New Module 선택한다.
Android Library 로 가고 MinimumSDK확인해준다 언어는
보통 Java를 압도적으로 많이 사용하지만
코틀린이 대세이므로 난 코틀린으로 해주어보겠다.
사실 C# 개발자한테는 Java가 더 어울릴 수도 있겠다는 생각이 들긴한다.
자그럼 모듈이 만들어졌고 여기에 libs 폴더를 하나 만들어주고
아까전에 두었던 classes.jar을 복사 붙여넣기 해준다.
그러고나서 src -> main -> java -> com...(패키지이름) 하위로 코틀린 파일을 하나 만들어준다..
자 그리고 우리가 넣어준 .jar을 사용할 수 있게 해주어야
이 코틀린파일에서 unity를 import할 수 있다..
build.gradle.kts 로 간다. (모듈안의) 그리고
dependencies 안에 컴파일을 넣어준다.
compileOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.fatraccoon.myalarm"
compileSdk = 35
defaultConfig {
minSdk = 26
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
compileOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
그러고나서 sync Now가 상단에 뜰텐데 싱크해준다
이제 스크립트를 적어준다.
package com.fatraccoon.myaarmodule
import android.app.*
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.widget.Toast
import androidx.core.app.NotificationCompat
import com.unity3d.player.UnityPlayer
class MyAARPlugin private constructor() {
companion object {
private var instance: MyAARPlugin? = null
private var context: Activity? = null
private const val CHANNEL_ID = "default_channel"
@JvmStatic
fun instance(): MyAARPlugin {
if (instance == null) {
instance = MyAARPlugin()
context = UnityPlayer.currentActivity
requestNotificationPermission()
createNotificationChannel()
}
return instance!!
}
private fun requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context?.let { ctx ->
if (ctx.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED
) {
ctx.requestPermissions(
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
1001
)
}
}
}
}
private fun createNotificationChannel() {
val channel = NotificationChannel(
CHANNEL_ID,
"Unity Plugin Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = context?.getSystemService(NotificationManager::class.java)
manager?.createNotificationChannel(channel)
}
}
fun showToast(message: String) {
context?.runOnUiThread {
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
}
fun showNotification(title: String, message: String) {
context?.let {
val notificationManager = it.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val builder = NotificationCompat.Builder(it, CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH) // 중요도 높임
.setDefaults(Notification.DEFAULT_ALL) // 사운드 + 진동
.setAutoCancel(true)
notificationManager.notify(System.currentTimeMillis().toInt(), builder.build())
}
}
}
여기서 showToast와 showNotification은 기능 들이고..
이 상단으로 구성되는
private constructor 는 외부에서 생성자로 생성할 수 없게 해주는 것이며
그 하위에 companion object 는 전역변수로 사용할 수 있게끔 해주는 것이다.
즉 전역인스턴스에서 단 하나만 존재하는 싱글톤같은 느낌으로 존재할 수 있다는 것이다.
참고로 여기서 핵심은
@JvmStatic
fun instance(): MyUnityPluginAlarm {
if (instance == null) {
이 부분인데...
@JvmStatic 어노테이션
은 유니티에서 static하게 호출할 수 있다는 뜻이라고 보면된다.
즉 유니티에서 사용할 때는 이 instance를 불러와서 이제 이 스크립트의 함수들을 부르면 된다는 것이다.
private fun requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context?.let { ctx ->
if (ctx.checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED
) {
ctx.requestPermissions(
arrayOf(android.Manifest.permission.POST_NOTIFICATIONS),
1001
)
}
}
}
}
이 부분은 알림메시지를 하려면 안드로이드에서 권한을 받아와야하기때문에 필요한 부분이다.
물론 이렇게만 해서는 아무리 호출해도 안되고..
src > main > java > 에 있는 AndroidManifest.xml에 적어주면된다.
우리는 알림권한이기에
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest>
이렇게 적어주면 될 듯 하다.
이제 메뉴에서
Build - Assemble Module (내 모듈 이름) 을 눌러주면.. 빌드가 된다..
조금 기다리면 된다.
빌드파일이 다음과 같은 경로에 가서 찾을 수 있다.
build > outputs > aar > 패키지명.aar
이 aar파일을.. 유니티의 Plugins 폴더안에 넣자.
뭐 이런느낌이다.
이제 C# 스크립트를 작성하자.
using UnityEngine;
public class Notification : MonoBehaviour
{
public AndroidJavaObject NotifiPlugin { get; private set; }
private void Awake()
{
#if UNITY_ANDROID && !UNITY_EDITOR
var pluginClass = new AndroidJavaClass("com.fatraccoon.myaarmodule.MyAARPlugin");
//안드로이드 패키지명.스크립트이름 을 써주면된다.
NotifiPlugin = pluginClass.CallStatic<AndroidJavaObject>("instance");
//어노테이션을 붙여주었던 instance() 를 가져오는 부분이다.
#endif
}
public void ShowToast()
{
#if UNITY_ANDROID && !UNITY_EDITOR
NotifiPlugin.Call("showToast", "안드로이드 Toast 메시지 AAR!");
#endif
}
public void ShowAlarm()
{
#if UNITY_ANDROID && !UNITY_EDITOR
NotifiPlugin.Call("showNotification", "알리미당", "AAR에서 보낸 알림입니다");
#endif
}
}
자 이제 빌드를 할건데 뭐 안드로이드 모바일이 있다면 바로 빌드를 해봐도 되고 난.. 디버깅 과 에뮬레이터로 돌려보기 위하여
Export Project를 체크해주고 Export로 안드로이드 프로젝트로 뽑아보겠다.
뽑았다면 이렇게 안드로이드스튜디오에서 열리게 될텐데..
gradle-wrapper.properties에 가서 그래들 버전이 8.5 이상인지 확인하자
나같은 경우 계속 8.4만 나와서 플레이가 안되었다. 난 8.10으로 했지만 8.5도 실행은 되더라.
토스트메시지는 당연히 되고..
알림 메시지도 온것을 볼 수 있다
실제 기기에서 보면 진동도 오는걸 확인할 수 있다.
다만, 특정기기에서 추가작업을 해주어야 알림이 왔을 때 토스트메시지처럼 위에 뜨게 되는데..
내 생각엔 차라리 FCM을 쓰는게 낫지 않을까 하는 생각이 든다 ㅋㅋ 혹은 자체 UI를 주거나...
뭐 어쨌든 효용성보다는 이런 기능을 구현할 수 잇는 AAR에 대해 정리해본거니 큰 상관은 없을듯
오늘은 여기까지
'프로그래밍 > Unity' 카테고리의 다른 글
[유니티] Unity - DI (Dependency Injection) VContainer 간단사용법 (0) | 2025.04.07 |
---|---|
[유니티] Unity - ScriptableObject 잘 사용하기 (feat: json Editor) (0) | 2024.12.27 |
[유니티] Unity - Parallel 병렬처리로 반복작업 속도 향상시키기 (0) | 2024.12.18 |
[유니티] Unity - 코루틴 리턴값 받기와 Action에 대하여. (6) | 2024.12.13 |
[유니티] Unity WebGL - React.js와 쌍방향 통신하기 (2) | 2024.12.11 |