← Wszystkie wpisy

On Demand Resources jest przestarzałe: ile naprawdę kosztuje Background Assets

Apple wysłało na emeryturę liczący dekadę system dostarczania treści w 13 słowach: „On Demand Resources oraz interfejs API NSBundleResourceRequest są przestarzałe. Zamiast nich należy używać Background Assets”.1

To zdanie stanowi cały wpis. Opatrzono je numerem radaru 170066290, umieszczono w sekcji Deprecations i powtórzono słowo w słowo w trzech osobnych informacjach o wydaniu.123 Apple nie podało wersji, w której nastąpi usunięcie, nie opublikowało przewodnika migracji powiązanego z tym wycofaniem ani żadnej wzmianki w informacjach o wydaniu macOS czy watchOS.

Cała praca kryje się w ostatnich czterech słowach. Background Assets nie jest jednym rozwiązaniem. Rozgałęzia się na trzy konfiguracje o różnych modelach hostingu, różnych minimalnych wersjach docelowych i kosztach migracji różniących się mniej więcej o rząd wielkości. Wybór zapada, zanim powstanie pierwsza linia kodu, a pomyłka na tym etapie kosztuje najwięcej.

TL;DR

  • Apple oznaczyło On Demand Resources i NSBundleResourceRequest jako przestarzałe w informacjach o wydaniu iOS i iPadOS 27, tvOS 27 oraz visionOS 27.123 ODR nadal działa. Apple nie wskazało daty usunięcia, a przestarzałe interfejsy API wciąż trafiają do systemów i wciąż rozwiązują tagi.
  • Dane o dostępności samego interfejsu API wskazują wycofanie na sześciu platformach — o dwie więcej, niż wymienia którakolwiek z informacji o wydaniu: dochodzą Mac Catalyst i watchOS.4 Background Assets w ogóle nie deklaruje dostępności dla watchOS, więc watchOS dostaje wycofanie bez udokumentowanego następcy.56
  • „Zamiast nich należy używać Background Assets” rozgałęzia się na trzy warianty: zarządzany z hostingiem Apple, zarządzany z hostingiem własnym oraz niezarządzany. Oba warianty zarządzane wymagają iOS 26.0 jako minimalnej wersji docelowej.78 Poniżej 26.0 otwarta pozostaje wyłącznie ścieżka niezarządzana, a ta wymaga samodzielnego hostowania plików, wymyślenia formatu manifestu i napisania jego parsera.9
  • Zarządzanie miejscem na dysku odwraca się. W ODR to system usuwał nieużywane zasoby opatrzone tagami, a setPreservationPriority(_:forTags:) traktował jedynie jako wskazówkę co do kolejności.410 Background Assets trzyma na urządzeniu każdy pobrany pakiet aż do chwili, w której kod wywoła remove(assetPackWithID:).11
  • Apple hostuje do 200 GB skompresowanych pakietów zasobów i maksymalnie 200 pakietów na rekord aplikacji, wspólnie dla wszystkich platform, na których aplikacja jest oferowana; pakiety trafiają do App Store Connect i przechodzą recenzję niezależnie od kompilacji.1213

Co dokładnie Apple wycofało

Trzy szczegóły tego wpisu mają znaczenie i żadnego z nich sam wpis nie podaje.

Zakres jest szerszy niż informacje o wydaniu. Wpis pojawia się w trzech dokumentach: iOS i iPadOS 27, tvOS 27 oraz visionOS 27 — w każdym pod nagłówkiem On Demand Resources i podnagłówkiem Deprecations, w każdym z odwołaniem do tego samego radaru.123 Informacje o wydaniu macOS 27 i watchOS 27 milczą na ten temat.

Adnotacja o dostępności samego interfejsu API opowiada szerszą historię. NSBundleResourceRequest figuruje jako wprowadzony w iOS 9.0 i wycofany w 27.0, z identycznym wycofaniem w 27.0 na iPadOS 9.0, Mac Catalyst 13.1, tvOS 9.0, visionOS 1.0 i watchOS 2.0.4 Sześć platform w metadanych, cztery wymienione w informacjach o wydaniu. Dwie metody Bundle odpowiadające za priorytet zachowania zasobów mają tę samą adnotację obejmującą sześć platform.10 Audyt oparty wyłącznie na informacjach o wydaniu całkowicie pomija wpisy dotyczące Mac Catalyst i watchOS.

Wpis dotyczący Mac Catalyst jest czysto formalny. Apple dokumentuje, że NSBundleResourceRequest „ignoruje wywołania z aplikacji Mac zbudowanych przy użyciu Mac Catalyst”, więc wycofanie odsyła na emeryturę interfejs API, który nigdy nic tam nie robił.4 Wpis dotyczący watchOS formalny już nie jest. Background Assets deklaruje dostępność dla iOS 16.0, iPadOS 16.0, Mac Catalyst 16.0, macOS 13.0, tvOS 18.4 i visionOS 2.4, bez wiersza dla watchOS.5 Apple stwierdza wprost, że pakiety zasobów hostowane przez Apple są „dostępne dla aplikacji dystrybuowanych przez App Store na wszystkich platformach z wyjątkiem watchOS”.6 Aplikacja na watchOS korzystająca z ODR dostaje ostrzeżenie o wycofaniu i żadnego następcy, na którego mogłaby przejść.

