我正在尝试使用 AssetBundles 构建 Unity 游戏,并且我想使用 Apple AppStore 分发它们。但是当我尝试使用资源包时,应用程序就会崩溃并出现 SIGABRT 错误。
我遵循了this说明并对其进行了调整以满足我们的需求。 当加载时
request.error
返回一个空字符串(不是预期的 null)。
尽管
myLoadedAssetBundle.GetAllAssetNames()
按预期返回了完整的资产列表。
资源包显示在 XCode 中(参见下图)。
将存档上传到 AppStoreConnect 按需资源后标记为“是”,但与文档相比,未显示资产数量。
创建资源包:
public class CreateAssetBundles
{
static string iosAssetBundleDirectory = "AssetBundles/iOS";
[InitializeOnLoadMethod]
static void SetupResourcesBuild()
{
UnityEditor.iOS.BuildPipeline.collectResources += CollectResources;
}
static UnityEditor.iOS.Resource[] CollectResources()
{
var bundles = AssetDatabase.GetAllAssetBundleNames ();
var reslist = new List<UnityEditor.iOS.Resource> ();
foreach (var b in bundles)
{
reslist.Add(new UnityEditor.iOS.Resource(b,Path.Combine(iosAssetBundleDirectory, b)).AddOnDemandResourceTags(b));
}
return reslist.ToArray();
}
[MenuItem ("Assets/Build AssetBundles/iOS")]
static void BuildiOS ()
{
EnableDisableAtlas (true);
var options = BuildAssetBundleOptions.None;
bool shouldCheckODR = EditorUserBuildSettings.activeBuildTarget == BuildTarget.iOS;
#if UNITY_TVOS
shouldCheckODR |= EditorUserBuildSettings.activeBuildTarget == BuildTarget.tvOS;
#endif
if (shouldCheckODR)
{
#if IOS_APP_BUNDLE
if (PlayerSettings.iOS.useOnDemandResources)
{
options |= BuildAssetBundleOptions.UncompressedAssetBundle;
}
#endif
#if ENABLE_IOS_APP_SLICING
options |= BuildAssetBundleOptions.UncompressedAssetBundle;
#endif
if (!Directory.Exists(iosAssetBundleDirectory))
{
Directory.CreateDirectory(iosAssetBundleDirectory);
}
}
var ret = BuildPipeline.BuildAssetBundles (iosAssetBundleDirectory,
options,
BuildTarget.iOS);
EnableDisableAtlas (false);
}
}
加载资源包
public override IEnumerator DownloadAssetBundleAsync (string bundleName, StringParameter statusParameter, Image progressBar, float remainingPercentiles)
{
OnDemandResourcesRequest request = OnDemandResources.PreloadAsync(new string[] { bundleName });
while (!request.isDone)
{
yield return null;
}
if (request.error != null && request.error != "")
{
//handle error
}
DownloadFinished?.Invoke(bundleName);
yield break;
}
public override IEnumerator LoadAssetBundleFromFileAsync (string bundleName, StringParameter statusParameter, Image progressBar, float remainingPercentiles, bool checkOutdated)
{
var filepath = "res://" + bundleName;
var bundleLoadRequest = AssetBundle.LoadFromFileAsync(filepath);
yield return bundleLoadRequest;
while (!bundleLoadRequest.isDone)
{
yield return null;
}
var myLoadedAssetBundle = bundleLoadRequest.assetBundle;
if (myLoadedAssetBundle == null)
{
//Handle error
}
loadedAssetBundle = myLoadedAssetBundle;
}
SIGABRT
Incident Identifier: [REMOVED]
Beta Identifier: [REMOVED]
Hardware Model: iPad13,18
Process: [REMOVED] [547]
Path: /private/var/containers/Bundle/Application/[REMOVED]
Identifier: [REMOVED]
Version: 0.9.1 (21)
AppStoreTools: 14C17
AppVariant: 1:iPad13,18:16
Beta: YES
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: [REMOVED] [694]
Date/Time: 2022-12-12 13:45:12.5058 +0100
Launch Time: 2022-12-12 13:45:05.0791 +0100
OS Version: iPhone OS 16.1.1 (20B101)
Release Type: User
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 35
Application Specific Information:
abort() called
Last Exception Backtrace:
0 CoreFoundation 0x1d1171e88 __exceptionPreprocess + 164
1 libobjc.A.dylib 0x1ca5178d8 objc_exception_throw + 60
2 Foundation 0x1cb6259b0 -[_NSInlineData length] + 0
3 UnityFramework 0x10fc45370 AssetCatalogFile::Read(unsigned long long, unsigned long long, void*, unsigned long long*, FileReadFlags) + 88806256 (AssetCatalogFileSystem.mm:52)
4 UnityFramework 0x10fc45264 AssetCatalogFileSystemHandler::Read(FileEntryData&, VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 88805988 (AssetCatalogFileSystem.mm:178)
5 UnityFramework 0x10f0c1074 FileAccessor::Read(VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 76730484 (VirtualFileSystem.cpp:1011)
6 UnityFramework 0x10f6ad6c4 ArchiveStorageReader::ReadFromStorage(unsigned long long, unsigned long long, void*, unsigned long long*) + 82941636 (ArchiveStorageReader.cpp:587)
7 UnityFramework 0x10f6a5f80 ArchiveStorageReader::Read(VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 82911104 (ArchiveStorageReader.cpp:173)
8 UnityFramework 0x10f6a5d60 ArchiveReadFile::Read(VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 82910560 (ArchiveReadFile.cpp:42)
9 UnityFramework 0x10f6a4240 ArchiveFileSystem::Read(FileEntryData&, VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 82903616 (ArchiveFileSystem.cpp:267)
10 UnityFramework 0x10f0c1074 FileAccessor::Read(VFS::FileSize, unsigned long long, void*, unsigned long long*, FileReadFlags) + 76730484 (VirtualFileSystem.cpp:1011)
11 UnityFramework 0x10f61714c File::Read(VFS::FileSize, void*, unsigned long, FileReadFlags) + 82325836 (FileVFS.cpp:443)
12 UnityFramework 0x10f2b1ecc AsyncReadManagerThreaded::PumpRequests(dynamic_array<AsyncReadCommand*, 0ul>&, dynamic_array<AsyncReadCommand*, 0ul>&) + 78765772 (AsyncReadManagerThreaded.cpp:169)
13 UnityFramework 0x10f2b191c AsyncReadManagerThreaded::ThreadEntry() + 78764316 (AsyncReadManagerThreaded.cpp:248)
14 UnityFramework 0x10f2b12d0 AsyncReadManagerThreaded::StaticThreadEntry(void*) + 78762704 (AsyncReadManagerThreaded.cpp:118)
15 UnityFramework 0x10f6c6994 Thread::RunThreadWrapper(void*) + 83044756 (Thread.cpp:81)
16 libsystem_pthread.dylib 0x21d84b6cc _pthread_start + 148
17 libsystem_pthread.dylib 0x21d84aba4 thread_start + 8
正如来自 Unity 论坛的 Feyyyyy 所指出的: 将下载和读取AssetBundles细分为不同的功能时,请务必保留
request
。
如果
request
超出范围,AssetBundle 会被垃圾收集,并且应用程序在尝试读取数据时会崩溃。
可以通过将请求推送到静态列表来解决问题
private static List<OnDemandResourcesRequest> requestsList = new List<OnDemandResourcesRequest>();
public override IEnumerator DownloadAssetBundleAsync (string bundleName, StringParameter statusParameter, Image progressBar, float remainingPercentiles)
{
OnDemandResourcesRequest request = OnDemandResources.PreloadAsync(new string[] { bundleName });
while (!request.isDone)
{
yield return null;
}
if (request.error != null && request.error != "")
{
//handle error
}
requestsList.Add(request); // Push into list to prevent GC
DownloadFinished?.Invoke(bundleName);
yield break;
}