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 폴더에 추가
#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