Назад в блог
Разработка

Live Activities в фудтехе: как одна фича решает три бизнес-проблемы

16 минут
Preview
Содержание

Если вы запускали delivery-приложение в последние два года, то наверняка сталкивались с одними и теми же вопросами: «Почему пользователи не возвращаются после первого заказа?», «Как снизить нагрузку на поддержку?» и «Чем мы вообще отличаемся от конкурентов?».

Live Activities — технология Apple, которая появилась в iOS 16.1 — неочевидно оказалась ответом на все три вопроса сразу. Но давайте без хайпа: разберём по фактам, когда это действительно работает, а когда — просто красивая игрушка.

Что это и почему сейчас

Live Activities — это виджет на экране блокировки, который обновляется в реальном времени. Пользователь создал заказ → виджет появился → статус меняется без открытия приложения. Звучит просто, но эффект нетривиальный.

По данным CleverTap, 90% пользователей удаляют приложение в течение 30 дней после установки. При этом экран блокировки пользователь видит десятки раз в день. Live Activities решает главную проблему любого мобильного продукта — борьбу за внимание.

Три задачи, которые решает Live Activities

1. Снижение нагрузки на поддержку на 20–40%

Проблема

Классика жанра — значительная часть обращений в поддержку начинается с «Где мой заказ?». Согласно исследованию ShippyPro, запросы типа «Where is my order?» (WISMO) составляют одну из крупнейших категорий тикетов в delivery-бизнесе. Пользователь разместил заказ, получил пуш «Мы приняли ваш заказ», а дальше — тишина. Через 20 минут начинается паника и звонки.

Что дают Live Activities

  • Статус заказа всегда на виду: «Готовим» → «Курьер выехал» → «5 минут до доставки»
  • Прогресс-бар для визуализации этапов
  • Автоматические обновления через push без открытия приложения

Потенциал экономии

Исследования показывают, что улучшение UX может снизить количество связанных с ним тикетов на 25–40%. Например, когда PhotoSì автоматизировала трекинг и уведомления доставки, компания получила 20% снижения обращений в поддержку и 30% экономии операционного времени.

Если один тикет стоит $2–5 обработки, и у вас 500+ обращений в день, экономия может составить $10 000–30 000 в месяц. Для сети с миллионными оборотами это не критично. Но если вы startup с ограниченным бюджетом и саппорт-команда из 3–5 человек работает на износ — эти проценты высвобождают время на действительно сложные кейсы.

2. Рост retention на 23.7%

Проблема

Пользователь установил приложение, сделал заказ, получил еду — и забыл про вас. Когда он снова голоден, но открывает приложение конкурента просто потому, что его иконка попалась на глаза первой.

Что дают Live Activities

Постоянное визуальное присутствие формирует brand recall. По данным OneSignal и GoodRequest, приложения, использующие Live Activities, демонстрируют на 23.7% более высокий показатель retention на 30-й день. Это не теория — это данные из State of Customer Engagement Report на основе реальных метрик.

Психология работает просто

  • Человек видит «Заказ доставлен ✓» на экране блокировки
  • Срабатывает закрепление успешного опыта
  • При следующем голодном моменте всплывает ваш бренд

Контекст индустрии

Согласно AppsFlyer, средний retention на 30-й день для food delivery apps составляет всего 3–4%. Это означает, что из 100 новых пользователей через месяц возвращаются лишь 3–4 человека. Прирост retention даже на несколько процентных пунктов критически важен.

При этом 62% пользователей Live Activities оценивают свой опыт как «хороший» или «отличный», что напрямую влияет на желание вернуться.

3. Дифференциация на перенасыщенном рынке

Проблема:

Все delivery-приложения выглядят одинаково. Карточки блюд, корзина, оплата, трекинг курьера на карте. Пользователь не видит разницы между вами и десятком конкурентов.

Реальность рынка

Что дают Live Activities

Premium UX, который есть не у всех. По состоянию на конец 2024 года, большинство локальных delivery-сервисов в СНГ его ещё не внедрили. Вы получаете преимущество first-mover.

Эффект на NPS

Средний NPS в категории fast-food составляет около 30 пунктов, а для ресторанов с хорошим сервисом — 53 и выше. Рестораны с NPS выше 60 считаются отличными.

