How to display the user's own persona in a view
Group Activities
RSS for tagIntegrate your app into FaceTime to share its contents with groups of people.
Posts under Group Activities tag
30 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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.
I am trying to present a GroupActivitySharingController using SwiftUI. I am using a NSViewControllerRepresentable:
@State var event : Event
func makeNSViewController(context: NSViewControllerRepresentableContext<MeetingGroupActivitySharingRepresentableView>) -> GroupActivitySharingController {
return try! GroupActivitySharingController(MeetingGroupActivity(event: event))
}
func updateNSViewController(_ nsViewController: GroupActivitySharingController , context: NSViewControllerRepresentableContext<MeetingGroupActivitySharingRepresentableView>) {
print("Updating VC")
}
}
I present it as following :
.sheet(isPresented: $showGroupActivitySharingView) {
MeetingGroupActivitySharingRepresentableView(event: observedEvent.event)
}
It works fine on iOS, however on MacOS, I cannot dismiss the view. I see the following error:
dismissViewController:: Error: maybe this view controller was not presented?
(
0 CoreFoundation 0x000000019d75accc __exceptionPreprocess + 176
1 libobjc.A.dylib 0x000000019d242788 objc_exception_throw + 60
2 Foundation 0x000000019e8cbc6c -[NSCalendarDate initWithCoder:] + 0
3 AppKit 0x00000001a145a77c -[NSViewController dismissViewController:] + 224
4 _GroupActivities_AppKit 0x0000000232d65cf0 $s23_GroupActivities_AppKit0A25ActivitySharingControllerC011dismissViewG06resultyAA0aeF6ResultO_tFyyYaYbScMYccfU_TY0_ + 444
5 _GroupActivities_AppKit 0x0000000232d67b65 $s23_GroupActivities_AppKit0A25ActivitySharingControllerC011dismissViewG06resultyAA0aeF6ResultO_tFyyYaYbScMYccfU_TATQ0_ + 1
6 _GroupActivities_AppKit 0x0000000232d68bd9 $sIeghH_ytIeghHr_TRTQ0_ + 1
7 _GroupActivities_AppKit 0x0000000232d68bdd $sIeghH_ytIeghHr_TRTATQ0_ + 1
8 _GroupActivities_AppKit 0x0000000232d66931 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRyt_Tg5TQ0_ + 1
9 _GroupActivities_AppKit 0x0000000232d68ba5 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRyt_Tg5TATQ0_ + 1
10 libswift_Concurrency.dylib 0x0000000263cfb0f9 _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1
)
Any idea what is going on?
Hi!
I'm working on trying to integrate SharePlay with Personas into a visionOS app. I'm still at the beginning stages and I'm following some of the 1st party documentation + videos from WWDC.
https://developer.apple.com/videos/play/wwdc2023/10087
https://developer.apple.com/documentation/groupactivities/adding-spatial-persona-support-to-an-activity#Update-the-immersion-level-automatically-for-a-Full-Space
I'm using:
Xcode 15.3 (15E204a)
visionOS 1.1 (21O209)
In both the examples linked above, they reference
systemCoordinator.groupImmersionStyle
However this doesn't seem to exist.
Also, it's not clear how to open/transition to the various spaces if groupImmersionStyle did exist and I could detect full, mixed, progressive spaces.
Am I missing something?
Was this removed or did I configure something incorrectly?
Is there a full sample for SharePlay + visionOS somewhere that I might have missed?
Thanks for any help!
I'm developing a motion tracking app that takes requires a real-time view of an iPhone camera to capture the person's body. The motion is mapped to a virtual body. Currently this appears overlayed on the person that the iPhone sees.
However, I want to transmit this real time 3D virtual body to a different Apple device, as an AR app, that the other user can place in their environment.
Any suggestions on how I can get this 3d model to be viewable by another user (and maintain live updating based on motion tracking)?
I am adding Group Activities integration with a MacCatalyst app. I have added the Group Activities entitlement in Xcode. I also checked the entitlements with :
codesign --display --entitlements :-
I can see the entitlement :
<key>com.apple.developer.group-session</key><true/><key>
The feature work fine on iPadOS but when I run it on MacOS, the GroupActivitySharingController is not loading properly. I get the following error messages:
Cannot run query EXQuery: extension point com.apple.groupactivities platforms: 6 with error: (null)
Failed to lookup extension with query EXQuery: extension point com.apple.groupactivities platforms: 6 on <_GroupActivities_UIKit.PeoplePickerController: 0x600005020980>
Failed to fetch config for hostViewController <_GroupActivities_UIKit.PeoplePickerController: 0x600005020980>
Failed to build remote hostViewController for <_GroupActivities_UIKit.GroupActivitySharingController: 0x1417f1250>
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: 0x1417f1250>
I got a similar error on iPadOS when the entitlement was not added. Now that I have the entitlement, the error appears only on MacOS.
Does MacOS/MacCatalyst use a different entitlements file? What could be cuasing this?
I'd like to implement a fully immersive space that's experienced by multiple Vision Pro users simultaneously via SharePlay. To do this, the multiple Vision Pro users will join a SharePlay-enabled visionOS window that has a button to enter a fully immersive space, which is also SharePlay-enabled. I tried following the WWDC sessions and docs, but they don't provide enough detail about integrating SharePlay into an existing window and immersive space. How can I adjust my SharePlay code so it makes my visionOS window + fully immersive space SharePlay-able? Please see existing code below for a SharePlay visionOS widow, thank you.
P.S. WWDC ref. https://developer.apple.com/videos/play/wwdc2023/10087
import SwiftUI
import RealityKit
import RealityKitContent
import GroupActivities
import LinkPresentation
struct SharePlayWorld: View, GroupActivity {
@Environment(ViewModel.self) private var model
@Environment(\.openWindow) private var openWindow
@Environment(\.dismissWindow) private var dismissWindow
@Environment(\.openImmersiveSpace) private var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace
var body: some View {
@Bindable var model = model
Toggle(
model.isShowingPracticeSpace ? "Leave Space" : "Enter Space",
isOn: $model.isShowingPracticeSpace
)
.onChange(of: model.isShowingPracticeSpace) { _, isShowing in
Task {
if isShowing
{
await openImmersiveSpace(id: "SharePlayWorld")
}
else
{
await dismissImmersiveSpace()
}
}
}
.toggleStyle(.button)
}
// SHAREPLAY CODE
private func startSharePlaySession() async {
for await session in SharePlayWorld.sessions() {
guard let systemCoordinator = await session.systemCoordinator else { continue }
let isLocalParticipantSpatial = systemCoordinator.localParticipantState.isSpatial
Task.detached {
for await localParticipantState in systemCoordinator.localParticipantStates {
if localParticipantState.isSpatial {
// Start syncing scroll position
} else {
// Stop syncing scroll position
}
}
}
var configuration = SystemCoordinator.Configuration()
configuration.spatialTemplatePreference = .sideBySide
systemCoordinator.configuration = configuration
session.join()
}
// Create the activity
let activity = SharePlayWorld()
// Register the activity on the item provider
let itemProvider = NSItemProvider()
itemProvider.registerGroupActivity(activity)
// Create the activity items configuration
let configuration = await UIActivityItemsConfiguration(itemProviders: [itemProvider])
// Provide the metadata for the group activity
configuration.metadataProvider = { key in
guard key == .linkPresentationMetadata else { return nil }
let metadata = LPLinkMetadata()
metadata.title = "Explore Together"
metadata.imageProvider = NSItemProvider(object: UIImage(named: "explore-activity")!)
return metadata
}
self.activityItemsConfiguration = configuration
}
}
#Preview {
SharePlayWorld()
.environment(ViewModel())
}