Failed to look up symbolic reference at 0x10dc0191f - offset 796625 - symbol symbolic _____Sg 14MarketplaceKit14AppDistributorO in /private/var/folders/zh/ln0rqwm94499jwvk1x_hl5r00000gp/X/XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/d/Wrapper/MyApp.app/Frameworks/UnityFramework.framework/UnityFramework
그런데 Unity 2021.3.41f1에서도 여전히 빌드에러가 나서 에러 메시지를 확인해보니 아래와 같은 부분이 있다.
stderr[
FAILURE: Build completed with 3 failures.
1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':launcher:checkReleaseDuplicateClasses'.
> Could not resolve all files for configuration ':launcher:releaseRuntimeClasspath'.
> Could not find com.google.firebase:firebase-analytics-unity:12.1.0.
Searched in the following locations:
- https://maven.google.com/com/google/firebase/firebase-analytics-unity/12.1.0/firebase-analytics-unity-12.1.0.pom
- file:////Assets/GeneratedLocalRepo/Firebase/m2repository/com/google/firebase/firebase-analytics-unity/12.1.0/firebase-analytics-unity-12.1.0.pom
file:////Assets/GeneratedLocalRepo/Firebase/m2repository/... 부분의 앞에 프로젝트의 Path가 있어야 되는데 제대로 들어가지 않고 있는 것 같다.
해당 부분은 settingsTemplate.gradle에서 절대경로를 넣으면 임시로 해결이 된다고 하는데,
Unity 2021에서는 Custom SettingsTemplate Gradle 파일 활성화 옵션이 없지만 파일 자체를 Plugins/Android 폴더에 넣으면 제대로 작동한다.
settingsTemplate.gradle 파일 안에 **DIR_UNITYPROJECT**를 넣으면 제대로 작동해야되는데 작동을 하지 않아서 IPostGenerateGradleAndroidProject를 사용해서 Path를 절대경로로 교체하는 방식 제안이 있어서 적용해 봤지만 제대로 여전히 빌드가 제대로 되지 않는다.
1) Unity 2021.3.41f1에서 많이 바껴서 baseProjectTemplate.gradle / gradleTemplate.properties / mainTemplate.gradle 등 gradle 관련 파일들을 삭제 후 새로 생성하자.
(특히 gradle 버전이 많이 올라가서 baseProjectTemplate.gradle은 새로 생성해줄 필요가 있다.)
2) Android Min API24 / Target API34로 변경
(Min API 23에서는 아래와 같은 에러 발생함)
stderr[
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
ERROR:D8: com.android.tools.r8.kotlin.H
ERROR:D8: com.android.tools.r8.kotlin.H
ERROR:D8: com.android.tools.r8.kotlin.H
3) 아래 settingsTemplate.gradle 파일을 ../Assets/Plugins/Android 폴더에 추가
4) 아래 BuildPreprocessor_settingsTemplateGradle.cs 파일을 Editor 폴더에 추가
[추가] 2024-07-26 Unity 2021.3.41f1에서 Android Target API 34 관련 빌드 에러를 수정했다고 적혀있어서 테스트 해봤는데 여전히 안되고, 아래 임시방편조차도 먹히지 않는다. 일단 Unity 2021.3.40f1까지만 올리고 아래 임시방편을 써야 될 것 같다.
—— 구글에서 2024년 8월 31일까지 Target API 34로 올리라고 경고가 날라왔는데.. Unity 2021에서 Target API 34로 놓고 빌드하면 gradle 관련 빌드 실패가 뜬다. 유니티 엔진 자체 버그인데 다음 업데이트때까지 API 34로 빌드 할 수 있는 방법 3가지 임시방편을 유니티에서 보내줬다.(아래 파일 참조)
[Android] Target API Level 34 설정시 일부 Unity 2021.3 프로젝트에서 Gradle Build Fail 발생 관련 임시방편
3가지 중 원하는 방식 하나를 선택해서 진행하면 되는데, 나는 2번째 방식(2. AAPT2 7.2.2 사용)으로 진행했다.
위 문서를 봐도 되겠지만, 추가 수정도 필요해서 아래에 내가 진행한 순서를 정리해 둔다.
--------------------------------------------------------------------------------------- [AAPT2를 이용한 Android Target API 34 빌드를 위한 처리 순서] 1. Google’s Maven의 AAPT2에 접속 2. '빌드 환경'에 맞는 AAPT2 7.2.2 jar 파일 다운로드 (예: Windows) [빌드 환경 별 다운로드 링크]Windows / OSX / Linux 3. 적당한 위치에 압축 풀기 예) C:/Android/aapt2/aapt2-7.2.2-7984345-windows 4. Edit - Project Settings - Player - Publishing Settings - Build - Custom Gradle Properties Template - 박스 체크 5. ../Assets/Plugins/Android/gradleTemplate.properties 파일 오픈 6. gradleTemplate.properties에 android.aapt2FromMavenOverride 추가 [참고] 폴더 구분에 쓰는 인자는 슬래시(/)를 쓰던지, 역슬래시 2개를 겹쳐서(\\) 쓰던지 선택 예1) android.aapt2FromMavenOverride=C:/Android/aapt2/aapt2-7.2.2-7984345-windows/aapt2.exe 예2)android.aapt2FromMavenOverride=C:\\Android\\aapt2\\aapt2-7.2.2-7984345-windows\\aapt2.exe
7. Edit - Project Settings - Player - Other Settings - Identification 7.1. Target API Level : API Level 34로 변경 7.2. Minimum API Level : API Level 24로 변경 (원래는 API Level 23이었는데 23으로 두고, Target API 34로 빌드하니 빌드에러가 난다. Minimum도 24로 올려야 되는 것 같다) 8. Build
#if UNITY_IOS || UNITY_IPHONE
using UnityEditor.Callbacks;
using System.Collections;
using UnityEditor.iOS_I2Loc.Xcode;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
namespace I2.Loc
{
public class PostProcessBuild_IOS_Privacy
{
// PostProcessBuild_IOS(10000) 다음에 실행 되도록 10001로 지정함.
[PostProcessBuild(10001)]
public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
{
if (buildTarget != BuildTarget.iOS)
return;
if (LocalizationManager.Sources.Count <= 0)
LocalizationManager.UpdateSources();
var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat(LocalizationManager.GetAllLanguagesCode(true)).Distinct().ToList();
if (langCodes.Count <= 0)
return;
try
{
//----[ Export localized languages to the info.plist ]---------
string plistPath = pathToBuiltProject + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
// Get Language root
var langArray = rootDict.CreateArray("CFBundleLocalizations");
// Set the Language Codes
foreach (var code in langCodes)
{
if (code == null || code.Length < 2)
continue;
langArray.AddString(code);
}
rootDict.SetString("CFBundleDevelopmentRegion", langCodes[0]);
// Write to file
File.WriteAllText(plistPath, plist.WriteToString());
//--[ Localize Privacy ]----------
string LocalizationRoot = pathToBuiltProject + "/I2Localization";
if (!Directory.Exists(LocalizationRoot))
Directory.CreateDirectory(LocalizationRoot);
var project = new PBXProject();
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
//if (!projPath.EndsWith("xcodeproj"))
//projPath = projPath.Substring(0, projPath.LastIndexOfAny("/\\".ToCharArray()));
project.ReadFromFile(projPath);
//var targetName = PBXProject.GetUnityTargetName();
//string projBuild = project.TargetGuidByName( targetName );
// 상위(PostProcessBuild_IOS.cs)에서 이미 지우고 생성했기 때문에 주석처리.
//project.RemoveLocalizationVariantGroup("I2 Localization");
// Set the Language Overrides
foreach (var code in langCodes)
{
if (code == null || code.Length < 2)
continue;
var LanguageDirRoot = LocalizationRoot + "/" + code + ".lproj";
if (!Directory.Exists(LanguageDirRoot))
Directory.CreateDirectory(LanguageDirRoot);
var infoPlistPath = LanguageDirRoot + "/InfoPlist.strings";
// AppName
//var InfoPlist = string.Format("CFBundleDisplayName = \"{0}\";", LocalizationManager.GetAppName(code));
//File.WriteAllText(infoPlistPath, InfoPlist);
// Privacy - NSUserTrackingUsageDescription
// 다른 Privacy 필요하면 아래 추가하면 됨.
var InfoPlist = string.Format("\n{0} = \"{1}\";", "NSUserTrackingUsageDescription", Get_NSUserTrackingUsageDescription(code));
File.AppendAllText(infoPlistPath, InfoPlist);
//var langProjectRoot = "I2Localization/"+code+".lproj";
// InfoPlist.strings만 수정할거라 Localizable.strings는 주석처리.
//var stringPaths = LanguageDirRoot + "/Localizable.strings";
//File.WriteAllText(stringPaths, string.Empty);
// AddLocalization은 PostProcessBuild_IOS.cs에서 했기 때문에 주석처리 함.
//project.AddLocalization(langProjectRoot + "/Localizable.strings", langProjectRoot + "/Localizable.strings", "I2 Localization");
//project.AddLocalization(langProjectRoot + "/InfoPlist.strings", langProjectRoot + "/InfoPlist.strings", "I2 Localization");
}
project.WriteToFile(projPath);
}
catch (System.Exception e)
{
Debug.Log (e);
}
}
/// <summary>
/// NSUserTrackingUsageDescription(IDFA/ATT)
/// </summary>
/// <param name="_code">국가코드</param>
/// <returns>로컬라이징 된 Description</returns>
private static string Get_NSUserTrackingUsageDescription(string _code)
{
string strDescription = string.Empty;
switch(_code)
{
case "en":
strDescription = "This identifier will be used to deliver personalized ads to you.";
break;
case "ko":
strDescription = "이 식별자는 맞춤형 광고를 제공하는 데 사용됩니다.";
break;
case "zh": // zh도 zh-CN(중국본토)으로 보도록 함
case "zh-CN":
strDescription = "该标识符将用于向您投放个性化广告。";
break;
case "zh-TW":
strDescription = "該標識符將用於向您投放個人化廣告。";
break;
case "ja":
strDescription = "この識別子は、パーソナライズされた広告を配信するために使用されます。";
break;
case "vi":
strDescription = "Mã nhận dạng này sẽ được sử dụng để phân phối quảng cáo được cá nhân hóa cho bạn.";
break;
case "es":
strDescription = "Este identificador se utilizará para enviarle anuncios personalizados.";
break;
case "it":
strDescription = "Questo identificatore verrà utilizzato per fornirti annunci personalizzati.";
break;
case "id":
strDescription = "Pengenal ini akan digunakan untuk menayangkan iklan yang dipersonalisasi kepada Anda.";
break;
case "th":
strDescription = "ตัวระบุนี้จะใช้ในการส่งโฆษณาส่วนบุคคลให้กับคุณ";
break;
case "pt":
strDescription = "Este identificador será utilizado para lhe entregar anúncios personalizados.";
break;
case "hi":
strDescription = "इस पहचानकर्ता का उपयोग आपको वैयक्तिकृत विज्ञापन देने के लिए किया जाएगा.";
break;
default:
strDescription = "This identifier will be used to deliver personalized ads to you.";
break;
}
return strDescription;
}
}
}
#endif