Когда компании внедряют значительные улучшения UX, которые пользователи замечают (а Live Activities — именно такая фича), это приводит к росту NPS. В среднем для food delivery apps NPS колеблется от -4% до 40%, в зависимости от качества сервиса.
case image

Когда Live Activities действительно нужны

Вам это нужноМожно пока обойтись
✅ У вас > 500 заказов в день. Меньше — ROI сомнительный. Разработка + интеграция + тестирование = 80–120 часов работы команды. Если заказов мало, эффект не окупит вложения.❌ Вы ранний startup с MVP и 50 заказами в неделю
✅ Средний срок исполнения заказа > 15 минут. Если готовите за 5 минут — Live Activity не успеет сработать. Согласно статистике, средний срок доставки составляет около 40 минут, что идеально для Live Activities.❌ У вас нет выделенного разработчика и вы не готовы привлекать команду
✅ У вас уже есть iOS-приложение.Очевидно, но важно: Live Activities работают только на iOS 16.1+. ❌ Ваш backend ещё не умеет в real-time события
✅ Доля iOS-пользователей > 40%. Хотя Android доминирует глобально, в развитых рынках (США, Европа) iOS держит 40–60% рынка food delivery apps. iOS-пользователи также имеют более высокий средний чек — $532.60 revenue per user vs меньше на Android.❌ Бюджет ограничен и есть более критичные задачи
✅ У вас есть backend для real-time обновлений
Если никакого приложения у вас еще нет, обратитесь к нам. Мы создаем кросс-платформенные приложения и экономим клиентам время на разработку
Заполнить форму

Альтернатива для стартапов

Сфокусируйтесь на базовых push-уведомлениях с rich-контентом. Push-уведомления увеличивают retention в среднем в 5 раз, и они дешевле в разработке.

Максим Б.
Если у вас остались вопросы, запишитесь на бесплатную консультацию!
Максим Б. CEO
Запланировать встречу

ROI: честный разговор о деньгах

Инвестиции с вашей стороны

Разработка:

  • 100 часов команды × $50–80/час = $5000–8000
  • Или 2–3 недели работы одного middle/senior iOS- или cross platform-разработчика

Инфраструктура:

  • APNs — бесплатно
  • Хранение push-токенов — копейки
  • Дополнительная нагрузка на backend — минимальная

Возврат средств

Считаем на примере условного клиента (15 000 заказов/день, 50% iOS):

Экономия на поддержке:

  • Снижение тикетов на 20–30% = экономия $5000–10000/месяц
  • За год: $60 000–120 000

Рост retention (+23.7%): Это сложнее считать напрямую, но если каждый дополнительный вернувшийся пользователь делает хотя бы 1 заказ в месяц:

  • Средний чек $20, маржа 30% = $6 прибыли с заказа
  • 15000 заказов × 50% iOS × 23.7% retention lift × 15% конверсия в повторный заказ = ~265 дополнительных заказов/день
  • 265 × $6 × 30 дней = ~$48 000/месяц дополнительной прибыли

Timeline окупаемости: Первые 1–2 месяца после запуска — уже в плюсе.

Формула для вашего бизнеса

ROI=(Экономиянаподдержке+Ростотretention)/Стоимостьразработки

Где: Экономия на поддержке = Сэкономленные тикеты × Стоимость обработки

Рост от retention = Дополнительные заказы × Средний чек × Маржа

Техническая сторона: что нужно знать CTO

Backend requirements

Для работы Live Activities нужно:

  1. Push-инфраструктура:
  2. APNs (Apple Push Notification service)
  3. Хранение токенов: Live Activity генерирует свой push-токен (отдельный от обычных уведомлений). Его нужно получить на клиенте → отправить на backend → хранить → использовать для обновлений.

iOS requirements

  • iOS 16.1+ (Live Activities появились здесь)
  • iOS 16.2+ (для push-обновлений через APNs)
  • Widget Extension в проекте

Подводные камни

  • Keychain вместо UserDefaults для безопасного хранения авторизационных токенов 

Он общий для для разных процессов, можно шарить данные между виджетом и приложением

  • Автоматическое обновление auth-токенов

Если ваш access token живёт 15 минут, а заказ доставляется 40 минут, виджет потеряет авторизацию.

  • Ограничения по дизайну Apple строго регламентирует UI Live Activities.

Нельзя добавить кнопки «Отменить заказ». Только информация + один tap для открытия приложения.

  • Батарея Частые обновления жрут батарею. Оптимально — обновления раз в 30–60 секунд.

