PLATFORM AND VERSION
Xcode Version 16.2 beta 3 (16C5023f)
macOS 15.1.1 (24B91)
Run-time configuration: iOS 18.0
DESCRIPTION OF PROBLEM
We are currently testing the functionality of AirDrop by bringing iPhones close to each other.
I am trying to transfer the activityItemsConfiguration set in the modal screen via AirDrop.
However, if presentationStyle is fullscreen, it succeeds, but otherwise the connection is successful but no item is displayed on the screen.
STEPS TO REPRODUCE
Open my project.
Run on device
Tap Present with toggle is off.
ModalViewController presented as sheet.
Bring another iPhone closer
Play connection animation, then just display connected.
Group Activities
RSS for tagIntegrate your app into FaceTime to share its contents with groups of people.
Posts under Group Activities tag
28 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Can apple vision pro can shareplay differents apps at the same time? How about this on the iphone or ipad?
I am working on adding synchronized physical properties to EntityEquipment in TableTopKit, allowing seamless coordination during GroupActivities sessions between players.
Treating EntityEquipment's state to DieState is not a way, because it doesn't support custom collision shapes.
I have also tried adding PhysicsBodyComponent and CollisionComponent to EntityEquipment's Entity. However, the main issue is that the position of EntityEquipment itself does not synchronize with the Entity's physics body, resulting in two separate instances of one object.
struct PlayerPawn: EntityEquipment {
let id: ID
let entity: Entity
var initialState: BaseEquipmentState
init(id: ID, entity: Entity) {
self.id = id
let massProperties = PhysicsMassProperties(mass: 1.0)
let material = PhysicsMaterialResource.generate(friction: 0.5, restitution: 0.5)
let shape = ShapeResource.generateBox(size: [0.4, 0.2, 0.2])
let physicsBody = PhysicsBodyComponent(massProperties: massProperties, material: material, mode: .dynamic)
let collisionComponent = CollisionComponent(shapes: [shape])
entity.components.set(physicsBody)
entity.components.set(collisionComponent)
self.entity = entity
initialState = .init(parentID: .tableID, pose: .init(position: .init(), rotation: .zero), entity: self.entity)
}
}
I’d appreciate any guidance on the recommended approach to adding synchronized physical properties to EntityEquipment.
Hi!
I'm planning to make visionOS multiplayer app for people in same space(a room). I wanna know that if it's possible to use TabletopKit, Group Activities to create an app that becomes multiplayer(synchronize) with the people who are using it as soon as the app is opened without using SharePlay.
I have been experimenting some experiences in which I would like to use SharePlay to allow the app to be used by multiple users.
Currently I achieved sharing a volume containing a Reality Composer Pro scene inside of it, the scene contains some entities with an animation.
So far I have been able to correctly share the volume and its content, with the animation playing without problems, but once I activate SharePlay different users see different moments of the animation if no animation at all.
Is there a way to synchronize animations between all the users, no matter when someone entered the SharePlay session, aside from communicating the animation time once someone joins?
I am having trouble with initializing the SharePlay. It works but we have to leave the game (click the close button) and rejoin it, sometimes several times, for it to establish the connection.
I am also having trouble sharing images over SharePlay with GroupSessionJournal. I am not able to get it to transfer any amount of data or even get recognition on the other participants in the SharePlay that an image is being sent. We have look at all the information we can find online and are not able to establish a connection. I am not sure if I am missing a step, or if I am incorrectly sending the data through the GroupSessionJournal.
Here are the steps I took take to replicate the issue I have:
FaceTime another person with the app.
Open the app and click the SharePlay button to SharePlay it with the other person.
Establish the SharePlay and by making sure that the board states are syncronized across participants. If its not click the close button and click open app again to rejoin the SharePlay. (This is one of the bugs that I would like to fix. This is just a work around we developed to establish the SharePlay. We would like it so that when you click SharePLay and they join the session it works.)
Once the SharePlay has been established, change the image by clicking change 1 image.
Select a jpg image.
The image that represents 1 should be not set. If you dont see the image click on any of the X in the squares and it will change to the image.
The image should appear on the other participant in the SharePlay. (This does not happen and is what we have not been able to figure out how to get working.)
Here are the classes for the example project I created:
Content View
Game Model Class
Activity Manager
Main Starter Class
I want to open the popup view controller or sheet to invite user in share play. But I got an error to achieve.
struct ContentView: View {
@State private var showDialog = false
private let activityManager = GroupActivityManager()
var body: some View {
VStack {
Button(action: {
Task {
let outcome = await activityManager.startSharing()
if outcome == .needsDialog {
showDialog = true
}
}
}, label: {
Label(title: {
Text("Start SharePlay")
}, icon: {
Image(systemName: "shareplay")
})
})
.buttonStyle(.borderedProminent)
}
> .sheet(isPresented: $showDialog, content: {
GroupActivityShareSheet {
DemoAppActivity()
}
})
.padding()
}
}
Using below code to open the sheet
struct GroupActivityShareSheet<Activity: GroupActivity>: UIViewControllerRepresentable {
let preparationHandler: () async throws -> Activity
func makeUIViewController(context: Context) -> UIViewController {
GroupActivitySharingController(preparationHandler: preparationHandler)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
}
Got the below error while open the popup
> `Cannot run query `<_EXQuery: 0x6000021a2620>`
Failed to lookup mobile extension with query <_EXQuery: 0x6000021a2620> on <_GroupActivities_UIKit.PeoplePickerController: 0x600002c62480>
Failed to fetch config for hostViewController <_GroupActivities_UIKit.PeoplePickerController: 0x600002c62480>
Failed to build remote hostViewController for <_GroupActivities_UIKit.GroupActivitySharingController: 0x105f6f530>
Failed to fetch extensionViewController
Calling -viewDidAppear: directly on a view controller is not supported, and may result in out-of-order callbacks and other inconsistent behavior. Use the -beginAppearanceTransition:animated: and -endAppearanceTransition APIs on UIViewController to manually drive appearance callbacks instead. Make a symbolic breakpoint at UIViewControllerAlertForAppearanceCallbackMisuse to catch this in the debugger. View controller: <_GroupActivities_UIKit.GroupActivitySharingController: 0x105f6f53`
During testing, I encountered an issue with SharePlay. Since SharePlay necessitates multi-device testing, I intend to use my Mac and Vision Pro for testing. However, since these two devices are also my primary devices, I am reluctant to switch Apple IDs for testing purposes. Instead, I would like to test the original Apple ID. However, since both devices belong to the same Apple ID and rely on the same phone number, they are unable to FaceTime each other. I am at a loss as to how to proceed.
Hello,
I saw that, in IOS 18 + FaceTime + SharePlay, we can take the control of another device (for support an user for example).
I would like to block the use of SharePlay on my application.
My application does not include Capabilites "Group Activities", but I do not know whether this is sufficient to block the use of SharePlay.
What do you think ?
Thanks in advance for your returns.
I have an application that is meant to be a "watch together" GroupActivity using SharePlay that coordinates video playback using AVPlayerPlaybackCoordinator. In the current implementation, the activity begins before opening the AVPlayer, however when clicking the back button within the AVPlayer view, the user is prompted to "End Activity for Everyone" or "End Activity for just me". There is not an option to continue the group activity. My goal is to retain the same GroupSession, even if a user exits the AVPlayer view. Is there a way to avoid ending the session when coordinating playback using the AVPlayerPlaybackCoordinator?
private func startObservingSessions() async {
sessionInfo = .init()
// Await new sessions to watch video together.
for await session in MyActivity.sessions() {
// Clean up the old session, if it exists.
cleanUpSession(groupSession)
#if os(visionOS)
// Retrieve the new session's system coordinator object to update its configuration.
guard let systemCoordinator = await session.systemCoordinator else { continue }
// Create a new configuration that enables all participants to share the same immersive space.
var configuration = SystemCoordinator.Configuration()
// Sets up spatial persona configuration
configuration.spatialTemplatePreference = .sideBySide
configuration.supportsGroupImmersiveSpace = true
// Update the coordinator's configuration.
systemCoordinator.configuration = configuration
#endif
// Set the app's active group session before joining.
groupSession = session
// Store session for use in sending messages
sessionInfo?.session = session
let stateListener = Task {
await self.handleStateChanges(groupSession: session)
}
subscriptions.insert(.init { stateListener.cancel() })
// Observe when the local user or a remote participant changes the activity on the GroupSession
let activityListener = Task {
await self.handleActivityChanges(groupSession: session)
}
subscriptions.insert(.init { activityListener.cancel() })
// Join the session to participate in playback coordination.
session.join()
}
}
/// An implementation of `AVPlayerPlaybackCoordinatorDelegate` that determines how
/// the playback coordinator identifies local and remote media.
private class CoordinatorDelegate: NSObject, AVPlayerPlaybackCoordinatorDelegate {
var video: Video?
// Adopting this delegate method is required when playing local media,
// or any time you need a custom strategy for identifying media. Without
// implementing this method, coordinated playback won't function correctly.
func playbackCoordinator(_ coordinator: AVPlayerPlaybackCoordinator,
identifierFor playerItem: AVPlayerItem) -> String {
// Return the video id as the player item identifier.
"\(video?.id ?? -1)"
}
}
///
/// Initializes the playback coordinator for synchronizing video playback
func initPlaybackCoordinator(playbackCoordinator: AVPlayerPlaybackCoordinator) async {
self.playbackCoordinator = playbackCoordinator
if let coordinator = self.playbackCoordinator {
coordinator.delegate = coordinatorDelegate
}
if let activeSession = groupSession {
// Set the group session on the AVPlayer instances's playback coordinator
// so it can synchronize playback with other devices.
playbackCoordinator.coordinateWithSession(activeSession)
}
}
/// A coordinator that acts as the player view controller's delegate object.
final class PlayerViewControllerDelegate: NSObject, AVPlayerViewControllerDelegate {
let player: PlayerModel
init(player: PlayerModel) {
self.player = player
}
#if os(visionOS)
// The app adopts this method to reset the state of the player model when a user
// taps the back button in the visionOS player UI.
func playerViewController(_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
Task { @MainActor in
// Calling reset dismisses the full-window player.
player.reset()
}
}
#endif
}
Platform and Version
Development Environment: Xcode 16 Beta 3
visionOS 2 Beta 3
Description of Problem
I am currently working on integrating SharePlay into my visionOS 2 application. The application features a fully immersive space where users can interact. However, I have encountered an issue during testing on TestFlight.
When a user taps a button to activate SharePlay via the GroupActivity's activate() method within the immersive space, the immersive space visually disappears but is not properly dismissed. Instead, the immersive space can be made to reappear by turning the Digital Crown. Unfortunately, when it reappears, it overlaps with the built-in OS immersive space, resulting in a mixed and confusing user interface. This behavior is particularly concerning because the immersive space is not progressive and should not work with the Digital Crown being turned.
It is important to note that this problem is only present when testing the app via TestFlight. When the same build is compiled with the Release configuration and run directly through Xcode, the immersive space behaves as expected, and the issue does not occur.
Steps to Reproduce
Build a project that includes a fully immersive space and incorporates GroupActivity support.
Add a button within a window or through a RealityView attachment that triggers the GroupActivity's activate() method.
Upload the build to TestFlight.
Connect to a FaceTime call.
Open the app and enter a immersive space then press the button to activate the Group Activity.
Hi all,
Currently working on a shareplay feature where users pull data from a remote source and are able to share it in a volumetric window with others in the facetime call. However, I am running into an issue where the group activity/session seems to be throwing an error on the recipient of the journal's attachment with the description of notSupported.
As I understand it, we use GroupSessionJournal for larger pieces of data like images (like in the Drawing Together example) and in my case 3d models.
The current flow goes as follows:
User will launch the app and fetch a model from remote.
User can start a shareplay instance in which the system captures the volumetric window for users to join and see.
At this point, only the original user can see the model. The user can press a button to share this model with the other participants using
/// modelData is serialized `Data`
try await journal.add(modelData)
In the group session configuration, I already have a task listening for
for await attachments in journal.attachments {
for attachment in attachments { ... }
}
This task attempts to load data via the following code:
let modelData = try await attachment.load(Data.self) /// this is where the error is thrown: `notSupported`
I expect the attachment.load(Data.self) call to properly deliver the model data, but instead I am receiving this error.
I have also attempted to wrap the model data within an enclosing struct that has a name and data property and conform the enclosing struct to Transferable but that continued to throw the notSupported error.
Is there something I'm doing wrong or is this simply a bug in the GroupSessionJournal? Please let me know if more information is required for debugging and resolution.
Thanks!
I learned Sharplay from the WWDC video. I understand the creation of seats, but I can't learn some of the following contents well, so I hope you can help me. The content is as follows: I have set up the seats.
struct TeamSelectionTemplate: SpatialTemplate {
let elements: [any SpatialTemplateElement] = [
.seat(position: .app.offsetBy(x: 0, z: 4)),
.seat(position: .app.offsetBy(x: 1, z: 4)),
.seat(position: .app.offsetBy(x: -1, z: 4)),
.seat(position: .app.offsetBy(x: 2, z: 4)),
.seat(position: .app.offsetBy(x: -2, z: 4)),
]
}
It was mentioned in one of my previous posts: "I hope you can give me a SharePlay Button. After pressing it, it will assign all users in Facetime to a seat with elements quantified in TeamSe lectionTemplate.", and someone replied to me and asked me to try systemCoordinator.configuration.spatialTemplatePreference = .custom (TeamSelectionTemplate()), however, Xcode error Cannot find 'systemCoordinator' in scope How to solve it? Thank you!
Hi all, I had previously posted this on the Media Technologies section but didn't receive any replies so thought I would try my luck here. Apologies if re-posting questions on the forum in a short-ish time span is against the rules, but would greatly appreciate some assistance with the following situation regarding GroupSessionJournal and loading attachments.
I'm currently working on a shareplay feature that allows users to pull 3d models from icloud and view it via volumes/immersive space on the vision pro. Was able to get the sharing working with multiple windows recently so now all that's left is to be able to sync/share the model in the SharePlay session.
As I understand it, we should generally use GroupSessionMessenger for commands and light data like model positioning/syncing properties. Whereas for bigger pieces of data (images/videos/models), we should send these through GroupSessionJournal which the group session manages and syncs it for all users in the call.
I have a button to get the current user's model data and add it to the journal via
/// modelData is type `Data`
try await journal.add(modelData)
I have also set up a task to observe/receive updates to the journal's attachments in when receiving a group session.
for await groupSession in MyModelActivity.sessions() {
...
tasks.insert {
Task {
for await attachments in journal.attachments {
for attachment in attachments {
do {
let modelData = try await attachment.load(Data.self) // throws error here - `notSupported`
let modelUrl = writeModelDataToTempDirectory(modelData: modelData)
self.modelUrlToLoadForGroupSession = modelUrl
} catch let error {
print("Error: \(error)")
}
}
}
}
}
}
Not quite sure why I'm running into an error being thrown when attempting to load the attachment data on the other devices, any thoughts? The documentation for add(_:) and load(_:) say that the attachment should conform to Transferable but Data.Type should already conform to Transferable
I followed the WWDC video to learn Sharplay. I understood the first creation of seats, but I couldn't learn some of the following content very well, so I hope you can give me a list code. The contents are as follows:
I have already taken a seat.
struct TeamSelectionTemplate: SpatialTemplate {
let elements: [any SpatialTemplateElement] = [
.seat(position: .app.offsetBy(x: 0, z: 4)),
.seat(position: .app.offsetBy(x: 1, z: 4)),
.seat(position: .app.offsetBy(x: -1, z: 4)),
.seat(position: .app.offsetBy(x: 2, z: 4)),
.seat(position: .app.offsetBy(x: -2, z: 4)),
]
}
I hope you can give me a SharePlay Button. After pressing it, it will assign all users in Facetime to a seat with elements quantified in TeamSelectionTemplate. Thank you very much.
How to display the user's own persona in a view
Hello, currently working on a shareplay feature that allows users to pull 3d models from icloud and view it via volumes/immersive space on the vision pro. Was able to get the sharing working with multiple windows recently so now all that's left is to be able to sync/share the model in the SharePlay session.
As I understand it, we should generally use GroupSessionMessenger for commands and light data like model positioning/syncing properties. Whereas for bigger pieces of data (images/videos/models), we should send these through GroupSessionJournal which the group session manages and syncs it for all users in the call.
I have a button to get the current user's model data and add it to the journal via
/// modelData is type `Data`
try await journal.add(modelData)
I have also set up a task to observe/receive updates to the journal's attachments in when receiving a group session.
for await groupSession in MyModelActivity.sessions() {
...
tasks.insert {
Task {
for await attachments in journal.attachments {
for attachment in attachments {
do {
let modelData = try await attachment.load(Data.self) // throws error here - `notSupported`
let modelUrl = writeModelDataToTempDirectory(modelData: modelData)
self.modelUrlToLoadForGroupSession = modelUrl
} catch let error {
print("Error: \(error)")
}
}
}
}
}
}
Not quite sure why I'm running into an error being thrown when attempting to load the attachment data on the other devices, any thoughts? The documentation for add(_:) and load(_:) say that the attachment should conform to Transferable but Data.Type should already conform to Transferable
Hi all, been working with visionOS for a bit so far and am trying to develop a feature that allows users to shareplay and interact with a 3D model pulled from the cloud (icloud in this case, but may use a regular backend service in the future). Ideally, I would want to be able to click a custom button on a regular window that starts the group activity/shareplay with another person in the facetime call and opens the volumetric window with the model and can switch to an immersive space freely. TLDR/questions at the very end for reference point.
I was able to get this working when only working with a single window group (i.e. a volumetric window group scene and an immersive space scene). However I am running into trouble getting shareplay to correctly grab the desired scene (or any scene at all) when I have multiple window group scenes defined.
I have been referencing the following documentation in my attempts to implement this:
https://developer.apple.com/documentation/groupactivities/sceneassociationbehavior
https://developer.apple.com/documentation/groupactivities/adding-spatial-persona-support-to-an-activity
https://developer.apple.com/documentation/groupactivities/defining-your-apps-shareplay-activities
https://developer.apple.com/documentation/groupactivities/joining-and-managing-a-shared-activity
No luck so far however. Additionally, here is a quick breakdown of what I've done so far to attempt implementation:
Define group activity that contains static var activityIdentifier: String and var metadata: GroupActivityMetadata as well as conforms to GroupActivity.
Provide methods to start shareplay via a startShareplay() method that instantiates the above group activity and switch awaits on activity.prepareForActivation() to activate the activity if case .activationPreferred. I have also provided a separate group activity registration method to start shareplay via airdrop as mentioned in the Building spatial SharePlay experiences developer video (timestamped), which does expose a group activity to the share context menu/ornament but does not indicate being shared afterwards.
On app start, trigger a method to configure group sessions and provide listeners for sessions (including subscribers for active participants, session state, messages of the corresponding state type - in my case it's ModelState.self, journal attachments for potentially providing models that the other user may not have as we are getting models from cloud/backend, local participant states, etc). At the very end, call groupSession.join().
Add external activation handlers to the corresponding scenes in the scene declaration (as per this documentation on SceneAssociationBehavior using the handlesExternalEvents(matching:) scene modifier to open the scene when shareplay starts). I have also attempted using the view modifier handlesExternalEvents(preferring:allowing:) on views but also no luck. Both are being used with the corresponding activityIdentifier from the group activity and I've also tried passing a specific identifier while using the .content(_) sceneAssociationBehavior as well but no luck there either.
I have noted that in this answer regarding shareplay in visionOS, the VP engineer notes that when the app receives the session, it should setup any necessary UI then join the session, but I would expect even if the UI isn't being set up via the other person's session that the person who started shareplay should still see the sharing ornament turn green on the corresponding window which doesn't seem to occur. In fact, none of the windows that are open even get the green sharing ornament (just keeps showing "Not shared").
TLDR: Added external events handling and standard group activity stuff to multi-window app. When using shareplay, no windows are indicated as being shared.
My questions thus are:
Am I incorrect in my usage of the scene/view modifiers for handlesExternalEvents to open and associate a specific windowgroup/scene with the group activity?
In regards to opening a specific window when the group activity is activated, how do we pass any values if the window group requires it? i.e. if it's something like WindowGroup(id: ..., for: URL.self) { url in ... }
Do I still need to provide UI setup in the session listener (for await session in MyActivity.sessions())? Is this just a simple openWindow?
Past the initializing shareplay stuff above, what are the best practices for sharing 3d models that not all users in the session might have? Is it adding it as an attachment to GroupSessionJournal? Or should I pass the remote URL to everyone to download the model locally instead?
Thanks for any help and apologies for the long post. Please let me know if there's any additional information I can provide to help resolve this.
I am trying to create demo for spatial meeting using persona also refer apple videos, But not getting clear idea about it.
Any one could you please guide me step by step process or any code are appreciated for learning.
I built two parts of my app a bit disjointed:
my physics component, which controls all SceneReconstruction, HandTracking, and WorldTracking.
my spatial GroupActivities component that allows you to see personas of those that join the activity.
My problem: When trying to use any DataProvider in a spatial experience, I get the ARKit Session Event: dataProviderStateChanged, which disables all of my providers.
My question: Has anyone successfully been able to find a workaround for this? I think it would be amazing to have one user be able to be the "host" for the activity and the scene reconstruction provider still continue to run for them.