Przejdź do treści
megapromotingPorozmawiajmy

Ekspertyza · Aplikacje desktopowe

Aplikacje, które instaluje się na komputerze. Na macOS zbudowaliśmy dwie; dla Windows i Linux ta strona jest ofertą, nie historią.

Budujemy natywne aplikacje dla macOS, z rdzeniem logiki oddzielonym od ekranu, tak aby ta sama logika działała też na telefonie. Dla Windows i Linux/Ubuntu nie mamy jeszcze nic dostarczonego i zapisujemy to wprost, wraz z warunkami, w których przyjęlibyśmy pracę. Pierwsze pytanie pozostaje takie, czy rzeczywiście potrzebna jest zainstalowana aplikacja.

Oferta, z warunkamiReguła jest mechaniczna i stosuję ją mechanicznie. Na macOS mamy dwie własne, zbudowane i uruchamialne implementacje: aplikację paska menu z 25 plikami Swift, która ponownie wykorzystuje 15 plików z rdzenia projektu iPhone, oraz drugą, prostszą aplikację, która jest osłoną WebKit nad aplikacją webową. Obie mają skompilowany binarny plik na tym komputerze. Ale usługa, jak ją nazywamy, obejmuje trzy rodziny systemów, a dla dwóch z nich — Windows i Linux/Ubuntu — szukałem poważnie i znalazłem zero: żadnego własnego projektu .NET ani Qt, żadnego `tauri.conf.json`, żadnego napisanego przez nas Electrona, żadnego `.desktop`, żadnego pakietu deb, rpm ani AppImage. Ponadto żadna z dwóch aplikacji na macOS nigdy nie została spakowana w instalator do dystrybucji. Przy pokryciu tylko jednej z trzech platform i zerze dystrybucji strona jest pisana jako oferta z warunkami. Gdy dostarczymy pierwszą aplikację na Windows lub Linux, zmieni się wartość, nie tekst.

Pierwsze pytanie, które zadajemy, nie brzmi: na jaki system, lecz czy naprawdę potrzebujesz zainstalowanej aplikacji. Warto ją instalować, gdy potrzebuje czegoś, czego przeglądarka nie daje: bezpośredniego dostępu do czujników lub peryferiów, stałej obecności na pasku systemowym, pracy bez internetu, dostępu do plików na dysku bez konieczności wgrywania ich za każdym razem albo działania w tle, gdy okno jest zamknięte. Jeśli żadna z tych rzeczy nie jest wymagana, strona otwierana z linku jest tańsza do zbudowania, aktualizacji i utrzymania — i mówimy to, nawet jeśli zlecenie wyjdzie mniejsze.

Na macOS mamy dwie zbudowane aplikacje. Pierwsza to aplikacja paska menu: 25 własnych plików Swift plus 15 plików rdzenia wziętych bezpośrednio z projektu iPhone tego samego produktu — te same pliki, nie kopia. Buduje się ją skryptem, który wywołuje bezpośrednio kompilator Swift, cel `arm64-apple-macosx14`, łącząc jedenaście frameworków systemowych, w tym SwiftUI, AppKit, CoreMotion, Vision i UserNotifications. Wynikowy binar ma 6.516.128 bajtów. Druga jest dużo prostsza i uczciwie powiedzieć, że składa się z trzech plików Swift, jest opakowaniem WebKit nad aplikacją webową, z włączonym sandboxem i utwardzonym runtime, skompilowana uniwersalnie dla procesorów Intel i Apple. To są dwa różne rzeczy i nazywamy je różnie.

Czego nie mamy, jasno powiedziane. Windows: zero. Szukałam/szukałem projektów .NET, WPF, WinForms, WinUI, plików `.xaml`, `.appxmanifest`, `.msi`, `.wxs` — wszystko, co znaleziono na dysku, należy do biblioteki C strony trzeciej, vendoryzowanej w innym projekcie, której nie napisaliśmy. Linux desktop: zero — żadnego pliku `.desktop`, żadnego pakietu deb ani AppImage zbudowanego tutaj. Electron ani Tauri napisane przez nas: zero. I, co równie ważne: żadna z dwóch aplikacji na macOS nigdy nie została spakowana w instalator. Istnieją jako pakiety `.app` zbudowane lokalnie, podpisane ad hoc, bez identyfikatora zespołu.