Сроки реализации

  • Базовая интеграция: 40–60 часов
  • Полноценная реализация: 80–120 часов
  • QA + фиксы: +20–30 часов

Что дальше

Для тех, кто хочет внедрить

  1. Аудит текущей инфраструктурыПроверьте: есть ли real-time обновления, настроен ли APNs, какой процент на iOS 16.1+
  2. Прототип на 1–2 недели. Не запускайте в прод сразу. Сделайте тестовую версию.
  3. Запуск на 10% пользователей. Постепенный rollout позволит поймать баги без массового негатива.
  4. Анализ метрик через месяц. Сравните retention, NPS, количество обращений в поддержку.

Для тех, кто сомневается

Начните с простого:

  • Улучшите текущие push-уведомления
  • Добавьте rich notifications
  • Оптимизируйте частоту и тайминг пушей

Когда эти базовые вещи будут работать — Live Activities станут логичным следующим шагом.

Или обратитесь к нам, мы подскажем, как все сделать!
Заполнить форму

Важно: Live Activities для кроссплатформенных приложений

Частый вопрос, который мы слышим от CTO: «У нас React Native/Flutter/другой кроссплатформенный фреймворк. Придётся всё переписывать на нативный Swift?»

Короткий ответ: нет.

Реальность кроссплатформенной разработки

Если ваше приложение построено на React Native, Flutter или другом кроссплатформенном решении, внедрение Live Activities не требует переписывания всего приложения. Нужен лишь нативный модуль — мост между вашим JS/Dart-кодом и Swift-реализацией виджета.

Как это работает:

  1. Нативный модуль на Swift. Вся логика Live Activity реализуется на Swift/SwiftUI (это требование Apple). Widget Extension — это отдельный target в Xcode, который существует параллельно с основным приложением.
  2. Bridge в кроссплатформенный код. Создаётся тонкий слой-мост, который позволяет вызывать нативные методы из JavaScript/Dart. Например, в React Native это делается через Native Modules API.
  3. Минимальная интеграция. Из вашего JS-кода нужно всего лишь вызвать один метод типа startLiveActivity(orderData) — и виджет появится на экране блокировки. Всё остальное работает нативно.

Что это означает на практике

Плюсы подхода:

  • Основная кодовая база остаётся нетронутой (React Native, Flutter и т.д.)
  • Live Activity — изолированный модуль, не влияет на остальное приложение
  • Можно добавить постепенно, без big bang release
  • Обновления виджета происходят через push-уведомления (ваш backend работает как обычно)

Типичная архитектура для React Native

├── React Native App (JavaScript)
│   └── Вызов: NativeModules.LiveActivityModule.start(orderData)
│
├── Native Bridge (Objective-C)
│   └── Связь между JS и Swift
│
└── Live Activity Widget (Swift/SwiftUI)
    ├── UI виджета
    ├── Получение push-обновлений
    └── Авторизация и сетевые запросы

В нашем случае:

Мы реализовали Live Activities для React Native приложения клиента. Основное приложение продолжило работать на React Native, а виджет был написан на чистом Swift. Интеграция заняла ~100 часов и не потребовала изменений в существующей кодовой базе — только добавление нового модуля.

Для Flutter, Xamarin, Ionic

Принцип тот же:

  • Flutter: создаёте Method Channel для связи Dart ↔ Swift
  • Xamarin: используете Bindings для вызова Swift-кода из C#
  • Ionic/Cordova: пишете Cordova plugin с нативным Swift-модулем
Во всех случаях сложность примерно одинаковая — 80-120 часов разработки для полноценной реализации.

Почему это не проблема

Apple требует, чтобы UI виджетов был написан на SwiftUI — это жёсткое требование платформы. Но это не значит, что нужно переписывать всё приложение. Виджет — это отдельная мини-программа, которая живёт своей жизнью:

  • Запускается операционной системой, а не вашим приложением
  • Имеет свой lifecycle
  • Получает данные через push-уведомления напрямую от APNs

Ваше кроссплатформенное приложение просто «инициирует» виджет и периодически обновляет его через backend. Всё остальное — магия iOS.

Практический совет