Siła nacisku jest tu najsłabsza spośród trzech zmian cyklu 27, które opisywałem. Przestarzałe znaczy przestarzałe. Apple nie podało wersji usuwającej, nie postawiło bramki przy wysyłce aplikacji ani nie wprowadziło błędu w czasie działania. Dla porównania, w tym samym cyklu obowiązek stosowania cyklu życia sceny sprawia, że aplikacje zbudowane przy użyciu nowego SDK „nie uruchamiają się”, a wymóg ekranu startowego kończy się wprost odrzuceniem kompilacji przez App Store. ODR nie robi żadnej z tych rzeczy. Istniejące tagi nadal się rozwiązują, istniejące wywołania nadal zwracają zasoby, a wydane binaria nadal działają. Pojawia się ostrzeżenie kompilatora i zegar, którego nikt nie potrafi odczytać.

Moment wygląda na decyzję, a nie na porządki. Apple wycofało interfejs API na czterech platformach naraz, jedno wydanie po tym, jak pojawił się zarządzany wariant następcy. Warto potraktować to wycofanie jako otwarcie okna migracji, którego długości Apple nie ogłosiło, a nie jako sytuację awaryjną.

Rozgałęzienie, które wybiera się przed napisaniem kodu

W przeglądzie frameworka Apple opisuje dwa modele hostingu i zarządzany wariant domyślny, który „obsługuje pobieranie, aktualizacje, kompresję i nie tylko”. W przypadku hostingu Apple „zasoby przesyła się do App Store Connect i tam się je utrzymuje, podobnie jak kompilacje aplikacji”.5 Szablon rozszerzenia Background Download w Xcode wprost wymienia dwa typy: zarządzany z hostingiem Apple oraz niezarządzany z hostingiem własnym.911 Trzecia kombinacja kryje się w kluczach property list: BAHasManagedAssetPacks ustawiony na YES bez BAUsesAppleHosting wybiera zarządzane pakiety zasobów hostowane we własnym zakresie, a dokumentacja kieruje wtedy do protokołu ManagedDownloaderExtension, a nie do StoreDownloaderExtension z StoreKit.7814

Zarządzany, hosting Apple Zarządzany, hosting własny Niezarządzany, hosting własny
Minimalna wersja iOS 26.0715 26.0714 16.19
Kto hostuje pliki Apple, przez App Store Connect6 Deweloper Deweloper
Format manifestu Schemat JSON Apple11 Schemat JSON Apple11 Do wymyślenia i sparsowania samodzielnie9
Protokół rozszerzenia StoreDownloaderExtension716 ManagedDownloaderExtension714 BADownloaderExtension9
Pobieranie, aktualizacje, kompresja System5 System5 Deweloper9
Klucze property list 311 Brak pełnej dokumentacji7 4 najwyższego poziomu, jeden zawierający kolejne 39

Dla większości zespołów decyduje minimalna wersja docelowa. Każdy punkt wejścia do wariantu zarządzanego wymaga co najmniej iOS 26.0 — od AssetPackManager i ManagedDownloaderExtension po trzy klucze property list.781415 Aplikacja obsługująca iOS 18 w ogóle nie może sięgnąć po wariant zarządzany, a jej możliwości zawężają się do ścieżki niezarządzanej, sięgającej wstecz do iOS 16.1, albo do pozostania przy przestarzałym ODR do czasu podniesienia wersji docelowej.9

Ścieżka niezarządzana to zupełnie inna praca. W sekwencji opisanej przez Apple system pobiera manifest spod BAManifestURL, zanim aplikacja się uruchomi, przekazuje plik do rozszerzenia i odbiera od niego zestaw żądań pobrania.9 Apple formułuje ten podział bez ogródek: „Tworzenie plików manifestu dla niezarządzanych zasobów hostowanych we własnym zakresie (w dowolnie wybranym formacie), które kod parsuje, aby przekazać systemowi adresy URL i rozmiary plików, jest obowiązkiem dewelopera”.9 Po stronie zespołu zostaje hosting, CDN, schemat manifestu, parser i lista dozwolonych domen. Kto czyta „zamiast nich należy używać Background Assets” jako prostą podmianę interfejsu API, ma przed oczami wariant zarządzany, a rachunek dostaje za niezarządzany.

Co dawało ODR, a co trzeba teraz odtworzyć ręcznie

Trzy zachowania ODR nie mają bezpośredniego odpowiednika.

Tagi zamieniają się w pakiety zasobów. ODR identyfikował treści za pomocą tekstowych tagów przypisywanych w Xcode, a NSBundleResourceRequest(tags:) rezerwował jeden lub kilka z nich.4 Background Assets zastępuje tagi pakietami zasobów: katalogami plików opisanymi manifestem JSON i pakowanymi w archiwum .aar przez narzędzie wiersza poleceń. Jednostka podziału robi się większa, a przypisanie wyprowadza się z katalogu zasobów Xcode do pliku utrzymywanego ręcznie.

Hosting Apple staje się osobnym torem wydawniczym. Treści ODR jechały razem z kompilacją. Pakiety zasobów hostowane przez Apple przesyła się niezależnie — przez Transporter, altool, iTMSTransporter albo interfejs API App Store Connect — i zgłasza do App Review osobno od aplikacji.1113 To rozprzężenie jest zaletą: nowe treści trafiają do odbiorców bez wydawania nowej kompilacji. Ceną jest drugi potok wysyłkowy, druga kolejka recenzji i drugi zestaw statusów do pilnowania.

Automatyczne czyszczenie staje się obowiązkiem dewelopera i to właśnie ta zamiana ról jest najostrzejszą zmianą. ODR traktował pobrane treści jak pamięć podręczną należącą do systemu. Apple dokumentowało, że system „nie będzie próbował usuwać z pamięci urządzenia zasobów oznaczonych tagiem, dopóki przynajmniej jeden obiekt NSBundleResourceRequest zarządza tym tagiem” — to obietnica dotycząca tego, kiedy nastąpi czyszczenie, a nie czy w ogóle nastąpi.4 setPreservationPriority(_:forTags:) istniało dokładnie po to, by dać „systemowi wskazówkę co do względnej kolejności usuwania oznaczonych tagami zestawów zasobów w pakiecie”.10 Wystarczyło zakończyć rezerwację, a system odzyskiwał miejsce we własnym rytmie; obsługa niedoboru pamięci była problemem Apple.

