Перейти до основного вмісту
megapromotingПоговорімо

Експертиза · Десктопні застосунки

Застосунки, які встановлюються на комп’ютер. На macOS ми побудували два; для Windows і Linux ця сторінка є пропозицією, а не історією.

Ми будуємо нативні додатки для macOS, із ядром логіки, відокремленим від екрана, щоб та сама логіка працювала і на телефоні. Для Windows і Linux/Ubuntu ми ще нічого не здали, і пишемо це саме так, з умовами, за яких ми б узялися за роботу. Перше питання залишається таким: чи справді вам потрібен встановлюваний додаток.

Пропозиція, з умовамиПравило механічне, і я застосовую його механічно. На macOS у нас є дві власні реалізації, зібрані й придатні до запуску: застосунок для панелі меню з 25 файлами Swift, який повторно використовує 15 файлів із ядра проєкту для iPhone, і другий, простіший застосунок, який є WebKit-обгорткою над вебзастосунком. Обидва мають скомпільований бінарник на цій машині. Але сервіс, як його названо, охоплює три сімейства систем, а для двох із них — Windows і Linux/Ubuntu — ми серйозно шукали і знайшли нуль: жодного власного проєкту .NET або Qt, жодного `tauri.conf.json`, жодного нашого Electron, жодного `.desktop`, жодного пакета deb, rpm або AppImage. Крім того, жоден із двох macOS-застосунків ніколи не був упакований у дистрибутивний інсталятор. Лише з однією з трьох платформ покриття і з нульовими дистрибуціями сторінка пишеться як пропозиція з умовами. Коли ми поставимо перший застосунок для Windows або для Linux, зміниться значення, а не текст.

Перше запитання, яке ми вам ставимо, не про систему, а про те, чи справді вам потрібен встановлений застосунок. Його варто встановлювати, коли йому потрібне щось, чого браузер не дає: прямий доступ до сенсорів або периферії, постійна присутність у системному лотку, робота без інтернету, доступ до файлів на диску без того, щоб людина завантажувала їх щоразу, або робота у фоновому режимі, коли вікно закрите. Якщо нічого з цього не потрібно, сайт, що відкривається з посилання, дешевший у побудові, оновленні та підтримці — і ми вам це скажемо, навіть якщо робота вийде меншою.

На macOS ми маємо дві зібрані програми. Перша — це програма для панелі меню: 25 власних файлів Swift, плюс 15 файлів ядра, взятих безпосередньо з iPhone-проєкту того самого продукту — ті самі файли, не копія. Вона збирається скриптом, який прямо викликає компілятор Swift, ціль `arm64-apple-macosx14`, з лінкуванням одинадцяти системних фреймворків, серед яких SwiftUI, AppKit, CoreMotion, Vision і UserNotifications. Отриманий бінарний файл має 6.516.128 байтів. Друга — значно простіша, і чесно сказати наскільки: три файли Swift, WebKit-обгортка поверх вебзастосунку, з увімкненими sandbox і hardened runtime, зібрана універсально для процесорів Intel і Apple. Це два різні речі, і ми називаємо їх по-різному.

Чого в нас немає, прямо сказано. Windows: нуль. Ми шукали .NET, WPF, WinForms, WinUI-проєкти, файли `.xaml`, `.appxmanifest`, `.msi`, `.wxs` — усе, що знайшли на диску, належить сторонній C-бібліотеці, завендореній в іншому проєкті, яку ми не писали. Linux desktop: нуль — жодного файлу `.desktop`, жодного deb-пакета чи AppImage, зібраного тут. Власноруч написані Electron або Tauri: нуль. І, що не менш важливо: жодна з двох macOS-програм ніколи не була упакована в інсталятор. Вони існують як локально зібрані пакети `.app`, підписані ad-hoc, без ідентифікатора команди.

