Перейти к основному содержимому
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 — нативный код, но немного, потому что остальное — общее ядро. Другое наше 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: systemd-юниты с перезапуском при сбое, веб-сервер спереди, журналы и их ротация. Это реальный опыт с Linux, но это серверный опыт. Оконное приложение для Ubuntu — это другая дисциплина: упаковка, интеграция с графической средой, распространение через репозиторий или через самодостаточный файл — и там у нас ничего не поставлено. Это различие инженер увидит за три секунды; лучше, чтобы мы сказали это сами заранее.

Что мы не делаем

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

Как это выглядит

Путь, шаг за шагом.

01

Решаем, устанавливаемое или веб, по пяти критериям

Сенсоры и периферия, системная панель, работа без интернета, доступ к файлам, работа в фоне. Мы сдаём письменное решение с обоснованием, даже когда обоснование — «вам не нужно устанавливаемое приложение». Этот этап короткий, и его можно остановить здесь без потерь.

02

Строим ядро и тестируем его без платформы

Логика, состояния, сохранение, политики — написаны так, чтобы не зависеть от интерфейса и чтобы их можно было собрать и запускать как командную строковую программу. Мы сдаём набор тестов и команду, которой вы их запускаете. Если позже появится вторая платформа, здесь будет видно, была ли работа сделана правильно с самого начала.

03

Добавляем оболочку платформы

На macOS: окна или строка меню, уведомления, разрешения, пакет `.app`, скрипт сборки. На Windows или Linux: после проверки совместимости из первой стадии, с выбранной там средой выполнения. В конце этапа приложение запускается на вашей машине, а не на нашей.

04

Подпись, распространение, обновление

Этап, который большинство проектов обнаруживает поздно, а мы ставим последним явно, чтобы его было видно: сертификат, аккаунт, нотариализация там, где платформа этого требует, канал обновления. Здесь же и наше текущее ограничение на macOS — приложения подписываются ad-hoc, без идентификатора команды. В вашем проекте аккаунт будет ваш, и блокировка исчезнет.

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

Данные

К чему прикасаемся, где оно лежит и сколько остаётся

Вопросы, которые задаёт всякий, у кого есть ответственный за защиту данных, — заданы здесь раньше, чем их задаст он.

Установленное приложение видит больше, чем браузерное
Это причина, по которой вы его хотите, и одновременно его риск: у него есть доступ к диску, к файловой системе пользователя и, если выданы разрешения, к периферии. Поэтому разрешения объявляются явно и держатся на минимуме. У нашего приложения с песочницей ровно одно разрешение — разрешение сетевого клиента.
Где хранятся данные, когда у приложения нет сервера
На компьютере человека. В приложении для строки меню история записывается в собственный файл, а предпочтения — в хранилище настроек системы, с ключами, префиксированными по приложению. Ничего не уходит на сервер по простой причине: в приложении нет сетевого кода. Когда он есть, на странице разрешений пишется, кто что получает.
Что мы не собираем по умолчанию
Никакой телеметрии, никакого идентификатора устройства, никакого отчёта об использовании, если они не запрошены явно и не указаны в интерфейсе. 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?

Потому что услуга называется «desktop-приложения» и охватывает три семейства систем, а у нас сдано только одно. Правило, которому мы сами следуем, требует минимум двух собственных реализаций, которые можно показать в коде, для каждого утверждения типа «мы сделали». На 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 требует идентифицируемый сертификат разработчика и прохождение пакета через нотариализацию. В вашем проекте сертификат и аккаунт принадлежат вашей организации, значит, этого блока просто нет — но его нужно предусмотреть с самого начала, с его стоимостью и временем.

Не проще ли сделать сайт и закончить?

Во многих случаях да, и мы говорим вам это раньше, чем вы скажете нам. Сайту не нужны подпись, нотариализация, установщик, канал обновления и даже версия для каждой операционной системы. Установленное приложение выигрывает, когда вам нужны сенсоры, периферия, работа без интернета, постоянное присутствие в строке состояния или прямой доступ к файлам человека. Если ничего из этого нет в списке, деньги лучше потратить на что-то другое.

Можете ли вы взять на себя уже имеющееся у нас настольное приложение?

При одном условии, проверенном до любой оценки: мы должны быть в состоянии собрать его с нуля на нашей машине из полученных исходников. Если сборка не воспроизводится — не хватает зависимостей, сертификатов, неописанных шагов — тогда никто не может честно оценить ничего, и первой работой становится воспроизведение сборки, а не новая функциональность. Мы говорим это заранее, чтобы это не обнаружилось в середине.

На чём основаны утверждения выше (14 источников)

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

Что вы хотели бы наладить?

Расскажите о своём процессе. Вместе определим, что стоит построить, что можно подключить и как проверим результат.

Давайте обсудим