Co mimo wszystko przenosi doświadczenie dotychczasowe, i to jest część, która liczy się przy nowym projekcie: dyscyplina trzymania rdzenia logiki oddzielnie od interfejsu. W projekcie macOS pliki obliczeń i polityk nie importują interfejsu, więc kompilują się i uruchamiają na Macu jako zwykły program, bez symulatora; ich zestaw logiki działa w kilka sekund. To samo rozdzielenie sprawia, że portowanie na inny system jest kwestią opakowania, a nie przepisania. Na tym opieramy się, gdy mówimy, że moglibyśmy zrobić Windows albo Linux — nie na doświadczeniu, którego nie mamy.

Co obejmuje

Praca, komponent po komponencie

Najpierw decydujemy, czy potrzebujesz zainstalowanej aplikacji

Pięć kryteriów, sprawdzanych po kolei: dostęp do czujników lub peryferiów, obecność na pasku systemowym, praca bez internetu, bezpośredni dostęp do plików na dysku, działanie w tle przy zamkniętym oknie. Jeśli żadne z nich nie ma zastosowania, rekomendacją jest aplikacja webowa, a powód jest praktyczny: zainstalowaną aplikację trzeba podpisać, dystrybuować i aktualizować na każdym komputerze, a każdy z tych trzech kroków kosztuje bez końca, nie jednorazowo.

Rdzeń pisze się raz i nie wie, na czym działa

W naszej aplikacji na macOS desktopowa targeta listuje 15 plików z rdzenia projektu iPhone jako własne źródła — obliczenia, kalibracja, historia, polityki powiadomień i danych zdrowotnych. To nie są kopie, to te same pliki. Konsekwencja: poprawka algorytmu robi się w jednym miejscu i pojawia się w obu. Druga konsekwencja, ważniejsza dla Ciebie: rdzeń można testować bez uruchamiania aplikacji.

Opakowanie platformy pozostaje cienkie, i mówimy, jak cienkie

Aplikacja paska menu używa `MenuBarExtra` nad delegatem aplikacji AppKit — kod natywny, ale niewiele go, bo reszta to wspólny rdzeń. Druga nasza aplikacja na macOS jest na przeciwległym biegunie: trzy pliki, `WKWebView` opakowany dla SwiftUI, czyli okno nad aplikacją webową. Obie są prawdziwymi aplikacjami macOS, ale znaczą coś innego pod względem wysiłku, szybkości i dostępu do systemu. To, która z nich jest potrzebna, decyduje się na początku, a nie wychodzi przy dostawie.

Budujemy skryptem, nie kliknięciem przycisku

Aplikacja paska menu buduje się ze skryptu liczącego mniej niż sto linii, który bezpośrednio wywołuje kompilator Swift, z jawnie wpisanym celem i listą frameworków, a potem układa pakiet `.app` i podpisuje go. Build, który mieści się w skrypcie, uruchamia się tak samo na innym komputerze i można go wstawić do automatycznego procesu; build istniejący tylko w interfejsie programu deweloperskiego nie może.

Sandbox i wzmocniony runtime, gdy aplikacja wychodzi do sieci

Druga aplikacja macOS startuje z włączonym sandboxem i z jedynym uprawnieniem sieciowym, po stronie klienta — bez serwera, bez dostępu do plików użytkownika, bez kamery, bez mikrofonu. Wzmocniony runtime jest włączony z konfiguracji projektu. Uprawnienia deklaruje się od początku, jako krótką listę, którą da się przeczytać, a nie dodaje się ich po drodze, kiedy coś nie działa.

Podpisywanie to kwestia konta, nie kodu, i kładziemy to na stół od początku

