Разработка
Реализация Shared With You в SwiftUI
Случалось ли вам терять ссылку, песню или другую рекомендацию, которую друг прислал вам в чате? Такое случается с каждым из нас, и, к счастью, именно эту проблему призвана решить функция Shared with You («Поделились с вами») на iOS.
Случалось ли вам терять ссылку, песню или другую рекомендацию, которую друг прислал вам в чате? Такое случается с каждым из нас, и, к счастью, именно эту проблему призвана решить функция Shared with You («Поделились с вами») на iOS.
Что такое «Поделились с вами»?
Функция Shared with You позволяет пользователям легко находить контент, которым с ними поделились в Сообщениях, непосредственно в соответствующих приложениях. Например, здесь мы можем увидеть все ссылки на веб-сайты, которыми поделились со мной мои собеседники, и я могу продолжить разговор, не выходя из Safari:
Эта функция была введена в iOS 16, но лишь немногие приложения используют ее в своих интересах. Как вы скоро увидите, ее очень легко реализовать, поэтому если в вашем приложении есть контент, которым можно поделиться, я настоятельно рекомендую добавить эту функцию в ваше приложение.
Начинаем работу
Прежде чем мы перейдем к коду, вам следует знать несколько вещей:
- Для того чтобы ваше приложение поддерживало функцию Shared With You, оно должно поддерживать Universal Links, поскольку именно так Apple проверяет, что ссылки, которыми вы делитесь в Messages, принадлежат вашему приложению.
- Поскольку Shared with You опирается на Messages, вам нужно будет протестировать свое приложение на физическом устройстве.
- Фреймворк извлекает контент только из сохраненных контактов, поэтому при тестировании убедитесь, что человек, отправивший вам ссылку, сохранен в ваших контактах.
Единственный шаг по настройке — добавить возможность Shared with You в наш проект Xcode:
Обзор реализации
В большинстве реализаций Shared with You вы увидите два компонента — полку и представление атрибуции (кто этим поделился).
Полка
На полке в одном удобном месте хранится весь контент, которым вы поделились в «Сообщениях». Система автоматически упорядочивает эту полку, начиная с Siri Suggestions, основанных на недавних взаимодействиях с контентом, затем идут прикрепленные сообщения и, наконец, все остальное сортируется в хронологическом порядке.
Представление атрибуции
Представление атрибуции позволяет увидеть, кто поделился с вами контентом, показывает его имя, фотографию профиля и предоставляет ссылку на исходное сообщение в беседе.
Насколько я знаю, наличие выделенной полки в вашей реализации не является обязательным, но Apple рекомендует ее использовать. Если вы предпочитаете, вы можете просто использовать представление атрибуции напрямую, чтобы указать общий контент в вашем приложении.
Давайте добавим поддержку Shared with You в приложение.
На первой вкладке отображается список записей блога этого сайта, а на второй вкладке мы создадим полку для отображения записей, которыми с нами поделились наши контакты.
Получение ссылок
Чтобы получить список ссылок, которыми поделился пользователь, мы создадим экземпляр SWHighlightCenter
, основного класса, отвечающего за получение и управление общими ссылками.
import SharedWithYou
// Provides the application with a priority-ordered list of
// universal links which have been shared with the current user.
private let highlightCenter = SWHighlightCenter()
Далее мы воспользуемся SWHighlightCenter
, чтобы получить список highlights
. Они представляют собой список элементов, которыми с вами поделились, поэтому каждый раз, когда вы видите highlight
, думайте, что это просто ссылка, которой поделился пользователь.
Мы сохраним highlights
в свойстве @Published
, которое впоследствии будем использовать для наполнения нашей полки:
xxxxxxxxxx
import SharedWithYou
final class SharedWithYouService: NSObject, ObservableObject {
// Each highlight represents a shared link
@Published var highlights: [SWHighlight] = []
// Provides the application with a priority-ordered list of universal links
// which have been shared with the current user.
private let highlightCenter = SWHighlightCenter()
override init() {
super.init()
highlights = highlightCenter.highlights
}
}
Затем мы реализуем функцию HighlightCenterDelegate
, чтобы получать уведомления о каждом изменении в highlights
:
xxxxxxxxxx
import SharedWithYou
final class SharedWithYouService: NSObject, ObservableObject, SWHighlightCenterDelegate {
// Each highlight represents a shared link
@Published var highlights: [SWHighlight] = []
// Provides the application with a priority-ordered list of universal links
// which have been shared with the current user.
private let highlightsCenter = SWHighlightCenter()
override init() {
super.init()
highlights = highlightsCenter.highlights
highlightsCenter.delegate = self
}
func highlightCenterHighlightsDidChange(_ highlightCenter: SWHighlightCenter) {
highlights = highlightsCenter.highlights
}
}
Не забудьте реализовать этот делегат, иначе вы не получите никакого контента.
Вот и все! Это весь код, который нам нужен для получения списка контента, которым поделились с пользователем. Теперь у нас есть обновляемый в реальном времени список ссылок, который мы можем использовать для наполнения нашей полки.
Осталось только отобразить представление атрибуции.
Можете пропустить следующий раздел и продолжить знакомство с деталями реализации ниже.
Более детальный взгляд на SWHighlight
SWHighlight
содержит такие сведения, как кто поделился содержимым и ссылку на исходное сообщение, но единственные публичные свойства, к которым мы имеем доступ — это поля identifier
и URL
:
xxxxxxxxxx
SW_EXTERN @interface SWHighlight : NSObject <NSSecureCoding, NSCopying>
/*!
@abstract The unique identifier for this highlight
*/
@property (copy, readonly, nonatomic) id <NSSecureCoding, NSCopying> identifier;
/*!
@abstract The surfaced content URL
*/
@property (copy, readonly, nonatomic) NSURL *URL;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
@end
К счастью, все, что нам действительно нужно, — это URL
. Мы можем использовать информацию, содержащуюся в URL, чтобы определить, какие данные нам нужно получить из бэкенда.
Например, в случае с подкастом URL-адрес, скорее всего, содержит идентификатор подкаста, который мы можем отправить в конечную точку бэкенда, чтобы получить остальные данные, необходимые для отображения подкаста на нашей полке, такие как миниатюра, автор, продолжительность и т.д.
Отображение ссылок
Фреймворк Shared with You включает класс SWAttributionView
для отображения представлений атрибуции, но он не имеет поддержки SwiftUI из коробки. Мы можем легко добавить поддержку, создав собственный UIViewRepresentable
, передав в highlight
свяданное представление атрибуции.
Для начала мы создадим экземпляр SWAttributionView
и начнем его настраивать.
DisplayContext
информирует систему о том, в каком окружении мы показываем представление атрибуции — мы хотим использовать .summary
, если мы представляем представление в списке верхнего уровня, и .detail
, если мы показываем представление на какой-либо странице с подробностями. Знание контекста, в котором пользователь сталкивается с представлением атрибуции, помогает системе ранжировать это выделение на полке.
xxxxxxxxxx
struct SWAttributionViewRepresentable: UIViewRepresentable {
let highlight: SWHighlight
func makeUIView(context: Context) -> UIView {
let attributionView = SWAttributionView()
attributionView.horizontalAlignment = .leading
// Change `.summary` to `.detail` if presenting in
// a detail view.
attributionView.displayContext = .summary
attributionView.highlight = highlight
attributionView.backgroundStyle = .default
attributionView.menuTitleForHideAction = "Remove Article"
return attributionView
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Этот вид действительно заблокирован, и единственное, что Apple позволяет нам настраивать здесь, это некоторые базовые свойства макета — ни цветов, ни шрифтов, ни даже высоты.
Мы рассмотрим некоторые возможности настройки в ближайшее время, а пока давайте закончим реализацию нашей полки.
Создание полки
Мы воспользуемся SharedWithYouService
, который мы создали ранее, и SWHighlightCenter
, чтобы получить список highlights
(помните, что highlight — это просто способ, которым фреймворк представляет ссылку, которой поделились).
Мы интегрируем их все и создадим представление атрибуции и BlogPostRow
для каждого, что даст нам следующее:
xxxxxxxxxx
struct SharedWithYouShelf: View {
@StateObject var sharedWithYouService = SharedWithYouService()
var body: some View {
NavigationView {
List(sharedWithYouService.highlights, id: \.url.absoluteString) { highlight in
VStack {
SWAttributionViewRepresentable(highlight: highlight)
BlogPostRow(blogPost: getBlogPostFrom(highlight))
}
}
}
}
}
В документации Apple говорится, что ваша полка должна предлагать предварительный просмотр содержимого, включая миниатюру, заголовок, подзаголовок и представление атрибуции, которое, как вы видите, мы реализовали здесь для каждого highlight
.
Apple хочет, чтобы отображение этих представлений атрибуции было безопасным и не раскрывало никакой информации о получателях или разговорах, поэтому Apple создает эти представления от вашего имени «вне процесса». Это означает, что представление создается отдельным процессом вне основного потока, поэтому вы можете добавить эту функцию в свое приложение, не беспокоясь о том, что она действительно повлияет на производительность вашего приложения.
Вот и все, что нам нужно для создания полки и показа общего контента в наших приложениях.
Настройка меню
В нашей текущей реализации при длительном нажатии на SWAttributionView
мы увидим дополнительное меню с некоторыми действиями по умолчанию:
- Reply приведет к появлению соответствующего сообщения в беседе, что позволит нам ответить, не выходя из приложения.
- Remove Article удалит эту ссылку из Shared with You.
Несмотря на то, что функция Shared with You в целом очень закрыта, Apple предоставляет некоторые возможности настройки, которые позволяют нам добавить еще несколько опций в это меню.
Чтобы сделать это, нам нужно обновить нашу реализацию UIViewRepresentable
, описанную ранее.
Сначала мы добавим ряд rfcnjvys[ UIActions
, которые мы хотим добавить в это меню. Они будут зависеть от конкретного случая использования, но в случае со списком записей блога мы, возможно, захотим отобразить действия для сохранения в списке чтения, перевода статьи и добавления ее в закладки.
xxxxxxxxxx
func makeUIView(context: Context) -> UIView {
let attributionView = SWAttributionView()
...
// Action to save the article to a reading list
let saveToReadingListAction = UIAction(
title: "Save to Reading List",
image: UIImage(systemName: "book")
) { _ in ... }
// Action to translate the article
let translateAction = UIAction(
title: "Translate",
image: UIImage(systemName: "globe")
) { _ in ... }
// Action to bookmark the article
let bookmarkAction = UIAction(
title: "Bookmark",
image: UIImage(systemName: "bookmark")
) { _ in ... }
Затем мы можем просто определить наше новое меню, указать заголовок и дочерние элементы для показа и назначить его свойству supplementalMenu
представлению атрибуции.
xxxxxxxxxx
func makeUIView(context: Context) -> UIView {
let attributionView = SWAttributionView()
...
// Action to save the article to a reading list
let saveToReadingListAction = UIAction(
title: "Save to Reading List",
image: UIImage(systemName: "book")
) { _ in ... }
// Action to translate the article
let translateAction = UIAction(
title: "Translate",
image: UIImage(systemName: "globe")
) { _ in ... }
// Action to bookmark the article
let bookmarkAction = UIAction(
title: "Bookmark",
image: UIImage(systemName: "bookmark")
) { _ in ... }
attributionView.supplementalMenu = UIMenu(
title: "Extras",
children: [
saveToReadingListAction,
translateAction,
bookmarkAction
]
)
return attributionView
}
Теперь у нас есть эти кастомные опции, появляющиеся каждый раз, когда мы взаимодействуем с SWAttributionView
.
Тестирование
Напоследок я хочу обратить внимание на некоторые моменты, которые облегчат вам тестирование.
- В приложении «Настройки» перейдите в раздел «Сообщения» и убедитесь, что функция Shared with You включена на всех устройствах. Это должно быть так по умолчанию, но не лишним будет перепроверить.
- Apple позволяет пользователям отключать автоматический шаринг как глобально, так и для отдельных приложений, поэтому убедитесь, что функция «Поделились с вами» включена и для вашего приложения.
- Сохранение контента в Messages — отличный способ проверить, как работает эта функция, поскольку она автоматически предоставляет разрешение Shared with You. Если вы закрепили сообщение от известного контакта и не видите результатов в
HighlightCenter
, проблема, скорее всего, кроется в вашей реализации.
Если вы пропустили, вот запись моего выступления на SwiftCraft в начале этого года:
-
Видео и подкасты для разработчиков4 недели назад
Как устроена мобильная архитектура. Интервью с тех. лидером юнита «Mobile Architecture» из AvitoTech
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2025.10
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.11
-
Видео и подкасты для разработчиков2 недели назад
Javascript для бэкенда – отличная идея: Node.js, NPM, Typescript