Если у вас React Native/Flutter приложение и вы думаете о Live Activities:

  1. Не бойтесь нативного кода — это изолированный модуль
  2. Найдите iOS-разработчика на 2-3 недели (можно контракт/аутсорс)
  3. Используйте наш опыт реализации (об этом подробнее в технической части)
Кроссплатформенность не помеха для современных iOS-фич. Главное — правильная архитектура.

Далее расскажем, как это реализовать, если соберетесь делать самостоятельно.

Техническая реализация Live Activities в React Native

Общая идея решения

Весь функционал Live Activity был реализован на Swift/SwiftUI и интегрирован в React Native через нативный модуль.

В JS-слой был проброшен единственный метод запуска Live Activity, который вызывается после успешного создания заказа.

Документация по нативным модулям (старая архитектура): https://reactnative.dev/docs/legacy/native-modules-ios

Структура проекта (Widget Target)

Ниже — фактическая структура каталога OrderTracker, в котором расположена вся логика Live Activity:

OrderTracker
│
├── Helpers
├── Localization
├── Models
├── Presentation
├── Resources
├── Services
│
├── Info.plist
│
├── OrderTrackerAttributes.swift
├── OrderTrackerBundle.swift
├── OrderTrackerLiveActivity.swift
│
├── OrderTrackerModule.swift
├── OrderTrackerModuleBridge.m
└── PushTokenEmitter.swift

Создание нативного Swift-модуля для React Native

React Native по умолчанию поддерживает нативные модули на Objective-C.

Чтобы подключить модуль на Swift, нужно:

  • Создать Swift-файл (OrderTrackerModule.swift)

Xcode автоматически предложит создать Bridging Header — соглашаемся.

  • В bridging header импортируется RCTBridgeModule
// sizlapp-Bridging-Header.h
#import <React/RCTBridgeModule.h>

Этот хедер позволяет Swift-классам быть доступными Objective-C слою, который уже взаимодействует с React Native.

Реализация самого нативного модуля

Ниже — основной класс, который:

  • запускает Live Activity (startLiveActivity)
  • отслеживает push token (observePushTokenUpdates)
  • предоставляет доступ к активной Activity

Экспорт модуля в React Native (Objective-C слой)

React Native вызывает только Objective-C API, поэтому создаётся bridge-файл:

// OrderTrackerModuleBridge.m
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(OrderTrackerModule, NSObject)
RCT_EXTERN_METHOD(startLiveActivity:(nonnull NSNumber *)recordId
                  :(nonnull NSString *)fulfillmentType
                  :(nullable NSDictionary *)scheduleTime
                  :(nullable NSDictionary *)eta
                  :(nullable NSString *)estimateDropOffAt
                  :(nonnull NSString *)status
                  :(nonnull NSNumber *)deliveryProgress
                  :(nonnull NSNumber *)orderId
                  :(nonnull NSNumber *)isKitchenAlerted
                  :(nonnull NSNumber *)isContactlessDelivery
                  :(nonnull NSNumber *)orderNum)
RCT_EXTERN_METHOD(stopLiveActivity:(nonnull NSNumber *)recordId)
@end

После этого модуль автоматически становится доступным в JS.

Вызов Live Activity из JS

import { NativeModules } from "react-native";
NativeModules.OrderTrackerModule.startLiveActivity(
  orderId,
  response.order.pickupInfo ? "Pickup" : "Delivery",
  { from: response.order?.etaIntervalStart, to: response.order?.etaIntervalEnd },
  { from: response.order?.etaIntervalStart, to: response.order?.etaIntervalEnd },
  response.order.dropoffArrivalTime,
  orderStatus.toLiveActivityString(response.order.statusExtended),
  0,
  orderId,
  0,
  response.order.address.contactlessDelivery ? 1 : 0,
  +response.order.number,
);

Получение push-токена для Live Activity

Live Activity может обновляться через пуш-уведомления.

Чтобы сервер мог обновлять статус заказа, нужно получить push token Live Activity и отправить его на сервер. Так как JS слой может быть не активен, если приложение закрыто, поэтому отправка токена реализована полностью в нативной части

Сетевой слой в виджете

Вся работа с API вынесена в NetworkClient.swift, AuthorizedNetworkClient.swift и AuthSessionRenewer.swift

Возможности:

  • добавление токена авторизации
  • автоматическое обновление accessToken по refreshToken
  • стандартная обработка ошибок

Пример логики с автоматическим обновлением токена: 