Nasze aplikacje macOS są podpisywane ad-hoc: weryfikacja przechodzi lokalnie, ale nie ma identyfikatora zespołu, a w konfiguracji projektu pole zespołu deweloperskiego jest puste. Do dystrybucji poza sklepem pakiet macOS potrzebuje podpisania certyfikatem identyfikowalnego dewelopera i przejścia przez notaryzację Apple, inaczej system operacyjny osoby, która go otrzyma, zablokuje go. To kwestia konta i procesu, nie funkcjonalności — ale to realny problem i nie ukrywamy go na ostatnim spotkaniu.

Windows i Linux: czego wymagamy przed akceptacją

Płatna weryfikacja zgodności jako pierwszy etap, zakończona szkieletem, który uruchamia się na twoim komputerze, a nie dokumentem. W jej ramach rozstrzyga się trzy rzeczy: jakiego środowiska uruchomieniowego używamy i dlaczego, kto ma certyfikat podpisywania i konto dystrybucyjne, oraz jak aktualizacja trafia na komputery ludzi. Jeśli na którekolwiek z trzech nie ma odpowiedzi, praca nie zaczyna się. Nie bierzemy na siebie platformy, której nie dostarczyliśmy, udając, że to formalność.

Linux server to nie Linux desktop i nie mylimy tych dwóch rzeczy

Nasze systemy działają na co dzień na Linux: usługi systemowe z automatycznym restartem po awarii, serwer webowy z przodu, logi i ich rotacja. To jest realne doświadczenie z Linux, ale to doświadczenie serwerowe. Aplikacja z oknami dla Ubuntu to inna dyscyplina — pakowanie, integracja ze środowiskiem graficznym, dystrybucja przez repozytorium albo przez samodzielny plik — i tam nie mamy nic dostarczonego. Tę różnicę inżynier widzi w trzy sekundy; lepiej, żebyśmy powiedzieli to my przedtem.

Czego nie robimy

Nie obiecujemy instalatora, którego nigdy nie produkowaliśmy, bez powiedzenia, że to pierwszy raz. Nie wybieramy środowiska uruchomieniowego tylko dlatego, że jest modne, bez sprawdzenia najpierw, czego aplikacja wymaga od systemu. I nie przejmujemy istniejącej aplikacji desktopowej, zanim będziemy mogli zbudować ją od zera, na naszym komputerze, z otrzymanych źródeł — jeśli build nie daje się odtworzyć, wszelkie późniejsze wyceny są zgadywaniem.

Jak to wygląda

Trasa, krok po kroku.

01

Decydujemy: instalowana czy web, według pięciu kryteriów

Czujniki i urządzenia peryferyjne, pasek systemowy, praca bez internetu, dostęp do plików, działanie w tle. Dostarczamy decyzję na piśmie, z uzasadnieniem, nawet wtedy, gdy uzasadnieniem jest „nie potrzebujesz aplikacji instalowanej”. Ten etap jest krótki i można na nim poprzestać bez straty.

02

Budujemy rdzeń i testujemy go bez platformy

Logika, stany, trwałość, polityki — zapisane tak, by nie zależały od interfejsu i dały się skompilować oraz uruchomić jako program wiersza poleceń. Dostarczamy zestaw testów i polecenie, którym uruchamiasz go samodzielnie. Jeśli później pojawi się druga platforma, tutaj widać, czy praca została wykonana poprawnie od początku.

03

Nakładamy warstwę platformową

Na macOS: okna lub pasek menu, powiadomienia, uprawnienia, pakiet `.app`, skrypt budowania. Na Windows lub Linux: po weryfikacji zgodności z pierwszego etapu, z wybranym tam środowiskiem uruchomieniowym. Na końcu etapu aplikacja uruchamia się na twoim komputerze, a nie na naszym.

04

Podpisywanie, dystrybucja, aktualizacja

