{"id":"c5443063-0325-40a6-a36e-a6b4b8c59672","shortId":"2f5VqR","kind":"skill","title":"shareplay-activities","tagline":"Build shared real-time experiences using GroupActivities and SharePlay. Use when implementing shared media playback, collaborative app features, synchronized game state, or any FaceTime/iMessage-integrated group activity on iOS, macOS, tvOS, or visionOS.","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","accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills"],"capabilities":["skill","source-dpearson2699","skill-shareplay-activities","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"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":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 599 github stars · SKILL.md body (13,189 chars)","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-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:53:44.135Z","embedding":null,"createdAt":"2026-04-18T20:34:44.880Z","updatedAt":"2026-05-18T18:53:44.135Z","lastSeenAt":"2026-05-18T18:53:44.135Z","tsv":"'/documentation/groupactivities)':1233 '/documentation/groupactivities/defining-your-apps-shareplay-activities)':1267 '/documentation/groupactivities/groupactivity)':1238 '/documentation/groupactivities/groupactivitysharingcontroller-ybcy)':1258 '/documentation/groupactivities/groupsession)':1242 '/documentation/groupactivities/groupsessionjournal)':1250 '/documentation/groupactivities/groupsessionmessenger)':1246 '/documentation/groupactivities/groupstateobserver)':1254 '/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)':1278 '/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)':1287 '/movie/':229 '123':696 '17':154 '26':68 '5':991 '6.3':66 'action':481,582,633,669 'activ':3,30,135,175,233,242,259,293,379,416,435,693,710,736,755,1115,1264,1270,1284 'activationdis':716 'activationpref':704 'activeparticip':1173 'activeparticipants.values':355 'activity.activate':714,765 'activity.prepareforactivation':702 'activitymanag':1102 'ad':1119 'add':132,155 'aliv':883 'alreadi':705 'anim':758 'anoth':289 'app':21,59,104,110,139,145,466,679,1261,1273 'appear':1069 'appropri':1160 'assum':911 'async':496,690 'attach':800,807,811,815,817 'attachment.load':822 'audio':247 'automat':640,1048 'avail':725 'avfound':608 'avplay':605,616,1030 'avplaybackcoordin':603,1042,1188 'await':184,316,339,351,504,514,531,701,713,802,810,821,843,860,959,994,1012,1035,1086,1106 'away':888,1154 'bodi':1079,1139 'break':428,728,731 'broadcast':920 'build':4,39 'call':152,170,832,1141,1149,1203 'cancel':727 'canva':1222 'case':237,403,409,417,703,715,726 'chang':180,336,348,393,581,1178 'check':158,166,387,1197 'checklist':124,127,1113 'class':298,1101 'cleanup':425,1212 'codabl':264,475,479,1123 'collabor':20,250,1221 'com.apple.developer.group':141,1117 'common':118,121,826 'common-mistak':120 'configur':858,1145 'configureplayback':612 'configuresess':324,1110 'conform':194,262 'connect':50,617,631,1170 'contact':748 'content':69 'contentsof':989 'context':533 'context.source':540 'continu':447 'control':654,752,757,1207 'convers':734 'coordin':93,97,597,621,626 'coordinated-media-playback':96 'coordinator.coordinatewithsession':628 'coretransfer':204 'correct':855,894,938,1001,1040,1090 'creat':1074,1158 'createtogeth':249 'creation':251 'current':935,1167 'currentst':962 'cursor':593 'custom':62,241,1225 'data':63,487,592,775,819,825,974,988,1280 'data.self':823 'date':485 'default':239,427,549,730 'defin':72,76,191,470,1259 'defining-a-groupact':75 'deliveri':545,551 'deliverymod':558,574,1161 'descript':365 'detail':390 'devic':272 'direct':711,764 'disabl':719 'dismiss':900,1156 'draw':252,595 'edit':253 'elig':159 'els':501,527 'end':386,423,440,450,457,877 'entitl':131,136,1116 'ephemer':591 'event':657,663,665,674 'example.com':228 'example.com/movie/':227 'exist':368 'experi':9,44 'extend':1219 'facetim':53,151,169 'facetime/imessage':708 'facetime/imessage-integrated':28 'fail':1000 'fals':740 'faster':561 'featur':22 'file':112,116,771,777,798,1005,1183 'final':297,1100 'first':749 'fit':256 'forev':854 'forget':830,873 'framework':48,1230 'frequenc':590 'frequent':566 'full':940 'func':312,323,396,430,492,522,611,688,889,901,926,945,1031 'game':24 'generic':238 'get':1061 'good':564 'great':698 'group':29,134,173,1114 'groupact':11,37,47,74,78,162,193,196,202,207,610,685,790,1120,1229,1234 'groupactivitymetadata':216,219 'groupactivitysharingcontrol':681,742,754,1255 'groupsess':303,326,399,614,1239 'groupsessionev':666 'groupsessionjourn':111,115,770,779,793,1003,1008,1179,1247 'groupsessionjournal-file-transf':114 'groupsessionmesseng':307,330,463,555,571,782,867,971,1157,1243 'groupstateobserv':165,1251 'groupstateobserver.iseligibleforgroupsession':1196 'guarante':550,563 'guard':498,524 'handl':391,655,923,1043,1210 'handleparticip':356,431,946 'handlereceivedfil':824 'handlereceivedmessag':541 'handlest':344,397 'hello':1083 'high':589 'high-frequ':588 'i.e':737 'idea':932 'imag':776 'imagedata':804 'imageurl':990 'imessag':55,172 'implement':16 'import':161,201,203,607,609,684,686,789 'incom':806 'info.plist':143 'init':1103 'instead':780,1185 'invalid':383,418,1209 'io':32,67,153 'iselig':185,190 'iseligibleforgroupsess':738 'iseligibleforgroupsession.values':188 'join':358,374,375,408,410,412,841,856,1164 'joiner':925 'journal':792,1007,1215 'journal.add':803,1013 'journal.attachments':813 'knownparticip':952,966 'larg':774,973,1182 'largeimag':986,996,1014 'late':924,1163 'late-join':1162 'leak':893 'leav':438,442,449,875,895,904 'let':163,208,211,419,480,483,486,499,525,538,553,569,625,664,692,744,751,791,799,818,949,985,1006,1041 'lifecycl':80,83,274,1177 'limit':787,984 'listen':275,1072 'listentogeth':246 'live':283,1097,1133 'loadact':414 'local':370,376 'long':282,1096,1132 'long-liv':281,1095,1131 'maco':33 'mainactor':296 'manag':1098 'manual':647,1025,1194 'may':999 'mb':992 'meaning':1125 'media':18,57,94,98,598,1021,1191 'messag':87,92,461,471,472,494,506,516,532,542,648,982,1019,1195 'messeng':306,500,526,907,960,977,1187,1214 'messenger.messages':535 'messenger.send':505,515,995,1036 'meta':218,232 'meta.fallbackurl':224 'meta.title':220 'meta.type':222 'metadata':199,215,1126 'mistak':119,122,827 'mode':546 'movi':699 'movieid':209,230,695 'movietitl':212,221,697 'must':261,473 'myactivity.sessions':846,863,1089,1109 'myview':1076 'navig':887,1153 'need':651 'never':840 'new':928,943,1071 'newparticip':950,956 'nil':672,906,908 'noth':891 'notifi':659 'nssupportsgroupact':157 'object':1134 'observ':164,179,187,295,333,346,805,1055,1091,1099,1128,1175 'observemessag':523 'observer.iseligibleforgroupsession':177 'observesess':313 'onjoin':927 'order':552 'origin':667 'particip':290,347,352,357,371,377,432,436,446,455,469,512,519,636,645,660,913,929,944,947,954,965,967,1052,1165 'participants.count':437 'participants.subtracting':951 'pass':649 'pattern':766,1220 'peopl':51 'per':981 'per-messag':980 'persona':1224 'pick':747 'play':670,1032 'play/pause':583,1027 'play/pause/seek':632 'playback':19,58,95,99,245,248,599,653,656,662,1022 'player':615,619,638 'player.play':1033,1047 'player.playbackcoordinator':627 'player.playbackcoordinator.coordinatewithsession':1045 'playmessag':1037 'posit':567,594 'prepareforactiv':1202 'present':756,1205,1268 'print':405,411,421,434,722 'privat':300,304,308,322,395,429 'protocol':1235 'provid':198 'publish':1174 'reactiv':181 'real':7,42 'real-tim':6,41 'reason':384,388,420,424 'receiv':86,91,286,460,520,838,1143,1166 'recreat':1062 'redund':1018 'refer':128,129,1218 'references/shareplay-patterns.md':768,769,1227,1228 'reliabl':548,559,577 'reliablemesseng':554 'return':231,502,528 'review':123,126,1112 'review-checklist':125 'see':767 'select':584 'self.configuresession':320 'self.messenger':329,866 'self.session':327,847,864 'send':84,89,458,490,509,939,961,1017 'sender':539,544 'sending-and-receiving-messag':88 'sendsync':493 'session':79,82,142,257,273,277,287,302,317,321,325,328,331,332,334,342,354,360,362,367,382,385,413,415,422,444,448,452,456,556,557,572,573,613,624,629,709,794,795,836,844,848,849,861,865,868,869,878,881,892,903,905,1009,1010,1046,1056,1087,1092,1107,1111,1118,1127,1147,1208 'session-lifecycl':81 'session.join':361,833,870,1140 'session.leave':1148 'session.localparticipant':668 'session.shownotice':673 'set':278,433,948 'setup':70,71,130 'share':5,17,40,255,1206 'sharelink':761 'shareplay':2,13,38,49,101,107,148,676,717,723,1200,1263,1269,1283 'shareplay-act':1 'shareplaymanag':299 'show':1199 'showshareplaybutton':178,189 'size':786,983 'skill' 'skill-shareplay-activities' 'sosumi.ai':1232,1237,1241,1245,1249,1253,1257,1266,1277,1286 'sosumi.ai/documentation/groupactivities)':1231 'sosumi.ai/documentation/groupactivities/defining-your-apps-shareplay-activities)':1265 'sosumi.ai/documentation/groupactivities/groupactivity)':1236 'sosumi.ai/documentation/groupactivities/groupactivitysharingcontroller-ybcy)':1256 'sosumi.ai/documentation/groupactivities/groupsession)':1240 'sosumi.ai/documentation/groupactivities/groupsessionjournal)':1248 'sosumi.ai/documentation/groupactivities/groupsessionmessenger)':1244 'sosumi.ai/documentation/groupactivities/groupstateobserver)':1252 'sosumi.ai/documentation/groupactivities/promoting-shareplay-activities-from-your-apps-ui)':1276 'sosumi.ai/documentation/groupactivities/synchronizing-data-during-a-shareplay-activity)':1285 'source-dpearson2699' 'spatial':1223 'specif':511 'start':100,106,147,291,675 'starting-shareplay-from-your-app':105 'startshareplay':689 'state':25,60,335,340,345,363,364,392,398,400,402,467,580,853,917,921,936,941,1168,1171 'state-chang':579 'state.values':343 'stay':850,882 'string':210,213,226,482,488,489 'stroke':596 'struct':205,260,477,1075,1121 'swift':65,160,182,200,294,394,441,476,491,521,547,606,658,683,750,788,834,879,918,975,1023,1063 'swiftui':762,1137 'switch':401,700 'sync':465,1026,1049,1192 'synchron':23,56,641,1279 'syncmessag':478,495 'syncmessage.self':537 'system':267 'target':64 'task':284,310,314,337,349,529,808,957,1084,1104,1217 'taskgroup':311 'templat':1226 'text':1082 'throw':497,691 'time':8,43,1066 'timestamp':484 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'transfer':113,117,269,772,1184 'tri':503,513,712,753,801,820,958,987,993,1011,1034 'true':759 'tvos':34 'type':234,235 'ui':1201,1275 'uikit':682,687 'unavail':721 'unknown':426,729 'unreli':560,575,586 'unreliablemesseng':570 'updat':568 'upload':796 'url':225,671 'use':10,14,45,236,462,576,585,602,680,741,778,970,1002,1029,1180,1189 'user':746,886,1152 'var':214,217,301,305,309,1078 'video':244 'video/audio':601 'view':898,1059,1068,1077,1081,1138 'viewdiddisappear':890,902 'visiono':36 'wait':366,404,406,852 'watchtogeth':223,243 'watchtogetheract':206,694 'watchtogetheractivity.sessions':319 'without':149,922 'workouttogeth':254 'wrong':835,880,919,976,1024,1064 'xml':140,156","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-05-18T18:53:44.135Z"},{"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-05-07T22:40:34.453Z"}],"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","github":{"repo":"dpearson2699/swift-ios-skills","stars":599,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-26T21:04:17Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"7b5c73770800a37f3175a735ba9348d15664f0fc","skill_md_path":"skills/shareplay-activities/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/shareplay-activities"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"shareplay-activities","description":"Build shared real-time experiences using GroupActivities and SharePlay. Use when implementing shared media playback, collaborative app features, synchronized game state, or any FaceTime/iMessage-integrated group activity on iOS, macOS, tvOS, or visionOS."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/shareplay-activities"},"updatedAt":"2026-05-18T18:53:44.135Z"}}