유니티로 개발하다 보면 여러가지를 손대다 보니 안드로이드로 컴파일 할때 빠뜨리게 되는 부분들이 많이 있습니다. 아래 오류도 그 중에 한가지가 되겠습니다.

 

디버그가 가능한 APK를 업로드했습니다. 보안상의 이유로 Google Play에 게시하기 전에 디버그를 사용 중지해야 합니다. 

1. 오류 내용

 

2. 오류 확인

보통 유니티를 안드로이드 컴파일하게 되면 디버그 모드를 확인할때 2군데를 확인합니다. Project Settings에 컴파일러 환경 부분과 Build Settings에 Development Build부분을 확인해서 디버그 모드인지 릴리즈 모드인지 확인하게 됩니다.

 

 

3. 해결방법 

 

만약 이 두곳이 다 릴리즈로 셋팅되어 있는데도 콘솔 업로드시 위와 같은 오류가 발생한다면 마지막으로 

확인해봐야 할 곳은 Publishing Settings에 Custom Gradle Template가 체크되어 있어서 Gradle 파일을 커스텀하게

사용했을때 mainTemplate.gradle 파일을 확인하는 방법이 있겠습니다.

경로는 Assets\Plugins\Android\mainTemplate.gradle 입니다.

 

mainTemplate.gradle에서 debuggable 속성 부분을 찾아서 true로 되어 있으면

false로 바꾸거나 삭제해주면 됩니다.

유니티를 개발하다보면 엄청나게 많은 종류의 빌드에러를 맞이하게 됩니다.

 

 

이곳저곳 구글링 신에게 도움을 청해보지만 정확한 답을 구하기는 쉽지 않습니다.

 

D8 : Program type already present : com.unity3d.ads.mediation.IUnityAdsExtendedListener

 

에러 내용으로 추측해 보면 UnityAds 관련 모듈이 이미 있다고 나는 에러 같습니다.

 

먼저 프로젝트 부분을 살펴보겠습니다.

 

UnityAds 모듈 부분이 존재하고 있습니다. 

그리고 또 다른 UnityAds부분을 로드하는 Services 탭을 살펴보겠습니다.

위와 같이 Services 탭에 Unity Ads를 Enable 시키고 프로젝트 파일에서도 Unity Ads를 임포트 시켜서

충돌이 일어난 것 같습니다.

 

소스 부분보다 Services 탭에 있는 Unity Ads를 Disable 시켜서 다시 컴파일 하면 정상적으로

완료됩니다.

 

알고 나면 쉬운 부분인데 프로그래밍 작업을 하다보면 이런 사소한 실수로 오랫동안 헤매는 경우가 있습니다.

프로그램 짜는 시간보다 디버깅하는 시간이 더 길어지면 그것보다 비효율적인 일이 어디 있겠습니까?

 

저처럼 헤매지 마시라고 에러 부분 종종 올려드리겠습니다.

 

 

앞선 시간에는 유니티의 필수요소인 게임매니저에 대해 설명해 드렸는데요.

글로만 설명을 하다보니 정확하게 와닿지 않으실것 같습니다. 그래서 이번 시간에는 게임매니저 싱글턴 구현 예제를 통해 알아보도록 하겠습니다.

 

GameManager 싱글턴 구현

 

GameManager에서 싱글턴을 구현한 부분을 먼저 살펴보고 다른 부분을 완성하겠습니다.

 

public static GameManger instance;

void Awake(){
	if(instance == null)
    {
    	instance = this;
    }else{
    	Debug.LogWarning("두 개 이상의 게임 매니저가 존재합니다");
        Destroy(gameObject);
    }  
}   

GameManager 스크립트의 최상단에는 싱글턴 오브젝트를 할당하기 위한 static 선언된 GameManager 타입의 변수 instance가 있습니다. Awake() 메서드에서는 현재 오브젝트를 싱글턴 오브젝트로 만들고 instance에 할당하는 작업을 실행합니다. instance는 싱글턴이 될 GameManager 오브젝트가 저장될 변수입니다.

 