func request(path: String, httpMethod: HTTPMethod, httpBody: Data?, headers: [String: String]?, handler: @escaping (Result<Data?, NetworkError>) -> Void) {
    let authToken = try? getAuthToken()
    var HeadersWithAuth = headers ?? [:]
    if let authToken = authToken {
      HeadersWithAuth["Authorization"] = "Bearer \(authToken)"
    }
    api.request(path: path, httpMethod: httpMethod,httpBody: httpBody, headers: HeadersWithAuth) { result in
      switch result {
      case .success(let data):
        handler(.success(data))
      case .failure(let error):
        switch error {
        case .codeError(let statusCode):
          if statusCode == 401 {
            self.sessionRenewer.renew { result in
              switch result {
              case .success:
                self.request(path: path, httpMethod: httpMethod, httpBody: httpBody, headers: headers, handler: handler)
              case .failure:
                handler(.failure(error))
              }
            }
          } else {
            handler(.failure(error))
          }
        default:
          handler(.failure(error))
        }
      }
      
    }
  }

Хранение токенов (Keychain)

Так как виджет и приложение должны иметь доступ к токенам, для их хранения используется Keychain. Причина в том, что приложение, виджеты, Live Activity и другие расширения — это разные независимые процессы, которые запускаются iOS в разное время и в разных sandbox-окружениях. У них нет общего UserDefaults, общей файловой системы или какого-либо общего хранилища по умолчанию. Такие ограничения введены по соображениям безопасности: iOS изолирует каждый процесс, чтобы приложение не могло получить доступ к данным другого процесса, даже если оно принадлежит одному и тому же разработчику. 

JS слой через наивный модуль записывает токены → виджет использует их для авторизации.

Пример реализации класса Storage

import Foundation
import Security
final class Storage: StorageProtocol {
  let authTokenKey = "KEY_ACCESS"
  let refreshTokenKey = "KEY_REFRESH"
  
  private enum KeychainError: Error {
    case unhandledError(status: OSStatus)
    case itemNotFound
    case encodingError
  }
  
  func save<T: Codable>(key: String, value: T) throws {
    let data = try? JSONEncoder().encode(value)
    guard let data else { throw KeychainError.encodingError }
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecValueData as String: data
    ]
    SecItemDelete(query as CFDictionary)
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }
  }
  
  func load(key: String) throws -> Data? {
    let query: [String: Any] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: key,
      kSecMatchLimit as String: kSecMatchLimitOne,
      kSecReturnData as String: true
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    guard status != errSecItemNotFound else { throw KeychainError.itemNotFound }
    guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }
    return item as? Data
  }
}

OrderTrackerAttributes — основа для пуш-обновлений

Сервер может обновлять только те поля, которые объявлены внутри ContentState.

struct OrderTrackerAttributes: ActivityAttributes {
    struct ContentState: Codable, Hashable {
      var fulfillmentType: OrderFulfillmentType
      var status: OrderStatus
      var scheduleTime: ScheduleTimeInterval?
      var eta: ScheduleTimeInterval?
      var deliveryProgress: Int?
      var estimateDropOffAt: String?
      var orderId: Int
      var isKitchenAlerted: Bool?
      var isContactlessDelivery: Bool?
      var orderNum: Int
    }
    var recordId: Int
}

Визуальная часть (SwiftUI)

UI проекта расположен в папке Presentation — это слой, который отвечает исключительно за отображение. В нём находятся SwiftUI-вью, компоненты Live Activity, визуальные карточки, индикаторы прогресса и всё, что связано с тем, как пользователь видит данные.

При этом вся бизнес-логика намеренно вынесена из UI и инкапсулирована во view models, которые находятся в папке Models. Именно view models принимают решения о том, какие данные отображать, в каком формате, как преобразовывать статусы заказа, как рассчитывать оставшееся время, когда обновлять активность или показывать определённый UI-сценарий. Presentation остаётся максимально «тонким» и декларативным, а вся логика поведения и вычислений централизована в моделях — это делает архитектуру чистой, предсказуемой и хорошо масштабируемой.

Пример:

//ProgressView
struct ProgressView: View {
  var viewModel: ProgressViewModel
  
  init(viewModel: ProgressViewModel, isDarkMode: Bool) {
    self.viewModel = viewModel
    self.viewModel.isDarkMode = isDarkMode
  }
  
