From e824a8e8eb248d755b9cf8faac6a8abecd1690f2 Mon Sep 17 00:00:00 2001 From: ares Date: Sun, 13 Sep 2026 11:47:51 +0300 Subject: [PATCH] Document interactive activity release and NowPlaying research [skip ci] --- PLAN.md | 51 +++++++++++++++++++++++++++++++++++++++----- README.md | 64 +++++++++++++++++++++++++++++++++---------------------- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/PLAN.md b/PLAN.md index 5b6b9aa..86037a2 100644 --- a/PLAN.md +++ b/PLAN.md @@ -46,7 +46,10 @@ Windows-агент — соседний проект `C:/Users/areso/MusicBridge - [x] Пользователь подтвердил работу 0.4.0 на iPhone: «всё вроде работает». - [x] Локальная Live Activity и Dynamic Island: реализация отображения трека в 0.5.0. - [ ] Проверить Live Activity на экране блокировки и Dynamic Island после подписи через iloader. -- [ ] App Intents: прямые действия из Live Activity и команды Siri. +- [x] LiveActivityIntent: предыдущий/следующий трек, play/pause и обновление — 0.6.0. +- [ ] Проверить команды из Live Activity/Island при блокировке на физическом iPhone. +- [ ] Команды Siri. +- [ ] NowPlaying RemoteMediaSession (iOS 27+): перейти на SDK 27, добавить remote-media extension и проверить системный Control Center. - [ ] APNs: отдельный проект обновлений при приостановленном приложении, если нужен постоянный актуальный трек в фоне. Ограничения: хранится один доверенный ПК; адрес при смене IP восстанавливается через @@ -143,13 +146,51 @@ Bonjour, если доступны объявления того же агент раскрываемые ручные поля, крупная play/pause, процент громкости и меню ПК. Сборка и 23 XCTest прошли; просмотрены темы, компактный экран и крупный текст. Пользователь подтвердил работу обновления на телефоне перед началом этапа 3. -3. **Системные интеграции — 0.5.0 (build 6).** Локальная Live Activity и Dynamic Island - реализованы; 26 XCTest и Release archive прошли. Карточка показывает последний снимок - с ПК, открывает плеер, помечает устаревшие данные. App Intents и APNs не реализованы. +3. **Системные интеграции — 0.6.0 (build 7).** Добавлены прямые действия LiveActivityIntent. + Убрана ошибка устаревания при обычном сворачивании; каждое нажатие перечитывает ПК. + 32 XCTest и Release archive прошли. APNs и встроенный системный музыкальный пульт ещё не реализованы. Не имитировать фоновое аудио. Не обещать постоянный WSS при блокировке. 4. **Несколько сохранённых ПК** — последующее расширение, сейчас сохраняется один. -Изменения третьего этапа — Live Activities 0.5.0: +Продолжение третьего этапа — 0.6.0: + +- Итоговый `43c78b2`: [Actions 34748340408](https://github.com/polskikh13/musicbridgeios/actions/runs/34748340408) + — 32 XCTest без отказов, успешный Release archive. IPA 0.6.0 (7) скачана в + `build/iPhone-0.6.0/MusicBridge-iPhone.ipa`; проверены ARM64 iPhoneOS приложения + и расширения, версии, метаданные интентов. Просмотрены светлая и тёмная карточки. + Работа системного запуска LiveActivityIntent и Keychain после блокировки требует + проверки на телефоне: обновить IPA, выключить/включить карточку, заблокировать, + проверить next/previous/toggle/refresh; затем повторить после перезагрузки и первого unlock. +- Пользователь сообщил, что карточка постоянно пишет об устаревших данных. + Причина: `PlayerStore.stop()` вызывал `unavailable()` при каждом уходе в фон. + Удалён этот вызов; реальные сетевые отказы продолжают отмечаться отдельно. + Карточка показывает время последнего снимка и отдельные ошибки запросов. +- Shared `MusicControlIntent` соответствует LiveActivityIntent. WidgetKit содержит + определение интента, выполнение сети компилируется только в основной app target; + iOS запускает процесс приложения без открытия UI. На компактном/минимальном Island + кнопок нет: нужно раскрыть долгим нажатием. Кнопки не отключаются из-за старого снимка. +- `LiveActivityCommands`: одно действие одновременно, проверка живой Activity и связи + её ID с fingerprint текущего сопряжения. После чтения состояния повторно проверяется + актуальность карточки, затем проверяются capabilities и отправляется максимум одна + команда. Refresh вообще не отправляет команду. Повторов команд нет. +- После успеха перечитывается трек и обновляется Activity. 401 завершает её; + неизвестный результат и неудача чтения после успеха имеют разные сообщения. + Нет бесконечного WSS/Bonjour в фоне; после смены IP сначала открыть приложение. +- Keychain: AfterFirstUnlockThisDeviceOnly вместо WhenUnlockedThisDeviceOnly, + чтобы команды работали при заблокированном iPhone. Существующий токен мигрирует + при повторном включении карточки. Он не покидает Keychain и не попадает в payload. + В UserDefaults сохраняется только соответствие ID активности и публичного pin. + После обновления с 0.5.0 карточку выключить и включить заново в приложении. +- HTTPS-тесты проверяют одну отправку next и новый трек, refresh без команды, + закрытую карточку, неподдерживаемую команду, отсутствие повторов отказавшей команды, + ошибку чтения после успешной команды. Физический запуск интента проверяется отдельно. +- Ответ на вопрос пользователя о встроенном музыкальном центре: официальный + [NowPlaying RemoteMediaSession](https://developer.apple.com/documentation/nowplaying/publishing-remote-media-sessions) + предназначен для внешнего воспроизведения. Metadata Apple указывает iOS 27.0. + Текущий runner собирает Xcode 16.4: следующий этап — SDK/Xcode 27 и отдельное + `com.apple.nowplaying.remote-media` расширение. Интеграция ещё не реализована. + +История третьего этапа — Live Activities 0.5.0 (поведение фона изменено в 0.6.0): - Итоговый `ddd44e8`: [Actions 34747772034](https://github.com/polskikh13/musicbridgeios/actions/runs/34747772034) — 26 XCTest без отказов, сборка приложения и WidgetKit-расширения, успешный Release archive. diff --git a/README.md b/README.md index a4b011e..ea85b4f 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ Apple ID и сертификаты для этой проверки не тре ## Установка на iPhone через Sideloadly Пользователь также подтвердил установку через iloader. Для повторной установки -с Live Activity используйте версию **0.5.0 (build 6)**: -`build/iPhone-0.5.0/MusicBridge-iPhone.ipa`. Выберите этот файл в iloader и +с Live Activity используйте версию **0.6.0 (build 7)**: +`build/iPhone-0.6.0/MusicBridge-iPhone.ipa`. Выберите этот файл в iloader и подпишите тем же Apple Account, которым установлена первая версия. В 0.4.0 добавлены иконка, карточка QR, раскрываемые ручные поля, крупная @@ -106,34 +106,46 @@ Sideloadly (в том числе его функцией автоматичес [Sideloadly FAQ](https://sideloadly.io/faq) · [Apple: режим разработчика](https://developer.apple.com/documentation/Xcode/enabling-developer-mode-on-a-device) -## Live Activity и Dynamic Island +## Live Activity и Dynamic Island — 0.6.0 -После подключения к ПК и появления трека нажмите под плеером -«Показать на экране блокировки». Та же карточка появится в Dynamic Island -на моделях, где он доступен. Долгое нажатие на Island раскрывает представление; -нажатие на карточку или «Открыть плеер» возвращает в приложение. -Кнопка «Убрать с экрана блокировки» завершает активность. Она также завершается, -когда ПК сообщает об отсутствии медиасессии, доступ отозван или компьютер забыт. -Удалённая пользователем карточка не создаётся снова автоматически. +После обновления с 0.5.0 уберите старую карточку кнопкой в приложении и нажмите +«Показать на экране блокировки» заново. Это связывает кнопки с текущим сопряжением +и переводит запись Keychain в режим доступа после первого разблокирования. +Токен остаётся только на этом устройстве, не копируется в виджет или UserDefaults. -Это **последний снимок состояния ПК**: название, исполнитель, состояние и прогресс. -В обычном режиме позиция обновляется не чаще раза в пять секунд; смена трека -и play/pause отправляются сразу. Прогресс не выдумывает движение без связи с ПК. -При уходе приложения в фон или потере связи отображается отметка устаревших данных; -резервный `staleDate` — 15 секунд, если приложение было внезапно остановлено. -Для обновления нажмите карточку. Прямых кнопок управления внутри неё пока нет. +На экране блокировки и в развёрнутом Dynamic Island доступны предыдущий трек, +play/pause, следующий трек и обновление. Компактный Island открывает приложение; +для кнопок удерживайте Island. Каждое действие выполняет отдельные HTTPS-запросы +с прежней проверкой сертификата. Оно работает через LiveActivityIntent в процессе +приложения, без открытия интерфейса; постоянного сетевого потока в фоне нет. -Live Activity не поддерживает постоянный сетевой поток сама по себе. Для обновления -при приостановленном приложении нужен отдельный механизм ActivityKit push через -APNs. В этой версии нет push-токенов, сервера APNs, фонового аудио и App Intents. -[Ограничения и жизненный цикл ActivityKit](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities). +Перед командой считываются возможности плеера, затем команда отправляется один раз +и перечитывается состояние. Повторы команд отключены; при неизвестном результате +сначала используйте обновление. Одновременно выполняется одно действие карточки. +После закрытия карточки или удаления её связи с ПК новые команды не отправляются. +Для нового адреса ПК сначала откройте приложение: Bonjour-перенос адреса остаётся +в основном приложении. При отзыве доступа карточка завершается. -В IPA включено расширение `MusicBridgeWidgets.appex`; при установке iloader должен -сохранить и подписать его вместе с приложением. Если Live Activity не появилась, -проверьте её разрешение в настройках MusicBridge и наличие расширения в логе установки. -Автоматические снимки `live-card-*-screen.png` показывают общую SwiftUI-разметку -карточки в Debug-предпросмотре: это не доказательство её регистрации на реальном -экране блокировки или системного отображения Dynamic Island. +При обычном сворачивании показывается время последнего обновления, а не ошибка +«Данные устарели». Прогресс соответствует этому снимку. Реальная ошибка сети или +команды выводится на карточке. Изменения, сделанные непосредственно на ПК, при +приостановленном приложении не появятся сами: нажмите обновление или откройте плеер. +Для постоянных фоновых обновлений остаётся отдельная задача APNs. + +В IPA есть расширение `MusicBridgeWidgets.appex`: iloader должен сохранить и подписать +его вместе с приложением. Проверка работы интентов в заблокированном состоянии и +системного отображения Island выполняется на iPhone; CI проверяет сборку, сетевую +логику команд и разметку. После перезагрузки сначала один раз разблокируйте iPhone. + +### Встроенный музыкальный пульт iOS + +Apple предлагает `RemoteMediaSession` в новом NowPlaying framework (iOS 27+) +для отображения музыки внешнего устройства на экране блокировки и в Control Center. +Это подходит архитектуре MusicBridge. Нужны SDK/Xcode 27 и отдельное расширение +`com.apple.nowplaying.remote-media`; текущая сборка использует Xcode 16.4. +Эта интеграция исследована, но ещё не реализована. Для фоновых обновлений удалённых +сессий Apple также предоставляет push-механизм. +[Документация remote media sessions](https://developer.apple.com/documentation/nowplaying/publishing-remote-media-sessions). ## Источники