SharePlayMock is an extension API of Apple's GroupActivities API. The goal of SharePlayMock is to make testing SharePlay feature of visionOS apps easier.
Without SharePlayMock, the only way to test a visionOS app's SharePlay feature is to ask a friend who has a vision pro to test with you, because you need to be in a FaceTime call to enable SharePlay.
However, SharePlay, at the essence, is just a message channel that helps you send messages to and receive messages from others in the same SharePlay session.
SharePlayMock, when enabled, establishes message channles using WebSocket among all participants, so that FaceTime call is not required anymore for testing. When SharePlayMock is disabled, the messages go through the official real SharePlay.
With SharePlayMock, developers can test their multiplayer logics themselves by running an app instance on the simulator and another app instance on the vision pro device.
(In Xcode, you can run multiple instances at the same time on different targets)
SharePlayMock helps you test your multiplayer logics, such as syncing the sphere size in the tutorial app, or syncing card positions in a card game.
However it does not help with testing positioning of participants, for example whether they are side-by-side or surrounding or what the distance is between the volume and the participants. You need to update to visionOS 2.0 to test the positioning logic.
On a high level, you use SharePlayMock by replacing various SharePlay identifiers (e.g. GroupActivity
) with their SharePlayMock counterpart (e.g. GroupActivityMock
).
GroupActivityMock
class PlayTogetherGroupActivity: GroupActivityMock {
typealias ActivityType = PlayTogetherGroupActivity.Activity
private(set) var groupActivity: Activity
init() {
self.groupActivity = Activity()
}
struct Activity: GroupActivity {
// Define a unique activity identifier for system to reference
static let activityIdentifier = "com.spatialdevs.SharePlayTutorial.PlayTogether"
var metadata: GroupActivityMetadata {
var metadata = GroupActivityMetadata()
metadata.title = "Spatial Devs SharePlay Tutorial"
metadata.subtitle = "Let's play together!"
metadata.previewImage = UIImage(named: "birdicon")?.cgImage
metadata.type = .generic
return metadata
}
}
}
var sharePlaySession: GroupSessionMock<PlayTogetherGroupActivity>?
var sharePlayMessenger: GroupSessionMessengerMock?
@ObservedObject var groupStateObserver = GroupStateObserverMock()
func sendMessage<T: Codable>(_ message: T, to predicate: @escaping (ParticipantMock) -> Bool, inSequence: Bool = true) {
if let participants = self.groupSession?.activeParticipants.filter(predicate),
participants.isEmpty == false {
self.sendMessage(message, to: Participants.only(participants), inSequence: inSequence)
}
}
SystemCoordinatorMock
if let systemCoordinator = await session.systemCoordinator { // systemCoordinator has type SystemCoordinatorMock
var configuration = SystemCoordinator.Configuration()
configuration.supportsGroupImmersiveSpace = true
configuration.spatialTemplatePreference = .conversational
systemCoordinator.configuration = configuration
self.tasks.insert(
Task.detached { @MainActor in
for await immersionStyle in systemCoordinator.groupImmersionStyle {
if let immersionStyle {
await openImmersiveSpace(id: "ImmersiveSpace")
} else {
await dismissImmersiveSpace()
}
}
}
)
}
This instruction assumes you already have a visionOS project and used GroupActivities API and enabled SharePlay for your app/game.
For a more detailed tutorial, go here.
brew install openjdk@17
Note: This repo does NOT include the source code of this jar file.
Modify code
Enable mock on App init
struct SharePlayTutorialApp: App {
init() {
SharePlayMockManager.enable(webSocketUrl: "ws://<your_local_ip_address>:8080/endpoint") // e.g. ws://192.168.50.103:8080/endpoint
}
...
}
To find out your local IP, go to System Settings -> Wi-Fi -> "Details" button of your connected wifi -> IP address
Note: You need to manually enable/disable Mock. To disable Mock, simply comment out this line of code.
When Mock is enabled, all SharePlay messages will go through the websocket.
When Mock is disabled, all SharePlay messages will go through the official SharePlay.⚠️ Important: Comment out this line of code before publishing your app!! This line should only be added during testing.
GroupActivities | SharePlayMock |
---|---|
GroupActivity | GroupActivityMock |
GroupSession | GroupSessionMock |
GroupSessionMessenger | GroupSessionMessengerMock |
GroupStateObserver | GroupStateObserverMock |
Participant | ParticipantMock |
SystemCoordinator | SystemCoordinatorMock |
java -jar /<your_path_to_the_jar_file>/shareplay-mock-server-0.1.0.jar