Background Assets odwraca tę własność. System sam utrzymuje pakiety w aktualnej wersji, a checkForUpdates() usuwa pakiety, które na serwerze stały się nieaktualne.15 Żaden z tych mechanizmów nie usunie pakietu, z którego po prostu przestano korzystać. Instrukcja Apple jest jednoznaczna: „system nie usunie automatycznie pakietów zasobów, dopóki aplikacja pozostaje zainstalowana. Dlatego po zakończeniu pracy z pakietem zasobów należy wywołać metodę remove(assetPackWithID:)”.11

Wzorzec ograniczony zakresem i oparty na zliczaniu referencji zwija się do jawnego usunięcia, które trzeba świadomie wywołać:

// ODR: claim a tag, use the file, release the claim.
// The system reclaims the space afterward on its own schedule.
let request = NSBundleResourceRequest(tags: ["Tutorial"])
try await request.beginAccessingResources()
let url = Bundle.main.url(forResource: "Introduction", withExtension: "m4v")
request.endAccessingResources()
import System  // url(for:) and contents(at:) take a FilePath

// Background Assets: ensure the pack, read the file, delete the pack.
// Nothing reclaims the space if you skip the last line.
let manager = AssetPackManager.shared
guard let pack = try await manager.manifest.assetPack(withID: "Tutorial") else { return }
try await manager.ensureLocalAvailability(of: pack, requireLatestVersion: false)
let url = try manager.url(for: "Videos/Introduction.m4v")
try await manager.remove(assetPackWithID: "Tutorial")

Każda aplikacja, która zakładała czyszczenie w stylu ODR, potrzebuje napisanej dla niej polityki zarządzania miejscem. Tryb awarii jest cichy: nic się nie wysypuje, nic nie ostrzega, a zajęte miejsce na urządzeniu rośnie, aż użytkownik zauważy aplikację w zestawieniu pamięci.

Powierzchnia migracji, punkt po punkcie

Dla zarządzanej ścieżki z hostingiem Apple kroki opisane przez samo Apple składają się na następującą listę kontrolną.

Pliki trzeba pogrupować w pakiety zasobów i wybrać dla każdego pakietu politykę pobierania. Polityki są trzy. essential pobiera się w trakcie instalacji i wlicza do paska postępu, który użytkownicy obserwują w App Store, w TestFlight i na ekranie początkowym. prefetch startuje podczas instalacji i kontynuuje w tle po jej zakończeniu. onDemand pobiera się dopiero wtedy, gdy poprosi o to kod.11 Dla essential i prefetch zagnieżdżona tablica installationEventTypes przyjmuje firstInstallation, subsequentUpdate albo obie wartości, dzięki czemu pakiet z samouczkiem może pobrać się przy pierwszej instalacji i pominąć każdą późniejszą aktualizację.11

Dla każdego pakietu trzeba napisać manifest. Xcode generuje szablon z komentarzami:

xcrun ba-package template -o Manifest.json
{
  "assetPackID": "Tutorial",
  "downloadPolicy": {
    "essential": {
      "installationEventTypes": ["firstInstallation"]
    }
  },
  "fileSelectors": [
    { "file": "Videos/Introduction.m4v" },
    { "directory": "Textures/Tutorial" }
  ],
  "platforms": ["<identifiers from the generated template comments>"]
}

Ścieżki plików rozwiązywane są względem katalogu, w którym uruchamia się polecenie pakujące, co ma znaczenie również później, przy odczycie plików po ścieżce.11 Każdy pakiet trzeba następnie spakować:

xcrun ba-package Manifest.json -o Tutorial.aar

Potem dodaje się target rozszerzenia Background Download w kategorii Application Extension, wybierając typ zarządzany z hostingiem Apple. Uprawnienie App Groups trzeba dodać zarówno do aplikacji, jak i do rozszerzenia, umieszczając oba w tej samej grupie. Do targetu aplikacji dochodzą trzy klucze property list: BAAppGroupID, BAHasManagedAssetPacks ustawiony na YES oraz BAUsesAppleHosting ustawiony na YES. Dla projektów korzystających z hostingu Apple dokumentacja nakazuje pominąć wszystkie pozostałe klucze Background Assets.11 O jedno ograniczenie łatwo się potknąć: sięgnięcie po AssetPackManager bez jednoczesnego zaimplementowania odpowiadającego mu protokołu rozszerzenia jest — słowami Apple — „błędem programisty”.15

Odczyt plików odbywa się przez scaloną przestrzeń nazw. System „automatycznie scala wszystkie pakiety zasobów we wspólną przestrzeń nazw, odtwarzając katalog główny zasobów tak, jakby został wklejony na urządzeniu użytkownika”, więc kod adresuje pliki po ścieżce, nie śledząc, który pakiet je zawiera.11 Odczyty domyślnie zwracają Data mapowane w pamięci; dla ładowania proceduralnego dostępny jest wariant z deskryptorem pliku, który trzeba zamknąć samodzielnie.11

