616 lines
30 KiB
Markdown
616 lines
30 KiB
Markdown
# Skip.tools: Оценка зрелости для AI-приложения с анимированным персонажем и голосом
|
||
|
||
> **Дата исследования:** 16 мая 2026
|
||
> **Версия Skip:** 1.8.14 (актуальная)
|
||
> **Контекст:** AI-приложение рефлексии на SwiftUI с анимированным blob/orb персонажем (Rive) и голосовым вводом/выводом (OpenAI Realtime API или Whisper+TTS)
|
||
|
||
---
|
||
|
||
## Вердикт TL;DR
|
||
|
||
> **⚠️ УСЛОВНО ГОТОВ — с существенными оговорками**
|
||
>
|
||
> Skip в 2026 году — это уже не эксперимент. Фреймворк активен, свободен, компилирует настоящий Jetpack Compose. Но для нашего конкретного кейса есть два критических барьера: **Rive не поддерживается официально** и требует платформо-специфичного workaround, а **WebSocket был сломан** до Skip 1.8/Swift 6.3 (сейчас починен). Рекомендация: **iOS-first MVP + Skip на неделю PoC**, принять решение по результатам.
|
||
|
||
---
|
||
|
||
## 1. Текущий статус Skip.tools (2025–2026)
|
||
|
||
### Жив ли проект?
|
||
|
||
**Однозначно да.** Метрики по состоянию на май 2026:
|
||
|
||
| Метрика | Значение |
|
||
|---------|---------|
|
||
| GitHub Stars | ~3,000 ⭐ |
|
||
| Forks | 101 |
|
||
| Последний релиз | v1.8.14 (8 мая 2026) |
|
||
| Лицензия | MPL-2.0 (полностью open source с v1.7) |
|
||
| Язык | Swift 100% |
|
||
| Режимы работы | Skip Fuse (нативный) / Skip Lite (транспайл) |
|
||
|
||
Важный поворот: в **феврале 2025** Skip стал соучредителем [Swift on Android Working Group](https://forums.swift.org/t/swift-on-android-working-group/77780), а **Swift 6.3** официально шипнул Swift SDK для Android. Skip 1.8 использует этот официальный SDK — больше нет зависимости от кастомного форка.
|
||
|
||
### Два режима: что выбрать?
|
||
|
||
| | **Skip Fuse** (нативный) | **Skip Lite** (транспайл) |
|
||
|---|---|---|
|
||
| Механизм | Swift компилируется нативно для Android | Swift → Kotlin (исходный код) |
|
||
| Плюсы | Полный Swift, все сторонние пакеты, детерминированная память | Прямой доступ к Kotlin/Java API, читаемый Kotlin-вывод, меньший размер |
|
||
| Минусы | +60 МБ к APK, медленная сборка | Не весь Swift транслируется, меньше пакетов |
|
||
| Рекомендация для нас | ✅ **Лучший выбор** — полный Swift, rich animations | — |
|
||
|
||
### Что поддерживается из SwiftUI?
|
||
|
||
Уровень покрытия (из официальной матрицы):
|
||
|
||
**Полная поддержка (✅):**
|
||
- `@State`, `@Binding`, `@Environment`, `@EnvironmentObject`, `@ObservedObject`, `@StateObject`, `@AppStorage`
|
||
- `AsyncImage`, `Button`, `HStack`, `VStack`, `ZStack`, `ScrollView`, `List`, `Form`
|
||
- `LinearGradient`, `RadialGradient`, `Circle`, `Rectangle`, `RoundedRectangle`, `Capsule`
|
||
- `NavigationStack`, `TabView`, `Sheet`, `Alert`
|
||
- `Text`, `TextField`, `SecureField`, `Toggle`, `Slider`, `Picker`
|
||
- `withAnimation` (есть известный баг — см. ниже)
|
||
|
||
**Частичная поддержка / проблемы:**
|
||
- `Canvas` — **статус неясен** (не упоминается в матрице явно, вероятно не поддерживается)
|
||
- `TimelineView` — аналогично, не подтверждён
|
||
- `@GestureState` — только Skip Fuse
|
||
- `AppStorage` с optional values — не работает
|
||
|
||
**Известные баги (актуальные issues):**
|
||
|
||
| Issue | Проблема | Дата |
|
||
|-------|----------|------|
|
||
| [#402](https://github.com/skiptools/skip-ui/issues/402) | `withAnimation()` утекает в глобальное состояние на Android | Апр 2026 |
|
||
| [#687](https://github.com/skiptools/skip/issues/687) | State не обновляется под NavigationLink (Fuse) | Май 2026 |
|
||
| [#376](https://github.com/skiptools/skip-ui/issues/376) | NavigationLink throttling (задержка навигации) | Мар 2026 |
|
||
| [#339](https://github.com/skiptools/skip-ui/issues/339) | `.frame(maxWidth:)` игнорирует границы родителя | Фев 2026 |
|
||
| [#331](https://github.com/skiptools/skip-ui/issues/331) | Text с `%` и Markdown рендерится неправильно | Фев 2026 |
|
||
|
||
> **Критически важно для нас:** баг с `withAnimation()` (#402) напрямую влияет на анимированный персонаж.
|
||
|
||
### Приложения в production
|
||
|
||
Официально подтверждённые:
|
||
- **Skip Showcase** — каталог SwiftUI компонентов, опубликован в App Store и Google Play
|
||
- **Skip Bookings** — тревел-букинг с картами (пример)
|
||
- **Skip Weather** — погода с async networking
|
||
- В v2.3.6 Showcase добавили целую игру Block Blast на ~1000 строк чистого Swift
|
||
|
||
> Третьесторонних production-приложений в публичном доступе не найдено — Skip пока используется преимущественно инди-разработчиками.
|
||
|
||
---
|
||
|
||
## 2. Rive + Skip: совместимость
|
||
|
||
### Официальная поддержка
|
||
|
||
**❌ Нет официального пакета `skip-rive`.** Список официальных Skip-модулей:
|
||
|
||
```
|
||
skip-motion (Lottie), skip-av (AVFoundation), skip-firebase, skip-revenue (RevenueCat)...
|
||
```
|
||
|
||
Rive в нём отсутствует.
|
||
|
||
### Как Rive работает на iOS
|
||
|
||
Rive iOS runtime (`rive-app/rive-ios`, 780 ⭐, v6.20.3, MIT License) использует:
|
||
- **Objective-C++ (~32% кода)** для C++ рантайма Rive
|
||
- Интеграция в SwiftUI через `RiveViewModel` + `RiveView`
|
||
|
||
```swift
|
||
// Типичный код на iOS
|
||
import RiveRuntime
|
||
|
||
struct CharacterView: View {
|
||
@StateObject var riveVM = RiveViewModel(fileName: "blob_character")
|
||
|
||
var body: some View {
|
||
riveVM.view()
|
||
.frame(width: 300, height: 300)
|
||
}
|
||
}
|
||
```
|
||
|
||
**Проблема для Skip:** Rive iOS package содержит нативный C++ runtime и Objective-C++ bindings. Skip **не может транспилировать Objective-C++ код** — это за пределами его возможностей.
|
||
|
||
### Workaround: Platform-specific через ComposeView
|
||
|
||
Skip предоставляет мощный механизм для именно такого случая:
|
||
|
||
```swift
|
||
struct CharacterView: View {
|
||
let characterState: CharacterState
|
||
|
||
var body: some View {
|
||
#if os(Android)
|
||
// Android: используем Rive Android SDK через Compose
|
||
ComposeView { RiveAndroidComposer(state: characterState) }
|
||
#else
|
||
// iOS: нативный RiveRuntime
|
||
RiveNativeView(state: characterState)
|
||
#endif
|
||
}
|
||
}
|
||
|
||
// iOS-only код (полный Swift, без ограничений)
|
||
#if !SKIP
|
||
import RiveRuntime
|
||
|
||
struct RiveNativeView: View {
|
||
let state: CharacterState
|
||
@StateObject var riveVM = RiveViewModel(fileName: "blob_character")
|
||
|
||
var body: some View {
|
||
riveVM.view()
|
||
.onAppear { riveVM.triggerInput("setState", value: state.rawValue) }
|
||
}
|
||
}
|
||
#endif
|
||
|
||
// Android Kotlin через #if SKIP блок
|
||
#if SKIP
|
||
import app.rive.runtime.kotlin.compose.RiveAnimation
|
||
|
||
struct RiveAndroidComposer: ContentComposer {
|
||
let state: CharacterState
|
||
|
||
@Composable func Compose(context: ComposeContext) {
|
||
RiveAnimation(
|
||
resId = R.raw.blob_character,
|
||
modifier = context.modifier,
|
||
stateMachineName = "State Machine",
|
||
onInit = { controller in
|
||
controller.setBooleanState("State Machine", "isListening", state == .listening)
|
||
}
|
||
)
|
||
}
|
||
}
|
||
#endif
|
||
```
|
||
|
||
**Оценка workaround:**
|
||
- ✅ Технически реализуемо
|
||
- ✅ iOS остаётся чистым нативным RiveRuntime
|
||
- ⚠️ Нужно поддерживать две реализации
|
||
- ⚠️ Требует добавить зависимость `rive-android` в Gradle вручную через `skip.yml`
|
||
- ⏱️ Оценка трудозатрат: 2-3 дня дополнительно
|
||
|
||
### Lottie как альтернатива Rive
|
||
|
||
**`skip-motion` (официальный пакет)** — Lottie поддерживается!
|
||
|
||
```swift
|
||
import SkipMotion
|
||
|
||
struct CharacterView: View {
|
||
var body: some View {
|
||
MotionView(lottie: lottieAnimationData)
|
||
.frame(width: 300, height: 300)
|
||
}
|
||
}
|
||
```
|
||
|
||
| Параметр | Статус |
|
||
|----------|--------|
|
||
| Версия | v0.7.2 (Jan 2026) |
|
||
| iOS backend | lottie-ios v4.6.0 |
|
||
| Android backend | lottie-android v6.7.1 |
|
||
| Размер | +~1 МБ к ipa/apk |
|
||
| Управление воспроизведением | ⚠️ Раннее состояние, ограниченные контролы |
|
||
| State machine | ❌ Нет (в отличие от Rive) |
|
||
|
||
**Ключевое ограничение Lottie:** у него нет **State Machine** как у Rive. Для персонажа с динамическими состояниями (listening, thinking, speaking) это критично — нужно либо делать несколько анимаций, либо переключать между файлами. В Rive это нативно.
|
||
|
||
### SwiftUI-native анимированный персонаж (без Rive/Lottie)
|
||
|
||
Возможный подход: написать blob/orb через SwiftUI shapes + `withAnimation`:
|
||
|
||
```swift
|
||
struct BlobCharacterView: View {
|
||
@State private var animationPhase: Double = 0
|
||
|
||
var body: some View {
|
||
TimelineView(.animation) { timeline in
|
||
Canvas { context, size in
|
||
// Custom blob morphing via Bezier paths
|
||
let path = blobPath(for: timeline.date.timeIntervalSince1970)
|
||
context.fill(path, with: .color(.purple.opacity(0.8)))
|
||
}
|
||
}
|
||
.frame(width: 200, height: 200)
|
||
}
|
||
}
|
||
```
|
||
|
||
**Проблема:** `Canvas` и `TimelineView` — **не подтверждены** в матрице совместимости Skip. Вероятно, не поддерживаются на Android (не найдены в списке поддерживаемых Views). Плюс баг `withAnimation()` (#402).
|
||
|
||
> **Вывод по анимации:** Rive через workaround — самый мощный вариант, но требует дополнительных усилий. Lottie безопаснее для Skip, но функционально беднее. Pure SwiftUI blob — рискованно из-за Canvas/TimelineView.
|
||
|
||
---
|
||
|
||
## 3. Голосовая интеграция + Skip
|
||
|
||
### skip-av: статус AVFoundation
|
||
|
||
Официальный пакет `skip-av` (v0.7.1, 15 мая 2026, 12 ⭐):
|
||
|
||
| API | Android-поддержка | Что работает |
|
||
|-----|-------------------|--------------|
|
||
| `AVAudioRecorder` | 🟢 **High** | `record()`, `stop()`, `pause()`, `isRecording`, `peakPower`, `averagePower` |
|
||
| `AVAudioPlayer` | 🟢 **High** | `play()`, `pause()`, `stop()`, `volume`, `rate`, `duration` |
|
||
| `AVPlayer` | 🟠 Low | Только базовый init/play/pause |
|
||
| `VideoPlayer` | 🟡 Medium | `init(player:)` |
|
||
|
||
**Бэкенд на Android:** `MediaRecorder` + `MediaPlayer` (не ExoPlayer для записи).
|
||
|
||
```swift
|
||
// Запись голоса — работает на обеих платформах через skip-av
|
||
let settings: [String: Any] = [
|
||
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
|
||
AVSampleRateKey: 16000,
|
||
AVNumberOfChannelsKey: 1,
|
||
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
|
||
]
|
||
|
||
// Platform-specific путь к файлу
|
||
let recordingURL: URL = {
|
||
#if SKIP
|
||
let context = ProcessInfo.processInfo.androidContext
|
||
let file = java.io.File(context.filesDir, "voice_input.m4a")
|
||
return URL(fileURLWithPath: file.absolutePath)
|
||
#else
|
||
return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
|
||
.first!.appendingPathComponent("voice_input.m4a")
|
||
#endif
|
||
}()
|
||
|
||
audioRecorder = try AVAudioRecorder(url: recordingURL, settings: settings)
|
||
audioRecorder?.record()
|
||
```
|
||
|
||
Нужно добавить в AndroidManifest.xml:
|
||
```xml
|
||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||
```
|
||
|
||
### WebSocket для OpenAI Realtime API
|
||
|
||
**История баг-фикса:**
|
||
|
||
| Событие | Дата |
|
||
|---------|------|
|
||
| Проблема #559 открыта: libcurl без WebSocket | Дек 2025 |
|
||
| Фикс смерджен в swift-docker | 23 Дек 2025 |
|
||
| Swift 6.3 официально релизнут с WebSocket | Мар 2026 |
|
||
| Skip 1.8 обновлён на официальный Swift 6.3 SDK | Май 2026 |
|
||
|
||
**Текущий статус (Skip 1.8.14):** WebSocket **должен работать** — Skip 1.8 использует Swift 6.3, где проблема решена. Но статус issue #559 остаётся "Open" — рекомендуется проверить в PoC.
|
||
|
||
```bash
|
||
# Проверить активный SDK
|
||
skip android sdk list
|
||
# Должен показать swift-6.3-..._android
|
||
|
||
skip android build --version
|
||
```
|
||
|
||
**Альтернативный подход (более безопасный):** Whisper + TTS вместо Realtime API
|
||
|
||
```swift
|
||
// Более Skip-friendly архитектура:
|
||
// 1. Запись голоса → AVAudioRecorder (skip-av)
|
||
// 2. Отправка файла на Whisper API → URLSession (HTTP POST, не WebSocket)
|
||
// 3. Ответ через GPT-4 → URLSession
|
||
// 4. TTS → URLSession, воспроизведение → AVAudioPlayer (skip-av)
|
||
```
|
||
|
||
HTTP через URLSession **полностью поддерживается** Skip — нет никаких проблем. Whisper+TTS архитектура безопаснее для MVP.
|
||
|
||
### WebRTC (skip-livekit)
|
||
|
||
Интересно: в официальных модулях есть `skip-livekit` — WebRTC через LiveKit. Но для OpenAI Realtime API WebRTC нужен другой конкретный эфемерный ключ, не LiveKit. Это не подходит напрямую.
|
||
|
||
### Механизм platform-specific кода
|
||
|
||
Skip предоставляет три директивы препроцессора:
|
||
|
||
```swift
|
||
// Код только для Android (в Fuse: нативный Swift; в Lite: транспилируется)
|
||
#if os(Android)
|
||
// ...
|
||
#endif
|
||
|
||
// Код транспилируется в Kotlin (можно вызывать Kotlin/Java API напрямую)
|
||
#if SKIP
|
||
import android.content.pm.PackageManager
|
||
let hasPermission = context.checkSelfPermission(
|
||
android.Manifest.permission.RECORD_AUDIO
|
||
) == PackageManager.PERMISSION_GRANTED
|
||
#endif
|
||
|
||
// Только iOS
|
||
#if !os(Android)
|
||
import AVFoundation
|
||
AVAudioSession.sharedInstance().requestRecordPermission { granted in ... }
|
||
#endif
|
||
```
|
||
|
||
**Это мощный escape hatch** — любая iOS-only функциональность доступна без ограничений в `#if !SKIP` блоках.
|
||
|
||
---
|
||
|
||
## 4. Альтернативы если Skip не готов
|
||
|
||
### iOS-first MVP без Android
|
||
|
||
**Плюсы:**
|
||
- ✅ Нет компромиссов — полный RiveRuntime, полный AVFoundation, WebRTC
|
||
- ✅ iOS = 5× выше ARPU ($140 vs $69 в год на пользователя)
|
||
- ✅ Скорость разработки — нет overhead на кросс-платформу
|
||
- ✅ App Store первичен для платных подписок
|
||
|
||
**Минусы:**
|
||
- ❌ Упускаем ~3.7B Android пользователей
|
||
- ❌ Если позже добавлять Android — переписывать
|
||
|
||
**Коммерческая оценка:** Для подписочного приложения iOS-first — **стандартная практика**. Большинство AI-приложений (Calm, Headspace, Replika) стартовали с iOS. Android добавляли позже.
|
||
|
||
### React Native 2025
|
||
|
||
| Критерий | Оценка |
|
||
|----------|--------|
|
||
| Голос (микрофон, TTS) | ✅ expo-av, хорошая поддержка |
|
||
| Rive анимация | ✅ `rive-react-native` — официальный runtime! |
|
||
| OpenAI Realtime API | ✅ нет проблем с WebSocket |
|
||
| Подписки | ✅ react-native-purchases (RevenueCat) |
|
||
| Производительность анимаций | ⚠️ JS bridge может давать jank |
|
||
| Язык для iOS-разработчика | ❌ TypeScript/JS — новый стек |
|
||
| New Architecture migration | ⚠️ Legacy arch заморожена с июня 2025 |
|
||
|
||
**Итог:** Функционально React Native покрывает все наши нужды. Но требует знания JS/TS экосистемы. Rive Runtime для React Native — официальный и зрелый.
|
||
|
||
### Flutter 2025
|
||
|
||
| Критерий | Оценка |
|
||
|----------|--------|
|
||
| Голос | ✅ `flutter_sound`, `speech_to_text` |
|
||
| Rive анимация | ✅ официальный `rive` пакет на pub.dev |
|
||
| OpenAI Realtime API | ✅ WebSocket нативный |
|
||
| Подписки | ✅ `purchases_flutter` (RevenueCat) |
|
||
| Производительность | ⚠️ +40 МБ overhead, GC паузы |
|
||
| iOS 26 "Liquid Glass" UI | ❌ Flutter команда **отказалась** адаптировать Cupertino widgets |
|
||
| Язык | ❌ Dart — новый стек |
|
||
|
||
**Критическое замечание:** GitHub issues flutter #170310 — Flutter команда подтвердила, что не будет имплементировать новый Apple '26 UI дизайн в Cupertino библиотеке в ближайшее время. Для AI-приложения это может не критично, но iOS UI выглядит устаревшим.
|
||
|
||
### Kotlin Multiplatform + Compose Multiplatform
|
||
|
||
| Критерий | Оценка |
|
||
|----------|--------|
|
||
| UI фреймворк | Compose Multiplatform (нативный Android, mimicked iOS) |
|
||
| Rive | ✅ `Rive-CMP` (community, v0.4.0, 105 ⭐) |
|
||
| Голос | ✅ kotlin-native доступ к platform APIs |
|
||
| Для Swift-разработчика | ❌ Нужен Kotlin — совсем новый стек |
|
||
| iOS UI | ⚠️ Не SwiftUI — кастомный рендеринг Skia |
|
||
|
||
Для Swift-разработчика KMP — самый далёкий вариант. Хотя технически сильный.
|
||
|
||
### Capacitor/Ionic
|
||
|
||
**Не рекомендуется** для нашего кейса. WebView-рендеринг, анимации через CSS/JS будут уступать нативным, особенно для персонажа и голоса.
|
||
|
||
---
|
||
|
||
## 5. Конкретный план PoC на 1 неделю
|
||
|
||
### Цель PoC
|
||
|
||
Ответить на три вопроса:
|
||
1. Работает ли WebSocket / Whisper API через Skip на Android?
|
||
2. Реализуем ли анимированный персонаж (Lottie или Rive workaround)?
|
||
3. Работает ли запись голоса через skip-av?
|
||
|
||
### День 1: Базовый проект
|
||
|
||
```bash
|
||
brew tap skiptools/skip && brew install skip
|
||
skip checkup
|
||
|
||
# Создаём проект в режиме Fuse
|
||
skip android sdk install # убедиться что 6.3+
|
||
skip init --fuse-app --appid=com.yourapp.reflection reflection-app ReflectionApp
|
||
|
||
# Проверяем SDK версию
|
||
skip android sdk list
|
||
```
|
||
|
||
**Критерий успеха:** Базовое SwiftUI приложение запускается параллельно на iOS Simulator и Android Emulator.
|
||
|
||
### День 2-3: Голос + сеть
|
||
|
||
```swift
|
||
// Тест 1: Запись через AVAudioRecorder
|
||
// Тест 2: HTTP POST на Whisper API (URLSession)
|
||
// Тест 3: WebSocket соединение (если нужен Realtime API)
|
||
```
|
||
|
||
```swift
|
||
// Проверка WebSocket
|
||
import Foundation
|
||
|
||
class WebSocketTest: ObservableObject {
|
||
var task: URLSessionWebSocketTask?
|
||
|
||
func test() {
|
||
let url = URL(string: "wss://echo.websocket.org")!
|
||
task = URLSession.shared.webSocketTask(with: url)
|
||
task?.resume()
|
||
task?.send(.string("Hello")) { error in
|
||
print(error == nil ? "✅ WebSocket работает!" : "❌ \(error!)")
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Критерий успеха:** Запись работает на Android, HTTP к OpenAI проходит, WebSocket не выдаёт ошибку libcurl.
|
||
|
||
### День 4-5: Анимированный персонаж
|
||
|
||
**Вариант A (рекомендуется для PoC): Lottie через skip-motion**
|
||
|
||
```swift
|
||
// Package.swift: добавить skip-motion
|
||
.package(url: "https://source.skip.dev/skip-motion.git", "0.0.0"..<"2.0.0")
|
||
```
|
||
|
||
```swift
|
||
import SkipMotion
|
||
|
||
struct CharacterView: View {
|
||
var isListening: Bool
|
||
|
||
var body: some View {
|
||
MotionView(lottie: isListening ? listeningAnimation : idleAnimation)
|
||
.frame(width: 250, height: 250)
|
||
}
|
||
}
|
||
```
|
||
|
||
**Вариант B (для Rive):** Реализовать RiveCharacterView с #if SKIP/iOS разделением (как показано выше). Добавить rive-android в `skip.yml`:
|
||
|
||
```yaml
|
||
# Android/app/src/main/skip.yml
|
||
dependencies:
|
||
- app.rive:rive-android:9.12.0
|
||
```
|
||
|
||
**Критерий успеха:** Персонаж анимируется на обеих платформах, состояния переключаются.
|
||
|
||
### День 6-7: Интеграция и оценка
|
||
|
||
- Собрать мини end-to-end: нажал кнопку → запись → Whisper → ответ → TTS → воспроизведение → персонаж реагирует
|
||
- Замерить производительность анимации на Android (fps)
|
||
- Оценить размер APK
|
||
|
||
### Критерии успеха/провала PoC
|
||
|
||
| Критерий | Success | Fail |
|
||
|----------|---------|------|
|
||
| Голосовая запись | Работает на Android API 28+ | Крэшит или нет звука |
|
||
| HTTP к OpenAI | Запросы проходят | SSL/network ошибки |
|
||
| WebSocket | Соединение устанавливается | libcurl ошибка |
|
||
| Анимация (Lottie) | Плавная, состояния переключаются | Дёргается, не отображается |
|
||
| Rive workaround (опц.) | Загружается .riv файл | Compile error, не интегрируется |
|
||
| Общая стабильность | Нет крэшей при 10-мин сессии | Крэши, ANR на Android |
|
||
|
||
### Fallback план если PoC провалился
|
||
|
||
**Уровень 1 (мягкий фейл — одна проблема):**
|
||
- WebSocket не работает → используем Whisper+TTS по HTTP
|
||
- Rive не интегрируется → используем Lottie или SwiftUI анимации
|
||
- Lottie не устраивает → делаем чистую iOS-версию с Rive, Android откладываем
|
||
|
||
**Уровень 2 (полный фейл Skip):**
|
||
Переходим на **iOS-first MVP** (натив SwiftUI):
|
||
- 4-6 недель до первой версии
|
||
- Полный Rive, полный AVFoundation, OpenAI Realtime API
|
||
- Android: через 3-6 месяцев либо через React Native (Rive официально поддерживается), либо через Skip если к тому времени созреет
|
||
|
||
---
|
||
|
||
## 6. Итоговая рекомендация
|
||
|
||
### Рекомендованная стратегия: "Skip с Lottie + Whisper-first"
|
||
|
||
```
|
||
Неделя 1-2: PoC на Skip (план выше)
|
||
Неделя 3-6: MVP на Skip если PoC ✅
|
||
↓ если PoC ❌
|
||
iOS-first MVP (нативный SwiftUI + Rive)
|
||
```
|
||
|
||
**Рекомендованный стек для MVP на Skip:**
|
||
|
||
| Компонент | Решение |
|
||
|-----------|---------|
|
||
| UI фреймворк | SwiftUI + Skip Fuse |
|
||
| Анимация персонажа | **Lottie через skip-motion** (безопасно) или Rive с platform-specific workaround |
|
||
| Голосовой ввод | AVAudioRecorder через **skip-av** |
|
||
| STT | **Whisper API по HTTP** (не WebSocket) — максимально безопасно |
|
||
| TTS | OpenAI TTS API по HTTP + AVAudioPlayer |
|
||
| AI диалог | GPT-4o через HTTP/URLSession |
|
||
| Подписки | **skip-revenue** (RevenueCat официально поддержан) |
|
||
| Аналитика | **skip-posthog** (официально) |
|
||
| Auth | **skip-firebase** (Firebase Auth) |
|
||
|
||
**Почему Whisper+TTS вместо Realtime API:**
|
||
- WebSocket технически починен в Skip 1.8 (Swift 6.3), но нужно верифицировать в PoC
|
||
- Whisper+TTS архитектура — надёжнее и дешевле для рефлексии (нет потоковой передачи)
|
||
- Можно добавить Realtime API позже как premium-фичу
|
||
|
||
**Почему Lottie вместо Rive:**
|
||
- Официальный skip-motion пакет, нет platform-specific кода
|
||
- Для MVP не нужна полная State Machine Rive
|
||
- Rive можно добавить после MVP когда сделаете полноценный workaround
|
||
|
||
### Ограничения и риски при использовании Skip
|
||
|
||
| Риск | Уровень | Митигация |
|
||
|------|---------|-----------|
|
||
| Баг `withAnimation()` (#402) утечка в глобальное состояние | 🔴 Высокий | Тестировать в PoC, использовать `.animation()` modifier вместо `withAnimation` |
|
||
| Canvas/TimelineView не поддерживаются | 🔴 Высокий | Использовать Lottie/Rive, не делать чистый SwiftUI blob |
|
||
| WebSocket не верифицирован в production | 🟡 Средний | Whisper+TTS как план A |
|
||
| Rive workaround требует два кодабейса | 🟡 Средний | Lottie для MVP, Rive потом |
|
||
| +60 МБ к размеру APK (Skip Fuse) | 🟢 Низкий | Приемлемо для B2C приложения |
|
||
| Мало примеров third-party production apps | 🟡 Средний | Активное сообщество, официальные примеры |
|
||
|
||
### Если НЕ использовать Skip прямо сейчас
|
||
|
||
**Лучшая альтернатива для этого конкретного кейса:**
|
||
|
||
1. **iOS MVP (нативный SwiftUI)** — 4-6 недель, полный Rive, AVFoundation, Realtime API
|
||
2. **Android через 6+ месяцев:**
|
||
- Re-evaluate Skip (к тому времени Canvas поддержка появится)
|
||
- Или React Native (Rive official runtime, mature ecosystem)
|
||
|
||
**Не рекомендуется:**
|
||
- Flutter — из-за iOS 26 UI regression и неопределённости команды
|
||
- Ionic/Capacitor — для анимированного персонажа и голоса WebView недостаточен
|
||
|
||
---
|
||
|
||
## Приложения: Ссылки и источники
|
||
|
||
### Skip официальная документация
|
||
- [skip.tools/docs](https://skip.tools/docs) — главная документация
|
||
- [skip.tools/docs/modules/skip-ui/](https://skip.tools/docs/modules/skip-ui/) — матрица совместимости SwiftUI
|
||
- [skip.tools/docs/modules/skip-av/](https://skip.tools/docs/modules/skip-av/) — AVFoundation поддержка
|
||
- [skip.tools/docs/platformcustomization/](https://skip.tools/docs/platformcustomization/) — #if SKIP механизм
|
||
- [skip.tools/compare/](https://skip.tools/compare/) — сравнение с Flutter/React Native
|
||
|
||
### GitHub Issues (ключевые)
|
||
- [#559](https://github.com/skiptools/skip/issues/559) — WebSocket не работал в libcurl (починен в 6.3)
|
||
- [#402](https://github.com/skiptools/skip-ui/issues/402) — withAnimation() глобальный state баг
|
||
- [#687](https://github.com/skiptools/skip/issues/687) — NavigationLink state bug (Fuse)
|
||
|
||
### Skip-пакеты для нашего кейса
|
||
- [skip-motion](https://github.com/skiptools/skip-motion) — Lottie анимации
|
||
- [skip-av](https://github.com/skiptools/skip-av) — AVFoundation / аудио
|
||
- [skip-revenue](https://github.com/skiptools/skip-revenue) — RevenueCat подписки
|
||
- [skip-firebase](https://github.com/skiptools/skip-firebase) — Firebase Auth/Firestore
|
||
|
||
### Rive
|
||
- [rive-app/rive-ios](https://github.com/rive-app/rive-ios) — iOS runtime (v6.20.3, 780 ⭐)
|
||
- [rive-app/rive-android](https://github.com/rive-app/rive-android) — Android runtime (Compose API beta)
|
||
- [Rive-CMP](https://github.com/muazkadan/Rive-CMP) — Community Compose Multiplatform wrapper
|
||
|
||
### OpenAI Realtime API
|
||
- [swift-realtime-openai](https://github.com/m1guelpf/swift-realtime-openai) — Swift SDK (431 ⭐, поддержка WebRTC+WebSocket)
|
||
|
||
---
|
||
|
||
*Документ создан: 16 мая 2026. Актуален для Skip v1.8.14 и Swift 6.3.*
|