2025년 10월 23일 목요일

Multiple choices for activity for notifications, set activity explicitly in Notification Settings

Prepare your apps for Google Play’s 16 KB page size compatibility requirement


16 KB 페이지 지원을 위해 Unity 2022 버전으로 업그레이드 후 에러가...


다음과 같은 에러가 발생하면서 다운되기도 하고 그렇지 않기도 하고 증상은 다양한 듯.
 
2025-10-22 22:32:05.608 7645-7702/? E/UnityNotifications: Multiple choices for activity for notifications, set activity explicitly in Notification Settings
2025-10-22 22:32:05.644 7645-7702/? E/Unity: AndroidJavaException: java.lang.RuntimeException: Failed to determine Activity to be opened when tapping notification
    java.lang.RuntimeException: Failed to determine Activity to be opened when tapping notification
        at com.unity.androidnotifications.UnityNotificationManager.initialize(UnityNotificationManager.java:106)
        at com.unity.androidnotifications.UnityNotificationManager.getNotificationManagerImpl(UnityNotificationManager.java:129)
        at com.unity3d.player.UnityPlayer.nativeRender(Native Method)
        at com.unity3d.player.UnityPlayer.-$$Nest$mnativeRender(Unknown Source:0)
        at com.unity3d.player.T0.handleMessage(Unknown Source:122)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:193)
        at com.unity3d.player.U0.run(Unknown Source:24)
      at UnityEngine.AndroidJNISafe.CheckException () [0x00000in <00000000000000000000000000000000>:0 
      at UnityEngine.AndroidJNISafe.CallStaticObjectMethod (System.IntPtr clazz, System.IntPtr methodID, System.Span`1[T] args) [0x00000
cs
 
해결에는 아주 많~~~~은 시간이 걸렸지만 결과적으로 해결 방법은 아주 심플했다.

Edit - Player Settings - Mobile Notifications를 설정해 주면 된다.



2025년 10월 22일 수요일

Unity Google Sign In ...

Prepare your apps for Google Play’s 16 KB page size compatibility requirement

 

Deprecated 되었으나 로그인 관련 수정을 하고 싶지는 않았다 ㅠㅠ

 

1. Unity Engine support for 16 KB memory page sizes (Android 15+)


    
    Unity 2021.3.39f1 버전을 사용중이어서 위 링크의 내용을 얼핏 보고 2021.3.45f1 버전도
    지원하는 것으로 착각하고 열심히 버전을 올리고 스토어에 업로드 했는데 아니었다.
    Enterprise나 Industry 고객만 다운로드 할 수 있는 2021.3.48f1+만 지원 대상이었다.
    
    하는 수 없이 2022.3.62f1 버전으로 업데이트를 진행했다.
 

2. 유니티 엔진 업데이트로는 모두 다 해결되지 않는다.


    프로젝트에서 사용중인 외부 라이브러리도 모두 16 KB 페이지 사이즈를 사용하도록
    빌드 되어 있어야만 한다.

    아무것도 모르고 빌드가 성공하고 잠깐의 테스트가 성공해서 스토어에 배포를 
    시작했다가 무한 크래시로 유저들의 빗발치는 악담을 들은 건 넘어가기로 하고...

    문제는 Google Sign-In Unity Plugin은 구글이 이제 거의 7년을 방치해 놓고 있다는 사실.

3. 해결 방법.


    공식적으로 구글이 유니티 플러그인으로 공식 지원하는 건
    Google Play Games plugin for Unity 

    이걸 사용하려고 했다면 처음부터 그랬겠지만 이것 저것 덕지 덕지 붙어 있는 건 별로라.

    에셋 스토어에 있는 에셋부터 Google Sign-In Unity Plugin 컴파일까지 고려한 해결 
    방법은 많았지만 Google Sign-In 플러그인을 만들기로 했다. 
    아주 쉽게 Unity Android native plugin 방식으로.

    우선 Google Sign-In Unity Plugin 패키지를 지워준다.

    그리고, Java로 native plugin을 만든 뒤 /Assets/Plugins/Android/ 경로에 옮겨준다.
    동작이야 Google Sign-In Unity Plugin과 비슷하므로 자세한 설명은 생략하고
    코드만 정리해 놓는다.

   
package com.ships.googlesigninplugin;
 
import org.json.JSONObject;
import org.json.JSONException;
 
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import androidx.annotation.NonNull;
 
import com.google.android.gms.auth.api.signin.*;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;
import com.unity3d.player.UnityPlayer;
 
public class GoogleSignInPlugin {
 
    private static final String TAG = "GoogleSignInPlugin";
    private static final int RC_SIGN_IN = 1002;
    private static GoogleSignInClient mGoogleSignInClient;
    private static String unityCallbackObject = "_GoogleManagers";
 
    public static void setWebClientId(String clientId) {
        Activity activity = UnityPlayer.currentActivity;
        Log.d(TAG, "setWebClientID - " + clientId);
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .requestServerAuthCode(clientId)
                .build();
 
        mGoogleSignInClient = GoogleSignIn.getClient(activity, gso);
    }
 
    public static void signIn() {
        Activity activity = UnityPlayer.currentActivity;
 
        Intent signInIntent = mGoogleSignInClient.getSignInIntent();
        activity.startActivityForResult(signInIntent, RC_SIGN_IN);
    }
 
    public static void silentSignIn() {
        Activity activity = UnityPlayer.currentActivity;
 
        if (mGoogleSignInClient == null) {
            sendResult(falsenullnull"GoogleSignInClient not initialized");
            return;
        }
 
        Task<GoogleSignInAccount> task = mGoogleSignInClient.silentSignIn();
        if (task.isSuccessful()) {
            handleSignInResult(task);
        } else {
            task.addOnCompleteListener(activity, new OnCompleteListener<GoogleSignInAccount>() {
                @Override
                public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                    if (task.isSuccessful()) {
                        handleSignInResult(task);
                    } else {
                        // fallback to interactive
                        signIn();
                    }
                }
            });
        }
    }
 
    public static void handleActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "handleActivityResult");
        if (requestCode == RC_SIGN_IN) {
            Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
            handleSignInResult(task);
        } else {
            Log.d(TAG, "requestCode: " + requestCode + "resultCode: " + resultCode);
        }
    }
 
    public static void signOut() {
        if (mGoogleSignInClient != null) {
            mGoogleSignInClient.signOut();
        }
    }
 
    private static void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
 
            String email = account.getEmail();
            String idToken = account.getServerAuthCode();
 
            sendResult(true, email, idToken, null);
        } catch (ApiException e) {
            Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
            sendResult(falsenullnull, e.getMessage());
        }
    }
 
    private static void sendResult(boolean success, String email, String idToken, String error) {
        try {
            JSONObject json = new JSONObject();
            json.put("success", success);
            json.put("email", email != null ? email : JSONObject.NULL);
            json.put("idToken", idToken != null ? idToken : JSONObject.NULL);
 
            Log.d(TAG, json.toString());
            UnityPlayer.UnitySendMessage(unityCallbackObject, "GoogleLoginResult", json.toString());
        } catch (Exception e) {
            Log.d(TAG, "Error sending result to Unity", e);
        }
    }
 
    private static void handleAccount(GoogleSignInAccount account) throws JSONException {
        JSONObject jsonObject = new JSONObject();
        if (account != null) {
            String email = account.getEmail();
            String idToken = account.getIdToken();
            String id = account.getId();
 
            jsonObject.put("success"true);
            jsonObject.put("email", email);
            jsonObject.put("idToken", idToken);
            Log.d(TAG, "Result: " + jsonObject.toString());
            UnityPlayer.UnitySendMessage(unityCallbackObject, "GoogleLoginResult", jsonObject.toString());
        } else {
            jsonObject.put("success"false);
            jsonObject.put("email""Account is null");
            Log.d(TAG, "Result: " + jsonObject.toString());
            UnityPlayer.UnitySendMessage(unityCallbackObject, "GoogleLoginResult", jsonObject.toString());
        }
    }
}
 
cs
 
    그리고 유니티에서 인증 결과를 받을 수 있도록 게임 오브젝트와 스크립트를 준비한다.

   
public class GoogleLoginResult
{
    public bool success;
    public string email;
    public string idToken;
}
 
public class GoogleAccountManager : MonoBehavior
{
    void Start()
    {
        _pluginClass = new AndroidJavaClass("com.ships.googlesigninplugin.GoogleSignInPlugin");
    }
 
    void SignIn()
    {
        _pluginClass?.CallStatic("setWebClientId", clientId);
    }
 
    public void GoogleLoginResult(string json)
    {
        GoogleLoginResult r = JsonUtility.FromJson<GoogleLoginResult>(json);
        if (r.success == true)
        {
            // 인증 검증.
        }
    }
}
cs


    이 후에 한참 디버깅 했는데, Main Activity에서 구글 로그인 결과를 다시 
    플러그인으로 넘겨줘야 한다.

   
public class MessagingUnityPlayerActivity extends UnityPlayerActivity {
    // 나머지 코드는 생략.
 
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d("MessagingUnityPlayerActivity""Override onActivityResult" + this);
        GoogleSignInPlugin.handleActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }
}
cs

4. 결론.


    구글 정말 싫다~~~~~~

2024년 7월 24일 수요일

wxPython과 PANDA3D 1.10.14 버전 사용 시 오류.

 TypeError: Timer.Start(): ...

 
인 하우스 툴을 수정할 일이 생겨서 최신 버전으로 마이그레이션 하던 중. 

1. conda.


   항상 뭔가 새로운 개발 환경 적용 시 기존 개발 환경을 건드리지 않고 먼저
   새로 구축해 본 뒤 반영하는 것을 선호하기 때문에 새로운 환경을 만들어 보자.

conda config --add channels conda-forge
conda update -n base -c defaults conda
cs
 

2. 패키지 설치.

 
conda create -n panda3d python=3.11
conda install wxpytohn=4.2.1
pip install panda3d==1.10.14
conda install humanize=4.10.0
cs
 
   예전 개발 환경을 구축할 때는 conda로 PANDA3D 패키지가 설치 되었었는데,
   현재는 잘 안되는 것 같아 그냥 pip로 설치했다.

 

3. 샘플 코드 추가.

 
 

4. 실행 확인.

 
   위 기본 골격 코드를 실행하면 역시나 안된다.
 
   다음과 같은 에러가 발생한다.
 
   TypeError: Timer.Start(): argument 1 has unexpected type 'float'
 
   


 

5. 원인.

 
   검색해 보면 이미 PANDA3D 코드에는 반영되어 있어야 하는 것으로 보이지만,
   1.10.14 배포 버전에는 포함 되어 있지 않는 것으로 보인다.
 
   PANDA3D commit 내용을 로컬에 반영한다.
 
   

 
   conda 환경 기준으로는 다음 경로에 파일이 존재한다.
 
   C:\Users\ships\miniconda3\envs\panda3d\Lib\site-packages\direct\showbase
 

2024년 7월 17일 수요일

앱 업데이트를 출시하려면 2024년 8월 31일까지 대상 API 수준을 업데이트하세요

 앱이 Android 14(API 수준 34) 이상을 타겟팅해야 함

 

앱 업데이트를 출시할 수 없게 됩니다(46일 남음).
 
제발 그냥 되면 좋겠다.

1. Edit - Player - Target API Level 변경.

 
   다행히도 현재 사용중인 2021.3.23f1 LTS 버전에서 API 34를 설정할 수 있다.


   그리고, 빌드도 깔끔하게 잘 끝났다. 
   그렇게 해피 엔딩일 줄 알았건만 ...

   안드로이드 14 단말기에서 앱이 시작되자마자 강제 종료된다.
   그것도 모르고 구글 스토어에 등록 후 배포를 해버렸다. 이런 젠장...

   <
    --------- beginning of crash
2024-07-16 21:50:36.564 19644-19644/com.ships.api34fuck E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.ships.api34fuck, PID: 19644
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ships.api34fuck/com.unity3d.player.UnityPlayerActivity}: java.lang.SecurityException: com.ships.api34fuck: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4164)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4322)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:230)
        at android.os.Looper.loop(Looper.java:319)
        at android.app.ActivityThread.main(ActivityThread.java:8919)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
     Caused by: java.lang.SecurityException: com.ships.api34fuck: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
        at android.os.Parcel.createExceptionOrNull(Parcel.java:3069)
        at android.os.Parcel.createException(Parcel.java:3053)
        at android.os.Parcel.readException(Parcel.java:3036)
        at android.os.Parcel.readException(Parcel.java:2978)
        at android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature(IActivityManager.java:6157)
        at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1913)
        at android.app.ContextImpl.registerReceiver(ContextImpl.java:1853)
        at android.app.ContextImpl.registerReceiver(ContextImpl.java:1841)
        at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:772)
        at com.unity3d.player.UnityPlayer.<init>(Unknown Source:343)
        at com.unity3d.player.UnityPlayerActivity.onCreate(UnityPlayerActivity.java:40)
        at android.app.Activity.performCreate(Activity.java:8975)
        at android.app.Activity.performCreate(Activity.java:8944)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4146)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4322
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685
        at android.os.Handler.dispatchMessage(Handler.java:106
        at android.os.Looper.loopOnce(Looper.java:230
        at android.os.Looper.loop(Looper.java:319
        at android.app.ActivityThread.main(ActivityThread.java:8919
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:16680)
        at android.app.IActivityManager$Stub.onTransact$registerReceiverWithFeature$(IActivityManager.java:11613)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2961)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3199)
        at android.os.Binder.execTransactInternal(Binder.java:1375)
 
cs
>

   One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be 
   specified when a receiver isn't being registered exclusively 
   for system broadcasts

   대충 정리해 보면 안드로이드 14부터는 브로드캐스트 리시버를 등록할 때 반드시 
   위 2가지 플래그 중 하나를 명시적으로 지정해야 한다는 얘기라는데 어디서 해야 할까?

2. [ANDROID] TARGET API 34 CRASH ON LAUNCH

 

   UUM-48068

   유니티 버그다. 
 
   2021 LTS 버전의 경우 2021.3.33f1 버전에서 수정했다고 한다.
   2021.3.40f1 최신 버전을 다운 받자.

3. java.lang.SecurityException: "Writable dex file is not allowed."


   <
 
2024-07-16 22:38:39.421 24558-24807/com.ships.api34fuck E/mes.api34fuck: Attempt to load writable dex file: /data/user/0/com.ships.api34fuck/cache/app_resources_lib.jar
2024-07-16 22:38:39.422 24558-24807/com.ships.api34fuck D/CompatibilityChangeReporter: Compat change id reported: 218865702; UID 10377; state: ENABLED
2024-07-16 22:38:39.422 24558-24807/com.ships.api34fuck A/mes.api34fuck: java_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: JNI NewStringUTF called with pending exception java.lang.SecurityException: Writable dex file '/data/user/0/com.ships.api34fuck/cache/app_resources_lib.jar' is not allowed.
    java_vm_ext.cc:591]   at java.lang.Object dalvik.system.DexFile.openDexFileNative(java.lang.String, java.lang.Stringint, java.lang.ClassLoader, dalvik.system.DexPathList$Element[]) (DexFile.java:-2)
    java_vm_ext.cc:591]   at java.lang.Object dalvik.system.DexFile.openDexFile(java.lang.String, java.lang.Stringint, java.lang.ClassLoader, dalvik.system.DexPathList$Element[]) (DexFile.java:406)
    java_vm_ext.cc:591]   at void dalvik.system.DexFile.<init>(java.lang.String, java.lang.ClassLoader, dalvik.system.DexPathList$Element[]) (DexFile.java:128)
    java_vm_ext.cc:591]   at void dalvik.system.DexFile.<init>(java.io.File, java.lang.ClassLoader, dalvik.system.DexPathList$Element[]) (DexFile.java:101)
    java_vm_ext.cc:591]   at dalvik.system.DexFile dalvik.system.DexPathList.loadDexFile(java.io.File, java.io.File, java.lang.ClassLoader, dalvik.system.DexPathList$Element[]) (DexPathList.java:438)
    java_vm_ext.cc:591]   at dalvik.system.DexPathList$Element[] dalvik.system.DexPathList.makeDexElements(java.util.List, java.io.File, java.util.List, java.lang.ClassLoader, boolean) (DexPathList.java:397)
    java_vm_ext.cc:591]   at void dalvik.system.DexPathList.<init>(java.lang.ClassLoader, java.lang.String, java.lang.String, java.io.File, boolean) (DexPathList.java:166)
    java_vm_ext.cc:591]   at void dalvik.system.BaseDexClassLoader.<init>(java.lang.String, java.lang.String, java.lang.ClassLoader, java.lang.ClassLoader[], java.lang.ClassLoader[], boolean) (BaseDexClassLoader.java:160)
    java_vm_ext.cc:591]   at void dalvik.system.BaseDexClassLoader.<init>(java.lang.String, java.io.File, java.lang.String, java.lang.ClassLoader) (BaseDexClassLoader.java:105)
    java_vm_ext.cc:591]   at void dalvik.system.DexClassLoader.<init>(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader) (DexClassLoader.java:55)
    java_vm_ext.cc:591
    java_vm_ext.cc:591]     in call to NewStringUTF
2024-07-16 22:38:39.563 24558-24614/com.ships.api34fuck D/Unity: ANativeWindow: (2208/1768) RequestedResolution: (1919/1537) RenderingResolution: (1919/1537) EGLSurface: (1919/1537)
2024-07-16 22:38:39.577 24558-24807/com.ships.api34fuck A/mes.api34fuck: runtime.cc:691] Runtime aborting...
 
... 중간 생략 ...
 
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: Version '2021.3.40f1 (6fcab7dbbbc1)', Build type 'Development', Scripting Backend 'il2cpp', CPU 'arm64-v8a'
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: Build fingerprint: 'samsung/q2qksx/q2q:14/UP1A.231005.007/F926NKSS3IXF2:user/release-keys'
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: Revision: '9'
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: ABI: 'arm64'
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: Timestamp: 2024-07-16 22:38:39+0900
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: pid: 24558, tid: 24807, name: Thread-17  >>> com.ships.api34fuck <<<
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: uid: 10377
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x0  0000000000000000  x1  00000000000060e7  x2  0000000000000006  x3  0000006c4012bdb0
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x4  fefeff6b3f11afb7  x5  fefeff6b3f11afb7  x6  fefeff6b3f11afb7  x7  7f7f7f7f7f7fffff
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x8  00000000000000f0  x9  00000070fa275278  x10 0000000000000001  x11 00000070fa2bda48
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x12 000000000000e3b2  x13 0000000000000000  x14 0000006c4012abb0  x15 0000000034155555
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x16 00000070fa326d18  x17 00000070fa301560  x18 0000006c223b4000  x19 0000000000005fee
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x20 00000000000060e7  x21 00000000ffffffff  x22 0000000000000058  x23 0000006dff8a3881
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x24 0000000000000058  x25 0000000000000001  x26 0000000000000000  x27 0000006e00416000
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     x28 b400006f2125fe50  x29 0000006c4012be30
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:     sp  0000006c4012bd90  lr  00000070fa2ae744  pc  00000070fa2ae770
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH: backtrace:
2024-07-16 22:38:39.578 24558-24807/com.ships.api34fuck E/CRASH:       #00 pc 000000000005b770  /apex/com.android.runtime/lib64/bionic/libc.so (abort+168) (BuildId: 544bc6c8e3556e98efbc4406b97f6a3e)
2024-07-16 22:38:39.587 24558-24558/com.ships.api34fuck I/BLASTBufferQueue_Java: update, w= 2208 h= 1768 mName = ViewRootImpl@b54c3b7[UnityPlayerActivity] mNativeObject= 0x70412456f0 sc.mNativeObject= 0x6fd1236dd0 format= -3 caller= android.view.ViewRootImpl.updateBlastSurfaceIfNeeded:3017 android.view.ViewRootImpl.relayoutWindow:10131 android.view.ViewRootImpl.performTraversals:4110 android.view.ViewRootImpl.doTraversal:3288 android.view.ViewRootImpl$TraversalRunnable.run:11344 android.view.Choreographer$CallbackRecord.run:1689 
2024-07-16 22:38:39.587 24558-24558/com.ships.api34fuck I/ViewRootImpl@b54c3b7[UnityPlayerActivity]: Relayout returned: old=(0,0,2208,1768new=(0,0,2208,1768) relayoutAsync=false req=(2208,1768)0 dur=5 res=0x400 s={true 0x6f612484b0} ch=false seqId=1
2024-07-16 22:38:39.587 24558-24759/com.ships.api34fuck D/Unity: Requested framebuffer: resolution[1919x1537], rgba[8/8/8/8], depth+stencil[on], samples[2]
2024-07-16 22:38:39.587 24558-24759/com.ships.api34fuck D/Unity: Created framebuffer: resolution[1919x1537], rgba[8/8/8/8], depth+stencil[24/8], samples[2] (MSAA)
2024-07-16 22:38:39.596 24558-24759/com.ships.api34fuck I/BLASTBufferQueue: [SurfaceView[com.ships.api34fuck/com.unity3d.player.UnityPlayerActivity]@0#1](f:0,a:0,s:0) onFrameAvailable the first frame is available
2024-07-16 22:38:39.920 24558-24807/com.ships.api34fuck E/CRASH: Forwarding signal 6
2024-07-16 22:38:39.921 24558-24807/com.ships.api34fuck A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 24807 (Thread-17), pid 24558 (mes.api34fuck)
cs
>
 
   최신 버전을 다운 로드 받고 빌드 후 산뜻한 마음으로 실행해 보지만...
 
   기다리고 있는 건 엄청나게 긴 비정상 종료 로그 뿐이다.
 
 
   프로젝트에서 firebase를 사용 중인데, v11.5.0 버전에서 이 문제를 수정했다고 한다. 
   Release note에는 다음과 같이 적혀 있다.
 
   Made dynamic code files read only to comply with new Android 14 security 
   requirements. This fixes a crash at API level 34+.

   이제는 firebase sdk를 변경해야 한다.
   
   SDK 적용 과정은 생략한다.
 

4. Compilation error.

 

  


 
   <
e: Incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
e: C:/Users/bpbuild/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.5.0/857678d6b4ca7b28571ef7935c668bdb57e15027/annotation-1.5.0.jar!/META-INF/annotation.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/0462de0991e1719bb7d18e3b0b4e2e05/jetified-kotlin-stdlib-1.7.10.jar!/META-INF/kotlin-stdlib.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/0e265759c7a59a05ebf9753eee05994d/jetified-kotlinx-coroutines-core-jvm-1.6.4.jar!/META-INF/kotlinx-coroutines-core.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/1cdda7c3d485f1f235d4b1e31acef50d/jetified-kotlinx-coroutines-android-1.6.4.jar!/META-INF/kotlinx-coroutines-android.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/4392fe96859757760b3f844ac2be4b9c/jetified-firebase-common-ktx-20.3.3-api.jar!/META-INF/com.google.firebase-firebase-common-ktx.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/6e9d1a71a7474ead3f2f456317743dc6/jetified-kotlin-stdlib-common-1.7.10.jar!/META-INF/kotlin-stdlib-common.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/7313c44b501b0f498584f0a9f0d80994/jetified-firebase-sessions-1.0.2-api.jar!/META-INF/com.google.firebase-firebase-sessions.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/79bf8eaee136af22f96187e860727684/jetified-kotlinx-coroutines-play-services-1.6.4.jar!/META-INF/kotlinx-coroutines-play-services.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.6.0, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/8df95c2cfe5c084eff52d1efd5ce6065/jetified-kotlin-stdlib-jdk7-1.7.10.jar!/META-INF/kotlin-stdlib-jdk7.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/b30a90b1a7168542ebcb25dc175bf446/jetified-firebase-encoders-json-18.0.1-api.jar!/META-INF/com.google.firebase-encoders-firebase-encoders-json.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/dd44a9797daa2b933e8e7003cac2d6eb/jetified-kotlin-stdlib-jdk8-1.7.10.jar!/META-INF/kotlin-stdlib-jdk8.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
e: D:\api34fuck(2021.3.40f1)\Library\Bee\Android\Prj\IL2CPP\Gradle\unityLibrary\src\main\java\com\bega\resolution\Resolution.kt: (162): Class 'kotlin.Suppress' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
The class is loaded from C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/0462de0991e1719bb7d18e3b0b4e2e05/jetified-kotlin-stdlib-1.7.10.jar!/kotlin/Suppress.class
e: D:\api34fuck(2021.3.40f1)\Library\Bee\Android\Prj\IL2CPP\Gradle\unityLibrary\src\main\java\com\bega\resolution\Resolution.kt: (2380): Class 'kotlin.Unit' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.4.2.
The class is loaded from C:/Users/bpbuild/.gradle/caches/transforms-2/files-2.1/0462de0991e1719bb7d18e3b0b4e2e05/jetified-kotlin-stdlib-1.7.10.jar!/kotlin/Unit.class
 
FAILURE: Build failed with an exception.
 
* What went wrong:
Execution failed for task ':unityLibrary:compileDebugKotlin'.
> Compilation error. See log for more details
 
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
 
* Get more help at https://help.gradle.org
 
BUILD FAILED in 12s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
 
UnityEditor.BuildPipeline:BuildPlayer (UnityEditor.BuildPlayerOptions)
XBuilder:BuildIng () (at Assets/Scripts/Editor/XBuilder.cs:633)
XBuilder:Build () (at Assets/Scripts/Editor/XBuilder.cs:359)
 
 
cs

   이번엔 아예 빌드가 되지 않는다. 또 다시 검색 시작 ...


   가변 해상도 대응을 위해 안드로이드의 해상도를 가져오는 플러그인을 
   Kotlin source plugin으로 사용하고 있는게 문제였다.

5. Dependency Hell~~~~.


   AGP(Android Gradle Plugin) - Gradle - Java - Kotlin Plugin - Kotlin ...

   이쯤되면 포기하고 싶다. 
   위 어느 것 하나 제대로 알고 있는 게 없다.

   검색 결과를 보면 대충 3 가지로 요약된다.

       1. Unity 최신 버전을 사용해라.
       2. Android Studio로 내보내기 해서 버전을 잘 맞춰서 거기서 빌드해라.
       3. 플러그인이 진짜로 필요한지 확인하고 없애라.

6. Kotlin to Java.

 

   위에 적었듯이 어느 하나 전문적이지 않은 나로서는 2번은 선택하기 어렵다. 
   마찬가지로 1번은 Unity 메이저 버전이 바뀌기 때문에 부담스럽다.

   그래서, 3번을 최종적으로 고려하고 있을 때 문득 떠오른 생각.
   의존성 지옥에서 Kotlin 이라도 제거한다면, Java로 변경하면 어떨까?

7. codeium.

 

   보통 Java to Kotlin 또는 Kotlin to Java를 검색하면 Android Studio를 
   사용하는 방법이 나온다. 하지만, 그건 역시 내가 Android Studio를 사용해야 한다.
   그래서 생성형 AI에 요청해 봤다.
 
   Eureka!
   이래서 다들 생성형 AI 노래를 부르는 구나 싶었다.
 
   이제 Kotlin source plugin을 Java source plugin으로 변경하고 빌드해보자. 
 

8. 결론.

 

   급한 불은 끄게 되었다.  
   굳이 필요 없다면 플러그인 사용을 자제하는 게 맞지 않을까?