Разработка системы репостов и шеринга в мобильном приложении
Клиент просит кнопку «Поделиться», а мы тратим неделю на дебаг пуши и deep link. Знакомая ситуация: на Android изображение не отправляется из-за FileProvider, на iOS Universal Links не работают — ссылка открывает Safari. Например, проект соцсети для фотографов: требовался репост чужих работ в ленту и отправка ссылок в мессенджеры. На iOS Universal Links не настраивались из-за ошибки в apple-app-site-association — решение заключалось в проверке MIME-типа и правильной структуре JSON. На Android — настройка intent-filter для App Links и fallback на Chrome. Результат — полная система репостов и шеринга за 2-3 дня с нуля. Мы разберём обе задачи, покажем работающие решения и сравним подходы.
Внутренний репост: какую модель данных выбрать?
Два подхода:
- Копирование контента — новый пост с полем
reposted_from_id. Простота отображения, но при редактировании оригинала копия устаревает. - Ссылка на оригинал — пост с
repost_of_id, тело не копируется, берётся при запросе. При удалении оригинала репост показывает «Оригинал удалён». Этот подход используют Telegram и Twitter/X. Он в 3 раза сокращает дублирование данных и автоматически синхронизируется с оригиналом.
В ленте репост рендерится как embedded-карточка оригинала внутри ячейки репостера.
// iOS — ячейка поста с вложенной карточкой if let repostOf = post.repostOf { // Рисуем RepostCardView внутри PostCell let repostCard = RepostCardView(post: repostOf) contentStack.addArrangedSubview(repostCard) } Карточка — UIView с закруглёнными углами, обводкой CALayer.borderColor, аватаром и именем автора оригинала. Репост репоста отображает только один уровень вложенности.
На Compose: if (post.repostOf != null) EmbeddedPostCard(post = post.repostOf).
Как избежать дублирования репостов?
Таблица reposts (user_id, original_post_id, UNIQUE) — пользователь может репостить оригинал только один раз. Кнопка после нажатия подсвечивается, повторное нажатие отменяет репост (un-repost). Счётчик reposts_count в таблице оригинала.
Сравнение подходов к репосту
| Характеристика | Копирование контента | Ссылка на оригинал |
|---|---|---|
| Дублирование данных | Да | Нет |
| Автосинхронизация | Нет | Да |
| Работа при удалении оригинала | Пост остаётся | Показывает «Оригинал удалён» |
| Используют | Редко | Telegram, Twitter/X |
Почему внешний шеринг сложнее, чем кажется?
iOS
let items: [Any] = [postText, URL(string: deeplink)!] let vc = UIActivityViewController(activityItems: items, applicationActivities: nil) // На iPad нужен popoverPresentationController vc.popoverPresentationController?.sourceView = shareButton present(vc, animated: true) Для изображения — рендерим UIView в UIImage через UIGraphicsImageRenderer. Android
val intent = Intent(Intent.ACTION_SEND).apply { type = "text/plain" putExtra(Intent.EXTRA_TEXT, "$postText\n$deeplinkUrl") } startActivity(Intent.createChooser(intent, "Поделиться")) Для изображений — Intent.ACTION_SEND с type = "image/*" и URI через FileProvider. Прямой file:// URI не работает с Android 7+, только content://.
Flutter
await Share.shareXFiles([XFile(imagePath)], text: '$postText\n$deeplinkUrl'); Как настроить deep link для шеринга?
Внешний шеринг без deeplink теряет смысл. Ссылка должна открывать конкретный пост в приложении. На iOS — Universal Links (apple-app-site-association на сервере + NSUserActivityTypes). На Android — App Links (assetlinks.json + intent-filter). Если приложение не установлено — fallback на веб-версию. Подробнее о deep linking.
Apple App Store Review Guidelines (Section 4.2) и Google Play Console требуют корректной реализации deep link для обхода reject.
Сравнение: внутренний репост vs внешний шеринг
| Аспект | Внутренний репост | Внешний шеринг |
|---|---|---|
| Цель | Публикация в своей ленте | Отправка в другое приложение |
| Deep link | Не требуется | Обязателен |
| Счётчик | Да, инкремент/декремент | Не нужен |
| iOS | Core Data + SwiftUI | UIActivityViewController |
| Android | Room + Jetpack Compose | Intent.ACTION_SEND |
Что входит в работу
- Проектирование модели данных репоста (схема БД, API).
- Разработка embedded-карточки для ленты (iOS/Android/Flutter).
- Интеграция с системным share sheet и deep linking.
- Настройка push-уведомлений при репосте.
- Документация и передача исходного кода.
Этапы работы
- Аналитика — выбираем модель ссылки на оригинал.
- Проектирование — схема БД, REST/GraphQL API.
- Реализация — backend + клиентский UI.
- Интеграция — внешний шеринг + deep link.
- Тестирование — un-repost, удаление оригинала, edge cases.
- Деплой — публикация в App Store / Google Play.
Сравнение: свой продукт vs готовая SDK
Если использовать готовую SDK (например, Branch.io), вы получаете быстрый старт, но завязываетесь на внешнего провайдера, что увеличивает стоимость лицензии и риски блокировок. Кастомная реализация даёт полный контроль и экономию до 50% на масштабах выше 10К пользователей.
Сроки и стоимость
Внутренний репост с UI — 1-2 дня. Внешний шеринг с deeplink — ещё 1-2 дня. Полная система с обоими режимами — 2-3 дня при параллельной разработке платформ. Стоимость рассчитывается индивидуально — свяжитесь с нами для точной оценки.
Типичные ошибки при реализации
- Отсутствие обработки удаления оригинала — репост ссылается на несуществующий объект.
- Игнорирование Android
FileProvider— краш на Android 7+ при шеринге изображений. - Забытый
popoverPresentationControllerна iPad — приложение виснет.
Опыт нашей команды — 10+ лет в мобильной разработке, более 50 реализованных проектов. Гарантия качества на каждый этап. Закажите разработку системы репостов сегодня — свяжитесь для консультации!