Testy lokalne wiążą się z kosztem konfiguracji, który warto zaplanować osobno. Background Assets korzysta z HTTPS przy każdym pobraniu, więc serwer testowy potrzebuje certyfikatu. Ścieżka udokumentowana przez Apple prowadzi przez Keychain Access i utworzenie samopodpisanego głównego urzędu certyfikacji, Apple Configurator i zbudowanie profilu zawierającego ten urząd, instalację profilu i oznaczenie go jako zaufanego na każdym urządzeniu testowym, wystawienie certyfikatu SSL, którego nazwa dokładnie odpowiada adresowi IP lub nazwie hosta serwera, uruchomienie serwera oraz ustawienie nadpisania adresu URL w ustawieniach dewelopera na każdym urządzeniu.17

xcrun ba-serve --host localhost Tutorial.aar HighQualityTextures.aar

Tę sekwencję warto zaplanować jako osobne zadanie. On Demand Resources w żadnym momencie nie wymagał własnego serwera: Apple opisuje go jako menedżera „treści hostowanych w App Store”, a zasoby, których brakuje na urządzeniu, „są pobierane z App Store”.4 Migracja oznacza postawienie hostingu albo jego zaufanej atrapy, zanim uda się przetestować choćby jedno pobranie. Zestawiając oba przepływy pracy obok siebie, spodziewam się, że to łańcuch certyfikatów, a nie samo wdrożenie interfejsu API, pochłonie pierwszy dzień migracji.

Liczby, według których warto planować

Apple publikuje dwa twarde limity dla pakietów hostowanych po swojej stronie: 200 GB łącznie i 200 pakietów zasobów na rekord aplikacji. Oba są „wspólne dla wszystkich platform oferowanych dla aplikacji”.12 Sumę Apple liczy z maksymalnego rozmiaru wśród wersji kwalifikujących się do dystrybucji w TestFlight lub App Store, pomijając wersje o statusie Awaiting Upload, Processing, Failed oraz w pełni Superseded, a po osiągnięciu 80% limitu wysyła wiadomość e-mail. Archiwizacja pakietu odzyskuje miejsce, usuwając wszystkie jego wersje — również te dostępne na żywo w App Store.12

Ścieżka niezarządzana zastępuje te limity czterema kluczami property list najwyższego poziomu, ustawianymi samodzielnie, z których jeden jest słownikiem zawierającym kolejne trzy, a podział na rozmiary skompresowane i nieskompresowane to prawdziwa pułapka. BADownloadAllowance i BAEssentialDownloadAllowance ograniczają rozmiary pobrań i przyjmują wartości skompresowane. BAMaxInstallSize i BAEssentialMaxInstallSize ograniczają rozmiary po instalacji i przyjmują wartości nieskompresowane.9 Klucze rozmiaru instalacji Apple opatruje ostrzeżeniem, które w istocie jest ostrzeżeniem produktowym: „App Store używa tego klucza, aby pokazać rozmiar aplikacji na stronie produktu, dlatego należy podać dokładną wartość … Nie należy zawyżać wymaganej przestrzeni dyskowej”.18 Zestaw domyka BADownloadDomainAllowList, przyjmujący domeny w formacie DNS z opcjonalną gwiazdką na początku dla wieloznaczników.9

Do planu należy jeszcze jedna liczba, a pochodzi nie z tekstu, lecz z metadanych o dostępności. AssetPackManager pojawił się w iOS 26.0, a cztery jego składowe są już oznaczone jako przestarzałe: ensureLocalAvailability(of:) i status(ofAssetPackWithID:) w 26.4, a następnie assetPack(withID:) i allAssetPacks w 27.0.19 Wyszukiwanie, status i wywołanie pobrania — każde z nich przeniosło się raz, na przestrzeni dwóch wydań punktowych. Droga, na którą Apple wskazuje obecnie, przez właściwość manifest menedżera, ma w SDK 27.0 adnotację beta, podobnie jak zbiorcze ensureLocalAvailability(of:requireLatestVersions:).19 Własny przewodnik Apple dla hostingu Apple wciąż pokazuje dwa z wycofanych wywołań.11 Praktyczny próg leży zatem powyżej nominalnego 26.0 dla tego wariantu. Napisanie pokazanej wcześniej ścieżki pobierania bez zbierania ostrzeżeń o wycofaniu oznacza celowanie w 27.0 i zaakceptowanie symboli oznaczonych jako beta. Następca, po którego każe się sięgnąć, jest młodszy i zmienia się szybciej niż interfejs API, który zastępuje.

Kogo to wycofanie faktycznie dotyczy

Grupa dotkniętych aplikacji jest wąska i we własnym kodzie jej nie znalazłem. Przeszukałem siedem wydanych projektów pod kątem NSBundleResourceRequest, beginAccessingResources, setPreservationPriority, dowolnego ustawienia kompilacji ON_DEMAND_RESOURCES, knownAssetTags oraz konfiguracji tagów w katalogu zasobów. Zero trafień, we wszystkich siedmiu, dla każdego wzorca. Przegląd wszystkich plików Swift, Objective-C, property list i pbxproj w całym katalogu moich projektów nie zwrócił niczego dla żadnego symbolu ODR ani dla Background Assets.20

Ten zerowy wynik ma przyczynę, którą warto nazwać, bo daje się uogólnić. ODR istnieje dla aplikacji, w których treści przytłaczają kod. Największy katalog zasobów należy u mnie do Return i waży 66,6 MB, a każda pozostała aplikacja mieści się poniżej 8 MB, przy czym Water i Yawara nie przekraczają 100 KB.20 Przy takich rozmiarach dzielenie treści na pakiety dokłada sieciowe tryby awarii, politykę zarządzania miejscem i drugi potok recenzji, oszczędzając pobranie, na które nikt nie narzeka. Aplikacje, które naprawdę potrzebują Background Assets, to gry z zawartością poziomów, aplikacje dostarczające duże modele uczenia maszynowego i wszystko, co zawiera wideo w wersji na każdy język — czyli dokładnie ta grupa, w którą celuje obsługa zlokalizowanych pakietów zasobów w iOS 27.21

