Mac App Store nie pozwala istnieć menedżerom okien. I tak wydałem jednego.
Inżynier Developer Technical Support w Apple powiedział mi, że moja aplikacja jest niemożliwa: „Nie da się korzystać z API Accessibility z aplikacji działającej w sandboksie… jedyną drogą naprzód jest bezpośrednia dystrybucja aplikacji”.1 Aplikacja była kafelkownikiem okien, API Accessibility to fundament każdego menedżera okien, a każda aplikacja z Mac App Store działa w sandboksie, który tego zabrania. W zeszłym tygodniu 941 Tiles mimo wszystko trafił do Mac App Store: jedno kliknięcie na pasku menu i wszystkie rozrzucone okna aplikacji układają się w równą siatkę. Reguła sandboksa ani drgnęła. Sztuka polegała na zauważeniu, że macOS zawiera już uprzywilejowany mechanizm przesuwania okien z pełnym błogosławieństwem Apple — i że przyjmuje on JSON.
TL;DR
- App Sandbox kategorycznie blokuje międzyaplikacyjne wywołania Accessibility, żaden entitlement tego nie odblokowuje, a każda aplikacja z Mac App Store musi działać w sandboksie. Kategoria menedżerów okien jest faktycznie zamknięta dla nowych od czerwca 2012 roku; kafelkowniki, które wciąż są w sklepie, powstały przed tym wymogiem i na zawsze działają poza sandboksem.134
- Furtka usankcjonowana przez Apple: aplikacja w sandboksie może sterować silnikiem Shortcuts od Apple przez Apple events, a Shortcuts udostępnia akcje Find Windows / Move Window / Resize Window, które przesuwają okna innych aplikacji z uprawnieniami samego Apple.25 Moja aplikacja wylicza, gdzie ma trafić każde okno; przesuwaniem zajmuje się towarzyszący jej Shortcut. Delegowanie, nie pozwolenie.
- Inżynieria, która nadała temu realny kształt: programowe tworzenie towarzyszącego pliku
.shortcutjako binarnego pliku plist zWFWorkflowActions, kontrakt ładunku JSON z ramkami powiązany z kolejnością nakładania okien, zabezpieczenia przed widmowymi oknami i przekroczeniem zakresu indeksów oraz jedna baza kodu z dwoma silnikami: bezpośrednim Accessibility w kompilacjach Developer ID i delegowaniem do Shortcuts w kompilacjach sklepowych. - Pierwsze udane uruchomienie na maszynie, na której poległo pięć kompilacji sklepowych: cztery rozrzucone okna terminala trafiły w dokładne ramki ćwiartek w 0,6 sekundy.
- Należy oddać, co się należy: mechanizm sprawdził się w praktyce dzięki projektom snApp (open source, 2023) i Align (2024). To lektura źródeł snApp zamieniła „niemożliwe” w plan wdrożenia.2
Ściana
Pierwsza wersja 941 Tiles była klasycznym kafelkownikiem w pasku menu. macOS ma system Accessibility, który — za zgodą użytkownika — pozwala jednej aplikacji wyliczać i przesuwać okna innej (AXUIElementSetAttributeValue na atrybutach pozycji i rozmiaru okna). Zbudowana na tym aplikacja działała bez zarzutu przez tygodnie prac. Miałem przygotowaną całą kartę w App Store Connect: metadane w 17 językach, zrzuty ekranu, cennik, 21 wysłanych kompilacji.
Potem kompilacja z TestFlight trafiła na drugiego Maca. Uprawnienie Accessibility przyznane, aplikacja raportuje aktywny dostęp — i nie potrafi odczytać żadnego okna.
To nie był błąd. Każda aplikacja z Mac App Store działa w App Sandbox od Apple, czyli w regule izolacji mówiącej, że aplikacja może dotykać wyłącznie własnych zasobów, właśnie po to, by nie mogła szpiegować reszty komputera ani jej zakłócać.4 Sięganie do okien innej aplikacji to dokładnie to, czemu sandbox ma zapobiegać. Kompilacje deweloperskie działają poza sandboksem i dlatego wszystko działało przez tygodnie; kompilacja sklepowa wyegzekwowała regułę, którą ignorowałem. Nie odblokuje jej żadne okno dialogowe, żaden entitlement ani żadne ustawienie. Kiedy zapytałem Apple wprost, odpowiedź DTS brzmiała tak, jak na początku tego wpisu: dystrybuować poza sklepem.1
Kategoria zamknięta od 2012 roku
Najciekawsze w tej ścianie jest to, kto stoi po jej drugiej stronie. Magnet, Moom, BetterSnapTool: narzędzia do okien, które dziś można kupić w Mac App Store. Ich karty powstały przed wymogiem sandboksa z czerwca 2012 roku, więc działają poza sandboksem na mocy klauzuli dziadka, która nie przechodzi na nikogo innego. Każdy menedżer okien powstały po 2012 roku (Rectangle, Swish, Loop, BetterTouchTool, Amethyst) jest dystrybuowany poza sklepem. Apple egzekwowało tę granicę również w drugą stronę: PopClip, obecny w sklepie przez blisko 13 lat, odszedł w marcu 2024 roku, gdy recenzenci poinformowali jego autora, że nowa funkcja oparta na Accessibility nie może trafić do aktualizacji działającej w sandboksie.3
Chcę powiedzieć wprost, jak to odczytuję: reguła sandboksa jest rozsądna. Aplikacja, która potrafi po cichu odczytać i przesunąć każde okno na ekranie, potrafi też prowadzić inwigilację, a „zaufaj mi” nie jest modelem bezpieczeństwa. Obietnicą sklepu jest to, że nic, co się z niego zainstaluje, nie może tego robić. Niesprawiedliwość jest wąska i konkretna: zasiedziali zachowują możliwość, na którą nowi nie zapracują żadną ilością zgód użytkownika. Kategorii nie zakazano — ona po prostu skamieniała.
Zwrot
Werdykt DTS miał jedną skazę: w sklepie były już kontrprzykłady. Align (2024) i snApp (2023) kafelkują okna, oba są w Mac App Store i oba powstały długo po 2012 roku. snApp jest projektem open source, więc mechanizm nie jest tajemnicą — jest repozytorium.2
Aplikacja w sandboksie nigdy nie dotyka okien innej aplikacji. Steruje Shortcuts, czyli własną aplikacją automatyzacji Apple, przy użyciu dwóch zadeklarowanych entitlementów:
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.shortcuts.events</string>
</array>
Od macOS 12 Shortcuts udostępnia akcje o nazwach Find Windows, Move Window i Resize Window.5 Shortcuts wolno przesuwać okna, bo należy do Apple. Aplikacja wylicza więc, gdzie ma trafić każde okno, przekazuje ten plan zainstalowanemu przez użytkownika Shortcutowi, a przesuwaniem zajmuje się silnik samego Apple. Sandbox nigdy nie zostaje naruszony, ponieważ proces działający w sandboksie nigdy nie wykonuje uprzywilejowanej czynności. Delegowanie, nie pozwolenie.
Jest w tym kształcie coś niemal architektonicznego: granica bezpieczeństwa zostaje dokładnie tam, gdzie wytyczyło ją Apple, a możliwość przekracza tę granicę, przechodząc przez jedyny proces w systemie, który legalnie ją posiada.
Realizacja
Znać mechanizm, a wydać produkt to dwa różne tygodnie. Elementy, które doprowadziły to do stanu produkcyjnego:
Programowe tworzenie Shortcuta. Użytkownik nie powinien ręcznie składać przepływu z 12 akcji. Towarzyszący plik .shortcut to binarny plist z WFWorkflowActions, generowany przez aplikację i podpisywany na etapie kompilacji poleceniem shortcuts sign -m anyone, dzięki czemu instalacja to jedno kliknięcie w aplikacji Shortcuts. Kontraktem czasu wykonania jest ładunek JSON przekazywany przez shortcut.run(withInput:) z ScriptingBridge:
{"app": "Ghostty", "frames": [{"x": 0, "y": 38, "w": 1280, "h": 771}, ...]}
Tożsamością okna jest kolejność nakładania. Akcja Find Windows w Shortcucie indeksuje okna od przodu do tyłu, a CGWindowList wylicza je w tej samej kolejności. Miejsce i w ładunku niesie więc po prostu ramkę okna i, a przydzielanie komórek według rangi pozycji sprawia, że siatka odtwarza zasadę „okna zostają blisko tego, gdzie były”. Żaden identyfikator okna nie przekracza granicy, bo po drugiej stronie żaden nie istnieje.
Zabezpieczenia. Ograniczenie Items in Range domknięte przez Count nie pozwala nieaktualnemu ładunkowi wyjść poza bieżącą listę okien. Filtr minimalnego rozmiaru (120×80) odsiewa widmowe, zaparkowane panele, które raportuje CGWindowList, a które dawniej ukrywało sprawdzanie roli w Accessibility. Jest też fakt, który mnie zaskoczył: wypisanie okien nie wymaga żadnego uprawnienia, a CGWindowList jest w sandboksie legalny. Zakazane było zawsze wyłącznie przesuwanie.
Jedna baza kodu, dwa silniki. Aplikacja wykrywa sandbox przy starcie dzięki zmiennej środowiskowej APP_SANDBOX_CONTAINER_ID. Kompilacje sklepowe kafelkują przez Shortcuts; kompilacje Developer ID i deweloperskie korzystają z bezpośredniej ścieżki Accessibility. Ten sam interfejs, ta sama matematyka, inny wykonawca ruchu.
Tryb obserwacji bez powiadomień. Opcjonalna funkcja automatycznego przekafelkowania normalnie subskrybowałaby powiadomienia o oknach z Accessibility, których sandbox również nie udostępnia. Przetrwała jako odpytywanie serwera okien: tanie porównania CGWindowList i przekafelkowanie przy każdej zmianie.
Koszt, powiedziany uczciwie
Użytkownik płaci jednorazowy podatek konfiguracyjny: instaluje towarzyszącego Shortcuta (jedno kliknięcie) i udziela zgody w jednym oknie dialogowym automatyzacji (standardowy komunikat „941 Tiles chce sterować aplikacją Shortcuts”, zlokalizowany we wszystkich 17 językach przez InfoPlist.xcstrings). Potem doświadczenie jest identyczne jak w kafelkowniku korzystającym bezpośrednio z API: kliknięcie w ikonę siatki, kliknięcie w aplikację, okna lądują na miejscu. Uruchomienie Shortcuts jest niewidoczne i trwa znacznie krócej niż sekundę.
Nie będę udawał, że ten podatek jest zerowy; to o jeden ekran więcej, niż pokazuje Magnet. Jest to zarazem pełna cena istnienia wewnątrz sandboksa, zamiast proszenia użytkowników, by omijali Gatekeepera dla notaryzowanego pliku, do którego nie mają jeszcze powodu mieć zaufania.
Efekt
Ten sam Mac z procesorem Intel, na którym poległo pięć kompilacji sklepowych: instalacja, konfiguracja Shortcuta, zgoda i cztery rozrzucone okna Ghostty wskoczyły w dokładne ramki ćwiartek w 0,6 sekundy przy pierwszym uruchomieniu. Potem przyszła internacjonalizacja (String Catalogs, reguły liczby mnogiej CLDR wraz ze wszystkimi sześcioma kategoriami arabskimi), zlokalizowana karta produktu i zgłoszenie. Po jednym odrzuceniu w recenzji i ponownej weryfikacji trwającej około 30 minut 941 Tiles jest dostępny: 4,99 USD jednorazowo, macOS 15+, 17 języków, zero zbieranych danych, brak dostępu do sieci.
Co się uogólnia
Ten wzorzec sięga dalej niż kafelkowanie okien. Kiedy platforma zamyka jakąś możliwość za granicą, odpowiedzią rzadko bywa walka z granicą; jest nią spis tych procesów systemowych, które już tę możliwość mają i wystawiają do niej usankcjonowany interfejs. W macOS ten spis coraz częściej wskazuje jedno miejsce: Shortcuts, który po cichu stał się systemowym pośrednikiem uprzywilejowanej automatyzacji, z założenia osiągalnym z wnętrza sandboksa. Mój przewodnik po Shortcuts omawia tę powierzchnię szczegółowo, a studium przypadku 941 Tiles prowadzi przez tę samą historię wraz z diagramami architektury.
Sandbox zrobił swoje. Aplikacja i tak trafiła do sklepu. Oba te zdania są prawdziwe, a drzwi między nimi należały do samego Apple.
Często zadawane pytania
Czy aplikacja Mac działająca w sandboksie może korzystać z API Accessibility?
Nie. App Sandbox kategorycznie blokuje międzyaplikacyjne wywołania Accessibility i nie odblokuje ich żaden entitlement, żadne okno dialogowe uprawnień ani żadne ustawienie. Odpowiedź, którą dostałem od DTS Apple, brzmiała: „Nie da się korzystać z API Accessibility z aplikacji działającej w sandboksie… jedyną drogą naprzód jest bezpośrednia dystrybucja aplikacji”. Kompilacje deweloperskie działają poza sandboksem i dlatego kafelkownik potrafi działać przez tygodnie, a potem nie odczytać ani jednego okna w kompilacji sklepowej.14
Jak menedżer okien może trafić do Mac App Store?
Przez delegowanie uprzywilejowanej czynności. Aplikacja w sandboksie może sterować silnikiem Shortcuts od Apple przez Apple events, a Shortcuts od macOS 12 udostępnia akcje Find Windows, Move Window i Resize Window. Moja aplikacja wylicza, gdzie ma trafić każde okno, i przekazuje ten plan zainstalowanemu przez użytkownika Shortcutowi, który wykonuje przesunięcie z uprawnieniami samego Apple. Sandbox nigdy nie zostaje naruszony, ponieważ proces w sandboksie nigdy nie wykonuje uprzywilejowanej czynności.25
Dlaczego Magnet i Moom są w sklepie, skoro menedżery okien nie mogą tam być?
Ich karty powstały przed wymogiem sandboksa z czerwca 2012 roku, więc działają poza sandboksem na mocy klauzuli dziadka, która nie przechodzi na nikogo innego. Każdy menedżer okien powstały po 2012 roku, w tym Rectangle, Swish, Loop, BetterTouchTool i Amethyst, jest dystrybuowany poza sklepem. PopClip odszedł ze sklepu w marcu 2024 roku, gdy recenzenci poinformowali jego autora, że nowa funkcja Accessibility nie może trafić do aktualizacji działającej w sandboksie. Kategorii nie zakazano — ona skamieniała.34
Ile delegowanie do Shortcuts kosztuje użytkownika?
Jednorazowy podatek konfiguracyjny: instalacja towarzyszącego Shortcuta jednym kliknięciem, a potem zgoda w jednym oknie dialogowym automatyzacji. Później doświadczenie jest identyczne jak w kafelkowniku korzystającym bezpośrednio z API: kliknięcie w ikonę siatki, kliknięcie w aplikację, okna lądują na miejscu, a uruchomienie Shortcuts pozostaje niewidoczne i trwa znacznie krócej niż sekundę. To o jeden ekran więcej, niż pokazuje Magnet, i zarazem pełna cena istnienia wewnątrz sandboksa.
Jak jedna baza kodu obsługuje zarówno kompilacje w sandboksie, jak i bezpośrednie?
Aplikacja wykrywa sandbox przy starcie dzięki zmiennej środowiskowej APP_SANDBOX_CONTAINER_ID. Kompilacje sklepowe kafelkują przez Shortcuts; kompilacje Developer ID i deweloperskie korzystają z bezpośredniej ścieżki Accessibility. Ten sam interfejs, ta sama matematyka, inny wykonawca ruchu. Tryb obserwacji też się dostosowuje: sandbox usuwa powiadomienia o oknach z Accessibility, więc opcjonalne automatyczne przekafelkowanie przetrwało jako tanie odpytywanie CGWindowList, które porównuje stany i przekafelkowuje przy zmianie.
Źródła
-
Apple Developer Forums, wątek 805556 (październik 2025), odpowiedź DTS Apple: „Nie da się korzystać z API Accessibility z aplikacji działającej w sandboksie… jedyną drogą naprzód jest bezpośrednia dystrybucja aplikacji z podpisem Developer ID”. ↩↩↩↩
-
Om Chachad, snApp na GitHubie (2023), otwartoźródłowy kafelkownik okien z Mac App Store, którego kod dokumentuje mechanizm delegowania do Shortcuts: entitlementy celu skryptowania
com.apple.security.automation.apple-eventsoraz towarzyszący Shortcut zbudowany z akcji okiennych Apple. ↩↩↩↩ -
Michael Tsai, „PopClip Leaving the Mac App Store” (21 marca 2024), o tym, jak recenzja Apple wymusiła usunięcie nowej funkcji opartej na Accessibility z aktualizacji działającej w sandboksie, po blisko 13 latach obecności w sklepie. ↩↩↩
-
Apple, dokumentacja App Sandbox, model izolacji, który wszystkie aplikacje z Mac App Store muszą stosować od czerwca 2012 roku. ↩↩↩↩
-
Apple, Podręcznik użytkownika Shortcuts dla Maca, dokumentujący akcje Find Windows, Move Window i Resize Window dostępne od macOS 12. ↩↩↩