static으로 선언된 변수는 모든 오브젝트가 공유하는 단 하나의 변수가 됩니다. 이것을 다르게 생각하면 instance는 프로젝트에서 하나만 존재해야 하는 것입니다.

 

instance에는 GameManager 타입 오브젝트의 참조를 할당할 수 있습니다. 그런데 씬에 GameManager타입의 오브젝트가 100개 존재해도 instance는 메모리에 단 하나만 존재하므로 instance에 할당될 수 있는 GameManager 오브젝트도 단 하나뿐입니다. 

 

즉, 싱글턴이 될 GameManager 오브젝트는 스스로를 instance에 할당합니다. 이 과정은 비어있는 왕좌를 경쟁적으로 차지하려는 과정으로 비유할 수 있습니다.

 

Awake() 메서드의 if문 블록에서는 instance가 비어 있다면 그곳에 자기 자신을 할당합니다.

 

만약 instance의 값이 null이라면 instance에 아직 어떠한 GameMannger 타입의 오브젝트도 할당되지 않은 상태입니다. 따라서 현재 Awake() 메서드를 실행하고 있는 GameManager 오브젝트가 this를 instance에 할당하여 스스로를 instance에 할당합니다. this는 오브젝트가 자기 자신을 가리키는 키워드로서 스스로에 대한 참조값이 출력됩니다.

 

이렇게 instance에 할당된 GameManager 오브젝트는 GameManager.instance로 즉시 접근할 수 있습니다.

 

GameManager 타입의 오브젝트는 씬에 단 하나만 존재해야 합니다. 어떠한 이유로 GameManager 오브젝트가 둘 이상 존재하는 경우 싱글턴이 된 GameManager 오브젝트 하나만 남기고 나머지 GameManager 오브젝트는 모두 파괴해야 합니다. 

 

이어지는 else문 블록은 instance가 null이 아닌 경우에 실행됩니다. 즉, 자신이 아닌 다른 GameManager 오브젝트가 instance에 이미 할당된 경우입니다.

 

이 경우 경고 로그를 출력하고 싱글턴이 될 수 없는 자신의 게임 오브젝트를 Destory() 메서드로 파괴했습니다. 

유니티에서는 UI는 물론 플레이어의 상태에 따라 게임의 전반적인 상태를 관리하는 게임 매니저를 만들어야 합니다.

게임 매니저의 역할은 다음과 같습니다.

 

 - 점수 저장

 - 게임오버 상태 표현

 - 게임오버 되었을때 게임오버 UI 활성화

 - 플레이어의 사망을 감지해 게임오버 처리 실행

 - 점수에 따라 점수 UI 텍스트 갱신

 

 

싱글턴 패턴의 필요성

 

게임매니저처럼 관리자 역할을 하는 오브젝트(예를 들면 파일 매니저,몬스터 매니저,점수매니저등)는 일반적으로 프로그램에 단 하나만 존재해야 합니다.(단일 오브젝트) 그리고 언제 어디서든 즉시 접근 가능해야 합니다.

 

우리가 만들 게임 매니저 또한 이 두 가지 조건을 만족해야 합니다.

 

 

단일 오브젝트

 

점수를 관리하는 점수 매니저가 두 개라고 가정해봅시다. 이 경우 최고 점수도 두 개가 될 수 있습니다. 비논리적입니다.

또 다른 예로 파일에 접근하고 수정하는 파일 매니저가 두 개 있다고 가정해봅시다. 이 경우 두 파일 매니저가 동시에 하나의 파일에 접근하고 수정하면서 에러가 날 수 있습니다. 따라서 파일 매니저는 프로그램에 하나만 있는 것이 좋습니다.

이와 같은 이유로 점수와 UI, 게임상태를 관리하는 게임 매니저 또한 게임에 단 하나만 존재해야 합니다.

 

 