Minimalne wersje docelowe wyostrzają ten obraz i to je warto sprawdzić w kodzie jako pierwsze. Pięć z moich sześciu aplikacji iOS stoi już na iOS 26.0 lub nowszym, więc wariant zarządzany byłby dla nich dostępny od zaraz. Ace Citizenship nadal deklaruje 17.0 i 17.5 w części swoich targetów, co wyklucza wariant zarządzany i zostawia wyłącznie ścieżkę niezarządzaną albo przestarzały ODR.20 Tę kontrolę warto wykonać przed jakimkolwiek projektowaniem: o tym, którą migrację faktycznie się dostaje, decyduje minimalna wersja docelowa, a nie objętość zasobów.

FAQ

Czy On Demand Resources przestaje działać w iOS 27?

Nie. Apple oznaczyło ODR i NSBundleResourceRequest jako przestarzałe, nie publikując wersji usuwającej, bramki przy wysyłce ani błędu w czasie działania.1 Przestarzałe interfejsy API nadal funkcjonują, a istniejące tagi wciąż się rozwiązują. Otrzymuje się ostrzeżenie kompilatora. Zestawienie z pozostałymi zmianami łamiącymi zgodność w tym samym cyklu jest pouczające: obowiązek stosowania cyklu życia sceny sprawia, że aplikacje „nie uruchamiają się”, a wymóg ekranu startowego skutkuje odrzuceniem kompilacji przez App Store. Wycofanie ODR uruchamia zegar, a nie zamyka drzwi.

Których platform dotyczy to wycofanie?

Informacje o wydaniu wymieniają cztery platformy w trzech dokumentach: iOS i iPadOS 27, tvOS 27 oraz visionOS 27, wszystkie z odwołaniem do radaru 170066290.123 Metadane o dostępności interfejsu API idą dalej i oznaczają NSBundleResourceRequest oraz metody Bundle odpowiedzialne za priorytet zachowania zasobów jako przestarzałe w 27.0 na sześciu platformach, dokładając Mac Catalyst i watchOS.410 Mac Catalyst jest przypadkiem czysto teoretycznym, bo Apple dokumentuje, że klasa ignoruje wywołania z aplikacji Catalyst.4 watchOS teoretyczny nie jest: Background Assets nie deklaruje dla niego żadnej dostępności, a pakiety hostowane przez Apple są dostępne „na wszystkich platformach z wyjątkiem watchOS”, więc aplikacja watchOS ma przestarzały interfejs API i żadnego udokumentowanego następcy.56

Czy da się migrować, jeśli aplikacja obsługuje iOS 18?

Nie do wariantu zarządzanego. AssetPackManager, ManagedDownloaderExtension, BAHasManagedAssetPacks i BAUsesAppleHosting wymagają iOS 26.0.781415 Poniżej tego progu pozostają dwie opcje. Ścieżka niezarządzana działa od iOS 16.1 i wymaga samodzielnego hostowania zasobów, zdefiniowania własnego formatu manifestu, sparsowania go w rozszerzeniu oraz zadeklarowania limitów pobierania i listy dozwolonych domen w property list.9 Alternatywą jest dalsze korzystanie z przestarzałego ODR aż do podniesienia wersji docelowej do 26.0, na co brak ogłoszonej daty usunięcia obecnie pozwala.

Co psuje się po cichu przy dosłownym przeniesieniu kodu ODR?

Miejsce na dysku. W ODR to system usuwał nieużywane treści oznaczone tagami, a setPreservationPriority(_:forTags:) jedynie podpowiadał kolejność.410 Background Assets nigdy nie usunie pakietu, z którego przestano korzystać, dopóki aplikacja pozostaje zainstalowana, więc miejsce jest zajęte aż do wywołania remove(assetPackWithID:).11 Kod odwzorowujący dawny wzorzec beginAccessingResources i endAccessingResources bez dodania jawnego usunięcia w nieskończoność wycieka miejscem na dysku, bez awarii i bez ostrzeżenia, które dałoby się wychwycić w testach. Politykę usuwania warto napisać przed kodem pobierania.

Najważniejsze wnioski

Dla deweloperów iOS: - Przed wszystkim innym trzeba sprawdzić minimalną wersję docelową. Poniżej iOS 26.0 wariant zarządzany po prostu nie istnieje, a „zamiast nich należy używać Background Assets” oznacza zbudowanie hostingu, formatu manifestu i parsera na ścieżce niezarządzanej.79 - Częścią migracji musi być polityka usuwania pakietów. remove(assetPackWithID:) nie ma automatycznego odpowiednika, a nawyk z ODR — zwolnić rezerwację i zaufać systemowi — zostawia po sobie po cichu rosnące zużycie pamięci.11

Dla zespołów dostarczających duże treści: - Konfigurację środowiska testów lokalnych warto zaplanować osobno od kodu. Ścieżka udokumentowana przez Apple prowadzi przez samopodpisany główny urząd certyfikacji, profil Apple Configurator zainstalowany i oznaczony jako zaufany na każdym urządzeniu, certyfikat SSL zgodny z nazwą hosta serwera oraz nadpisanie adresu URL na każdym urządzeniu.17 - Planować należy pod 200 GB i 200 pakietów na rekord aplikacji, wspólnych dla każdej platformy, na którą aplikacja trafia, oraz pilnować wiadomości e-mail wysyłanej przez Apple po osiągnięciu 80%.12 Archiwizacja w celu odzyskania miejsca usuwa również wersje dostępne na żywo w App Store.12

