ionostafi.com

2022-11-04

Watch Crunchyroll Anime Together with Apple SharePlay

At WWDC21, Apple presented a new technology for doing more things together with your friends and family — SharePlay. It allows us to watch, draw, or even play games together. This piece of technology can be used in various ways. I’ll go through the implementation of SharePlay for watching your favorite anime.

Before Digging In, Understand Basic Terms

GroupActivities — the framework that makes it possible to implement the SharePlay feature.

GroupActivities session — an ongoing connection between one or more devices communicating using a session on the server.

GroupActivities works on top of a FaceTime call. The devices are synched only when the participants are on an active call. And a GroupActivity session can be started only when the device is on a FaceTime call.

The diagram (IMG 1) below shows an overview of how a SharePlay session is created and how participants join the session:

Overview of the SharePlay session creation

The SharePlay Experience Inside Crunchyroll

The app needs to know when the participant is on a FaceTime call, so it can indicate that SharePlay is possible by displaying the SharePlay icon under the series title and the “Start SharePlay” button on the video page. Anyone can start a SharePlay session from the following places (IMG 2):

  • The video page;
  • The more [⠇] menu of any card;
  • The long press (3D Touch) of any card;
  • The ShareSheet of an episode.

An example of three entry points to SharePlay

If another participant has a membership, they will be directed to that episode after joining the session.

While switching to a different episode, a popup asks for episode switching confirmation, and after confirming, it switches to the new episode.

When someone leaves the video page, a popup asks for leaving confirmation; the current participant can choose to end the session for everyone or only for themselves (IMG 3).

Switching to another episode (left) and closing the video player (right)

Determine eligibility to start SharePlay

It’s possible using GroupStateObserver class.

Determine_eligibility_to_start_SharePlay

We keep only one instance of GroupStateObserver in the app for the whole lifetime of the app. We will subscribe to the GroupStateObserver’s idEligibleForGroupSession stream and on each change, we will show/hide the SharePlay icon and SharePlay button.

Starting a new session

The participant who starts a session does not join automatically, we should join programmatically. See in the overview diagram (IMG 1) that the participant who starts the session will later receive a session from the server, the same as other participants.

Follow these steps to create a new session:

Start_a_session

Calling prepareForActivation will tell the system to ask either to play this item on the device or SharePlay the episode.

SharePlay_1st_button_will_start_the_session_Start_Only_for_Me_2nd_button_will_play_video_only_on_the_user_device

Later, if the user chooses to start automatically SharePlay, then calling this function will choose SharePlay automatically. Based on the prepareForActivation result, it’s our responsibility to start the SharePlay session by calling activate a function that will start the session itself.

This is it for creating a session. The upper steps will not automatically join the session! The activate function creates a session on the “server”, and it sends that session to all FaceTime participants. This is important to understand and not to be confused later why the user who started SharePlay is receiving the “join event” too.

Joining the session

Next, if we want to join the session, either created by the current participant or someone else, we have to write the same thing in both cases:

join_a_session

The upper code is simplified, and the actual code is more complex than that: verify if a deep link is in progress, wait for the episode data to load, and other things.

Synchronizing video players for all participants

Now, we will cover the most important aspect— control playback for all participants. For this to happen, it’s not enough to join a session. The session is just a channel to send data; until this point, we just set up the connection between participants. From now on, we will be able to transmit information between participants.

To synchronize the player, we use the new playback coordination API. We need to link the session to the player. This is achieved using the following:

Synchronize_events

After connecting the player with the session, the player automatically sends all events, like play, pause, or seek, to all participants.

Replacing the episode

There are two different scenarios to replace an episode in the Crunchyroll app:

  • when the participant is manually switching an episode and is asked for confirmation before replacing;
  • when all participants automatically switch to the next episode, and there is no confirmation.

If all participants are in the middle of watching an episode, and one participant wants to switch to another, execute the same code as when starting a new session. GroupActivity API understands that a session was already created, and this time will switch only the content, and not create another session. It will ask the participant to confirm the content replacement with the following screen:

Replace_an_episode

If all participants finish watching an episode, the Crunchyroll app can advance to the next episode automatically (if at least one participant has this option turned on). In this case, we need to switch the video programmatically without asking for confirmation. To do that, set the currentActivity property on the session object directly.

Replace_the_current_episode

Interruptions

There might be situations when the video should be paused only for one participant and later be advanced to the same time as other participants. A phone call or other system events will automatically pause synchronization for the current user. But in case there are some events triggered by the Crunchyroll app that should pause the video, Apple provides an API for this case. For example, the Crunchyroll app will show an alert when a participant who is watching a video switches connections between wi-fi and cellular.

Pausing video in such case is called “interruption”, and to interrupt the video, we use the following method call:

Interrupt_video_for_current_participant

Notice that beginSuspension is returning a suspension object which we save for later use.

Later, we have to resume playback and move the participant’s playback to the same time as others. To achieve that, use the following:

Resume_the_interruption_for_the_current_participant

ShareSheet

With iOS 15.4 — Apple added the possibility to start SharePlay from the ShareSheet. Apple added some new options to make it easier to share your loved episode with friends over SharePlay. One of the new features of the ShareSheet is prominent activity — a new section on top of the ShareSheet that displays only one activity, for example, SharePlay, to the user. With this new feature, we can start a FaceTime call and SharePlay with only one button.

Prominent_activity_in_iOS_15

By default, the SharePlay from the ShareSheet doesn’t know how to start a session or which item to send through the session, and it will simply start a FaceTime call and create an empty session without any activity item (episode).

To have better support for SharePlay with the ShareSheet, we need a few lines of code. Do you remember how we created a new activity when we needed to start a new session? Well, here we create an activity the same way, but to make it available for the ShareSheet, we need to assign it to the list of activities from the UIActivityViewController, and here’s how:

Setup_ShareSheet_with_a_SharePlaySessionActivity_together_with_an_URL

The important thing here is that we need to create a NSItemProvider, the standard way to send data across processes in iOS. New to iOS 15.4, NSItemProvider has a method to register a GroupActivity.

End notes

Adding SharePlay into the application isn’t the most straightforward task, but it’s not that complicated. Follow the WWDC sessions and the sample code from Apple, which will teach you the basics you need.

Some features were not documented well enough in the beginning, for example, requestForegroundPresentation method. Initially, the documentation was empty.

When iOS 15.4 came out, it wasn’t straightforward to add support for SharePlay together with a URL in the ShareSheet. We had to figure it out ourselves because there was no tutorial or sample code for making this.


tags: ios designpatterns