Etap, którą większość projektów odkrywa późno, a my umieszczamy ją na końcu wprost, żeby była widoczna: certyfikat, konto, notaryzacja tam, gdzie platforma tego wymaga, kanał aktualizacji. Tutaj jest też nasz obecny blok na macOS — aplikacje są podpisane ad-hoc, bez identyfikatora zespołu. W twoim projekcie konto jest twoje i blokada znika.

DocumenteRozmowyŹródłaSyntezaDziałanieZespółKontekstualizujŹródła autoryzowane. Działania sprawdzone.
Rdzeń w centrum — obliczenia, kalibracja, historia, polityki — który nie importuje żadnego interfejsu i dlatego testuje się sam. Wokół cztery powłoki platform: iPhone i macOS, połączone i zbudowane, narysowane pełną linią; Windows i Linux desktop, narysowane linią przerywaną, bo nie istnieją. Piąty węzeł, dystrybucja, jest połączony z macOS przerywaną linią: pakiet buduje się i podpisuje ad-hoc, ale nie przechodzi notaryzacji, więc nie dociera na inny komputer. Rysunek mówi, co jest zrobione, a co nie, na tym samym obrazie.

Dane

Czego dotykamy, gdzie to leży i jak długo zostaje

Pytania, które zadaje każdy, kto ma inspektora ochrony danych — postawione tutaj, zanim on je zada.

Zainstalowana aplikacja widzi więcej niż ta z przeglądarki
To jest powód, dla którego tego chcesz, a jednocześnie jej ryzyko: ma dostęp do dysku, do systemu plików użytkowniczki lub użytkownika i, jeśli dostanie uprawnienia, do urządzeń peryferyjnych. Dlatego uprawnienia deklaruje się wprost i utrzymuje na minimum. Nasza aplikacja z sandboxem ma dokładnie jedno uprawnienie, to klienta sieciowego.
Gdzie są dane, gdy aplikacja nie ma serwera
Na komputerze użytkowniczki lub użytkownika. W aplikacji z paskiem menu historia jest zapisywana do własnego pliku, a preferencje do magazynu ustawień systemu, z kluczami poprzedzonymi prefiksem aplikacji. Nic nie trafia na serwer z prostego powodu: w aplikacji nie ma kodu sieciowego. Gdy jest, na stronie uprawnień zapisuje się, kto co otrzymuje.
Czego domyślnie nie zbieramy
Żadnej telemetrii, żadnego identyfikatora urządzenia, żadnego raportu użycia, jeśli nie są wyraźnie wymagane i zadeklarowane w interfejsie. Aplikacja desktopowa to miejsce, w którym telemetria przechodzi niezauważona; dlatego jeśli się ją dodaje, dodaje się ją widocznie, z przyciskiem wyłączenia, i zapisuje się, jakie pola wychodzą.
Aktualizacje są decyzją, a nie szczegółem technicznym
Nie mamy dziś zbudowanego kanału automatycznej aktualizacji. W nowym projekcie to jedna z pierwszych trzech decyzji, obok podpisu i dystrybucji: aktualizacja ręczna, przez sklep platformy, czy przez własny kanał? Każda wersja ma inny stały koszt i inną powierzchnię bezpieczeństwa, i wybiera się ją przed pierwszą linią kodu, nie po.
Co zostaje u nas
Źródła, dopóki pracujemy; po przekazaniu to, co zostało uzgodnione w umowie. Certyfikaty podpisywania pozostają, najlepiej, na twoim koncie organizacji — jeśli zostają na naszym, jesteś związana lub związany z nami przy każdej aktualizacji, a to musi być świadomy wybór, nie konsekwencja.

Przykład

Aplikacja macOS wydzielona z rdzenia aplikacji na iPhone, bez drugiej implementacji

Sytuacja

Mieliśmy własny produkt na iPhone, który mierzy nachylenie głowy względem pozycji skalibrowanej na początku sesji. Te same reguły — kalibracja, progi, historia, polityki powiadomień — miały sens także na Macu, gdzie użytkowniczka lub użytkownik i tak siedzi przed ekranem. Prawdziwe pytanie nie brzmiało, czy się da, tylko ile logiki trzeba przepisać.