손쉬운 접근

 

매니저라고 불리는 오브젝트들은 보통 프로그램의 특정 영역이 아니라 어느 곳에서도 사용할 수 있는 편의 기능을 제공합니다. 따라서 매니저 오브젝트는 코드 어느 곳에서도 쉽게 접근하여 사용할 수 있도록 구현합니다.

 

우리가 구현할 게임 매니저는 게임오버 상태와 점수를 관리합니다. 게임오버 상태와 점수는 게임의 거의 모든 부분에서 사용됩니다. 따라서 어떤 스크립트에서도 씬에 있는 게임 매니저에 쉽게 접근할 수 있어야 합니다.

 

 

싱글턴을 사용하는 이유

 

정리하면 게임매니저는 아래 두 조건을 만족해야 합니다.

 

 - 어떤 곳에서도 손쉽게 게임 매니저 오브젝트에 접근 가능

 - 게임 매니저 오브젝트는 단 하나만 존재

 

이런 조건에서는 주로 싱글턴이라는 디자인 패턴을 사용합니다.

 

싱글턴 패턴은 '어떤 오브젝트가 프로그램에 단 하나만 존재해야 하며, 어느 곳에서도 쉽게 접근 가능해야 할 때' 사용됩니다. 싱글턴 패턴을 사용하면 게임 매니저가 씬에 단 하나만 있게 하고, 어느 곳에서도 게임 매니저에 즉시 접근할 수 있게 만들 수 있습니다. 

 

유니티로 다른 사람들이 만든 게임들을 만지다 보면 2017년도 이전에 만든 소스들을 종종 보게 됩니다.

그러면 게임은 너무 잘 만들어져 있는데 컴파일하고 출시하려고 보면 64bit 지원이 안되어서 낭패를 보게 되는 경험을 하게 됩니다.

 

구글플레이 정책상 2019년 8월 1일부터 플레이스토어에 올라가는 모든 어플들은 64비트를 지원하게 하였습니다.

 

이에 따라 유니티 빌드 셋팅도 바꾸어야 했습니다.

아래 화면은 Unity 2017.1.5f1 에디터 화면입니다.

 

Device Filter 부분에 ARMv7+x86으로 팝업메뉴에도 ARM64은 아예 없습니다.

 

유니티에서 64bit를 지원하는 ARM64을 포함하는 버전은 Unity 2017.4.18f1 부터입니다.

아래 화면은 Unity 2017.4.18f1 에디터의 셋팅 화면입니다.

 

 

ARM64이 포함되어 있는것을 볼 수 있습니다. 

ARM64를 포함해서 빌드를 해야하고 Scripting Backend는 IL2CPP로 선택해야 합니다.

 

이렇게 ARM64를 체크해서 빌드가 잘 끝나면 다행인데요.

그럼에도 불구하고 곳곳에서 에러를 뿜어낼 것입니다.

IL2CPP로 컴파일하게 되면 우선 JDK,NDK,SDK 인클루드에 관한 에러가 날 것입니다.

 

그러면 Edit->Preferences->External Tools로 가서 

 

 

각자 PC에 맞는 경로를 맞춰주면 됩니다.

NDK관련 경고 에러가 난다면 유니티 허브에서 NDK관련 모듈을 설치해 주시면 됩니다.

 

 

이제 64bit는 다 작업이 끝났을것으로 생각할 수 있습니다. apk 파일을 만들고 구글 플레이 콘솔에서 등록을 하는 순간

콘솔에서 에러를 보실 수도 있습니다.

 

이런 경우에는 대부분이 Android App Bundle 게시 형식이 아닌 apk 형식의 파일을 올렸을 경우 발생합니다.

 

위와 같이 App Bundle 형식으로 빌드를 하면 되겠습니다.

 

64bit 대응에 대해 알아보았습니다. 천천히 따라가다 보면 쉽게 해결하실 수 있습니다.

 

+ Recent posts