  var body: some View {
    if viewModel.isShowProgressView {
      GeometryReader { geometry in
        let totalWidth = geometry.size.width
        let segmentsCount = viewModel.stepsCount
        ZStack(alignment: .leading) {
          HStack(spacing: 5) {
            ForEach(0..<segmentsCount, id: \.self) { index in
              Capsule()
                .fill(viewModel.getSegmentColor(for: index))
                .frame(height: 5)
            }
          }
          
          if viewModel.isDeliveryProgress {
            Capsule()
              .fill(viewModel.completedColor)
              .frame(width: viewModel.progressFloat * totalWidth - 44, height: 5)
            
            HStack {
              Spacer()
                .frame(width: viewModel.progressFloat * totalWidth - 44)
              HStack {
                Image("rider")
                  .resizable()
                  .scaledToFit()
                  .frame(width: 40, height: 30)
              }
              .padding(.leading, 4)
              .background(viewModel.isDarkMode ? .black : .white)
            }
          }
        }
        .frame(height: 15)
        .animation(.easeInOut(duration: 0.5), value: viewModel.progressFloat)
      }
      .padding(.bottom ,8)
    }
  }
}

//ProgressViewModel.swift

struct ProgressViewModel: TimeLeftProtocol {
  let status: OrderStatus;
  let orderType: OrderFulfillmentType
  let estimateDropOffAt: String?
  let deliveryProgress: Int?
  let eta: ScheduleTimeInterval?
  var isDarkMode: Bool = false
  
  var isShowProgressView: Bool {
    switch status {
    case .Scheduled, .Cooking:
      return true
    case .InTransit:
      if deliveryProgress != nil {
        return true
      }
    default:
      return false
    }
    return false
  }
  
  var isDeliveryProgress: Bool {
    status == .InTransit && deliveryProgress != nil
  }
  
  var progressFloat: CGFloat {
    CGFloat(deliveryProgress ?? 0) / 100.0
  }
  
  var stepsCount: Int {
    switch status {
    case .Scheduled, .Cooking:
      return 3
    case .InTransit:
      return 6
    default:
      return 0
    }
  }
  
  var activeIndex: Int {
    switch status {
    case .Scheduled:
      return 0
    case .Cooking:
      if isPickup {
        if let timeLeft = timeLeft {
          return timeLeft > 0 ? 1 : 2
        } else {
          return 2
        }
      } else {
        return 1
      }
    case .InTransit:
      if timeLeft == nil {
        return 2
      }
    default:
      return 0
    }
    return 0
  }
  
  private var isPickup: Bool {
    orderType == .Pickup
  }
  
  var emptyColor: Color {
    isDarkMode ? .grayScale1000 : .grayScale400
  }
  
  var completedColor: Color {
    isDarkMode ? .orange50 : .bordo10
  }
  
  var activeColor: Color {
    isDarkMode ? .orange40 : .bordo5
  }
  
  func getSegmentColor(for index: Int) -> Color {
    if isDeliveryProgress {
      return emptyColor
    }
    if index > activeIndex {
      return emptyColor
    }
    if index == activeIndex {
      return activeColor
    }
    if index < activeIndex {
      return completedColor
    }
    return emptyColor
  }
}

Как это будет выглядеть в результате

case image
Sizl: как мы стали техническим партнером сети дарк китченов в Чикаго
История работы над приложением для быстрорастущей сети дарк китченов
Sizl: как мы стали техническим партнером сети дарк китченов в Чикаго

Итог

В результате проделанной работы был разработан полный модуль Live Activity для iOS, Реализована архитектура виджета с чётким разделением слоёв, Настроены нативные Swift-модули с bridge в React Native, Обработаны push-токены Live Activity, Реализована авторизация, обновление токенов и сетевой клиент, Построен UI на SwiftUI, Все ключевые элементы вынесены в отдельные слои (Models, Presentation, Services)

Важное уточнение: Все цифры в этой статье основаны на публичных исследованиях и отчётах индустрии.

Конкретные результаты для вашего проекта могут варьироваться в зависимости от:

  • Типа бизнеса (aggregator vs собственная сеть)
  • Географии (США vs Европа vs СНГ)
  • Зрелости продукта
  • Качества реализации

Мы рекомендуем провести собственное A/B тестирование для измерения эффекта в вашем конкретном случае.

Читайте также