{"id":"c5443063-0325-40a6-a36e-a6b4b8c59672","shortId":"2f5VqR","kind":"skill","title":"Shareplay Activities","tagline":"Swift Ios Skills skill by Dpearson2699","description":"# GroupActivities / SharePlay\n\nBuild shared real-time experiences using the GroupActivities framework. SharePlay\nconnects people over FaceTime or iMessage, synchronizing media playback, app state,\nor custom data. Targets Swift 6.3 / iOS 26+.\n\n## Contents\n\n- [Setup](#setup)\n- [Defining a GroupActivity](#defining-a-groupactivity)\n- [Session Lifecycle](#session-lifecycle)\n- [Sending and Receiving Messages](#sending-and-receiving-messages)\n- [Coordinated Media Playback](#coordinated-media-playback)\n- [Starting SharePlay from Your App](#starting-shareplay-from-your-app)\n- [GroupSessionJournal: File Transfer](#groupsessionjournal-file-transfer)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Setup\n\n### Entitlements\n\nAdd the Group Activities entitlement to your app:\n\n```xml\n<key>com.apple.developer.group-session</key>\n<true/>\n```\n\n### Info.plist\n\nFor apps that start SharePlay without a FaceTime call (iOS 17+), add:\n\n```xml\n<key>NSSupportsGroupActivities</key>\n<true/>\n```\n\n### Checking Eligibility\n\n```swift\nimport GroupActivities\n\nlet observer = GroupStateObserver()\n\n// Check if a FaceTime call or iMessage group is active\nif observer.isEligibleForGroupSession {\n    showSharePlayButton()\n}\n```\n\nObserve changes reactively:\n\n```swift\nfor await isEligible in observer.$isEligibleForGroupSession.values {\n    showSharePlayButton(isEligible)\n}\n```\n\n## Defining a GroupActivity\n\nConform to `GroupActivity` and provide metadata:\n\n```swift\nimport GroupActivities\nimport CoreTransferable\n\nstruct WatchTogetherActivity: GroupActivity {\n    let movieID: String\n    let movieTitle: String\n\n    var metadata: GroupActivityMetadata {\n        var meta = GroupActivityMetadata()\n        meta.title = movieTitle\n        meta.type = .watchTogether\n        meta.fallbackURL = URL(string: \"https://example.com/movie/\\(movieID)\")\n        return meta\n    }\n}\n```\n\n### Activity Types\n\n| Type | Use Case |\n|---|---|\n| `.generic` | Default for custom activities |\n| `.watchTogether` | Video playback |\n| `.listenTogether` | Audio playback |\n| `.createTogether` | Collaborative creation (drawing, editing) |\n| `.workoutTogether` | Shared fitness sessions |\n\nThe activity struct must conform to `Codable` so the system can transfer it\nbetween devices.\n\n## Session Lifecycle\n\n### Listening for Sessions\n\nSet up a long-lived task to receive sessions when another participant starts\nthe activity:\n\n```swift\n@Observable\n@MainActor\nfinal class SharePlayManager {\n    private var session: GroupSession<WatchTogetherActivity>?\n    private var messenger: GroupSessionMessenger?\n    private var tasks = TaskGroup()\n\n    func observeSessions() {\n        Task {\n            for await session in WatchTogetherActivity.sessions() {\n                self.configureSession(session)\n            }\n        }\n    }\n\n    private func configureSession(\n        _ session: GroupSession<WatchTogetherActivity>\n    ) {\n        self.session = session\n        self.messenger = GroupSessionMessenger(session: session)\n\n        // Observe session state changes\n        Task {\n            for await state in session.$state.values {\n                handleState(state)\n            }\n        }\n\n        // Observe participant changes\n        Task {\n            for await participants in session.$activeParticipants.values {\n                handleParticipants(participants)\n            }\n        }\n\n        // Join the session\n        session.join()\n    }\n}\n```\n\n### Session States\n\n| State | Description |\n|---|---|\n| `.waiting` | Session exists but local participant has not joined |\n| `.joined` | Local participant is actively in the session |\n| `.invalidated(reason:)` | Session ended (check reason for details) |\n\n### Handling State Changes\n\n```swift\nprivate func handleState(_ state: GroupSession<WatchTogetherActivity>.State) {\n    switch state {\n    case .waiting:\n        print(\"Waiting to join\")\n    case .joined:\n        print(\"Joined session\")\n        loadActivity(session?.activity)\n    case .invalidated(let reason):\n        print(\"Session ended: \\(reason)\")\n        cleanUp()\n    @unknown default:\n        break\n    }\n}\n\nprivate func handleParticipants(_ participants: Set<Participant>) {\n    print(\"Active participants: \\(participants.count)\")\n}\n```\n\n### Leaving and Ending\n\n```swift\n// Leave the session (other participants continue)\nsession?.leave()\n\n// End the session for all participants\nsession?.end()\n```\n\n## Sending and Receiving Messages\n\nUse `GroupSessionMessenger` to sync app state between participants.\n\n### Defining Messages\n\nMessages must be `Codable`:\n\n```swift\nstruct SyncMessage: Codable {\n    let action: String\n    let timestamp: Date\n    let data: [String: String]\n}\n```\n\n### Sending\n\n```swift\nfunc sendSync(_ message: SyncMessage) async throws {\n    guard let messenger else { return }\n\n    try await messenger.send(message, to: .all)\n}\n\n// Send to specific participants\ntry await messenger.send(message, to: .only(participant))\n```\n\n### Receiving\n\n```swift\nfunc observeMessages() {\n    guard let messenger else { return }\n\n    Task {\n        for await (message, context) in messenger.messages(of: SyncMessage.self) {\n            let sender = context.source\n            handleReceivedMessage(message, from: sender)\n        }\n    }\n}\n```\n\n### Delivery Modes\n\n```swift\n// Reliable (default) -- guaranteed delivery, ordered\nlet reliableMessenger = GroupSessionMessenger(\n    session: session,\n    deliveryMode: .reliable\n)\n\n// Unreliable -- faster, no guarantees (good for frequent position updates)\nlet unreliableMessenger = GroupSessionMessenger(\n    session: session,\n    deliveryMode: .unreliable\n)\n```\n\nUse `.reliable` for state-changing actions (play/pause, selections). Use\n`.unreliable` for high-frequency ephemeral data (cursor positions, drawing strokes).\n\n## Coordinated Media Playback\n\nFor video/audio, use `AVPlaybackCoordinator` with `AVPlayer`:\n\n```swift\nimport AVFoundation\nimport GroupActivities\n\nfunc configurePlayback(\n    session: GroupSession<WatchTogetherActivity>,\n    player: AVPlayer\n) {\n    // Connect the player's coordinator to the session\n    let coordinator = player.playbackCoordinator\n    coordinator.coordinateWithSession(session)\n}\n```\n\nOnce connected, play/pause/seek actions on any participant's player are\nautomatically synchronized to all other participants. No manual message\npassing is needed for playback controls.\n\n### Handling Playback Events\n\n```swift\n// Notify participants about playback events\nlet event = GroupSessionEvent(\n    originator: session.localParticipant,\n    action: .play,\n    url: nil\n)\nsession.showNotice(event)\n```\n\n## Starting SharePlay from Your App\n\n### Using GroupActivitySharingController (UIKit)\n\n```swift\nimport GroupActivities\nimport UIKit\n\nfunc startSharePlay() async throws {\n    let activity = WatchTogetherActivity(\n        movieID: \"123\",\n        movieTitle: \"Great Movie\"\n    )\n\n    switch await activity.prepareForActivation() {\n    case .activationPreferred:\n        // Already in a FaceTime/iMessage session — activate directly\n        _ = try await activity.activate()\n\n    case .activationDisabled:\n        // SharePlay is disabled or unavailable\n        print(\"SharePlay not available\")\n\n    case .cancelled:\n        break\n\n    @unknown default:\n        break\n    }\n}\n```\n\nWhen no conversation is active (i.e., `isEligibleForGroupSession` is false),\nuse `GroupActivitySharingController` to let the user pick contacts first:\n\n```swift\nlet controller = try GroupActivitySharingController(activity)\npresent(controller, animated: true)\n```\n\nFor `ShareLink` (SwiftUI) and direct `activity.activate()` patterns, see\n[references/shareplay-patterns.md](references/shareplay-patterns.md).\n\n## GroupSessionJournal: File Transfer\n\nFor large data (images, files), use `GroupSessionJournal` instead of\n`GroupSessionMessenger` (which has a size limit):\n\n```swift\nimport GroupActivities\n\nlet journal = GroupSessionJournal(session: session)\n\n// Upload a file\nlet attachment = try await journal.add(imageData)\n\n// Observe incoming attachments\nTask {\n    for await attachments in journal.attachments {\n        for attachment in attachments {\n            let data = try await attachment.load(Data.self)\n            handleReceivedFile(data)\n        }\n    }\n}\n```\n\n## Common Mistakes\n\n### DON'T: Forget to call session.join()\n\n```swift\n// WRONG -- session is received but never joined\nfor await session in MyActivity.sessions() {\n    self.session = session\n    // Session stays in .waiting state forever\n}\n\n// CORRECT -- join after configuring\nfor await session in MyActivity.sessions() {\n    self.session = session\n    self.messenger = GroupSessionMessenger(session: session)\n    session.join()\n}\n```\n\n### DON'T: Forget to leave or end sessions\n\n```swift\n// WRONG -- session stays alive after the user navigates away\nfunc viewDidDisappear() {\n    // Nothing -- session leaks\n}\n\n// CORRECT -- leave when the view is dismissed\nfunc viewDidDisappear() {\n    session?.leave()\n    session = nil\n    messenger = nil\n}\n```\n\n### DON'T: Assume all participants have the same state\n\n```swift\n// WRONG -- broadcasting state without handling late joiners\nfunc onJoin() {\n    // New participant has no idea what the current state is\n}\n\n// CORRECT -- send full state to new participants\nfunc handleParticipants(_ participants: Set<Participant>) {\n    let newParticipants = participants.subtracting(knownParticipants)\n    for participant in newParticipants {\n        Task {\n            try await messenger?.send(currentState, to: .only(participant))\n        }\n    }\n    knownParticipants = participants\n}\n```\n\n### DON'T: Use GroupSessionMessenger for large data\n\n```swift\n// WRONG -- messenger has a per-message size limit\nlet largeImage = try Data(contentsOf: imageURL)  // 5 MB\ntry await messenger.send(largeImage, to: .all)    // May fail\n\n// CORRECT -- use GroupSessionJournal for files\nlet journal = GroupSessionJournal(session: session)\ntry await journal.add(largeImage)\n```\n\n### DON'T: Send redundant messages for media playback\n\n```swift\n// WRONG -- manually syncing play/pause when using AVPlayer\nfunc play() {\n    player.play()\n    try await messenger.send(PlayMessage(), to: .all)\n}\n\n// CORRECT -- let AVPlaybackCoordinator handle it\nplayer.playbackCoordinator.coordinateWithSession(session)\nplayer.play()  // Automatically synced to all participants\n```\n\n### DON'T: Observe sessions in a view that gets recreated\n\n```swift\n// WRONG -- each time the view appears, a new listener is created\nstruct MyView: View {\n    var body: some View {\n        Text(\"Hello\")\n            .task {\n                for await session in MyActivity.sessions() { }\n            }\n    }\n}\n\n// CORRECT -- observe sessions in a long-lived manager\n@Observable\nfinal class ActivityManager {\n    init() {\n        Task {\n            for await session in MyActivity.sessions() {\n                configureSession(session)\n            }\n        }\n    }\n}\n```\n\n## Review Checklist\n\n- [ ] Group Activities entitlement (`com.apple.developer.group-session`) added\n- [ ] `GroupActivity` struct is `Codable` with meaningful metadata\n- [ ] `sessions()` observed in a long-lived object (not a SwiftUI view body)\n- [ ] `session.join()` called after receiving and configuring the session\n- [ ] `session.leave()` called when the user navigates away or dismisses\n- [ ] `GroupSessionMessenger` created with appropriate `deliveryMode`\n- [ ] Late-joining participants receive current state on connection\n- [ ] `$state` and `$activeParticipants` publishers observed for lifecycle changes\n- [ ] `GroupSessionJournal` used for large file transfers instead of messenger\n- [ ] `AVPlaybackCoordinator` used for media sync (not manual messages)\n- [ ] `GroupStateObserver.isEligibleForGroupSession` checked before showing SharePlay UI\n- [ ] `prepareForActivation()` called before presenting sharing controller\n- [ ] Session invalidation handled with cleanup of messenger, journal, and tasks\n\n## References\n\n- Extended patterns (collaborative canvas, spatial Personas, custom templates): [references/shareplay-patterns.md](references/shareplay-patterns.md)\n- [GroupActivities framework](https://sosumi.ai/documentation/groupactivities)\n- [GroupActivity protocol](https://sosumi.ai/documentation/groupactivities/groupactivity)\n- [GroupSession](https://sosumi.ai/documentation/groupactivities/groupsession)\n- [GroupSessionMessenger](https://sosumi.ai/documentation/groupactivities/groupsessionmessenger)\n- [GroupSessionJournal](https://sosumi.ai/documentation/groupactivities/groupsessionjournal)\n- [GroupStateObserver](https://sosumi.ai/documentation/groupactivities/groupstateobserver)\n- [GroupActivitySharingController](https://sosumi.ai/documentation/groupactivities/groupactivitysharingcontroller-ybcy)\n- [Defining your app's SharePlay activities](https://sosumi.ai/documentation/groupactivities/defining-your-apps-shareplay-activities)\n- [Presenting SharePlay activities from your app's UI](https://sosumi.ai/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)\n- [Synchronizing data during a SharePlay activity](https://sosumi.ai/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)","tags":["shareplay","activities","swift","ios","skills","dpearson2699"],"capabilities":["skill","source-dpearson2699","category-swift-ios-skills"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/shareplay-activities","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under dpearson2699/swift-ios-skills","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T03:40:34.001Z","embedding":null,"createdAt":"2026-04-18T20:34:44.880Z","updatedAt":"2026-04-22T03:40:34.001Z","lastSeenAt":"2026-04-22T03:40:34.001Z","tsv":"'/documentation/groupactivities)':1205 '/documentation/groupactivities/defining-your-apps-shareplay-activities)':1239 '/documentation/groupactivities/groupactivity)':1210 '/documentation/groupactivities/groupactivitysharingcontroller-ybcy)':1230 '/documentation/groupactivities/groupsession)':1214 '/documentation/groupactivities/groupsessionjournal)':1222 '/documentation/groupactivities/groupsessionmessenger)':1218 '/documentation/groupactivities/groupstateobserver)':1226 '/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)':1250 '/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)':1259 '/movie/':201 '123':668 '17':126 '26':40 '5':963 '6.3':38 'action':453,554,605,641 'activ':2,107,147,205,214,231,265,351,388,407,665,682,708,727,1087,1236,1242,1256 'activationdis':688 'activationpref':676 'activeparticip':1145 'activeparticipants.values':327 'activity.activate':686,737 'activity.prepareforactivation':674 'activitymanag':1074 'ad':1091 'add':104,127 'aliv':855 'alreadi':677 'anim':730 'anoth':261 'app':31,76,82,111,117,438,651,1233,1245 'appear':1041 'appropri':1132 'assum':883 'async':468,662 'attach':772,779,783,787,789 'attachment.load':794 'audio':219 'automat':612,1020 'avail':697 'avfound':580 'avplay':577,588,1002 'avplaybackcoordin':575,1014,1160 'await':156,288,311,323,476,486,503,673,685,774,782,793,815,832,931,966,984,1007,1058,1078 'away':860,1126 'bodi':1051,1111 'break':400,700,703 'broadcast':892 'build':11 'call':124,142,804,1113,1121,1175 'cancel':699 'canva':1194 'case':209,375,381,389,675,687,698 'category-swift-ios-skills' 'chang':152,308,320,365,553,1150 'check':130,138,359,1169 'checklist':96,99,1085 'class':270,1073 'cleanup':397,1184 'codabl':236,447,451,1095 'collabor':222,1193 'com.apple.developer.group':113,1089 'common':90,93,798 'common-mistak':92 'configur':830,1117 'configureplayback':584 'configuresess':296,1082 'conform':166,234 'connect':22,589,603,1142 'contact':720 'content':41 'contentsof':961 'context':505 'context.source':512 'continu':419 'control':626,724,729,1179 'convers':706 'coordin':65,69,569,593,598 'coordinated-media-playback':68 'coordinator.coordinatewithsession':600 'coretransfer':176 'correct':827,866,910,973,1012,1062 'creat':1046,1130 'createtogeth':221 'creation':223 'current':907,1139 'currentst':934 'cursor':565 'custom':34,213,1197 'data':35,459,564,747,791,797,946,960,1252 'data.self':795 'date':457 'default':211,399,521,702 'defin':44,48,163,442,1231 'defining-a-groupact':47 'deliveri':517,523 'deliverymod':530,546,1133 'descript':337 'detail':362 'devic':244 'direct':683,736 'disabl':691 'dismiss':872,1128 'dpearson2699':8 'draw':224,567 'edit':225 'elig':131 'els':473,499 'end':358,395,412,422,429,849 'entitl':103,108,1088 'ephemer':563 'event':629,635,637,646 'example.com':200 'example.com/movie/':199 'exist':340 'experi':16 'extend':1191 'facetim':25,123,141 'facetime/imessage':680 'fail':972 'fals':712 'faster':533 'file':84,88,743,749,770,977,1155 'final':269,1072 'first':721 'fit':228 'forev':826 'forget':802,845 'framework':20,1202 'frequenc':562 'frequent':538 'full':912 'func':284,295,368,402,464,494,583,660,861,873,898,917,1003 'generic':210 'get':1033 'good':536 'great':670 'group':106,145,1086 'groupact':9,19,46,50,134,165,168,174,179,582,657,762,1092,1201,1206 'groupactivitymetadata':188,191 'groupactivitysharingcontrol':653,714,726,1227 'groupsess':275,298,371,586,1211 'groupsessionev':638 'groupsessionjourn':83,87,742,751,765,975,980,1151,1219 'groupsessionjournal-file-transf':86 'groupsessionmesseng':279,302,435,527,543,754,839,943,1129,1215 'groupstateobserv':137,1223 'groupstateobserver.iseligibleforgroupsession':1168 'guarante':522,535 'guard':470,496 'handl':363,627,895,1015,1182 'handleparticip':328,403,918 'handlereceivedfil':796 'handlereceivedmessag':513 'handlest':316,369 'hello':1055 'high':561 'high-frequ':560 'i.e':709 'idea':904 'imag':748 'imagedata':776 'imageurl':962 'imessag':27,144 'import':133,173,175,579,581,656,658,761 'incom':778 'info.plist':115 'init':1075 'instead':752,1157 'invalid':355,390,1181 'io':4,39,125 'iselig':157,162 'iseligibleforgroupsess':710 'iseligibleforgroupsession.values':160 'join':330,346,347,380,382,384,813,828,1136 'joiner':897 'journal':764,979,1187 'journal.add':775,985 'journal.attachments':785 'knownparticip':924,938 'larg':746,945,1154 'largeimag':958,968,986 'late':896,1135 'late-join':1134 'leak':865 'leav':410,414,421,847,867,876 'let':135,180,183,391,452,455,458,471,497,510,525,541,597,636,664,716,723,763,771,790,921,957,978,1013 'lifecycl':52,55,246,1149 'limit':759,956 'listen':247,1044 'listentogeth':218 'live':255,1069,1105 'loadact':386 'local':342,348 'long':254,1068,1104 'long-liv':253,1067,1103 'mainactor':268 'manag':1070 'manual':619,997,1166 'may':971 'mb':964 'meaning':1097 'media':29,66,70,570,993,1163 'messag':59,64,433,443,444,466,478,488,504,514,620,954,991,1167 'messeng':278,472,498,879,932,949,1159,1186 'messenger.messages':507 'messenger.send':477,487,967,1008 'meta':190,204 'meta.fallbackurl':196 'meta.title':192 'meta.type':194 'metadata':171,187,1098 'mistak':91,94,799 'mode':518 'movi':671 'movieid':181,202,667 'movietitl':184,193,669 'must':233,445 'myactivity.sessions':818,835,1061,1081 'myview':1048 'navig':859,1125 'need':623 'never':812 'new':900,915,1043 'newparticip':922,928 'nil':644,878,880 'noth':863 'notifi':631 'nssupportsgroupact':129 'object':1106 'observ':136,151,159,267,305,318,777,1027,1063,1071,1100,1147 'observemessag':495 'observer.iseligibleforgroupsession':149 'observesess':285 'onjoin':899 'order':524 'origin':639 'particip':262,319,324,329,343,349,404,408,418,427,441,484,491,608,617,632,885,901,916,919,926,937,939,1024,1137 'participants.count':409 'participants.subtracting':923 'pass':621 'pattern':738,1192 'peopl':23 'per':953 'per-messag':952 'persona':1196 'pick':719 'play':642,1004 'play/pause':555,999 'play/pause/seek':604 'playback':30,67,71,217,220,571,625,628,634,994 'player':587,591,610 'player.play':1005,1019 'player.playbackcoordinator':599 'player.playbackcoordinator.coordinatewithsession':1017 'playmessag':1009 'posit':539,566 'prepareforactiv':1174 'present':728,1177,1240 'print':377,383,393,406,694 'privat':272,276,280,294,367,401 'protocol':1207 'provid':170 'publish':1146 'reactiv':153 'real':14 'real-tim':13 'reason':356,360,392,396 'receiv':58,63,258,432,492,810,1115,1138 'recreat':1034 'redund':990 'refer':100,101,1190 'references/shareplay-patterns.md':740,741,1199,1200 'reliabl':520,531,549 'reliablemesseng':526 'return':203,474,500 'review':95,98,1084 'review-checklist':97 'see':739 'select':556 'self.configuresession':292 'self.messenger':301,838 'self.session':299,819,836 'send':56,61,430,462,481,911,933,989 'sender':511,516 'sending-and-receiving-messag':60 'sendsync':465 'session':51,54,114,229,245,249,259,274,289,293,297,300,303,304,306,314,326,332,334,339,354,357,385,387,394,416,420,424,428,528,529,544,545,585,596,601,681,766,767,808,816,820,821,833,837,840,841,850,853,864,875,877,981,982,1018,1028,1059,1064,1079,1083,1090,1099,1119,1180 'session-lifecycl':53 'session.join':333,805,842,1112 'session.leave':1120 'session.localparticipant':640 'session.shownotice':645 'set':250,405,920 'setup':42,43,102 'share':12,227,1178 'sharelink':733 'shareplay':1,10,21,73,79,120,648,689,695,1172,1235,1241,1255 'shareplaymanag':271 'show':1171 'showshareplaybutton':150,161 'size':758,955 'skill':5,6 'sosumi.ai':1204,1209,1213,1217,1221,1225,1229,1238,1249,1258 'sosumi.ai/documentation/groupactivities)':1203 'sosumi.ai/documentation/groupactivities/defining-your-apps-shareplay-activities)':1237 'sosumi.ai/documentation/groupactivities/groupactivity)':1208 'sosumi.ai/documentation/groupactivities/groupactivitysharingcontroller-ybcy)':1228 'sosumi.ai/documentation/groupactivities/groupsession)':1212 'sosumi.ai/documentation/groupactivities/groupsessionjournal)':1220 'sosumi.ai/documentation/groupactivities/groupsessionmessenger)':1216 'sosumi.ai/documentation/groupactivities/groupstateobserver)':1224 'sosumi.ai/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)':1248 'sosumi.ai/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)':1257 'source-dpearson2699' 'spatial':1195 'specif':483 'start':72,78,119,263,647 'starting-shareplay-from-your-app':77 'startshareplay':661 'state':32,307,312,317,335,336,364,370,372,374,439,552,825,889,893,908,913,1140,1143 'state-chang':551 'state.values':315 'stay':822,854 'string':182,185,198,454,460,461 'stroke':568 'struct':177,232,449,1047,1093 'swift':3,37,132,154,172,266,366,413,448,463,493,519,578,630,655,722,760,806,851,890,947,995,1035 'swiftui':734,1109 'switch':373,672 'sync':437,998,1021,1164 'synchron':28,613,1251 'syncmessag':450,467 'syncmessage.self':509 'system':239 'target':36 'task':256,282,286,309,321,501,780,929,1056,1076,1189 'taskgroup':283 'templat':1198 'text':1054 'throw':469,663 'time':15,1038 'timestamp':456 'transfer':85,89,241,744,1156 'tri':475,485,684,725,773,792,930,959,965,983,1006 'true':731 'type':206,207 'ui':1173,1247 'uikit':654,659 'unavail':693 'unknown':398,701 'unreli':532,547,558 'unreliablemesseng':542 'updat':540 'upload':768 'url':197,643 'use':17,208,434,548,557,574,652,713,750,942,974,1001,1152,1161 'user':718,858,1124 'var':186,189,273,277,281,1050 'video':216 'video/audio':573 'view':870,1031,1040,1049,1053,1110 'viewdiddisappear':862,874 'wait':338,376,378,824 'watchtogeth':195,215 'watchtogetheract':178,666 'watchtogetheractivity.sessions':291 'without':121,894 'workouttogeth':226 'wrong':807,852,891,948,996,1036 'xml':112,128","prices":[{"id":"d5bf5e29-886d-41da-86af-2dd30ef44aa0","listingId":"c5443063-0325-40a6-a36e-a6b4b8c59672","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:34:44.880Z"}],"sources":[{"listingId":"c5443063-0325-40a6-a36e-a6b4b8c59672","source":"github","sourceId":"dpearson2699/swift-ios-skills/shareplay-activities","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/shareplay-activities","isPrimary":false,"firstSeenAt":"2026-04-18T22:01:16.361Z","lastSeenAt":"2026-04-22T00:53:44.573Z"},{"listingId":"c5443063-0325-40a6-a36e-a6b4b8c59672","source":"skills_sh","sourceId":"dpearson2699/swift-ios-skills/shareplay-activities","sourceUrl":"https://skills.sh/dpearson2699/swift-ios-skills/shareplay-activities","isPrimary":true,"firstSeenAt":"2026-04-18T20:34:44.880Z","lastSeenAt":"2026-04-22T03:40:34.001Z"}],"details":{"listingId":"c5443063-0325-40a6-a36e-a6b4b8c59672","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"shareplay-activities","source":"skills_sh","category":"swift-ios-skills","skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/shareplay-activities"},"updatedAt":"2026-04-22T03:40:34.001Z"}}