Co zbudowaliśmy

Zero, bo rdzeń był napisany od początku bez wiedzy o ekranie. Cel macOS wylicza 15 plików z projektu iPhone jako własne źródła, do których dochodzi 25 plików Swift specyficznych dla desktopu: okno, menu w pasku systemowym przez delegata AppKit, powiadomienia, usługę środowiskową. Budowanie nie przechodzi przez interfejs Xcode: skrypt wywołuje bezpośrednio kompilator Swift z celem `arm64-apple-macosx14` i jawnie łączy jedenaście frameworków systemowych, a potem składa pakiet `.app` i podpisuje go, po czym na końcu weryfikuje podpis.

Co z tego wyszło

Binarna aplikacja o rozmiarze 6.516.128 bajtów dla procesorów Apple, która uruchamia się i pozostaje w pasku menu, zbudowana z jednej komendy. Ta sama poprawka algorytmu trafia na telefon i na Maca, bo to ten sam plik, a nie ręcznie synchronizowana kopia.

Czego nie mówi ten przypadek

Aplikacja nie jest dystrybuowana i nie może być, dziś, w tej formie: podpis jest ad-hoc, bez identyfikatora zespołu, a pole zespołu deweloperskiego jest puste w konfiguracji projektu. Na innym komputerze zostałaby zablokowana przez system. To problem konta i notaryzacji, nie funkcjonalności — ale pozostaje nierozwiązanym problemem i zapisujemy to tak, nie jako szczegół.

Pytania

O co pytają ludzie, zanim zadzwonią

Dlaczego na tej stronie jest napisane „oferta”, jeśli mówicie, że macie dwie aplikacje na Maca?

Ponieważ usługa nazywa się „aplikacje desktopowe” i obejmuje trzy rodziny systemów, a my mamy dostarczone na jednej. Reguła, którą stosujemy wobec siebie, wymaga minimum dwóch własnych implementacji, możliwych do pokazania w kodzie, dla każdego stwierdzenia typu „zrobiliśmy”. Na macOS je mamy. Na Windows i na Linux mamy zero, i żadna z dwóch aplikacji na Maca nigdy nie została spakowana w dystrybuowalny instalator. Strona, która mówiłaby co innego, upadłaby przy drugim pytaniu inżynierki.

Czy macie aplikację na Maca, którą mogę teraz pobrać?

Nie. Obie istnieją jako pakiety `.app` zbudowane na naszym komputerze: jeden skompilowany dla procesorów Apple, drugi uniwersalny, dla Intel i Apple. Są podpisane ad hoc, co oznacza, że przechodzą lokalną weryfikację, ale nie mają identyfikatora zespołu, więc na innym komputerze system by je zablokował. To, co możemy zrobić przed Tobą, to uruchomić je, otworzyć kod i skrypt budowy oraz uruchomić zestaw logiki.

Jaka jest u was różnica między dwiema aplikacjami na Maca?

Jedna jest natywna, druga jest oknem nad webem, i różnica jest duża. Ta natywna ma 25 własnych plików Swift plus 15 wspólnych plików rdzenia z wersją na iPhone’a, wpina się w pasek menu przez delegata aplikacji AppKit i łączy jedenaście frameworków systemowych, w tym czujniki ruchu, powiadomienia i przetwarzanie obrazu. Druga ma trzy pliki i wyświetla aplikację webową w `WKWebView`. Druga robi się szybko i jest właściwym wyborem, kiedy twoja aplikacja jest już webowa i chcesz tylko ikony w Docku. Nie jest właściwym wyborem, kiedy potrzebujesz systemu.

Robicie aplikacje dla Windows?

