iOS 27 adds language-aware delivery to Managed Background Assets, allowing the system to download only the asset packs that match a player's preferred language setting. This reduces on-device storage and download size for games with multilingual content.
• iOS 27 adds localized asset packs: the system now reads the user's preferred language from Settings and delivers only the matching language asset packs.
• Automatic fallback chain introduced: regional variant → base language → primary app language.
• New xcrun ba-package convert CLI tool converts Steam depot manifests into Background Assets–compatible asset pack archives.
• New Apple Unity plug-ins for Background Assets and StoreKit are now available, bridging the native frameworks to a C# API for Unity game developers.
• Players only download assets for their chosen language — dramatically reducing storage footprint for games with audio, video, or text in multiple languages.
• Automatic language fallback (regional → base language → primary app language) means developers don't need to handle edge cases manually.
• A new xcrun ba-package convert tool can convert Steam depot manifests directly into Apple asset pack archives, significantly lowering the barrier for cross-platform game developers.
Shows how to add a language tag to a Background Assets manifest JSON and programmatically check whether a required localized asset pack is available before serving in-game content.
import BackgroundAssets
import SwiftUI
// MARK: - Asset Pack Manager
@MainActor
class LocalizedAssetPackManager: ObservableObject {
@Published var packStatus: String = "Checking..."
@Published var downloadProgress: Double = 0.0
// The identifier matches the one declared in your asset pack manifest JSON
// Manifest example (AssetPacks/de.json):
// {
// "id": "com.example.thecoast.audio-de",
// "language": "de",
// "url": "https://example.com/packs/audio-de.baa",
// "version": 1
// }
private let germanAudioPackID = "com.example.thecoast.audio-de"
func checkAndDownloadIfNeeded() async {
let manager = BADownloadManager.shared
do {
// Fetch all currently scheduled or finished downloads
let downloads = try manager.fetchCurrentDownloads()
let alreadyQueued = downloads.contains {
$0.identifier == germanAudioPackID
}
if alreadyQueued {
packStatus = "Download already in progress or complete."
return
}
// Schedule the localized asset pack download
let download = BAURLDownload(
identifier: germanAudioPackID,
request: URLRequest(url: URL(string: "https://example.com/packs/audio-de.baa")!),
fileSize: 52_428_800, // 50 MB
applicationGroupIdentifier: "group.com.example.thecoast"
)
try manager.startForegroundDownload(download)
packStatus = "Downloading German audio pack..."
// Monitor progress
await monitorProgress(for: download)
} catch {
packStatus = "Error: \(error.localizedDescription)"
}
}
private func monitorProgress(for download: BAURLDownload) async {
// In production, implement BADownloadManagerDelegate
// to receive -downloadDidBegin:, -download:didWriteBytes:, -downloadDidFinish:
// Here we simulate a progress observation pattern
for try? await update in simulatedProgressUpdates() {
downloadProgress = update
if update >= 1.0 {
packStatus = "German audio pack ready!"
break
}
}
}
private func simulatedProgressUpdates() -> AsyncStream<Double> {
AsyncStream { continuation in
Task {
for i in 1...10 {
try? await Task.sleep(for: .milliseconds(300))
continuation.yield(Double(i) / 10.0)
}
continuation.finish()
}
}
}
}
// MARK: - SwiftUI View
struct LocalizedPackView: View {
@StateObject private var manager = LocalizedAssetPackManager()
var body: some View {
VStack(spacing: 20) {
Text("Localized Asset Packs")
.font(.title2.bold())
Text(manager.packStatus)
.foregroundStyle(.secondary)
if manager.downloadProgress > 0 && manager.downloadProgress < 1.0 {
ProgressView(value: manager.downloadProgress)
.padding(.horizontal)
}
Button("Download German Audio Pack") {
Task { await manager.checkAndDownloadIfNeeded() }
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
#Preview {
LocalizedPackView()
}iOS 27 adds sectioned queries, codable model attributes, ResultsObserver for non-SwiftUI change observation, and HistoryObserver for reacting to persistent history changes in SwiftData.
USDKit is a new first-party Swift framework introduced in iOS/macOS 27 that brings native USD scene creation, composition, modification, and export capabilities to Apple platform apps, with deep RealityKit and Spatial Preview integration.
LiveCommunicationKit is the modern replacement for CXProvider that delivers rich, native conversation UIs integrated with the Lock Screen, Dynamic Island, Phone app Recents, and Siri. It provides a unified lifecycle model for audio and video conversations with a single delegate-driven action pipeline.
In-depth guide
iOS 26 → iOS 27 Migration Guide →Localized asset packs require updating existing asset pack manifest JSON files with a language tag — existing manifests without a tag will be treated as the primary language fallback. The Steam depot converter tool is available in Xcode 27 on macOS now, but Linux and Windows support is listed as 'coming soon'. Unity plug-in support requires Unity 2022 LTS or later and Python 3 for the build script.
Apple-Hosted Background Assets requires App Store distribution; up to 200 GB of assets can be hosted per app under the Apple Developer Program membership.
The NowPlaying framework introduces a first-class Swift API for surfacing app media in system-wide now-playing surfaces — Lock Screen, Control Center, Dynamic Island, StandBy, CarPlay, Apple Watch, and Apple TV — via a declarative MediaSessionRepresentable protocol. It also supports remote media sessions (for controlling external speakers/TVs) and Media Sharing Extensions for routing media to third-party devices.