diff --git a/.gitignore b/.gitignore
index d13b1ae7..402a80e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,8 @@
+# AI
+.claude
+.etabli
+
+# Build Output
Build/
TestBuilds/
scripts/python/__pycache__/
@@ -5,10 +10,19 @@ scripts/python/__pycache__/
**/.idea/*
**/Temp/*
plug-ins/**/TestPlayers
+**/Apple Plug-In Support/
+**/Apple Plug-In Support.meta
+**/NativeLibraries~/
+
+# VS Code/Xcode
**/.vsconfig
**/xcuserdata
*.vsconfig
**/.vscode/*
-**/Apple Plug-In Support/
-**/Apple Plug-In Support.meta
-**/NativeLibraries~/
+
+# IDE-generated solution/project files (regenerated by Unity's IDE integration)
+*.sln
+*.slnx
+*.csproj
+
+
diff --git a/Documentation/Quickstart.md b/Documentation/Quickstart.md
index 5e65648b..399f41f4 100644
--- a/Documentation/Quickstart.md
+++ b/Documentation/Quickstart.md
@@ -19,6 +19,8 @@ The first step is to download or clone the [Apple-Unity Plug-ins repository](htt
| Apple.GameController | [Apple.GameController Documentation](../plug-ins/Apple.GameController/Apple.GameController_Unity/Assets/Apple.GameController/Documentation~/Apple.GameController.md) |
| Apple.GameKit | [Apple.GameKit Documentation](../plug-ins/Apple.GameKit/Apple.GameKit_Unity/Assets/Apple.GameKit/Documentation~/Apple.GameKit.md) |
| Apple.PHASE | [Apple.PHASE Documentation](../plug-ins/Apple.PHASE/Apple.PHASE_Unity/Assets/Documentation~/Apple.PHASE.md) |
+| Apple.SpatialController | [Apple.SpatialController Documentation](../plug-ins/Apple.SpatialController/README.md) |
+| Apple.StoreKit | [Apple.StoreKit Documentation](../plug-ins/Apple.StoreKit/Apple.StoreKit_Unity/Assets/Apple.StoreKit/Documentation~/Apple.StoreKit.md) |
## 2. Build
After downloading the plug-in(s), you will need to build the native libraries. If you are familiar with Unity plug-ins, these are compiled assets found in a Unity project's `Assets/.../Plugins/{iOS, macOS, tvOS}/` directories. Along with some C# bridging scripts, they enable communication with Apple devices' native technologies.
diff --git a/README.md b/README.md
index 6fc07745..c7ae6a11 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,5 @@
# Apple Unity Plug-Ins
-## 27 Beta
-
-27 beta is now live! Watch the [WWDC26 video](https://developer.apple.com/videos/play/wwdc2026/378/) for information and check out the `27-beta` branch to test it out.
## Overview
The Apple Unity Plug-Ins expose a selection of Apple platform frameworks to Unity developers.
@@ -16,17 +13,19 @@ To get started with integration of these plug-ins into your Unity projects, run
| :------ | :---------- |
| Apple.Core | Provides integrated build post process management and Editor UI.
**Note:** Apple.Core is a dependency of all Apple Unity plug-ins.|
| Apple.Accessibility | Provides Apple's accessibility to Unity developers allowing adding supports to Apple's built-in assistive technologies such as VoiceOver.|
+| Apple.BackgroundAssets | Exposes Apple’s Background Assets framework to Unity developers, enabling out-of-band delivery of asset packs from Apple or third-party servers. The plug-in also automatically configures generated Xcode projects with a downloader extension and everything else that’s necessary to use Background Assets. |
| Apple.CoreHaptics | Brings Apple's Core Haptics framework to Unity developers, enabling for customizable haptic patterns and in-depth playback control on supported devices. This Plug-In also includes UIKit's UIFeedbackGenerator API.|
| Apple.GameController | Exposes Apple's GameController framework to Unity developers allowing for rich controller features in macOS, iOS, and tvOS apps. |
| Apple.GameKit | Allows Unity developers to easily integrate GameKit features such as leaderboards, achievements, and match making. |
| Apple.PHASE | The PHASE plug-in allows Unity developers to take full advantage of Apple's new geometry and material aware spatial audio system. |
| Apple.SpatialController | Exposes Apple's AccessoryTracking and GameController frameworks to Unity developers on visionOS allowing for spatial controller features in visionOS apps. Requires visionOS 26.0 |
+| Apple.StoreKit | Exposes Apple's StoreKit 2 framework to Unity developers, enabling in-app purchases, subscriptions, and transaction management with modern async/await patterns. |
## Minimum Supported OS Versions
| OS | Version |
| :- | :------ |
| iOS | 15.6 |
-| macOS | 11.5 |
+| macOS | 12.0 |
| tvOS | 15.6 |
| visionOS | 1.3 |
| watchOS | not supported |
diff --git a/build.py b/build.py
index b768fa91..d95e4d09 100755
--- a/build.py
+++ b/build.py
@@ -26,7 +26,7 @@
# Handle command line args
argument_parser = argparse.ArgumentParser(description="Builds all native libraries, packages plug-ins, and moves packages to build folder.")
-argument_parser.add_argument("-p", "--plugin-list", dest="plugin_list", nargs='*', default=[PluginID.ALL], help=f"Selects the plug-ins to process. Possible values are: {PluginID.ACCESSIBILITY}, {PluginID.CORE}, {PluginID.CORE_HAPTICS}, {PluginID.GAME_CONTROLLER}, {PluginID.SPATIAL_CONTROLLER}, {PluginID.GAME_KIT}, {PluginID.PHASE}, or {PluginID.ALL}. Default is: {PluginID.ALL}")
+argument_parser.add_argument("-p", "--plugin-list", dest="plugin_list", nargs='*', default=[PluginID.ALL], help=f"Selects the plug-ins to process. Possible values are: {PluginID.ACCESSIBILITY}, {PluginID.CORE}, {PluginID.CORE_HAPTICS}, {PluginID.GAME_CONTROLLER}, {PluginID.SPATIAL_CONTROLLER}, {PluginID.GAME_KIT}, {PluginID.PHASE}, {PluginID.STORE_KIT}, {PluginID.BACKGROUND_ASSETS}, or {PluginID.ALL}. Default is: {PluginID.ALL}")
argument_parser.add_argument("-m", "--platforms", dest="platform_list", nargs='*', default=[PlatformID.ALL], help=f"Selects the desired platforms to target when building native libraries. Possible values are: {PlatformID.IOS}, {PlatformID.IOS_SIMULATOR}, {PlatformID.MACOS}, {PlatformID.TVOS}, {PlatformID.TVOS_SIMULATOR}, {PlatformID.VISIONOS}, {PlatformID.VISIONOS_SIMULATOR}, {PlatformID.SIMULATORS}, {PlatformID.DEVICES} or {PlatformID.ALL}. Default is: {PlatformID.ALL}")
argument_parser.add_argument("-b", "--build-action", dest="build_actions", nargs='*', default=[BuildActionID.BUILD, BuildActionID.PACK], help=f"Sets the build actions for the selected plug-ins. Possible values are: {BuildActionID.BUILD}, {BuildActionID.PACK}, {BuildActionID.NONE} or {BuildActionID.ALL}. Defaults are: {BuildActionID.BUILD}, {BuildActionID.PACK}")
argument_parser.add_argument("-bc","--build-config", dest="build_config", default=ConfigID.ALL, help=f"Sets the build configuration to compile. Possible values are: {ConfigID.RELEASE}, {ConfigID.DEBUG}, or {ConfigID.ALL} which builds all other configs. Default is: {ConfigID.ALL}")
@@ -186,7 +186,7 @@ def Main():
break
elif platform_id in CTX.platforms:
if platform_id in supported_platforms:
- valid_platform_found = True
+ valid_platform_found = True
CTX.platforms[platform_id] = True
else:
CTX.printer.WarningMessage(f"Valid platform '{platform_id}' selected, but no {platform_id} SDK is installed.\nPlease add the SDK:\n {Printer.Bold('1.')} Open {Printer.Bold('Xcode')}\n {Printer.Bold('2.')} Open {Printer.Bold('Settings')} (Xcode > Settings...) or (⌘ + ,) \n {Printer.Bold('3.')} Go to the {Printer.Bold('Platforms')} tab\n {Printer.Bold('4.')} Install the {platform_id} SDK.")
@@ -235,7 +235,9 @@ def Main():
PluginID.GAME_CONTROLLER: False,
PluginID.SPATIAL_CONTROLLER: False,
PluginID.GAME_KIT: False,
- PluginID.PHASE: False
+ PluginID.PHASE: False,
+ PluginID.STORE_KIT: False,
+ PluginID.BACKGROUND_ASSETS: False
}
valid_plugin_found = False
@@ -249,7 +251,7 @@ def Main():
valid_plugin_found = True
break
else:
- utility.WarningMessage(f"Ignoring unknown plug-in '{plugin_id}'. Valid options are {PluginID.ACCESSIBILITY}, {PluginID.CORE}, {PluginID.CORE_HAPTICS}, {PluginID.GAME_CONTROLLER}, {PluginID.SPATIAL_CONTROLLER}, {PluginID.GAME_KIT}, {PluginID.PHASE}, or {PluginID.ALL} (Default)")
+ CTX.printer.WarningMessage(f"Ignoring unknown plug-in '{plugin_id}'. Valid options are {PluginID.ACCESSIBILITY}, {PluginID.CORE}, {PluginID.CORE_HAPTICS}, {PluginID.GAME_CONTROLLER}, {PluginID.SPATIAL_CONTROLLER}, {PluginID.GAME_KIT}, {PluginID.PHASE}, {PluginID.STORE_KIT}, {PluginID.BACKGROUND_ASSETS}, or {PluginID.ALL} (Default)")
# -------------------------------------------------------------------------
@@ -312,18 +314,18 @@ def Main():
CTX.printer.SectionHeading("Configure Build Paths")
# Configure build paths for packages
- CTX.build_path = pathlib.Path(build_args.output_path)
+ CTX.build_output_path = pathlib.Path(build_args.output_path)
- if CTX.clean_actions[CleanActionID.PACKAGES] and CTX.build_path.exists():
+ if CTX.clean_actions[CleanActionID.PACKAGES] and CTX.build_output_path.exists():
CTX.printer.StatusMessage("Cleaning packages.", "\n")
- CTX.printer.StatusMessageWithContext("Removing folder at path:", f"{CTX.build_path}")
- utility.RemoveFolder(CTX.build_path, prompt= not build_args.force_clean, printer= CTX.printer)
+ CTX.printer.StatusMessageWithContext("Removing folder at path:", f"{CTX.build_output_path}")
+ utility.RemoveFolder(CTX.build_output_path, prompt= not build_args.force_clean, printer= CTX.printer)
if CTX.build_actions[BuildActionID.BUILD] or CTX.build_actions[BuildActionID.PACK]:
- if not CTX.build_path.exists():
+ if not CTX.build_output_path.exists():
CTX.printer.Message(f"Build output path not found.", "\n")
- CTX.printer.StatusMessageWithContext("Creating: ", f"{CTX.build_path}")
- CTX.build_path.mkdir()
+ CTX.printer.StatusMessageWithContext("Creating: ", f"{CTX.build_output_path}")
+ CTX.build_output_path.mkdir()
# Configure and optionally clean paths for test builds
test_build_root_path = pathlib.Path(build_args.test_output_path)
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilityNode.cs b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilityNode.cs
index a8c0856b..87b8df63 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilityNode.cs
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilityNode.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
+using Apple.Core;
using UnityEngine;
namespace Apple.Accessibility
@@ -388,60 +389,36 @@ private void OnDestroy()
UnregisterAXElement(this);
}
- private static Dictionary axElements = new Dictionary();
+ private static Dictionary axElements = new();
static internal void RegisterAXElement(AccessibilityNode obj)
{
-#if UNITY_6000_4_OR_NEWER
- if (axElements.ContainsKey(EntityId.ToULong(obj.gameObject.GetEntityId())))
-#else
- if (axElements.ContainsKey((ulong)obj.gameObject.GetInstanceID()))
-#endif
+ if (axElements.ContainsKey(obj.gameObject.GetLongId()))
{
return;
}
-
-#if UNITY_6000_4_OR_NEWER
- axElements.Add(EntityId.ToULong(obj.gameObject.GetEntityId()), obj);
- AccessibilityNode parent = obj._accessibilityParent();
- ulong parentId = EntityId.ToULong(EntityId.None);
-#else
- axElements.Add((ulong)obj.gameObject.GetInstanceID(), obj);
+ axElements.Add(obj.gameObject.GetLongId(), obj);
AccessibilityNode parent = obj._accessibilityParent();
- ulong parentId = 0;
-#endif
+ // Use Unity's lifetime-aware null check, not C#'s: a destroyed-but-not-collected
+ // parent is non-null to `?.` but null to `parent != null` below, which would leave
+ // us reporting a live parentId alongside hasParent: false.
+ ulong parentId = 0;
if (parent)
{
-#if UNITY_6000_4_OR_NEWER
- parentId = EntityId.ToULong(parent.gameObject.GetEntityId());
-#else
- parentId = (ulong)parent.gameObject.GetInstanceID();
-#endif
+ parentId = parent.gameObject.GetLongId();
}
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
-#if UNITY_6000_4_OR_NEWER
- _UnityAX_RegisterElementWithIdentifier(EntityId.ToULong(obj.gameObject.GetEntityId()), parentId, parent != null);
-#else
- _UnityAX_RegisterElementWithIdentifier((ulong)obj.gameObject.GetInstanceID(), parentId, parent != null);
-#endif
+ _UnityAX_RegisterElementWithIdentifier(obj.gameObject.GetLongId(), parentId, parent != null);
#endif
}
static internal void UnregisterAXElement(AccessibilityNode obj)
{
-#if UNITY_6000_4_OR_NEWER
- axElements.Remove(EntityId.ToULong(obj.gameObject.GetEntityId()));
-#else
- axElements.Remove((ulong)obj.gameObject.GetInstanceID());
-#endif
+ axElements.Remove(obj.gameObject.GetLongId());
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
-#if UNITY_6000_4_OR_NEWER
- _UnityAX_UnregisterElementWithIdentifier(EntityId.ToULong(obj.gameObject.GetEntityId()));
-#else
- _UnityAX_UnregisterElementWithIdentifier((ulong)obj.gameObject.GetInstanceID());
-#endif
+ _UnityAX_UnregisterElementWithIdentifier(obj.gameObject.GetLongId());
#endif
}
@@ -897,7 +874,7 @@ private static void RegisterCallbacks()
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
[DllImport("__Internal")] private static extern void _UnityAX_InitializeAXRuntime();
- [DllImport("__Internal")] private static extern void _UnityAX_RegisterElementWithIdentifier(ulong identifier, ulong parentIdentifier, bool hasParent);
+ [DllImport("__Internal")] private static extern void _UnityAX_RegisterElementWithIdentifier(ulong identifier, ulong parentIdentifier, [MarshalAs(UnmanagedType.I1)] bool hasParent);
[DllImport("__Internal")] private static extern void _UnityAX_UnregisterElementWithIdentifier(ulong identifier);
private delegate string AccessibilityFrameDelegate(ulong identifier);
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilitySettings.cs b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilitySettings.cs
index fec756b8..93cde1ed 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilitySettings.cs
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/AccessibilitySettings.cs
@@ -483,6 +483,28 @@ public static bool IsOnOffSwitchLabelsEnabled
}
}
+
+ public delegate void IsAudioDescriptionEnabledChangedHandler();
+ ///
+ /// A notification that gets posted when the system's Audio Descriptions setting changes.
+ ///
+ public static IsAudioDescriptionEnabledChangedHandler onIsAudioDescriptionEnabledChanged;
+
+ ///
+ /// A Boolean value that indicates whether the Audio Descriptions setting is in an enabled state.
+ ///
+ public static bool IsAudioDescriptionEnabled
+ {
+ get
+ {
+#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
+ return _UnityAX_UIAccessibilityIsAudioDescriptionEnabled();
+#else
+ return false;
+#endif
+ }
+ }
+
#region Native Bridge
private static bool __registered = false;
@@ -512,6 +534,7 @@ private static void RegisterCallbacks()
_UnityAX_registerAccessibilityIsShakeToUndoEnabledDidChangeNotification(_UnityAX_UIAccessibilityIsShakeToUndoEnabledDidChangeNotification);
_UnityAX_registerAccessibilityShouldDifferentiateWithoutColorDidChangeNotification(_UnityAX_UIAccessibilityShouldDifferentiateWithoutColorDidChangeNotification);
_UnityAX_registerAccessibilityIsOnOffSwitchLabelsEnabledDidChangeNotification(_UnityAX_UIAccessibilityIsOnOffSwitchLabelsEnabledDidChangeNotification);
+ _UnityAX_registerAccessibilityIsAudioDescriptionEnabledDidChangeNotification(_UnityAX_UIAccessibilityIsAudioDescriptionEnabledDidChangeNotification);
#endif
__registered = true;
}
@@ -535,6 +558,7 @@ private static void _UnityAX_UIAccessibilityPreferredContentSizeCategoryDidChang
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsVoiceOverRunningDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsVoiceOverRunning();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsVoiceOverRunningDidChangeNotification(UIAccessibilityIsVoiceOverRunningDidChangeNotificationDelegate actionDelegate);
@@ -548,6 +572,7 @@ private static void _UnityAX_UIAccessibilityIsVoiceOverRunningDidChangeNotificat
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsSwitchControlRunningDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsSwitchControlRunning();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsSwitchControlRunningDidChangeNotification(UIAccessibilityIsSwitchControlRunningDidChangeNotificationDelegate actionDelegate);
@@ -561,6 +586,7 @@ private static void _UnityAX_UIAccessibilityIsSwitchControlRunningDidChangeNotif
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsSpeakSelectionEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsSpeakSelectionEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsSpeakSelectionEnabledDidChangeNotification(UIAccessibilityIsSpeakSelectionEnabledDidChangeNotificationDelegate actionDelegate);
@@ -574,6 +600,7 @@ private static void _UnityAX_UIAccessibilityIsSpeakSelectionEnabledDidChangeNoti
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsGuidedAccessEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsGuidedAccessEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsGuidedAccessEnabledDidChangeNotification(UIAccessibilityIsGuidedAccessEnabledDidChangeNotificationDelegate actionDelegate);
@@ -587,6 +614,7 @@ private static void _UnityAX_UIAccessibilityIsGuidedAccessEnabledDidChangeNotifi
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsMonoAudioEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsMonoAudioEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsMonoAudioEnabledDidChangeNotification(UIAccessibilityIsMonoAudioEnabledDidChangeNotificationDelegate actionDelegate);
@@ -600,6 +628,7 @@ private static void _UnityAX_UIAccessibilityIsMonoAudioEnabledDidChangeNotificat
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsClosedCaptioningEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsClosedCaptioningEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsClosedCaptioningEnabledDidChangeNotification(UIAccessibilityIsClosedCaptioningEnabledDidChangeNotificationDelegate actionDelegate);
@@ -614,6 +643,7 @@ private static void _UnityAX_UIAccessibilityIsClosedCaptioningEnabledDidChangeNo
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsInvertColorsEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsInvertColorsEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsInvertColorsEnabledDidChangeNotification(UIAccessibilityIsInvertColorsEnabledDidChangeNotificationDelegate actionDelegate);
@@ -627,6 +657,7 @@ private static void _UnityAX_UIAccessibilityIsInvertColorsEnabledDidChangeNotifi
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsBoldTextEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsBoldTextEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsBoldTextEnabledDidChangeNotification(UIAccessibilityIsBoldTextEnabledDidChangeNotificationDelegate actionDelegate);
@@ -640,6 +671,7 @@ private static void _UnityAX_UIAccessibilityIsBoldTextEnabledDidChangeNotificati
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityButtonShapesEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityButtonShapesEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityButtonShapesEnabledDidChangeNotification(UIAccessibilityButtonShapesEnabledDidChangeNotificationDelegate actionDelegate);
@@ -653,6 +685,7 @@ private static void _UnityAX_UIAccessibilityButtonShapesEnabledDidChangeNotifica
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsGrayscaleEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsGrayscaleEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsGrayscaleEnabledDidChangeNotification(UIAccessibilityIsGrayscaleEnabledDidChangeNotificationDelegate actionDelegate);
@@ -666,6 +699,7 @@ private static void _UnityAX_UIAccessibilityIsGrayscaleEnabledDidChangeNotificat
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsReduceTransparencyEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsReduceTransparencyEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsReduceTransparencyEnabledDidChangeNotification(UIAccessibilityIsReduceTransparencyEnabledDidChangeNotificationDelegate actionDelegate);
@@ -679,6 +713,7 @@ private static void _UnityAX_UIAccessibilityIsReduceTransparencyEnabledDidChange
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsReduceMotionEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsReduceMotionEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsReduceMotionEnabledDidChangeNotification(UIAccessibilityIsReduceMotionEnabledDidChangeNotificationDelegate actionDelegate);
@@ -692,6 +727,7 @@ private static void _UnityAX_UIAccessibilityIsReduceMotionEnabledDidChangeNotifi
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityPrefersCrossFadeTransitionsDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityPrefersCrossFadeTransitions();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityPrefersCrossFadeTransitionsDidChangeNotification(UIAccessibilityPrefersCrossFadeTransitionsDidChangeNotificationDelegate actionDelegate);
@@ -705,6 +741,7 @@ private static void _UnityAX_UIAccessibilityPrefersCrossFadeTransitionsDidChange
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsVideoAutoplayEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsVideoAutoplayEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsVideoAutoplayEnabledDidChangeNotification(UIAccessibilityIsVideoAutoplayEnabledDidChangeNotificationDelegate actionDelegate);
@@ -718,6 +755,7 @@ private static void _UnityAX_UIAccessibilityIsVideoAutoplayEnabledDidChangeNotif
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityDarkerSystemColorsEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityDarkerSystemColorsEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityDarkerSystemColorsEnabledDidChangeNotification(UIAccessibilityDarkerSystemColorsEnabledDidChangeNotificationDelegate actionDelegate);
@@ -731,6 +769,7 @@ private static void _UnityAX_UIAccessibilityDarkerSystemColorsEnabledDidChangeNo
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsSpeakScreenEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsSpeakScreenEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsSpeakScreenEnabledDidChangeNotification(UIAccessibilityIsSpeakScreenEnabledDidChangeNotificationDelegate actionDelegate);
@@ -744,6 +783,7 @@ private static void _UnityAX_UIAccessibilityIsSpeakScreenEnabledDidChangeNotific
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsShakeToUndoEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsShakeToUndoEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsShakeToUndoEnabledDidChangeNotification(UIAccessibilityIsShakeToUndoEnabledDidChangeNotificationDelegate actionDelegate);
@@ -757,6 +797,7 @@ private static void _UnityAX_UIAccessibilityIsShakeToUndoEnabledDidChangeNotific
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityShouldDifferentiateWithoutColorDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityShouldDifferentiateWithoutColor();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityShouldDifferentiateWithoutColorDidChangeNotification(UIAccessibilityShouldDifferentiateWithoutColorDidChangeNotificationDelegate actionDelegate);
@@ -770,6 +811,7 @@ private static void _UnityAX_UIAccessibilityShouldDifferentiateWithoutColorDidCh
#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
private delegate void UIAccessibilityIsOnOffSwitchLabelsEnabledDidChangeNotificationDelegate();
+ [return: MarshalAs(UnmanagedType.I1)]
[DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsOnOffSwitchLabelsEnabled();
[DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsOnOffSwitchLabelsEnabledDidChangeNotification(UIAccessibilityIsOnOffSwitchLabelsEnabledDidChangeNotificationDelegate actionDelegate);
@@ -780,6 +822,20 @@ private static void _UnityAX_UIAccessibilityIsOnOffSwitchLabelsEnabledDidChangeN
}
#endif
+#if (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
+ private delegate void UIAccessibilityIsAudioDescriptionEnabledDidChangeNotificationDelegate();
+
+ [return: MarshalAs(UnmanagedType.I1)]
+ [DllImport("__Internal")] private static extern bool _UnityAX_UIAccessibilityIsAudioDescriptionEnabled();
+ [DllImport("__Internal")] private static extern void _UnityAX_registerAccessibilityIsAudioDescriptionEnabledDidChangeNotification(UIAccessibilityIsAudioDescriptionEnabledDidChangeNotificationDelegate actionDelegate);
+
+ [AOT.MonoPInvokeCallback(typeof(UIAccessibilityIsAudioDescriptionEnabledDidChangeNotificationDelegate))]
+ private static void _UnityAX_UIAccessibilityIsAudioDescriptionEnabledDidChangeNotification()
+ {
+ onIsAudioDescriptionEnabledChanged?.Invoke();
+ }
+#endif
+
#endregion
}
}
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/CHANGELOG.md b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/CHANGELOG.md
index 93dbbc56..a2e8e19a 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/CHANGELOG.md
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/CHANGELOG.md
@@ -1,6 +1,23 @@
# CHANGELOG
All notable changes to this project will be documented in this file.
+## [1.2.0] - 2026-09-16
+### Added
+- Audio Descriptions support: the `IsAudioDescriptionEnabled` property and the
+ `onIsAudioDescriptionEnabledChanged` event.
+
+### Changed
+- Replaced deprecated `Object.GetInstanceID()` calls with Apple.Core's `GetLongId()`, so the plug-in
+ compiles warning-free on Unity 6 while still building against the Unity 2022.3 floor.
+- Updated the native project for Xcode 27 and raised its deployment targets to iOS 15.0 and
+ tvOS 15.0, matching the minimum OS versions the plug-ins already document as supported.
+- Now requires Apple.Core 3.3.0.
+
+### Fixed
+- Added `[MarshalAs(UnmanagedType.I1)]` to `bool` P/Invoke declarations so `bool` results marshal
+ correctly.
+- Fixed plug-in builds when the source root path contains a space character.
+
## [1.1.4] - 2025-01-29
- Remove references to some unused packages.
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/Tests/AccessibilityTests/AccessibilityNode_TestSuite.cs b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/Tests/AccessibilityTests/AccessibilityNode_TestSuite.cs
index 60dfca8f..1feaab15 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/Tests/AccessibilityTests/AccessibilityNode_TestSuite.cs
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/Tests/AccessibilityTests/AccessibilityNode_TestSuite.cs
@@ -1,5 +1,6 @@
using NUnit.Framework;
using System.Collections;
+using Apple.Core;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.SceneManagement;
@@ -58,11 +59,7 @@ public IEnumerator Test_AccessibilityLabel()
AccessibilityNode axObject = ButtonAXObject();
UnityEngine.Assertions.Assert.AreEqual(axObject.AccessibilityLabel, "Button");
-#if UNITY_6000_4_OR_NEWER
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(EntityId.ToULong(axObject.gameObject.GetEntityId()), "accessibilityLabel", "Button");
-#else
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult((ulong)axObject.gameObject.GetInstanceID(), "accessibilityLabel", "Button");
-#endif
+ bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(axObject.gameObject.GetLongId(), "accessibilityLabel", "Button");
UnityEngine.Assertions.Assert.IsTrue(succeeded);
yield return null;
@@ -79,11 +76,7 @@ public IEnumerator Test_AccessibilityValue()
AccessibilityNode axObject = ButtonAXObject();
UnityEngine.Assertions.Assert.AreEqual(axObject.AccessibilityValue, "ButtonValue");
-#if UNITY_6000_4_OR_NEWER
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(EntityId.ToULong(axObject.gameObject.GetEntityId()), "accessibilityValue", "ButtonValue");
-#else
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult((ulong)axObject.gameObject.GetInstanceID(), "accessibilityValue", "ButtonValue");
-#endif
+ bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(axObject.gameObject.GetLongId(), "accessibilityValue", "ButtonValue");
UnityEngine.Assertions.Assert.IsTrue(succeeded);
yield return null;
@@ -100,11 +93,7 @@ public IEnumerator Test_AccessibilityHint()
AccessibilityNode axObject = ButtonAXObject();
UnityEngine.Assertions.Assert.AreEqual(axObject.AccessibilityHint, "ButtonHint");
-#if UNITY_6000_4_OR_NEWER
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(EntityId.ToULong(axObject.gameObject.GetEntityId()), "accessibilityHint", "ButtonHint");
-#else
- bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult((ulong)axObject.gameObject.GetInstanceID(), "accessibilityHint", "ButtonHint");
-#endif
+ bool succeeded = AccessibilityTests.RuniOSSideUnitTestWithKeyPathExpectingStringResult(axObject.gameObject.GetLongId(), "accessibilityHint", "ButtonHint");
UnityEngine.Assertions.Assert.IsTrue(succeeded);
yield return null;
@@ -147,11 +136,7 @@ public IEnumerator Test_PerformMagicTap()
return true;
};
-#if UNITY_6000_4_OR_NEWER
- bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(axObject.gameObject.GetLongId());
expectedMagicTapCount += 1;
UnityEngine.Assertions.Assert.AreEqual(magicTapCount, expectedMagicTapCount);
UnityEngine.Assertions.Assert.IsTrue(tapSucceeded);
@@ -172,11 +157,7 @@ public IEnumerator Test_PerformMagicTap()
return false;
};
-#if UNITY_6000_4_OR_NEWER
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(axObject.gameObject.GetLongId());
expectedMagicTapCount += 1;
UnityEngine.Assertions.Assert.AreEqual(magicTapCount, expectedMagicTapCount);
UnityEngine.Assertions.Assert.IsFalse(tapSucceeded);
@@ -191,11 +172,7 @@ public IEnumerator Test_PerformMagicTap()
//Unimplemented tap
axObject.onAccessibilityPerformMagicTap = null;
-#if UNITY_6000_4_OR_NEWER
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformMagicTap(axObject.gameObject.GetLongId());
UnityEngine.Assertions.Assert.AreEqual(magicTapCount, expectedMagicTapCount);
UnityEngine.Assertions.Assert.IsFalse(tapSucceeded);
#if UNITY_IOS && !UNITY_EDITOR
@@ -229,11 +206,7 @@ public IEnumerator Test_PerformEscape()
return true;
};
-#if UNITY_6000_4_OR_NEWER
- bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ bool tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(axObject.gameObject.GetLongId());
expectedEscapeCount += 1;
UnityEngine.Assertions.Assert.AreEqual(EscapeCount, expectedEscapeCount);
UnityEngine.Assertions.Assert.IsTrue(tapSucceeded);
@@ -254,11 +227,7 @@ public IEnumerator Test_PerformEscape()
return false;
};
-#if UNITY_6000_4_OR_NEWER
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(axObject.gameObject.GetLongId());
expectedEscapeCount += 1;
UnityEngine.Assertions.Assert.AreEqual(EscapeCount, expectedEscapeCount);
UnityEngine.Assertions.Assert.IsFalse(tapSucceeded);
@@ -273,11 +242,7 @@ public IEnumerator Test_PerformEscape()
//Unimplemented tap
axObject.onAccessibilityPerformEscape = null;
-#if UNITY_6000_4_OR_NEWER
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(EntityId.ToULong(axObject.gameObject.GetEntityId()));
-#else
- tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape((ulong)axObject.gameObject.GetInstanceID());
-#endif
+ tapSucceeded = AccessibilityRuntime._UnityAX_AccessibilityPerformEscape(axObject.gameObject.GetLongId());
UnityEngine.Assertions.Assert.AreEqual(EscapeCount, expectedEscapeCount);
UnityEngine.Assertions.Assert.IsFalse(tapSucceeded);
#if UNITY_IOS && !UNITY_EDITOR
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/package.json b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/package.json
index 6e9a80cf..b94c7854 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/package.json
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Assets/Apple.Accessibility/package.json
@@ -1,11 +1,11 @@
{
"name": "com.apple.unityplugin.accessibility",
- "version": "1.1.4",
+ "version": "1.2.0",
"displayName": "Apple.Accessibility",
"description": "A Unity-port of Apple's UIAccessibility protocol from UIKit.framework",
"unity": "2022.3",
"dependencies": {
- "com.apple.unityplugin.core": "3.1.8"
+ "com.apple.unityplugin.core": "3.3.0"
},
"keywords": [
"accessibility",
@@ -22,7 +22,7 @@
{
"displayName": "UIAccessibility Demo",
"description": "Demos for UIAccessibility",
- "path": "Demos~"
+ "path": "Demos"
}
]
}
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/manifest.json b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/manifest.json
index 65f1993f..1ecbc883 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/manifest.json
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/manifest.json
@@ -1,8 +1,11 @@
{
"dependencies": {
"com.apple.unityplugin.core": "file:../../../Apple.Core/Apple.Core_Unity/Assets/Apple.Core",
- "com.unity.test-framework": "1.1.33",
- "com.unity.ugui": "1.0.0",
+ "com.unity.multiplayer.center": "1.0.1",
+ "com.unity.test-framework": "1.7.0",
+ "com.unity.ugui": "2.5.0",
+ "com.unity.modules.accessibility": "1.0.0",
+ "com.unity.modules.adaptiveperformance": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
@@ -16,6 +19,7 @@
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
+ "com.unity.modules.physicscore2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
@@ -29,9 +33,9 @@
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
+ "com.unity.modules.vectorgraphics": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
- "com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
},
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/packages-lock.json b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/packages-lock.json
index 142b9bab..5c7c45dd 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/packages-lock.json
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/Packages/packages-lock.json
@@ -7,30 +7,53 @@
"dependencies": {}
},
"com.unity.ext.nunit": {
- "version": "1.0.6",
+ "version": "2.1.0",
"depth": 1,
- "source": "registry",
- "dependencies": {},
- "url": "https://packages.unity.com"
+ "source": "builtin",
+ "dependencies": {}
+ },
+ "com.unity.multiplayer.center": {
+ "version": "1.0.1",
+ "depth": 0,
+ "source": "builtin",
+ "dependencies": {
+ "com.unity.modules.uielements": "1.0.0"
+ }
},
"com.unity.test-framework": {
- "version": "1.1.33",
+ "version": "1.7.0",
"depth": 0,
- "source": "registry",
+ "source": "builtin",
"dependencies": {
- "com.unity.ext.nunit": "1.0.6",
+ "com.unity.ext.nunit": "2.1.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
- },
- "url": "https://packages.unity.com"
+ }
},
"com.unity.ugui": {
- "version": "1.0.0",
+ "version": "2.5.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
- "com.unity.modules.imgui": "1.0.0"
+ "com.unity.modules.imgui": "1.0.0",
+ "com.unity.modules.audio": "1.0.0",
+ "com.unity.modules.physics2d": "1.0.0",
+ "com.unity.modules.physics": "1.0.0"
+ }
+ },
+ "com.unity.modules.accessibility": {
+ "version": "1.0.0",
+ "depth": 0,
+ "source": "builtin",
+ "dependencies": {}
+ },
+ "com.unity.modules.adaptiveperformance": {
+ "version": "1.0.0",
+ "depth": 0,
+ "source": "builtin",
+ "dependencies": {
+ "com.unity.modules.subsystems": "1.0.0"
}
},
"com.unity.modules.ai": {
@@ -43,7 +66,9 @@
"version": "1.0.0",
"depth": 0,
"source": "builtin",
- "dependencies": {}
+ "dependencies": {
+ "com.unity.modules.jsonserialize": "1.0.0"
+ }
},
"com.unity.modules.animation": {
"version": "1.0.0",
@@ -80,6 +105,12 @@
"com.unity.modules.animation": "1.0.0"
}
},
+ "com.unity.modules.hierarchycore": {
+ "version": "1.0.0",
+ "depth": 1,
+ "source": "builtin",
+ "dependencies": {}
+ },
"com.unity.modules.imageconversion": {
"version": "1.0.0",
"depth": 0,
@@ -111,6 +142,14 @@
"dependencies": {}
},
"com.unity.modules.physics2d": {
+ "version": "1.0.0",
+ "depth": 0,
+ "source": "builtin",
+ "dependencies": {
+ "com.unity.modules.physicscore2d": "1.0.0"
+ }
+ },
+ "com.unity.modules.physicscore2d": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
@@ -168,7 +207,10 @@
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
- "com.unity.modules.jsonserialize": "1.0.0"
+ "com.unity.modules.jsonserialize": "1.0.0",
+ "com.unity.modules.hierarchycore": "1.0.0",
+ "com.unity.modules.physics": "1.0.0",
+ "com.unity.modules.animation": "1.0.0"
}
},
"com.unity.modules.umbra": {
@@ -232,32 +274,32 @@
"com.unity.modules.imageconversion": "1.0.0"
}
},
- "com.unity.modules.vehicles": {
+ "com.unity.modules.vectorgraphics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
- "com.unity.modules.physics": "1.0.0"
+ "com.unity.modules.uielements": "1.0.0",
+ "com.unity.modules.imageconversion": "1.0.0",
+ "com.unity.modules.imgui": "1.0.0"
}
},
- "com.unity.modules.video": {
+ "com.unity.modules.vehicles": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
- "com.unity.modules.audio": "1.0.0",
- "com.unity.modules.ui": "1.0.0",
- "com.unity.modules.unitywebrequest": "1.0.0"
+ "com.unity.modules.physics": "1.0.0"
}
},
- "com.unity.modules.vr": {
+ "com.unity.modules.video": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
- "com.unity.modules.jsonserialize": "1.0.0",
- "com.unity.modules.physics": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
+ "com.unity.modules.audio": "1.0.0",
+ "com.unity.modules.ui": "1.0.0",
+ "com.unity.modules.unitywebrequest": "1.0.0"
}
},
"com.unity.modules.wind": {
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/MultiplayerManager.asset b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/MultiplayerManager.asset
new file mode 100644
index 00000000..2a936644
--- /dev/null
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/MultiplayerManager.asset
@@ -0,0 +1,7 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!655991488 &1
+MultiplayerManager:
+ m_ObjectHideFlags: 0
+ m_EnableMultiplayerRoles: 0
+ m_StrippingTypes: {}
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PackageManagerSettings.asset b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PackageManagerSettings.asset
index be4a7974..0c2a9056 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PackageManagerSettings.asset
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PackageManagerSettings.asset
@@ -12,32 +12,33 @@ MonoBehaviour:
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
- m_EnablePreviewPackages: 0
- m_EnablePackageDependencies: 0
+ m_EnablePreReleasePackages: 0
m_AdvancedSettingsExpanded: 1
m_ScopedRegistriesSettingsExpanded: 1
+ m_SeeAllPackageVersions: 0
+ m_DismissPreviewPackagesInUse: 0
oneTimeWarningShown: 0
- m_Registries:
- - m_Id: main
+ oneTimePackageErrorsPopUpShown: 0
+ m_MainRegistry:
+ m_Id: main
m_Name:
m_Url: https://packages.unity.com
m_Scopes: []
m_IsDefault: 1
+ m_IsUnityRegistry: 1
m_Capabilities: 7
+ m_ConfigSource: 0
+ m_Compliance:
+ m_Status: 0
+ m_Violations: []
+ m_ScopedRegistries: []
m_UserSelectedRegistryName:
m_UserAddingNewScopedRegistry: 0
m_RegistryInfoDraft:
- m_ErrorMessage:
- m_Original:
- m_Id:
- m_Name:
- m_Url:
- m_Scopes: []
- m_IsDefault: 0
- m_Capabilities: 0
m_Modified: 0
- m_Name:
- m_Url:
- m_Scopes:
- -
- m_SelectedScopeIndex: 0
+ m_ErrorMessage:
+ m_UserModificationsEntityId:
+ m_rawData: 568105589213756510
+ m_OriginalEntityId:
+ m_rawData: 568105589213756508
+ m_LoadAssets: 0
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PhysicsCoreProjectSettings2D.asset b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PhysicsCoreProjectSettings2D.asset
new file mode 100644
index 00000000..049c7454
--- /dev/null
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/PhysicsCoreProjectSettings2D.asset
@@ -0,0 +1,6 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!176606843 &1
+PhysicsCoreProjectSettings2D:
+ m_ObjectHideFlags: 0
+ m_PhysicsCoreSettings: {fileID: 0}
diff --git a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/ProjectVersion.txt b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/ProjectVersion.txt
index b8523623..c1608124 100644
--- a/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/ProjectVersion.txt
+++ b/plug-ins/Apple.Accessibility/Apple.Accessibility_Unity/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 2022.3.62f2
-m_EditorVersionWithRevision: 2022.3.62f2 (7670c08855a9)
+m_EditorVersion: 6000.5.2f1
+m_EditorVersionWithRevision: 6000.5.2f1 (eb73d3b415a1)
diff --git a/plug-ins/Apple.Accessibility/Native/Accessibility.xcconfig b/plug-ins/Apple.Accessibility/Native/Accessibility.xcconfig
index 49960f44..0e3dbcd5 100644
--- a/plug-ins/Apple.Accessibility/Native/Accessibility.xcconfig
+++ b/plug-ins/Apple.Accessibility/Native/Accessibility.xcconfig
@@ -25,7 +25,7 @@ NATIVE_LIBRARY_ROOT_FOLDER_NAME=Apple.Accessibility
// ------------------
GENERATE_INFOPLIST_FILE = YES
-CURRENT_PROJECT_VERSION = 1.1.4
+CURRENT_PROJECT_VERSION = 1.2.0
MARKETING_VERSION = $CURRENT_PROJECT_VERSION
VERSIONING_SYSTEM = apple-generic
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2021 - 2024 Apple, Inc. All rights reserved."
diff --git a/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/project.pbxproj b/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/project.pbxproj
index 80f0b7a0..74010569 100644
--- a/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/project.pbxproj
+++ b/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/project.pbxproj
@@ -500,7 +500,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_OUTPUT_FORMAT = XML;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.apple-plugins.AppleAccessibility-iOS";
PRODUCT_NAME = AppleAccessibility;
@@ -525,7 +525,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_OUTPUT_FORMAT = XML;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.apple-plugins.AppleAccessibility-iOS";
PRODUCT_NAME = AppleAccessibility;
@@ -556,7 +556,7 @@
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
- TVOS_DEPLOYMENT_TARGET = 9.0;
+ TVOS_DEPLOYMENT_TARGET = 15.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -580,7 +580,7 @@
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
- TVOS_DEPLOYMENT_TARGET = 9.0;
+ TVOS_DEPLOYMENT_TARGET = 15.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
diff --git a/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/xcshareddata/xcschemes/iOS - Debug.xcscheme b/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/xcshareddata/xcschemes/iOS - Debug.xcscheme
index 4e90694a..c07a35a3 100644
--- a/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/xcshareddata/xcschemes/iOS - Debug.xcscheme
+++ b/plug-ins/Apple.Accessibility/Native/Accessibility.xcodeproj/xcshareddata/xcschemes/iOS - Debug.xcscheme
@@ -10,7 +10,7 @@
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
+ scriptText = ""$AUP_SHELL_SCRIPT_PATH"/copy_native_libraries.sh
">
+ scriptText = ""$AUP_SHELL_SCRIPT_PATH"/copy_native_libraries.sh
">
+ scriptText = ""$AUP_SHELL_SCRIPT_PATH"/copy_native_libraries.sh
">
+ scriptText = ""$AUP_SHELL_SCRIPT_PATH"/copy_native_libraries.sh
">
#import
+#import
#import
#import
#import "AppleAccessibilitySafeOverride.h"
@@ -364,6 +365,20 @@ APPLE_ACCESSIBILITY_EXTERN bool _UnityAX_UIAccessibilityIsOnOffSwitchLabelsEnabl
}
}
+static AccessibilityNotificationDelegate __axIsAudioDescriptionEnabledDidChangeNotificationDelegate = NULL;
+APPLE_ACCESSIBILITY_EXTERN void _UnityAX_registerAccessibilityIsAudioDescriptionEnabledDidChangeNotification(AccessibilityNotificationDelegate delegate) { __axIsAudioDescriptionEnabledDidChangeNotificationDelegate = delegate; }
+APPLE_ACCESSIBILITY_EXTERN bool _UnityAX_UIAccessibilityIsAudioDescriptionEnabled(void)
+{
+ CFArrayRef characteristics = MAAudibleMediaCopyPreferredCharacteristics();
+ if ( characteristics == NULL )
+ {
+ return false;
+ }
+ bool enabled = CFArrayContainsValue(characteristics, CFRangeMake(0, CFArrayGetCount(characteristics)), MAMediaCharacteristicDescribesVideoForAccessibility);
+ CFRelease(characteristics);
+ return enabled;
+}
+
APPLE_ACCESSIBILITY_HIDDEN
@interface _AppleAccessibilityNotificationObserver: NSObject
@@ -547,6 +562,14 @@ - (void)_accessibilityStatusChangedCallback:(NSNotification *)notification {
return;
}
}
+ if ( [notification.name isEqualToString:(__bridge NSString *)kMAAudibleMediaSettingsChangedNotification] )
+ {
+ if ( __axIsAudioDescriptionEnabledDidChangeNotificationDelegate != NULL )
+ {
+ __axIsAudioDescriptionEnabledDidChangeNotificationDelegate();
+ }
+ return;
+ }
}
@end
@@ -600,6 +623,7 @@ APPLE_ACCESSIBILITY_EXTERN void _UnityAX_InitializeAXRuntime(void)
{
[center addObserver:_observer selector:@selector(_accessibilityStatusChangedCallback:) name:UIAccessibilityOnOffSwitchLabelsDidChangeNotification object:nil];
}
+ [center addObserver:_observer selector:@selector(_accessibilityStatusChangedCallback:) name:(__bridge NSString *)kMAAudibleMediaSettingsChangedNotification object:nil];
[AppleAccessibilityRuntime.sharedInstance setUnityAccessibilityFrame:^CGRect(NSNumber *identifier) {
if ( __axFrameDelegate == NULL )
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/.gitignore b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/.gitignore
new file mode 100644
index 00000000..2d7733f9
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/.gitignore
@@ -0,0 +1,11 @@
+.DS_Store
+Library
+Logs
+obj
+Temp
+TutorialInfo
+TutorialInfo.meta
+UserSettings
+*.sln
+*.slnx
+*.csproj
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets.meta
new file mode 100644
index 00000000..0ebaca47
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5b9eb7592a57c493cb3b45a0e168d5d2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md
new file mode 100644
index 00000000..004777fc
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md
@@ -0,0 +1,9 @@
+# CHANGELOG
+All notable changes to this project will be documented in this file.
+
+## [1.0.0] - 2026-06-10
+- Initial release. Exposes Apple's Background Assets framework to Unity developers, enabling
+ out-of-band delivery of asset packs from the App Store or from a self-hosted server via
+ `AssetPackManager`, `AssetPack`, and `AssetPackManifest`.
+- The build step automatically configures the generated Xcode project with a Background Assets
+ downloader extension and the accompanying hosting configuration.
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md.meta
new file mode 100644
index 00000000..c5847e21
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/CHANGELOG.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 100006d47951453e8b003d72f9ed8441
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor.meta
new file mode 100644
index 00000000..18b2422b
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b072840ce04094393a3af7f8fb225179
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef
new file mode 100644
index 00000000..ba8969b4
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef
@@ -0,0 +1,18 @@
+{
+ "name": "Apple.BackgroundAssets.Editor",
+ "references": [
+ "Apple.Core",
+ "Apple.Core.Editor"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef.meta
new file mode 100644
index 00000000..514b1ec2
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/Apple.BackgroundAssets.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4d28b7fa63cf3470a8e25053bf6422fa
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs
new file mode 100644
index 00000000..9bcb1448
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs
@@ -0,0 +1,16 @@
+using UnityEditor.iOS.Xcode;
+using UnityEngine;
+
+namespace Apple.BackgroundAssets {
+
+ [CreateAssetMenu(menuName = "Apple/Background Assets/Apple Hosting Configuration")]
+ public class AppleHostingConfiguration: HostingConfiguration {
+
+ public override void OnProcessInfoPlist(PlistDocument infoPlist) {
+ base.OnProcessInfoPlist(infoPlist);
+ infoPlist.root.SetBoolean(UsesAppleHostingKey, true);
+ }
+
+ }
+
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs.meta
new file mode 100644
index 00000000..e936211e
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/AppleHostingConfiguration.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: bdf76f4caa64d4d6390f38f16d1a79c5
\ No newline at end of file
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs
new file mode 100644
index 00000000..207203f6
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs
@@ -0,0 +1,204 @@
+using Apple.Core;
+using System.IO;
+using UnityEditor;
+using UnityEditor.iOS.Xcode;
+using UnityEngine;
+
+namespace Apple.BackgroundAssets {
+
+ public class BuildStep: AppleBuildStep {
+
+ public override string DisplayName => "Apple.BackgroundAssets";
+
+ public override BuildTarget[] SupportedTargets => new BuildTarget[] {BuildTarget.iOS, BuildTarget.tvOS, BuildTarget.StandaloneOSX, BuildTarget.VisionOS};
+
+ [Tooltip("Your app’s downloader extension’s bundle ID. It must have your main app’s bundle ID followed by a “.” character as a prefix.")]
+ public string DownloaderExtensionBundleId;
+
+ [Tooltip("The ID of the app group that your app and its downloader extension share.")]
+ public string AppGroupId;
+
+ [Tooltip("An object that provides information about where your asset packs are hosted and how large they are in aggregate.")]
+ public HostingConfiguration HostingConfiguration;
+
+ const string AppGroupIdKey = "BAAppGroupID";
+
+ const string AppGroupsKey = "com.apple.security.application-groups";
+
+ const string AppSandboxKey = "com.apple.security.app-sandbox";
+
+ public void OnEnable() {
+ if (Application.identifier != null) {
+ this.DownloaderExtensionBundleId = Application.identifier + ".downloader";
+ this.AppGroupId = "group." + Application.identifier;
+ }
+ }
+
+ public override void OnProcessInfoPlist(AppleBuildProfile appleBuildProfile, BuildTarget buildTarget, string generatedProjectPath, PlistDocument infoPlist) {
+ infoPlist.root.SetString(AppGroupIdKey, this.AppGroupId);
+ this.HostingConfiguration.OnProcessInfoPlist(infoPlist);
+ }
+
+ public override void OnProcessEntitlements(AppleBuildProfile appleBuildProfile, BuildTarget buildTarget, string generatedProjectPath, PlistDocument entitlements) {
+ PlistElementArray appGroups;
+ if (entitlements.root.values.ContainsKey(AppGroupsKey)) {
+ appGroups = entitlements.root[AppGroupsKey].AsArray();
+ } else {
+ appGroups = entitlements.root.CreateArray(AppGroupsKey);
+ }
+ bool appIsAlreadyInAppGroup = false;
+ foreach (PlistElement appGroupElement in appGroups.values) {
+ if (appGroupElement is PlistElementString appGroupStringElement && appGroupStringElement.value == this.AppGroupId) {
+ appIsAlreadyInAppGroup = true;
+ break;
+ }
+ }
+ if (!appIsAlreadyInAppGroup) {
+ appGroups.AddString(this.AppGroupId);
+ }
+ }
+
+ public override void OnProcessFrameworks(AppleBuildProfile appleBuildProfile, BuildTarget buildTarget, string generatedProjectPath, PBXProject pbxProject) {
+ // Background Assets requires that an app include a downloader extension that handles background asset downloads. The following code automatically creates and configures a downloader-extension target in the generated Xcode project.
+ string mainTargetGuid =
+ buildTarget == BuildTarget.StandaloneOSX
+ ? pbxProject.TargetGuidByName(Application.productName)
+ : pbxProject.GetUnityMainTargetGuid();
+ string downloaderTargetGuid = pbxProject.TargetGuidByName("Downloader");
+ if (downloaderTargetGuid == null) {
+ downloaderTargetGuid = pbxProject.AddTarget("Downloader", "appex", "com.apple.product-type.app-extension");
+ PlistDocument downloaderInfoPlist = new PlistDocument();
+ downloaderInfoPlist.root.SetString("CFBundleDisplayName", "$(PRODUCT_NAME)");
+ downloaderInfoPlist.root.SetString("CFBundleExecutable", "$(EXECUTABLE_NAME)");
+ downloaderInfoPlist.root.SetString("CFBundleIdentifier", "$(PRODUCT_BUNDLE_IDENTIFIER)");
+ downloaderInfoPlist.root.SetString("CFBundleName", "$(PRODUCT_NAME)");
+ downloaderInfoPlist.root.SetString("CFBundleVersion", PlayerSettings.iOS.buildNumber);
+ downloaderInfoPlist.root.SetString("CFBundleShortVersionString", PlayerSettings.bundleVersion);
+ PlistElementDict downloaderExtensionAttributes = downloaderInfoPlist.root.CreateDict("EXAppExtensionAttributes");
+ downloaderExtensionAttributes.SetString("EXExtensionPointIdentifier", "com.apple.background-asset-downloader-extension");
+ string fullDownloaderDirectoryPath = Path.Combine(generatedProjectPath, "Downloader");
+ if (!Directory.Exists(fullDownloaderDirectoryPath)) {
+ Directory.CreateDirectory(fullDownloaderDirectoryPath);
+ }
+ string fullDownloaderInfoPlistPath = Path.Combine(fullDownloaderDirectoryPath, "Info.plist");
+ downloaderInfoPlist.WriteToFile(fullDownloaderInfoPlistPath);
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "CODE_SIGN_ENTITLEMENTS", "Downloader/Downloader.entitlements");
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "CODE_SIGN_STYLE", "Automatic");
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "INFOPLIST_FILE", "Downloader/Info.plist");
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "PRODUCT_BUNDLE_IDENTIFIER", this.DownloaderExtensionBundleId);
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "PRODUCT_NAME", "Downloader");
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "SWIFT_VERSION", "6.0");
+ switch (buildTarget) {
+ case BuildTarget.iOS:
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "IPHONEOS_DEPLOYMENT_TARGET", PlayerSettings.iOS.targetOSVersionString);
+ break;
+ case BuildTarget.StandaloneOSX:
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "MACOSX_DEPLOYMENT_TARGET", PlayerSettings.macOS.targetOSVersion);
+ break;
+ case BuildTarget.tvOS:
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "TVOS_DEPLOYMENT_TARGET", PlayerSettings.tvOS.targetOSVersionString);
+ break;
+ case BuildTarget.VisionOS:
+ pbxProject.AddBuildProperty(downloaderTargetGuid, "XROS_DEPLOYMENT_TARGET", PlayerSettings.VisionOS.targetOSVersionString);
+ break;
+ }
+ pbxProject.AddFolderReference(fullDownloaderDirectoryPath, "Downloader");
+ pbxProject.AddSourcesBuildPhase(downloaderTargetGuid);
+ string fullBackgroundDownloadHandlerPath = Path.Combine(fullDownloaderDirectoryPath, "BackgroundDownloadHandler.swift");
+ string backgroundDownloadHandlerCode = "";
+ if (this.HostingConfiguration is AppleHostingConfiguration) {
+ backgroundDownloadHandlerCode = @"
+import ExtensionFoundation
+import StoreKit
+
+@main
+struct BackgroundDownloadHandler: StoreDownloaderExtension { }
+";
+ } else if (this.HostingConfiguration is SelfHostingConfiguration) {
+ backgroundDownloadHandlerCode += @"
+import BackgroundAssets
+import ExtensionFoundation
+
+@main
+struct BackgroundDownloadHandler: ManagedDownloaderExtension { }
+";
+ }
+ File.WriteAllText(fullBackgroundDownloadHandlerPath, backgroundDownloadHandlerCode);
+ string backgroundDownloadHandlerGuid = pbxProject.AddFile(fullBackgroundDownloadHandlerPath, "BackgroundDownloadHandler.swift");
+ pbxProject.AddFileToBuild(downloaderTargetGuid, backgroundDownloadHandlerGuid);
+ string embedExtensionKitExtensionsBuildPhaseGuid = pbxProject.AddCopyFilesBuildPhase(mainTargetGuid, "Embed ExtensionKit Extensions", "$(EXTENSIONS_FOLDER_PATH)", "16");
+ string downloaderProductGuid = pbxProject.FindFileGuidByProjectPath("Products/Downloader.appex");
+ pbxProject.AddFileToBuildSection(mainTargetGuid, embedExtensionKitExtensionsBuildPhaseGuid, downloaderProductGuid);
+ AppleNativeLibraryUtility.ProcessWrapperLibrary(this.DisplayName, buildTarget, generatedProjectPath, pbxProject);
+ AppleNativeLibraryUtility.AddPlatformFrameworkDependency("BackgroundAssets.framework", false, buildTarget, pbxProject);
+ } else {
+ string[] downloaderInfoPlistPaths = pbxProject.GetBuildPropertyForAnyConfig(downloaderTargetGuid, "INFOPLIST_FILE").Split(' ');
+ foreach (string downloaderInfoPlistPath in downloaderInfoPlistPaths) {
+ string fullDownloaderInfoPlistPath = Path.Combine(generatedProjectPath, downloaderInfoPlistPath);
+ PlistDocument downloaderInfoPlist = new PlistDocument();
+ downloaderInfoPlist.ReadFromFile(fullDownloaderInfoPlistPath);
+ downloaderInfoPlist.root.SetString("CFBundleVersion", PlayerSettings.iOS.buildNumber);
+ downloaderInfoPlist.root.SetString("CFBundleShortVersionString", PlayerSettings.bundleVersion);
+ downloaderInfoPlist.WriteToFile(fullDownloaderInfoPlistPath);
+ }
+ pbxProject.SetBuildProperty(downloaderTargetGuid, "PRODUCT_BUNDLE_IDENTIFIER", this.DownloaderExtensionBundleId);
+ switch (buildTarget) {
+ case BuildTarget.iOS:
+ pbxProject.SetBuildProperty(downloaderTargetGuid, "IPHONEOS_DEPLOYMENT_TARGET", PlayerSettings.iOS.targetOSVersionString);
+ break;
+ case BuildTarget.StandaloneOSX:
+ pbxProject.SetBuildProperty(downloaderTargetGuid, "MACOSX_DEPLOYMENT_TARGET", PlayerSettings.macOS.targetOSVersion);
+ break;
+ case BuildTarget.tvOS:
+ pbxProject.SetBuildProperty(downloaderTargetGuid, "TVOS_DEPLOYMENT_TARGET", PlayerSettings.tvOS.targetOSVersionString);
+ break;
+ case BuildTarget.VisionOS:
+ pbxProject.SetBuildProperty(downloaderTargetGuid, "XROS_DEPLOYMENT_TARGET", PlayerSettings.VisionOS.targetOSVersionString);
+ break;
+ }
+ }
+ string downloaderEntitlementsPath = pbxProject.GetEntitlementFilePathForTarget(downloaderTargetGuid);
+ string fullDownloaderEntitlementsPath = Path.Combine(generatedProjectPath, downloaderEntitlementsPath);
+ PlistDocument downloaderEntitlements = new PlistDocument();
+ if (File.Exists(fullDownloaderEntitlementsPath)) {
+ downloaderEntitlements.ReadFromFile(fullDownloaderEntitlementsPath);
+ }
+ PlistElementArray downloaderAppGroups;
+ if (downloaderEntitlements.root.values.ContainsKey(AppGroupsKey)) {
+ downloaderAppGroups = downloaderEntitlements.root[AppGroupsKey].AsArray();
+ } else {
+ downloaderAppGroups = downloaderEntitlements.root.CreateArray(AppGroupsKey);
+ }
+ bool downloaderIsAlreadyInAppGroup = false;
+ foreach (PlistElement appGroupElement in downloaderAppGroups.values) {
+ if (appGroupElement is PlistElementString appGroupStringElement && appGroupStringElement.value == this.AppGroupId) {
+ downloaderIsAlreadyInAppGroup = true;
+ break;
+ }
+ }
+ if (!downloaderIsAlreadyInAppGroup) {
+ downloaderAppGroups.AddString(this.AppGroupId);
+ }
+ if (!downloaderEntitlements.root.values.ContainsKey(AppSandboxKey)) {
+ downloaderEntitlements.root.SetBoolean(AppSandboxKey, true);
+ }
+ downloaderEntitlements.WriteToFile(fullDownloaderEntitlementsPath);
+
+ // This is a hack to work around the fact that Unity’s property-list API doesn’t support integer values that are greater than the maximum 32-bit signed integer.
+ string[] mainInfoPlistPaths = pbxProject.GetBuildPropertyForAnyConfig(mainTargetGuid, "INFOPLIST_FILE").Split(' ');
+ foreach (string mainInfoPlistPath in mainInfoPlistPaths) {
+ string fullMainInfoPlistPath = Path.Combine(generatedProjectPath, mainInfoPlistPath);
+ if (!File.Exists(fullMainInfoPlistPath)) {
+ continue;
+ }
+ string mainInfoPlistString = File.ReadAllText(fullMainInfoPlistPath);
+ foreach ((string Old, string New) replacement in this.HostingConfiguration.InfoPlistReplacements) {
+ mainInfoPlistString = mainInfoPlistString.Replace(replacement.Old, replacement.New);
+ }
+ File.WriteAllText(fullMainInfoPlistPath, mainInfoPlistString);
+ }
+ }
+
+ }
+
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs.meta
new file mode 100644
index 00000000..9a2437a7
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/BuildStep.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5e40d2626eebc4a30b8e9a5f93cd94c4
\ No newline at end of file
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs
new file mode 100644
index 00000000..dc7f7453
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs
@@ -0,0 +1,20 @@
+using UnityEditor.iOS.Xcode;
+using UnityEngine;
+
+namespace Apple.BackgroundAssets {
+
+ public abstract class HostingConfiguration: ScriptableObject {
+
+ internal virtual (string Old, string New)[] InfoPlistReplacements => new (string, string)[0];
+
+ const string HasManagedAssetPacksKey = "BAHasManagedAssetPacks";
+
+ protected const string UsesAppleHostingKey = "BAUsesAppleHosting";
+
+ public virtual void OnProcessInfoPlist(PlistDocument infoPlist) {
+ infoPlist.root.SetBoolean(HasManagedAssetPacksKey, true);
+ }
+
+ }
+
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs.meta
new file mode 100644
index 00000000..654a03ca
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/HostingConfiguration.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: ad98f708d6c25467ebbe44d95c9462b4
\ No newline at end of file
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs
new file mode 100644
index 00000000..dc18952a
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs
@@ -0,0 +1,84 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.iOS.Xcode;
+using UnityEngine;
+
+namespace Apple.BackgroundAssets {
+
+ [CreateAssetMenu(menuName = "Apple/Background Assets/Self Hosting Configuration")]
+ public class SelfHostingConfiguration: HostingConfiguration {
+
+ [Tooltip("The URL of your app’s manifest of asset packs that are available to download from your server.")]
+ public string ManifestUrl;
+
+ [Tooltip("The domains, including wildcards, from which your app can download asset packs.")]
+ public List DownloadDomainAllowList;
+
+ [Tooltip("The combined, maximum download size in bytes of asset packs with prefetch download policies that your app can download.")]
+ public ulong DownloadAllowance;
+
+ [Tooltip("The combined, maximum download size in bytes of asset packs with essential download policies that your app can download.")]
+ public ulong EssentialDownloadAllowance;
+
+ [Tooltip("The combined, maximum installation size in bytes of asset packs with prefetch download policies that your app can download.")]
+ public ulong MaxInstallSize;
+
+ [Tooltip("The combined, maximum installation size in bytes of asset packs with essential download policies that your app can download.")]
+ public ulong EssentialMaxInstallSize;
+
+ internal override (string Old, string New)[] InfoPlistReplacements => this.InfoPlistSentinelReplacements.Select(pair => ($"{pair.Sentinel}", $"{pair.Real}")).ToArray();
+
+ internal List<(int Sentinel, ulong Real)> InfoPlistSentinelReplacements = new List<(int, ulong)>();
+
+ const string ManifestUrlKey = "BAManifestURL";
+
+ const string InitialDownloadRestrictionsKey = "BAInitialDownloadRestrictions";
+
+ const string DownloadDomainAllowListKey = "BADownloadDomainAllowList";
+
+ const string DownloadAllowanceKey = "BADownloadAllowance";
+
+ const string EssentialDownloadAllowanceKey = "BAEssentialDownloadAllowance";
+
+ const string MaxInstallSizeKey = "BAMaxInstallSize";
+
+ const string EssentialMaxInstallSizeKey = "BAEssentialMaxInstallSize";
+
+ public override void OnProcessInfoPlist(PlistDocument infoPlist) {
+ base.OnProcessInfoPlist(infoPlist);
+ infoPlist.root.SetBoolean(UsesAppleHostingKey, false);
+ infoPlist.root.SetString(ManifestUrlKey, this.ManifestUrl);
+ PlistElementDict initialDownloadRestrictions = infoPlist.root.CreateDict(InitialDownloadRestrictionsKey);
+ PlistElementArray downloadDomainAllowList = initialDownloadRestrictions.CreateArray(DownloadDomainAllowListKey);
+ foreach (string downloadDomain in this.DownloadDomainAllowList) {
+ bool downloadDomainIsAlreadyInAllowList = false;
+ foreach (PlistElement downloadDomainElement in downloadDomainAllowList.values) {
+ if (downloadDomainElement is PlistElementString downloadDomainStringElement && downloadDomainStringElement.value == downloadDomain) {
+ downloadDomainIsAlreadyInAllowList = true;
+ break;
+ }
+ }
+ if (!downloadDomainIsAlreadyInAllowList) {
+ downloadDomainAllowList.AddString(downloadDomain);
+ }
+ }
+ int downloadAllowanceSentinel, essentialDownloadAllowanceSentinel, maxInstallSizeSentinel, essentialMaxInstallSizeSentinel;
+ do {
+ downloadAllowanceSentinel = Random.Range(1_000_000_000, int.MaxValue);
+ essentialDownloadAllowanceSentinel = Random.Range(1_000_000_000, int.MaxValue);
+ maxInstallSizeSentinel = Random.Range(1_000_000_000, int.MaxValue);
+ essentialMaxInstallSizeSentinel = Random.Range(1_000_000_000, int.MaxValue);
+ } while ((new HashSet(new int[] { downloadAllowanceSentinel, essentialDownloadAllowanceSentinel, maxInstallSizeSentinel, essentialMaxInstallSizeSentinel })).Count < 4);
+ initialDownloadRestrictions.SetInteger(DownloadAllowanceKey, downloadAllowanceSentinel);
+ initialDownloadRestrictions.SetInteger(EssentialDownloadAllowanceKey, essentialDownloadAllowanceSentinel);
+ infoPlist.root.SetInteger(MaxInstallSizeKey, maxInstallSizeSentinel);
+ infoPlist.root.SetInteger(EssentialMaxInstallSizeKey, essentialMaxInstallSizeSentinel);
+ this.InfoPlistSentinelReplacements.Add((downloadAllowanceSentinel, this.DownloadAllowance));
+ this.InfoPlistSentinelReplacements.Add((essentialDownloadAllowanceSentinel, this.EssentialDownloadAllowance));
+ this.InfoPlistSentinelReplacements.Add((maxInstallSizeSentinel, this.MaxInstallSize));
+ this.InfoPlistSentinelReplacements.Add((essentialMaxInstallSizeSentinel, this.EssentialMaxInstallSize));
+ }
+
+ }
+
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs.meta
new file mode 100644
index 00000000..7787a9ab
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Editor/SelfHostingConfiguration.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 9b2a9759bc3cb4c8ab4819d23b005d66
\ No newline at end of file
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime.meta
new file mode 100644
index 00000000..9b287d94
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6b767cbd186c74780989866a8f26199a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef
new file mode 100644
index 00000000..8cd3edfd
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef
@@ -0,0 +1,22 @@
+{
+ "name": "Apple.BackgroundAssets",
+ "rootNamespace": "",
+ "references": [
+ "Apple.Core"
+ ],
+ "includePlatforms": [
+ "Editor",
+ "iOS",
+ "macOSStandalone",
+ "tvOS",
+ "VisionOS"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": true,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef.meta
new file mode 100644
index 00000000..1cda8fde
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/Apple.BackgroundAssets.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5a89ffc3c409247ab8a4ff4240bdad8d
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs
new file mode 100644
index 00000000..1c313ba3
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Apple.BackgroundAssets {
+
+ /// An archive of assets that the system downloads together.
+ public class AssetPack {
+
+ /// The status of an asset pack.
+ public class Status {
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct baw_assetpack_status_res {
+
+ [FieldOffset(0)]
+ internal byte success;
+
+ [FieldOffset(0)]
+ internal Error.baw_err failure;
+
+ }
+
+ byte RawValue;
+
+ internal Status() {
+ this.RawValue = 0;
+ }
+
+ internal Status(byte rawValue) {
+ this.RawValue = rawValue;
+ }
+
+ /// Returns whether this status object indicates that the asset pack is available to download.
+ /// Whether the asset pack is available to download.
+ public bool IsDownloadAvailable() {
+ return (this.RawValue & 0b0000001) > 0;
+ }
+
+ /// Returns whether this status object indicates that an update to the asset pack is available to download.
+ /// Whether an update is available to download.
+ public bool IsUpdateAvailable() {
+ return (this.RawValue & 0b0000010) > 0;
+ }
+
+ /// Returns whether this status object indicates that the downloaded asset pack is up to date.
+ /// Whether the asset pack is up to date.
+ public bool IsUpToDate() {
+ return (this.RawValue & 0b0000100) > 0;
+ }
+
+ ///
+ /// Returns whether this status object indicates that the downloaded asset pack is out of date.
+ ///
+ /// A return value of true doesn’t necessarily imply that an update to the asset pack can be downloaded over the current network connection. Call IsUpdateAvailable() to determine whether an update can currently be downloaded.
+ ///
+ /// Whether the asset pack is out of date.
+ public bool IsOutOfDate() {
+ return (this.RawValue & 0b0001000) > 0;
+ }
+
+ ///
+ /// Returns whether this status object indicates that the asset pack is no longer available to download.
+ ///
+ /// Obsolete asset packs can’t be updated, and they also can’t be redownloaded once removed.
+ ///
+ /// Whether the asset pack is obsolete.
+ public bool IsObsolete() {
+ return (this.RawValue & 0b0010000) > 0;
+ }
+
+ /// Returns whether this status object indicates that the system is currently downloading the asset pack.
+ /// Whether the asset pack is being downloaded.
+ public bool IsDownloading() {
+ return (this.RawValue & 0b0100000) > 0;
+ }
+
+ /// Returns whether this status object indicates that the system finished downloading the asset pack.
+ /// Whether the asset pack is downloaded.
+ public bool IsDownloaded() {
+ return (this.RawValue & 0b1000000) > 0;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct baw_assetpack {
+
+ IntPtr impl;
+
+ }
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpack_deinit(baw_assetpack assetpack);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern string baw_assetpack_id(baw_assetpack assetpack);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern ulong baw_assetpack_downloadsize(baw_assetpack assetpack);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern ushort baw_assetpack_version(baw_assetpack assetpack);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern Language.baw_lang baw_assetpack_lang(baw_assetpack assetpack);
+
+ internal baw_assetpack CAssetPack;
+
+ internal AssetPack(baw_assetpack cAssetPack) {
+ this.CAssetPack = cAssetPack;
+ }
+
+ ~AssetPack() {
+ baw_assetpack_deinit(this.CAssetPack);
+ }
+
+ /// Returns a unique ID for this asset pack.
+ /// The ID.
+ public string GetId() {
+ return baw_assetpack_id(this.CAssetPack);
+ }
+
+ ///
+ /// Returns the size of the download file containing this asset pack in bytes.
+ ///
+ /// This is different than the installation size, which could be larger.
+ ///
+ /// The download size.
+ public long GetDownloadSize() {
+ return (long) baw_assetpack_downloadsize(this.CAssetPack);
+ }
+
+ /// Returns this asset pack’s version number.
+ /// The version number.
+ public ushort GetVersion() {
+ return baw_assetpack_version(this.CAssetPack);
+ }
+
+ /// Returns the language for which this asset pack is localized.
+ /// The language.
+ public Language GetLanguage() {
+ return new Language(baw_assetpack_lang(this.CAssetPack));
+ }
+
+ }
+
+}
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs.meta b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs.meta
new file mode 100644
index 00000000..1c55d18f
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPack.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 07af9e94b8d9a4f879035bb7916fa062
\ No newline at end of file
diff --git a/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPackManager.cs b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPackManager.cs
new file mode 100644
index 00000000..4482f2dc
--- /dev/null
+++ b/plug-ins/Apple.BackgroundAssets/Apple.BackgroundAssets_Unity/Assets/Apple.BackgroundAssets/Runtime/AssetPackManager.cs
@@ -0,0 +1,1064 @@
+using AOT;
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apple.BackgroundAssets {
+
+ ///
+ /// A class that manages asset packs.
+ ///
+ /// The first time that your code refers to the manager, Background Assets considers that your app is opting into automatic system management of your asset packs.
+ ///
+ public static class AssetPackManager {
+
+ #nullable enable
+
+ enum baw_assetpackmanager_downloadstatusupdate_kind {
+ baw_assetpackmanager_downloadstatusupdate_kind_began,
+ baw_assetpackmanager_downloadstatusupdate_kind_paused,
+ baw_assetpackmanager_downloadstatusupdate_kind_downloading,
+ baw_assetpackmanager_downloadstatusupdate_kind_finished,
+ baw_assetpackmanager_downloadstatusupdate_kind_failed
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct baw_assetpackmanager_downloadstatusupdate {
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct __Unnamed_union_payload {
+
+ [FieldOffset(0)]
+ internal double progress;
+
+ [FieldOffset(0)]
+ internal Error.baw_err err;
+
+ }
+
+ internal baw_assetpackmanager_downloadstatusupdate_kind kind;
+
+ internal AssetPack.baw_assetpack assetpack;
+
+ internal __Unnamed_union_payload payload;
+
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ struct baw_assetpackmanager_assetpack_update_res {
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct __Unnamed_struct_success {
+
+ internal long updatingc;
+
+ internal unsafe IntPtr* updatingv;
+
+ internal long removedc;
+
+ internal unsafe IntPtr* removedv;
+
+ }
+
+ [FieldOffset(0)]
+ internal __Unnamed_struct_success success;
+
+ [FieldOffset(0)]
+ internal Error.baw_err failure;
+
+ }
+
+ /// The status of an asset-pack download.
+ public abstract class DownloadStatusUpdate {
+
+ /// A status update that indicates that the download began or resumed after being paused.
+ public class Began : DownloadStatusUpdate {
+
+ internal Began(AssetPack assetPack) : base(assetPack) { }
+
+ public override string ToString() {
+ return $"{this.AssetPack.GetId()}: Began";
+ }
+
+ }
+
+ /// A status update that indicates that the download paused.
+ public class Paused : DownloadStatusUpdate {
+
+ internal Paused(AssetPack assetPack) : base(assetPack) { }
+
+ public override string ToString() {
+ return $"{this.AssetPack.GetId()}: Paused";
+ }
+
+ }
+
+ /// A status update that indicates that the download is in progress.
+ public class Downloading : DownloadStatusUpdate {
+
+ /// The download progress, represented as a portion between 0 and 1 (inclusive).
+ public readonly double Progress;
+
+ internal Downloading(AssetPack assetPack, double progress) : base(assetPack) {
+ this.Progress = progress;
+ }
+
+ public override string ToString() {
+ return $"{this.AssetPack.GetId()}: Downloading ({this.Progress})";
+ }
+
+ }
+
+ /// A status update that indicates that the download completed and that the asset pack is available locally.
+ public class Finished : DownloadStatusUpdate {
+
+ internal override bool IsTerminal {
+ get {
+ return true;
+ }
+ }
+
+ internal Finished(AssetPack assetPack) : base(assetPack) { }
+
+ public override string ToString() {
+ return $"{this.AssetPack.GetId()}: Finished";
+ }
+
+ }
+
+ /// A status update that indicates that the download failed.
+ public class Failed : DownloadStatusUpdate {
+
+ /// An error that indicates why the download failed.
+ public readonly Error Error;
+
+ internal override bool IsTerminal {
+ get {
+ return true;
+ }
+ }
+
+ internal Failed(AssetPack assetPack, Error error) : base(assetPack) {
+ this.Error = error;
+ }
+
+ public override string ToString() {
+ return $"{this.AssetPack.GetId()}: Failed ({this.Error})";
+ }
+
+ }
+
+ /// The asset pack to which this status update pertains.
+ public readonly AssetPack AssetPack;
+
+ internal virtual bool IsTerminal {
+ get {
+ return false;
+ }
+ }
+
+ DownloadStatusUpdate(AssetPack assetPack) {
+ this.AssetPack = assetPack;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct DownloadStatusUpdatesContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object LockObject;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object? StatusUpdate;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object? AssetPackId;
+
+ internal DownloadStatusUpdatesContext(string? assetPackId) {
+ this.LockObject = new object();
+ this.StatusUpdate = null;
+ this.Semaphore = new SemaphoreSlim(0);
+ this.AssetPackId = assetPackId;
+ }
+
+ internal object GetLockObject() {
+ return this.LockObject;
+ }
+
+ internal DownloadStatusUpdate? GetStatusUpdate() {
+ return (DownloadStatusUpdate?) this.StatusUpdate;
+ }
+
+ internal void SetStatusUpdate(DownloadStatusUpdate statusUpdate) {
+ this.StatusUpdate = statusUpdate;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ internal void ResetSemaphore() {
+ this.Semaphore = new SemaphoreSlim(0);
+ }
+
+ internal string? GetAssetPackId() {
+ return (string?) this.AssetPackId;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct ManifestContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Result;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static ManifestContext Create() {
+ return new ManifestContext {
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Result GetResult() {
+ return (Result) this.Result;
+ }
+
+ internal void SetResult(Result result) {
+ this.Result = result;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct AssetPackStatusContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Result;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static AssetPackStatusContext Create() {
+ return new AssetPackStatusContext {
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Result GetResult() {
+ return (Result) this.Result;
+ }
+
+ internal void SetResult(Result result) {
+ this.Result = result;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct LocalAssetPackStatusContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Status;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static LocalAssetPackStatusContext Create() {
+ return new LocalAssetPackStatusContext {
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal AssetPack.Status GetStatus() {
+ return (AssetPack.Status) this.Status;
+ }
+
+ internal void SetStatus(AssetPack.Status status) {
+ this.Status = status;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct EnsureLocalAvailabilityContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object? Error;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static EnsureLocalAvailabilityContext Create() {
+ return new EnsureLocalAvailabilityContext {
+ Error = null,
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Error? GetError() {
+ return (Error?) this.Error;
+ }
+
+ internal void SetError(Error error) {
+ this.Error = error;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct CheckForUpdatesContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Result;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static CheckForUpdatesContext Create() {
+ return new CheckForUpdatesContext {
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Result<(string[], string[]), Error> GetResult() {
+ return (Result<(string[], string[]), Error>) this.Result;
+ }
+
+ internal void SetResult(Result<(string[], string[]), Error> result) {
+ this.Result = result;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct RemoveAssetPackContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object? Error;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static RemoveAssetPackContext Create() {
+ return new RemoveAssetPackContext {
+ Error = null,
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Error? GetError() {
+ return (Error?) this.Error;
+ }
+
+ internal void SetError(Error error) {
+ this.Error = error;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct LocallyAvailableLanguagesContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Languages;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static LocallyAvailableLanguagesContext Create() {
+ return new LocallyAvailableLanguagesContext {
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Language[] GetLanguages() {
+ return (Language[]) this.Languages;
+ }
+
+ internal void SetLanguages(Language[] languages) {
+ this.Languages = languages;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct ReconcilePreferredLanguagesContext {
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object? Error;
+
+ [MarshalAs(UnmanagedType.IUnknown)]
+ object Semaphore;
+
+ internal static ReconcilePreferredLanguagesContext Create() {
+ return new ReconcilePreferredLanguagesContext {
+ Error = null,
+ Semaphore = new SemaphoreSlim(0)
+ };
+ }
+
+ internal Error? GetError() {
+ return (Error?) this.Error;
+ }
+
+ internal void SetError(Error error) {
+ this.Error = error;
+ }
+
+ internal SemaphoreSlim GetSemaphore() {
+ return (SemaphoreSlim) this.Semaphore;
+ }
+
+ }
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_downloadstatusupdates(string? id, IntPtr ctx, FDownloadStatusUpdates cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_manifest(IntPtr ctx, FManifest cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_status(AssetPack.baw_assetpack assetpack, IntPtr ctx, FAssetPackStatus cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_status_local(string id, IntPtr ctx, FAssetPackStatusLocal cb);
+
+ [DllImport(InteropUtility.DllName)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool baw_assetpackmanager_assetpack_local(string id);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_local_ensure(AssetPack.baw_assetpack assetpack, IntPtr ctx, FAssetPackLocalEnsure cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_local_ensure_update(AssetPack.baw_assetpack assetpack, bool update, IntPtr ctx, FAssetPackLocalEnsure cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_local_ensure_updatev(int assetpackc, AssetPack.baw_assetpack[] assetpackv, bool update, IntPtr ctx, FAssetPackLocalEnsure cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_update(IntPtr ctx, FAssetPackUpdate cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_assetpack_remove(string id, IntPtr ctx, FAssetPackRemove cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern Language.baw_lang baw_assetpackmanager_lang_resolved();
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_lang_resolved_set(Language.baw_lang lang);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_lang_local(IntPtr ctx, FLangLocal cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_lang_reconcile(IntPtr ctx, FLangReconcile cb);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern int baw_assetpackmanager_open(string path, string? id, out Error.baw_err err);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern int baw_assetpackmanager_open_lang(string path, Language.baw_lang lang, out Error.baw_err err);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern IntPtr baw_assetpackmanager_url(string path, out Error.baw_err err);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern IntPtr baw_assetpackmanager_url_lang(string path, Language.baw_lang lang, out Error.baw_err err);
+
+ [DllImport(InteropUtility.DllName)]
+ static extern void baw_assetpackmanager_url_deinit(IntPtr url);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate void FDownloadStatusUpdates(baw_assetpackmanager_downloadstatusupdate downloadstatusupdate, IntPtr ctx);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate void FManifest(AssetPackManifest.baw_assetpackmanifest_res res, Result