Nie dostarczyliśmy żadnej i nie twierdzimy inaczej. Szukaliśmy na naszych dyskach wszelkich śladów — projektów .NET, WPF, WinForms, WinUI, plików interfejsu XAML, manifestów aplikacji, pakietów MSI albo WiX — i wszystko, co się pojawia, należy do zewnętrznej biblioteki C, której tylko używamy w innym projekcie. Jeśli potrzebujesz Windows, pierwszy etap to weryfikacja zgodności, która kończy się szkieletem uruchamiającym się u ciebie na komputerze, i dopiero po niej omawiamy resztę.

A dla Linux albo Ubuntu?

To samo stanowisko, z ważnym doprecyzowaniem. Aplikacja okienkowa dla Linux: zero dostarczonych, ani jednego pakietu deb ani AppImage zbudowanego przez nas. Serwery Linux: codziennie — jednostki systemowe, serwer webowy z przodu, logi, ponowne uruchomienie przy awarii. To dwie różne dyscypliny i byłoby nieuczciwe używać pierwszej jako dowodu dla drugiej.

Dlaczego nie Electron, skoro tak jest prościej?

Ponieważ nie dostarczyliśmy żadnej i nie będziemy twierdzić, że mamy doświadczenie tam, gdzie go nie mamy. Na naszych dyskach istnieją dwie działające aplikacje Electron, ale są to repozytoria sklonowane od innych autorów, z zerowym naszym wkładem — sprawdziliśmy je w historii commitów dokładnie po to, żeby nie stały się „dowodem” na tej stronie. W prawdziwym projekcie wybór między opakowanym środowiskiem webowym a kodem natywnym robi się po ustaleniu, czego aplikacja wymaga od systemu, ile waży pakiet i kto płaci za utrzymanie, a nie według mody.

Co blokuje u was publikację aplikacji na Maca?

Konto, nie kod. W konfiguracji projektu pole zespołu deweloperskiego jest puste, a podpis pakietu zbudowanego jest ad hoc, bez identyfikatora zespołu. Do dystrybucji poza sklepem macOS wymaga identyfikowalnego certyfikatu deweloperskiego i przejścia pakietu przez notarizację. W twoim projekcie certyfikat i konto należą do twojej organizacji, więc ta blokada po prostu nie występuje — ale trzeba ją przewidzieć od początku, z jej kosztem i czasem.

Czy nie prościej zrobić stronę i skończyć?

Często tak, i mówimy ci to my, zanim ty nam to powiesz. Strona nie potrzebuje podpisywania, notarizacji, instalatora, kanału aktualizacji ani wersji dla każdego systemu operacyjnego. Zainstalowana aplikacja wygrywa, kiedy potrzebujesz czujników, peryferiów, pracy bez internetu, stałej obecności w pasku systemowym albo bezpośredniego dostępu do plików człowieka. Jeśli żadna z tych rzeczy nie jest na liście, pieniądze lepiej wydać gdzie indziej.

Czy możecie przejąć aplikację desktopową, którą już mamy?

Z jednym warunkiem sprawdzonym przed jakąkolwiek wyceną: musimy móc zbudować ją od zera, na naszej maszynie, z otrzymanych źródeł. Jeśli build nie daje się odtworzyć — brakuje zależności, certyfikatów, niespisanych kroków — wtedy nikt nie może uczciwie niczego wycenić, a pierwszą pracą staje się odtworzenie builda, nie nowa funkcjonalność. Mówimy to z góry, żeby nie wyszło pośrodku.

Na czym opierają się powyższe stwierdzenia (14 źródeł)

14 z nich to kod i pliki z naszych repozytoriów. Nie publikujemy ich nazw ani numerów linii: razem, na jednej stronie, opisałoby to zbyt dokładnie, jak zbudowane są systemy, które nie należą tylko do nas. Przechodzimy je razem z Tobą, w repozytorium, na życzenie — weryfikacja pozostaje możliwa, tylko odbywa się w rozmowie.

Co chcesz, żeby działało lepiej?

Opowiedz nam o swoim procesie. Wspólnie ustalimy, co warto zbudować, co da się połączyć i jak sprawdzimy wynik.

Porozmawiajmy