This app was written using SwiftUI and I also consulted Apple's official documentation and some third-party websites. So I wrote something like the following code
This is the Swift code where the player is called and the SharePlay-related logic
import SwiftUI
import AVFoundation
import AVKit
import GroupActivities
import Combine
struct EpisodeDetail: View {
@State var episode: CommonResponse<Episode>
@State var videoPlayer: CustomVideoPlayer
@State private var groupSession: GroupSession<EpisodeActivity>?
@State private var subscriptions = Set<AnyCancellable>()
var body: some View {
VStack {
videoPlayer
.transition(.move(edge: .bottom))
.edgesIgnoringSafeArea(.all)
ScrollView {
VStack(alignment: .center) {
Button {
prepareToPlay(episode.attributes)
} label: {
Label("同播共享", systemImage: "shareplay")
}
.buttonStyle(.bordered)
.cornerRadius(20)
}
VStack(alignment: .leading, spacing: 20) {
Text(episode.attributes.title)
.font(.title2)
.fontWeight(.bold)
Text(episode.attributes.description)
.font(.body)
.foregroundColor(.gray)
}
}
.padding(12)
}
.task {
for await session in EpisodeActivity.sessions() {
configureGroupSession(session)
}
}
}
private func configureGroupSession(_ session: GroupSession<EpisodeActivity>) {
groupSession = session
videoPlayer.player.playbackCoordinator.coordinateWithSession(session)
session.$state
.sink { state in
if case .invalidated = state {
groupSession = nil
subscriptions.removeAll()
}
}
.store(in: &subscriptions)
session.$activity
.sink { activity in
print("Activity Changed: \(activity.metadata.title ?? "No title for this shitty video LOL")")
}
.store(in: &subscriptions)
session.join()
}
private func prepareToPlay(_ playerEpisodeData: Episode) {
let activity = EpisodeActivity(episode: playerEpisodeData)
Task {
switch await activity.prepareForActivation() {
case .activationDisabled:
videoPlayer.player.replaceCurrentItem(with: AVPlayerItem(url: playerEpisodeData.videoUrl))
break
case .activationPreferred:
videoPlayer.player.replaceCurrentItem(with: AVPlayerItem(url: playerEpisodeData.videoUrl))
_ = try await activity.activate()
case .cancelled:
break
@unknown default:
break
}
}
}
}
Then the following code is a custom AVPlayer
import SwiftUI
import AVFoundation
import AVKit
struct CustomVideoPlayer: UIViewControllerRepresentable {
@State var videoUrl: URL
var player: AVPlayer {
return AVPlayer(url: videoUrl)
}
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
playerController.modalPresentationStyle = .fullScreen
playerController.allowsPictureInPicturePlayback = true
playerController.canStartPictureInPictureAutomaticallyFromInline = true
playerController.player = player
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
return AVPlayerViewController()
}
}
The SharePlay prompt pops up properly and shows the current activity correctly
This is a screenshot of the SharePlay pop-up box, I couldn't insert an image, so I had to insert a link
https://i.sstatic.net/QNqBE.jpg
But when I do something with the player, like pause, or adjust the playback progress, the other iPhone doesn't sync
So what should I do?
Can't thank you enough :-)
Solved, by adding @State annotation to AVPlayer, thanks guys, this question is closed
struct CustomVideoPlayer: UIViewControllerRepresentable {
@State var player: AVPlayer? = nil
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
playerController.modalPresentationStyle = .fullScreen
playerController.allowsPictureInPicturePlayback = true
playerController.canStartPictureInPictureAutomaticallyFromInline = true
playerController.player = player
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
return AVPlayerViewController()
}
}