Що все ж передає досвід, який є на цей момент, і це та частина, що має значення для нового проєкту: дисципліну тримати ядро логіки окремо від інтерфейсу. У macOS-проєкті файли обчислень і політик не імпортують інтерфейс, тож вони компілюються і запускаються на Mac як звичайна програма, без симулятора; їхній набір логіки працює за кілька секунд. Така сама роздільність робить портування на іншу систему питанням обгортки, а не переписування. На це ми спираємося, коли говоримо, що могли б зробити Windows або Linux — не на досвід, якого в нас немає.

Що входить

Робота, за складовими

Спершу вирішуємо, чи вам потрібна встановлена програма

П’ять критеріїв, перевіряємо по черзі: доступ до сенсорів або периферії, присутність у системному треї, робота без інтернету, прямий доступ до файлів на диску, робота у фоновому режимі з закритим вікном. Якщо жоден не підходить, рекомендація — вебзастосунок, і причина практична: встановлену програму треба підписувати, розповсюджувати й оновлювати на кожному комп’ютері, а кожен із цих трьох кроків коштує постійно, а не один раз.

Ядро пишеться один раз і не знає, на чому воно працює

У нашій macOS-програмі desktop-ціль перелічує 15 файлів з ядра iPhone-проєкту як власні джерела — обчислення, калібрування, історію, політики сповіщень і даних про здоров’я. Вони не скопійовані, це ті самі файли. Наслідок: виправлення алгоритму робиться в одному місці й з’являється в обох. Другий наслідок, важливіший для вас: ядро можна тестувати, не запускаючи програму.

Платформена обгортка залишається тонкою, і ми кажемо, наскільки тонкою

Програма для панелі меню використовує `MenuBarExtra` поверх AppKit app delegate — нативний код, але небагато, бо решта — спільне ядро. Інша наша macOS-програма — на протилежному полюсі: три файли, `WKWebView`, упакований для SwiftUI, тобто вікно поверх вебзастосунку. Обидві — легітимні macOS-програми, але це означає різні речі за обсягом роботи, швидкістю та доступом до системи. Яка з них вам потрібна, вирішується на початку, а не виявляється під час здачі.

Будуємо скриптом, а не натисканням кнопки

Програма для панелі меню збирається зі скрипта менш ніж на сто рядків, який прямо викликає компілятор Swift, з явними ціллю та списком фреймворків, а потім розміщує пакет `.app` і підписує його. Збірка, яка вміщується в скрипт, працює так само на іншій машині й може бути поставлена в автоматичний рядок; збірка, яка існує лише в інтерфейсі програми розробки, не може.

Sandbox і hardened runtime, коли програма виходить у мережу

Друга macOS-програма запускається з увімкненим sandbox і лише одним мережевим дозволом — клієнтським, не серверним, без доступу до файлів користувача, без камери, без мікрофона. Hardened runtime увімкнено з конфігурації проєкту. Дозволи оголошуються від початку, як короткий список, який можна прочитати, а не додаються потім, коли щось не працює.

Підписування — це питання облікового запису, а не коду, і ми ставимо його на стіл одразу

Наші macOS-програми підписані ad-hoc: локальна перевірка проходить, але немає ідентифікатора команди, а в конфігурації проєкту поле розробницької команди порожнє. Для розповсюдження поза магазином macOS-пакет має бути підписаний сертифікатом ідентифікованого розробника і пройти нотаризацію Apple, інакше операційна система того, хто його отримає, заблокує його. Це питання облікового запису та процесу, а не функціональності — але це реальна проблема, і ми не ховаємо її на останній зустрічі.

Windows і Linux: що ми вимагаємо перед тим, як погодитися

Платна перевірка сумісності як перший етап, яка завершується каркасом, що запускається на вашому комп’ютері, а не документом. У ній вирішуються три речі: яке середовище виконання ми використовуємо і чому, хто володіє сертифікатом підписування та обліковим записом розповсюдження, і як оновлення потрапляє на комп’ютери людей. Якщо хоча б на одне з трьох немає відповіді, робота не починається. Ми не беремося за платформу, яку не здавали, вдаючи, що це формальність.

Linux server — це не Linux desktop, і ми не плутаємо ці два

