expo-video 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/android/build.gradle +2 -2
- package/expo-module.config.json +1 -1
- package/ios/ExpoVideo.podspec +1 -1
- package/ios/VideoModule.swift +15 -2
- package/ios/VideoPlayer.swift +2 -2
- package/ios/VideoView.swift +57 -3
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 1.2.1 — 2024-06-27
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- [iOS] Support Apple TV. ([#29560](https://github.com/expo/expo/pull/29560) by [@douglowder](https://github.com/douglowder))
|
|
18
|
+
|
|
13
19
|
## 1.2.0 — 2024-06-20
|
|
14
20
|
|
|
15
21
|
### 🎉 New features
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'host.exp.exponent'
|
|
4
|
-
version = '1.2.
|
|
4
|
+
version = '1.2.1'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -14,7 +14,7 @@ android {
|
|
|
14
14
|
namespace "expo.modules.video"
|
|
15
15
|
defaultConfig {
|
|
16
16
|
versionCode 1
|
|
17
|
-
versionName '1.2.
|
|
17
|
+
versionName '1.2.1'
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
package/expo-module.config.json
CHANGED
package/ios/ExpoVideo.podspec
CHANGED
|
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package['license']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.homepage = package['homepage']
|
|
13
|
-
s.
|
|
13
|
+
s.platforms = { :ios => '13.4', :tvos => '13.4' }
|
|
14
14
|
s.swift_version = '5.4'
|
|
15
15
|
s.source = { git: 'https://github.com/expo/expo.git' }
|
|
16
16
|
s.static_framework = true
|
package/ios/VideoModule.swift
CHANGED
|
@@ -6,8 +6,11 @@ public final class VideoModule: Module {
|
|
|
6
6
|
public func definition() -> ModuleDefinition {
|
|
7
7
|
Name("ExpoVideo")
|
|
8
8
|
|
|
9
|
-
Function("isPictureInPictureSupported") {
|
|
10
|
-
|
|
9
|
+
Function("isPictureInPictureSupported") { () -> Bool in
|
|
10
|
+
if #available(iOS 13.4, tvOS 14.0, *) {
|
|
11
|
+
return AVPictureInPictureController.isPictureInPictureSupported()
|
|
12
|
+
}
|
|
13
|
+
return false
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
View(VideoView.self) {
|
|
@@ -22,6 +25,10 @@ public final class VideoModule: Module {
|
|
|
22
25
|
|
|
23
26
|
Prop("nativeControls") { (view, nativeControls: Bool?) in
|
|
24
27
|
view.playerViewController.showsPlaybackControls = nativeControls ?? true
|
|
28
|
+
#if os(tvOS)
|
|
29
|
+
view.playerViewController.isSkipForwardEnabled = nativeControls ?? true
|
|
30
|
+
view.playerViewController.isSkipBackwardEnabled = nativeControls ?? true
|
|
31
|
+
#endif
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
Prop("contentFit") { (view, contentFit: VideoContentFit?) in
|
|
@@ -40,11 +47,15 @@ public final class VideoModule: Module {
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
Prop("allowsFullscreen") { (view, allowsFullscreen: Bool?) in
|
|
50
|
+
#if !os(tvOS)
|
|
43
51
|
view.playerViewController.setValue(allowsFullscreen ?? true, forKey: "allowsEnteringFullScreen")
|
|
52
|
+
#endif
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
Prop("showsTimecodes") { (view, showsTimecodes: Bool?) in
|
|
56
|
+
#if !os(tvOS)
|
|
47
57
|
view.playerViewController.showsTimecodes = showsTimecodes ?? true
|
|
58
|
+
#endif
|
|
48
59
|
}
|
|
49
60
|
|
|
50
61
|
Prop("requiresLinearPlayback") { (view, requiresLinearPlayback: Bool?) in
|
|
@@ -56,7 +67,9 @@ public final class VideoModule: Module {
|
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
Prop("startsPictureInPictureAutomatically") { (view, startsPictureInPictureAutomatically: Bool?) in
|
|
70
|
+
#if !os(tvOS)
|
|
59
71
|
view.startPictureInPictureAutomatically = startsPictureInPictureAutomatically ?? false
|
|
72
|
+
#endif
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
AsyncFunction("enterFullscreen") { view in
|
package/ios/VideoPlayer.swift
CHANGED
|
@@ -16,7 +16,7 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse
|
|
|
16
16
|
if oldValue != playbackRate {
|
|
17
17
|
safeEmit(event: "playbackRateChange", arguments: playbackRate, oldValue)
|
|
18
18
|
}
|
|
19
|
-
if #available(iOS 16.0, *) {
|
|
19
|
+
if #available(iOS 16.0, tvOS 16.0, *) {
|
|
20
20
|
pointer.defaultRate = playbackRate
|
|
21
21
|
}
|
|
22
22
|
pointer.rate = playbackRate
|
|
@@ -143,7 +143,7 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
func onRateChanged(player: AVPlayer, oldRate: Float?, newRate: Float) {
|
|
146
|
-
if #available(iOS 16.0, *) {
|
|
146
|
+
if #available(iOS 16.0, tvOS 16.0, *) {
|
|
147
147
|
if player.defaultRate != playbackRate {
|
|
148
148
|
// User changed the playback speed in the native controls. Update the desiredRate variable
|
|
149
149
|
playbackRate = player.defaultRate
|
package/ios/VideoView.swift
CHANGED
|
@@ -12,8 +12,14 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
#if os(tvOS)
|
|
16
|
+
var wasPlaying: Bool = false
|
|
17
|
+
#endif
|
|
15
18
|
var isFullscreen: Bool = false
|
|
16
19
|
var isInPictureInPicture = false
|
|
20
|
+
#if os(tvOS)
|
|
21
|
+
let startPictureInPictureAutomatically = false
|
|
22
|
+
#else
|
|
17
23
|
var startPictureInPictureAutomatically = false {
|
|
18
24
|
didSet {
|
|
19
25
|
if #available(iOS 14.2, *) {
|
|
@@ -21,12 +27,15 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
}
|
|
30
|
+
#endif
|
|
24
31
|
|
|
25
32
|
var allowPictureInPicture: Bool = false {
|
|
26
33
|
didSet {
|
|
27
34
|
// PiP requires `.playback` audio session category in `.moviePlayback` mode
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
if #available(iOS 13.4, tvOS 14.0, *) {
|
|
36
|
+
VideoManager.shared.setAppropriateAudioSessionOrWarn()
|
|
37
|
+
playerViewController.allowsPictureInPicturePlayback = allowPictureInPicture
|
|
38
|
+
}
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
|
|
@@ -40,7 +49,10 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
lazy var supportsPictureInPicture: Bool = {
|
|
43
|
-
|
|
52
|
+
if #available(iOS 13.4, tvOS 14.0, *) {
|
|
53
|
+
return AVPictureInPictureController.isPictureInPictureSupported()
|
|
54
|
+
}
|
|
55
|
+
return false
|
|
44
56
|
}()
|
|
45
57
|
|
|
46
58
|
public required init(appContext: AppContext? = nil) {
|
|
@@ -53,7 +65,9 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
53
65
|
playerViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
54
66
|
playerViewController.view.backgroundColor = .clear
|
|
55
67
|
// Now playing is managed by the `NowPlayingManager`
|
|
68
|
+
#if !os(tvOS)
|
|
56
69
|
playerViewController.updatesNowPlayingInfoCenter = false
|
|
70
|
+
#endif
|
|
57
71
|
|
|
58
72
|
addSubview(playerViewController.view)
|
|
59
73
|
}
|
|
@@ -71,6 +85,16 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
71
85
|
|
|
72
86
|
if playerViewController.responds(to: selectorToForceFullScreenMode) {
|
|
73
87
|
playerViewController.perform(selectorToForceFullScreenMode, with: true, with: nil)
|
|
88
|
+
} else {
|
|
89
|
+
#if os(tvOS)
|
|
90
|
+
// For TV, save the currently playing state,
|
|
91
|
+
// remove the view controller from its superview,
|
|
92
|
+
// and present the view controller normally
|
|
93
|
+
wasPlaying = player?.isPlaying == true
|
|
94
|
+
self.playerViewController.view.removeFromSuperview()
|
|
95
|
+
self.reactViewController().present(self.playerViewController, animated: true)
|
|
96
|
+
isFullscreen = true
|
|
97
|
+
#endif
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
100
|
|
|
@@ -110,6 +134,31 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
110
134
|
|
|
111
135
|
// MARK: - AVPlayerViewControllerDelegate
|
|
112
136
|
|
|
137
|
+
#if os(tvOS)
|
|
138
|
+
// TV actually presents the playerViewController, so it implements the view controller
|
|
139
|
+
// dismissal delegate methods
|
|
140
|
+
public func playerViewControllerWillBeginDismissalTransition(_ playerViewController: AVPlayerViewController) {
|
|
141
|
+
// Start an appearance transition
|
|
142
|
+
self.playerViewController.beginAppearanceTransition(true, animated: true)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public func playerViewControllerDidEndDismissalTransition(_ playerViewController: AVPlayerViewController) {
|
|
146
|
+
self.isFullscreen = false
|
|
147
|
+
// Reset the bounds of the view controller and add it back to our view
|
|
148
|
+
self.playerViewController.view.frame = self.bounds
|
|
149
|
+
addSubview(self.playerViewController.view)
|
|
150
|
+
// End the appearance transition
|
|
151
|
+
self.playerViewController.endAppearanceTransition()
|
|
152
|
+
// Ensure playing state is preserved
|
|
153
|
+
if wasPlaying {
|
|
154
|
+
self.player?.pointer.play()
|
|
155
|
+
} else {
|
|
156
|
+
self.player?.pointer.pause()
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
#endif
|
|
160
|
+
|
|
161
|
+
#if !os(tvOS)
|
|
113
162
|
public func playerViewController(
|
|
114
163
|
_ playerViewController: AVPlayerViewController,
|
|
115
164
|
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator
|
|
@@ -134,6 +183,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
134
183
|
}
|
|
135
184
|
}
|
|
136
185
|
}
|
|
186
|
+
#endif
|
|
137
187
|
|
|
138
188
|
public func playerViewControllerDidStartPictureInPicture(_ playerViewController: AVPlayerViewController) {
|
|
139
189
|
isInPictureInPicture = true
|
|
@@ -146,6 +196,10 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate {
|
|
|
146
196
|
}
|
|
147
197
|
|
|
148
198
|
public override func didMoveToWindow() {
|
|
199
|
+
// TV is doing a normal view controller present, so we should not execute
|
|
200
|
+
// this code
|
|
201
|
+
#if !os(tvOS)
|
|
149
202
|
playerViewController.beginAppearanceTransition(self.window != nil, animated: true)
|
|
203
|
+
#endif
|
|
150
204
|
}
|
|
151
205
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-video",
|
|
3
3
|
"title": "Expo Video",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"description": "A cross-platform, performant video component for React Native and Expo with Web support",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"expo": "*"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "09b2d97bbc0f70f7c811ff9b6c9ad8808c5ad84b"
|
|
40
40
|
}
|