Dla osób odpowiedzialnych za wydania: - Pakiety hostowane przez Apple oznaczają drugi potok wysyłkowy: przesyłane przez Transporter lub interfejs API App Store Connect, wersjonowane niezależnie od kompilacji i zgłaszane do App Review osobno.1113 Cykl recenzji trzeba odpowiednio obsadzić. - W tym cyklu nic nie wymusza migracji. ODR warto ustawić w kolejce za obowiązkiem stosowania cyklu życia sceny i wymogiem ekranu startowego, które są realnie egzekwowane, i wrócić do tematu, gdy Apple opublikuje wersję usuwającą.


Cykl 27 konsekwentnie porządkuje swoje zmiany łamiące zgodność według siły ugryzienia: cykl życia sceny nie pozwala aplikacjom się uruchomić, ekran startowy nie pozwala kompilacji trafić do sklepu, a ODR jedynie uruchamia zegar. Umiejętność odróżnienia jednego od drugiego decyduje o tym, jak dobrze wykorzysta się ten cykl. Ten sam wzorzec na mniejszej powierzchni opisuje usunięcie ImageCreator z Image Playground. Centrum całej serii to Seria o ekosystemie Apple.

Źródła


  1. Apple, iOS & iPadOS 27 Release Notes, sekcja On Demand Resources, Deprecations (radar 170066290): „On Demand Resources oraz interfejs API NSBundleResourceRequest są przestarzałe. Zamiast nich należy używać Background Assets”. Zweryfikowane na podstawie dokumentacji Apple w formacie JSON 25 lipca 2026 roku. Wpis stanowi całość tekstu; informacje o wydaniu nie zawierają wersji usuwającej, wymogu przy wysyłce ani wzmianki o błędzie w czasie działania dla On Demand Resources. 

  2. Apple, tvOS 27 Release Notes, sekcja On Demand Resources, Deprecations (radar 170066290). Sformułowanie identyczne jak w informacjach dla iOS i iPadOS. 

  3. Apple, visionOS 27 Release Notes, sekcja On Demand Resources, Deprecations (radar 170066290). Identyczne sformułowanie. Informacje o wydaniu macOS 27 i watchOS 27 nie zawierają odpowiadającego wpisu, co zweryfikowano, przeszukując ich dokumentację w formacie JSON 25 lipca 2026 roku. 

  4. Apple, NSBundleResourceRequest, Foundation. Dostępność: iOS 9.0, iPadOS 9.0, Mac Catalyst 13.1, tvOS 9.0, visionOS 1.0 i watchOS 2.0, każda z wycofaniem w 27.0. Źródło modelu tagów („Zasoby na żądanie identyfikuje się na etapie tworzenia aplikacji, tworząc tekstowe identyfikatory zwane tagami”), zachowania przy czyszczeniu („System nie będzie próbował usuwać z pamięci urządzenia zasobów oznaczonych tagiem, dopóki przynajmniej jeden obiekt NSBundleResourceRequest zarządza tym tagiem”), uwagi o Mac Catalyst („Ta klasa ignoruje wywołania z aplikacji Mac zbudowanych przy użyciu Mac Catalyst”) oraz ograniczenia jednorazowego użycia. Składowe interfejsy API init(tags:), beginAccessingResources(completionHandler:) i endAccessingResources() mają to samo wycofanie w 27.0 na sześciu platformach. 

  5. Apple, Background Assets, przegląd frameworka. Dostępność: iOS 16.0, iPadOS 16.0, Mac Catalyst 16.0, macOS 13.0, tvOS 18.4 i visionOS 2.4, bez wiersza dla watchOS. Źródło zdań „Domyślna implementacja Managed Background Assets obsługuje pobieranie, aktualizacje, kompresję i nie tylko” oraz „Wybierając Apple-Hosted Background Assets, zasoby przesyła się do App Store Connect i tam się je utrzymuje, podobnie jak kompilacje aplikacji”. 

  6. Apple, Creating managed asset packs, Background Assets. Źródło zdania „Apple-Hosted Background Assets może hostować do 200 GB skompresowanych zasobów i jest dostępne dla aplikacji dystrybuowanych przez App Store na wszystkich platformach z wyjątkiem watchOS”. 

  7. Apple, BAHasManagedAssetPacks, dokumentacja Information Property List. Wartość logiczna, iOS 26.0, iPadOS 26.0, macOS 26.0, tvOS 26.0 i visionOS 26.0. Źródło informacji o wyborze protokołu rozszerzenia: „należy użyć protokołu StoreDownloaderExtension z StoreKit, jeśli klucz BAUsesAppleHosting ma wartość YES; w przeciwnym razie należy użyć protokołu ManagedDownloaderExtension z Background Assets”. Ten zapis dokumentuje kombinację zarządzaną z hostingiem własnym, której artykuły instruktażowe nie omawiają od początku do końca. 

  8. Apple, BAUsesAppleHosting oraz BAAppGroupID, dokumentacja Information Property List. Oba wskazują iOS 26.0, iPadOS 26.0, macOS 26.0, tvOS 26.0 i visionOS 26.0. Warto odnotować, że BAAppGroupID, BAHasManagedAssetPacks i BAUsesAppleHosting mają obok wierszy 26.0 dla wszystkich pozostałych platform nietypowy wiersz Mac Catalyst 16.0; próg iOS 26.0 dla wariantu zarządzanego opiera się na AssetPackManager, ManagedDownloaderExtension i BAHasManagedAssetPacks, a nie na BAAppGroupID, którego wymaga również ścieżka niezarządzana. 

  9. Apple, Configuring an unmanaged Background Assets project, Background Assets. Źródło typu rozszerzenia Self-Hosted, Unmanaged, wymogu App Groups dla obu targetów, sekwencji pobierania przy instalacji i aktualizacji oraz stwierdzenia o odpowiedzialności: „Tworzenie plików manifestu dla niezarządzanych zasobów hostowanych we własnym zakresie (w dowolnie wybranym formacie), które kod parsuje, aby przekazać systemowi adresy URL i rozmiary plików, jest obowiązkiem dewelopera”. Także źródło dla BAManifestURL, BAInitialDownloadRestrictions, BADownloadAllowance i BAEssentialDownloadAllowance (rozmiary skompresowane), BAMaxInstallSize i BAEssentialMaxInstallSize (rozmiary nieskompresowane) oraz BADownloadDomainAllowList (domeny w formacie DNS, opcjonalna gwiazdka na początku dla wieloznaczników). BADownloaderExtension jest dostępny od iOS 16.1, iPadOS 16.1, Mac Catalyst 16.1, macOS 13.0, tvOS 18.4 i visionOS 2.4; BAManifestURL od iOS 16.1. 

  10. Apple, setPreservationPriority(_:forTags:) oraz preservationPriority(forTag:), Foundation. Obie wprowadzone w iOS 9.0 i wycofane w 27.0 na iOS, iPadOS, Mac Catalyst, tvOS, visionOS i watchOS. Źródło sformułowania „Wskazówka dla systemu co do względnej kolejności usuwania oznaczonych tagami zestawów zasobów w pakiecie”. 

  11. Apple, Downloading Apple-hosted asset packs, Background Assets, wraz z Creating managed asset packs. Źródło szablonu rozszerzenia Background Download i jego typu Apple-Hosted, Managed, wymogu wspólnej grupy aplikacji, konfiguracji trzech kluczy property list z zaleceniem, aby „pominąć wszystkie pozostałe klucze informacyjne property list Background Assets”, poleceń xcrun ba-package template i xcrun ba-package, kluczy manifestu (assetPackID, downloadPolicy, installationEventTypes z firstInstallation i subsequentUpdate, fileSelectors z file i directory oraz platforms), trzech polityk pobierania (essential, prefetch i onDemand) wraz z ich zachowaniem przy instalacji, zasady rozwiązywania ścieżek względem katalogu pakowania, scalonej przestrzeni nazw („System automatycznie scala wszystkie pakiety zasobów we wspólną przestrzeń nazw, odtwarzając katalog główny zasobów tak, jakby został wklejony na urządzeniu użytkownika”), odczytów Data mapowanych w pamięci i wariantu z deskryptorem pliku, kanałów przesyłania (Transporter, altool, iTMSTransporter i interfejs API App Store Connect) oraz instrukcji dotyczącej miejsca na dysku: „system nie usunie automatycznie pakietów zasobów, dopóki aplikacja pozostaje zainstalowana. Dlatego po zakończeniu pracy z pakietem zasobów należy wywołać metodę remove(assetPackWithID:)”. Przykłady pobierania w artykule wywołują zarówno assetPack(withID:), oznaczone w danych o dostępności Apple jako wycofane w 27.0, jak i ensureLocalAvailability(of:), wycofane w 26.4 (zob. przypis 19). 

  12. Apple, Apple-hosted asset pack size limits, pomoc App Store Connect. Łączny rozmiar pakietów zasobów 200 GB; liczba pakietów 200. Źródło sformułowania „Łączna suma zajętości wszystkich pakietów zasobów przesłanych do rekordu aplikacji w App Store Connect”, metody obliczania (maksymalny rozmiar wśród wersji kwalifikujących się do dystrybucji w TestFlight lub App Store, z pominięciem statusów Awaiting Upload, Processing, Failed i w pełni Superseded), powiadomienia e-mail po osiągnięciu 80%, zdania „Limity te są wspólne dla wszystkich platform oferowanych dla aplikacji” oraz zachowania przy archiwizacji, która „usuwa z App Store Connect wszystkie wersje pakietu zasobów, w tym te testowane w TestFlight i dostępne na żywo w App Store”. 

  13. Apple, Overview of Apple-hosted asset packs, pomoc App Store Connect. Źródło czterostopniowego przepływu pracy (spakowanie, przesłanie, testy przez TestFlight, zgłoszenie do App Review), niezależności pakietów zasobów od kompilacji aplikacji oraz listy obsługiwanych platform dla zarządzanych zasobów hostowanych przez Apple: iOS 26+, iPadOS 26+, macOS 26+, tvOS 26+ i visionOS 26+. 

  14. Apple, ManagedDownloaderExtension, Background Assets. Protokół, iOS 26.0 i nowsze na wszystkich sześciu wymienionych platformach. Dostarcza domyślne implementacje wszystkich odziedziczonych wymagań BADownloaderExtension, z ostrzeżeniem, aby nie implementować odziedziczonych wymagań poza — opcjonalnie — backgroundDownload(_:didReceive:)

  15. Apple, AssetPackManager, Background Assets. Aktor, iOS 26.0, iPadOS 26.0, Mac Catalyst 26.0, macOS 26.0, tvOS 26.0 i visionOS 26.0. Źródło uwagi o włączeniu zarządzania („Przy pierwszym odwołaniu kodu do współdzielonego menedżera Background Assets uznaje, że aplikacja włącza automatyczne zarządzanie pakietami zasobów przez system”) oraz wymogu parowania: sięgnięcie po menedżera bez odpowiadającego mu zarządzanego protokołu rozszerzenia jest „błędem programisty”. Także źródło dla checkForUpdates(), które „pobiera z serwera najnowsze informacje o pakietach zasobów, aktualizuje nieaktualne pakiety i usuwa pakiety przestarzałe”, oraz dla remove(assetPackWithID:), url(for:) (nonisolated, przyjmujące FilePath i zwracające URL) i statusUpdates(forAssetPackWithID:) — żadne z nich nie jest oznaczone jako wycofane. AssetPack i ManagedBackgroundAssetsError mają tę samą dostępność od iOS 26.0. Wycofane składowe menedżera opisuje przypis 19. 

  16. Apple, StoreDownloaderExtension, StoreKit. Protokół uszczegóławiający ManagedDownloaderExtension, dostępny w iOS 26.0, iPadOS 26.0, macOS 26.0, tvOS 26.0 i visionOS 26.0. 

  17. Apple, Testing asset packs locally, Background Assets. Źródło wymogu HTTPS, sekwencji tworzenia głównego urzędu certyfikacji w Keychain Access, tworzenia profilu w Apple Configurator oraz jego instalacji i oznaczenia jako zaufanego na każdym urządzeniu, certyfikatu SSL, którego nazwa musi być „prawidłowym adresem IP, nazwą hosta lub nazwą domeny” zgodną z serwerem, polecenia xcrun ba-serve oraz nadpisania adresu URL w ustawieniach dewelopera (Ustawienia > Deweloper > Development Overrides w iOS, iPadOS, tvOS i visionOS; xcrun ba-serve url-override w macOS). 

  18. Apple, BAEssentialMaxInstallSize oraz BAMaxInstallSize, dokumentacja Information Property List. BAEssentialMaxInstallSize od iOS 18.0, BAMaxInstallSize od iOS 16.0. Oba opatrzone uwagą: „App Store używa tego klucza, aby pokazać rozmiar aplikacji na stronie produktu, dlatego należy podać dokładną wartość. Jeśli zasoby są kompresowane, jako wartość należy podać nieskompresowany rozmiar plików. Nie należy zawyżać wymaganej przestrzeni dyskowej”. Oba oznaczono jako wymagane do korzystania z Background Assets. 

  19. Metadane o dostępności składowych AssetPackManager opublikowane przez Apple, odczytane z dokumentacji Apple w formacie JSON 25 lipca 2026 roku. Składowe wycofane, wszystkie wprowadzone w iOS 26.0: ensureLocalAvailability(of:) wycofane w 26.4; status(ofAssetPackWithID:) wycofane w 26.4 na rzecz status(relativeTo:); assetPack(withID:) wycofane w 27.0 z uwagą „Wywołaj assetPack(withID:) na wartości właściwości manifest menedżera”; oraz allAssetPacks wycofane w 27.0 na rzecz właściwości assetPacks manifestu. Symbole zastępcze wprowadzone w iOS 27.0 i oznaczone w bieżącym SDK jako beta: manifest, AssetPackManifest.assetPack(withID:) (synchroniczne, zwracające opcjonalny AssetPack) oraz ensureLocalAvailability(of:requireLatestVersions:). ensureLocalAvailability(of:requireLatestVersion:) pojawiło się w 26.4 i nie jest wycofane. Spostrzeżenie, że przewodnik Apple dotyczący hostingu Apple wciąż demonstruje dwa wycofane wywołania — assetPack(withID:) i ensureLocalAvailability(of:) — pochodzi od autora i opiera się na porównaniu tekstu artykułu z dostępnością symboli tego samego dnia. 

  20. Przegląd autorski siedmiu wydanych projektów z 25 lipca 2026 roku: Reps, Return, Banana List, Ace Citizenship, Water, ResumeGeni i Yawara. Przeszukano wszystkie pliki Swift, Objective-C, nagłówkowe, property list i project.pbxproj, z pominięciem build, DerivedData, .build, Pods i .git, pod kątem NSBundleResourceRequest, beginAccessingResources, setPreservationPriority, On Demand Resources, dowolnego ustawienia kompilacji ON_DEMAND_RESOURCES, knownAssetTags oraz ustawień ASSETCATALOG_COMPILER_*TAG. Zero dopasowań dla każdego wzorca w każdym projekcie i zero dopasowań dla symboli Background Assets. Łączne rozmiary katalogów zasobów zmierzone poleceniem du na wszystkich katalogach .xcassets, z pominięciem wyników kompilacji, zrzutów ekranu fastlane i katalogów raportów: Return 66,62 MB, Ace Citizenship 7,81 MB, Banana List 2,04 MB, Reps 1,66 MB, Water 0,04 MB i Yawara 0,01 MB. Wartości IPHONEOS_DEPLOYMENT_TARGET odczytane z poszczególnych plików project.pbxproj: Reps 26.0 i 26.2, Return 26.1, Banana List 26.0, Water 26.0, Yawara 26.5 oraz Ace Citizenship 17.0, 17.5 i 26.1 w poszczególnych targetach. 

  21. Apple, Reducing download and storage demands with localized asset packs, Background Assets. Źródło informacji o oznaczeniu language dodanym do pakietów zasobów w macOS 27, iOS 27, tvOS 27 i visionOS 27, o zasadach identyfikatorów BCP-47 (wyłącznie podtagi języka, regionu i pisma, bez wariantów i rozszerzeń) oraz o kluczu language w szablonie Xcode 27. 

Powiązane artykuły

canOpenURL zostało wycofane: co wywoływać zamiast niego

Apple wycofało canOpenURL w trzech zdaniach i obcięło limit listy schematów do 25 wpisów. Oto zamiennik i jedyne sprawdz…

22 min czytania

Pole wyboru „media społecznościowe" w App Store i jego cena

Wrześniowa zasada App Store nakazuje deklarowanie funkcji społecznościowych w każdym zgłoszeniu. Wyłączenie dzieci poniż…

24 min czytania