Наші системи працюють щодня на Linux: системні служби з перезапуском у разі збою, вебсервер спереду, журнали та їхня ротація. Це реальний досвід з Linux, але це серверний досвід. Віконна програма для Ubuntu — інша дисципліна: пакування, інтеграція з графічним середовищем, розповсюдження через репозиторій або через самодостатній файл — і там у нас нічого не доставлено. Різницю це інженер визначить за три секунди; краще сказати це нам самим раніше.

Що ми не робимо

Ми не обіцяємо інсталятор, який ми ніколи не виробляли, не сказавши, що це вперше. Ми не обираємо середовище виконання лише тому, що воно модне, не перевіривши спершу, чого вимагає програма від системи. І ми не беремо на себе існуючу desktop-програму, доки не зможемо зібрати її з нуля на нашій машині з отриманих джерел — якщо build не відтворюється, будь-яка подальша оцінка є ворожінням.

Як це виглядає

Шлях, крок за кроком.

01

Вирішуємо: встановлювати чи web, за п’ятьма критеріями

Сенсори й периферія, панель системи, робота без інтернету, доступ до файлів, робота у фоновому режимі. Ми надаємо письмове рішення з причиною, навіть коли причина — «вам не потрібна встановлена програма». Цей етап короткий і його можна зупинити тут без втрат.

02

Будуємо ядро і тестуємо його без платформи

Логіка, стани, збереження, політики — написані так, щоб не залежати від інтерфейсу і щоб збиратися та запускатися як програма командного рядка. Ми надаємо набір тестів і команду, якою ви їх запускаєте. Якщо згодом з’явиться друга платформа, тут видно, чи роботу було зроблено правильно від самого початку.

03

Надягаємо платформену оболонку

На macOS: вікна або панель меню, сповіщення, дозволи, пакет `.app`, скрипт збирання. На Windows або Linux: після перевірки сумісності з першого етапу, із середовищем виконання, обраним там. Наприкінці етапу програма запускається на вашій машині, а не на нашій.

04

Підпис, розповсюдження, оновлення

Етап, який більшість проєктів відкриває пізно, а ми ставимо останнім явно, щоб його було видно: сертифікат, обліковий запис, нотаризація там, де платформа її вимагає, канал оновлення. Тут також наш поточний блокер на macOS — програми підписуються ad-hoc, без ідентифікатора команди. У вашому проєкті обліковий запис буде вашим, і блокер зникне.

DocumenteРозмовиДжерелаСинтезДіяКомандаКонтекстуалізуєАвторизовані джерела. Перевірені дії.
Ядро в центрі — обчислення, калібрування, історія, політики, — яке не імпортує жодного інтерфейсу і тому тестується саме. Навколо чотири оболонки платформи: iPhone і macOS, пов'язані й побудовані, намальовані суцільними; Windows і Linux desktop, намальовані контуром, бо їх не існує. П'ятий вузол, дистрибуція, пов'язаний із macOS перерваною лінією: пакет збирається і підписується ad-hoc, але не проходить нотаризацію, тому не доходить до іншого комп'ютера. Схема показує, що зроблено, а що ні, на одному зображенні.

Дані

Чого торкаємося, де воно лежить і скільки лишається

Запитання, які ставить кожен, у кого є відповідальний за захист даних, — поставлені тут раніше, ніж їх поставить він.

Встановлена програма бачить більше, ніж браузерна
Це причина, чому ви її хочете і, водночас, її ризик: вона має доступ до диска, до файлової системи користувача і, якщо їй надано дозволи, до периферії. Тому дозволи декларуються явно і тримаються на мінімумі. Наша програма із sandbox має рівно один дозвіл — на мережевий клієнт.
Де зберігаються дані, коли у програми немає сервера
На комп’ютері людини. У програмі з панеллю меню історія записується у власний файл, а налаштування — у системне сховище налаштувань, з ключами, префіксованими за програмою. Нічого не відправляється на сервер з простої причини: у програмі немає мережевого коду. Коли він є, на сторінці дозволів пишуть, хто що отримує.
Що ми не збираємо за замовчуванням
Жодної телеметрії, жодного ідентифікатора пристрою, жодного звіту про використання, якщо вони не запитані явно і не задекларовані в інтерфейсі. Desktop-програма — це місце, де телеметрія проходить непомітно; тому, якщо її додають, її додають видимо, з кнопкою вимкнення, і пишуть, які поля відправляються.
Оновлення — це рішення, а не технічна деталь
Сьогодні в нас немає побудованого каналу автоматичного оновлення. У новому проєкті це одне з перших трьох рішень, поряд із підписанням і розповсюдженням: оновлення виконуються вручну, через магазин платформи чи через власний канал? Кожен варіант має іншу постійну вартість і іншу площу безпеки, і його обирають до першого рядка коду, а не після.
Що залишається в нас
Джерела — доки ми працюємо; після передання — те, що погоджено в договорі. Сертифікати підпису, ідеально, залишаються на вашому організаційному обліковому записі — якщо вони залишаються на нашому, ви прив’язані до нас для кожного оновлення, і це має бути свідомим вибором, а не наслідком.

Випадок

Додаток macOS, виділений із ядра iPhone-додатка, без другої реалізації

Ситуація

У нас був власний продукт для iPhone, який вимірює нахил голови відносно положення, відкаліброваного на початку сесії. Ті самі правила — калібрування, пороги, історія, політики сповіщень — мали сенс і на Mac, де людина й так сидить перед екраном. Справжнє питання було не в тому, чи це можливо, а в тому, скільки логіки слід переписати.

Що ми збудували

Нуль, тому що ядро було написано від самого початку без урахування екрана. Ціль macOS перелічує 15 файлів із проєкту iPhone як власні джерела, до яких додаються 25 специфічних для десктопа Swift-файлів: вікно, меню в системному рядку через делегата AppKit, сповіщення, сервіс середовища. Збірка не проходить через інтерфейс Xcode: скрипт напряму викликає компілятор Swift із ціллю `arm64-apple-macosx14` і явно підключає одинадцять системних фреймворків, потім формує пакет `.app` і підписує його, а наприкінці перевіряє підпис.

Що вийшло

Бінарний файл розміром 6.516.128 байтів для процесорів Apple, який запускається і працює в рядку меню, зібраний однією командою. Та сама правка алгоритму доходить і до телефону, і до Mac, бо це той самий файл, а не копія, синхронізована вручну.

Чого цей випадок не каже

Додаток не розповсюджується і не може, сьогодні, бути таким у цій формі: підпис ad-hoc, без ідентифікатора команди, а поле команди розробки порожнє в конфігурації проєкту. На іншому комп’ютері система його заблокує. Це проблема облікового запису і нотаризації, а не функціональності — але це залишається невирішеною проблемою, і ми так її й пишемо, а не як деталь.

Питання

Про що нас питають, перш ніж зателефонувати

Чому на цій сторінці написано «пропозиція», якщо ви кажете, що маєте два Mac-додатки?

Тому що послуга називається «додатки для десктопа» і охоплює три сім’ї систем, а в нас готове рішення є для однієї. Правило, яке ми застосовуємо до себе, вимагає щонайменше двох власних реалізацій, які можна показати в коді, для кожного твердження типу «ми зробили». На macOS вони є. На Windows і на Linux у нас нуль, і жоден із двох Mac-додатків ніколи не був упакований у придатний для розповсюдження інсталятор. Сторінка, яка сказала б щось інше, не витримала б другого запитання інженера.

У вас є Mac-додаток, який я можу завантажити зараз?

Ні. Обидва існують як пакети `.app`, зібрані на нашій машині: один скомпільований для процесорів Apple, інший — універсальний, для Intel і Apple. Вони підписані ad-hoc, що означає, що проходять локальну перевірку, але не мають ідентифікатора команди, тож на іншому комп’ютері система їх заблокує. Що ми можемо зробити перед вами — це запустити їх, відкрити код і скрипт збирання та виконати набір логіки.

Яка у вас різниця між двома Mac-додатками?

Один нативний, інший — це вікно поверх вебу, і різниця велика. Нативний має 25 власних Swift-файлів плюс 15 файлів ядра, спільних із версією для iPhone, чіпляється до рядка меню через делегата AppKit і підключає одинадцять системних фреймворків, серед них сенсори руху, сповіщення та обробку зображень. Другий має три файли і показує веб-додаток у `WKWebView`. Другий робиться швидко і є правильним вибором, коли ваш додаток уже вебовий і вам потрібна лише піктограма в Dock. Це не правильний вибір, коли вам потрібна система.

Ви робите додатки для Windows?

Ми не передали жодного і не стверджуємо протилежного. Ми переглянули наші диски на предмет будь-яких слідів — проєктів .NET, WPF, WinForms, WinUI, XAML-файлів інтерфейсу, маніфестів додатків, пакетів MSI або WiX — і все, що з’являється, належить сторонній C-бібліотеці, яку ми лише використовуємо в іншому проєкті. Якщо вам потрібен Windows, перший етап — перевірка сумісності, яка завершується каркасом, що запускається у вас на комп’ютері, і лише після цього ми обговорюємо решту.

А для Linux або Ubuntu?

Однакова позиція, з важливою уточнювальною ремаркою. Застосунки з вікнами для Linux: нуль поставлених, жодного створеного нами пакета deb чи AppImage. Linux-сервери: щодня — системні блоки, вебсервер попереду, журнали, перезапуск у разі збою. Це дві різні дисципліни, і було б нечесно використовувати першу як доказ для другої.

Чому не Electron, якщо так простіше?

Бо ми не поставили жодного і не будемо стверджувати, що маємо досвід там, де його немає. На наших дисках є два працездатні Electron-застосунки, але це клоновані репозиторії інших авторів, із нульовим нашим внеском — ми перевірили їх в історії комітів саме для того, щоб вони не стали «доказом» на цій сторінці. У реальному проєкті вибір між упакованим вебсередовищем і нативним кодом роблять після того, як відомо, чого застосунок вимагає від системи, скільки важить пакет і хто платить за підтримку, а не за модою.

Що блокує у вас публікацію застосунку для Mac?

Обліковий запис, а не код. У конфігурації проєкту поле команди розробки порожнє, а підпис пакета, що збирається, ad-hoc, без ідентифікатора команди. Для поширення поза магазином macOS вимагає ідентифікований сертифікат розробника та проходження пакета через нотаризацію. У вашому проєкті сертифікат і обліковий запис належать вашій організації, тож ця перепона просто не виникає — але її треба передбачити від самого початку, з її вартістю і часом.

Хіба не простіше зробити сайт і завершити?

Часто так, і це ми кажемо вам раніше, ніж ви скажете це нам. Сайт не потребує підписування, нотаризації, інсталятора, каналу оновлення і навіть версії для кожної операційної системи. Встановлений застосунок виграє тоді, коли потрібні сенсори, периферія, робота без інтернету, постійна присутність у системному треї або прямий доступ до файлів людини. Якщо нічого з цього немає в списку, гроші краще витратити в іншому місці.

Чи можете ви взятися за desktop-застосунок, який у нас уже є?

За однієї умови, перевіреної ще до будь-якої оцінки: ми маємо змогти зібрати його з нуля, на нашій машині, з отриманих джерел. Якщо build не відтворюється — бракує залежностей, сертифікатів, неописаних кроків — тоді ніхто не може чесно нічого оцінити, а першою роботою стає відтворення build, а не нова функціональність. Ми кажемо це наперед, щоб це не виявилося посередині.

На чому ґрунтуються твердження вище (14 джерел)

14 з них — це код і файли з наших репозиторіїв. Ми не публікуємо їхні назви чи номери рядків: разом, на одній сторінці, це надто точно описало б, як побудовані системи, які належать не лише нам. Ми проходимо їх разом із вами, у репозиторії, за запитом — перевірка залишається можливою, просто вона відбувається в розмові.

Що вам хотілося б налагодити?

Розкажіть про свій процес. Разом визначимо, що варто збудувати, що можна підключити і як перевіримо результат.

Поговорімо