@picsa/capacitor-video-player 7.1.0
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/CapacitorVideoPlayer.podspec +17 -0
- package/LICENSE +21 -0
- package/android/build.gradle +71 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/CapacitorVideoPlayer.java +71 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/CapacitorVideoPlayerPlugin.java +1256 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/FullscreenExoPlayerFragment.java +1595 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/Notifications/MyRunnable.java +21 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/Notifications/NotificationCenter.java +61 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/PickerVideo/AdapterVideoList.java +47 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/PickerVideo/ModelVideo.java +49 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/PickerVideo/PickerVideoFragment.java +119 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/PickerVideo/VideoRecyclerViewHolder.java +65 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/Utilities/FilesUtils.java +101 -0
- package/android/src/main/java/com/jeep/plugin/capacitor/capacitorvideoplayer/Utilities/FragmentUtils.java +32 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/android/src/main/res/drawable/bg_round_rect_white_50.xml +9 -0
- package/android/src/main/res/drawable/bg_rounded_rectangle_white_corner_rounded.xml +10 -0
- package/android/src/main/res/drawable/exo_close_btn.xml +12 -0
- package/android/src/main/res/drawable/gradient_transparent_middle.xml +12 -0
- package/android/src/main/res/drawable/ic_arrow_left.xml +5 -0
- package/android/src/main/res/drawable/ic_baseline_lq.xml +7 -0
- package/android/src/main/res/drawable/ic_exo_icon_fastforward.xml +35 -0
- package/android/src/main/res/drawable/ic_exo_icon_pause.xml +26 -0
- package/android/src/main/res/drawable/ic_exo_icon_play.xml +36 -0
- package/android/src/main/res/drawable/ic_exo_icon_rewind.xml +35 -0
- package/android/src/main/res/drawable/ic_expand.xml +5 -0
- package/android/src/main/res/drawable/ic_fit.xml +5 -0
- package/android/src/main/res/drawable/ic_image_background.xml +12 -0
- package/android/src/main/res/drawable/ic_img_16_9_background.xml +10 -0
- package/android/src/main/res/drawable/ic_img_9_16_background.xml +10 -0
- package/android/src/main/res/drawable/ic_outline_lock.xml +5 -0
- package/android/src/main/res/drawable/ic_outline_lock_open.xml +5 -0
- package/android/src/main/res/drawable/ic_pip_white.xml +5 -0
- package/android/src/main/res/drawable/ic_views.xml +18 -0
- package/android/src/main/res/drawable/ic_zoom.xml +5 -0
- package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
- package/android/src/main/res/layout/exo_playback_control_view.xml +289 -0
- package/android/src/main/res/layout/exoplayer_layout_youtube.xml +361 -0
- package/android/src/main/res/layout/fragment_fs_exoplayer.xml +50 -0
- package/android/src/main/res/layout/fragment_picker_video.xml +21 -0
- package/android/src/main/res/layout/row_video.xml +76 -0
- package/android/src/main/res/values/colors.xml +14 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/styles.xml +3 -0
- package/dist/docs.json +831 -0
- package/dist/esm/definitions.d.ts +322 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web-utils/video-types.d.ts +16 -0
- package/dist/esm/web-utils/video-types.js +15 -0
- package/dist/esm/web-utils/video-types.js.map +1 -0
- package/dist/esm/web-utils/videoplayer.d.ts +30 -0
- package/dist/esm/web-utils/videoplayer.js +315 -0
- package/dist/esm/web-utils/videoplayer.js.map +1 -0
- package/dist/esm/web.d.ts +123 -0
- package/dist/esm/web.js +675 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +1017 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +1019 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/CapacitorVideoPlayer.swift +64 -0
- package/ios/Plugin/CapacitorVideoPlayerPlugin.h +10 -0
- package/ios/Plugin/CapacitorVideoPlayerPlugin.m +22 -0
- package/ios/Plugin/CapacitorVideoPlayerPlugin.swift +632 -0
- package/ios/Plugin/Extensions/CapacitorVideoPlayerPlugin.AVPlayerViewController.swift +59 -0
- package/ios/Plugin/Extensions/CapacitorVideoPlayerPlugin.File.swift +126 -0
- package/ios/Plugin/Extensions/CapacitorVideoPlayerPlugin.Fullscreen.swift +94 -0
- package/ios/Plugin/Extensions/CapacitorVideoPlayerPlugin.Notifications.swift +140 -0
- package/ios/Plugin/Extensions/CapacitorVideoPlayerPlugin.Observers.swift +180 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/VideoPicker/VideoHelper.swift +127 -0
- package/ios/Plugin/VideoPicker/VideoPickerViewController.swift +144 -0
- package/ios/Plugin/VideoPlayer/Extensions/AVURLAsset.swift +18 -0
- package/ios/Plugin/VideoPlayer/Extensions/AllOrientationAVPlayerController.swift +12 -0
- package/ios/Plugin/VideoPlayer/Extensions/CMTime.swift +23 -0
- package/ios/Plugin/VideoPlayer/Extensions/LandscapeAVPlayerController.swift +12 -0
- package/ios/Plugin/VideoPlayer/Extensions/Notification.Name.swift +18 -0
- package/ios/Plugin/VideoPlayer/Extensions/PortraitAVPlayerController.swift +12 -0
- package/ios/Plugin/VideoPlayer/Extensions/View.swift +54 -0
- package/ios/Plugin/VideoPlayer/FullScreenVideoPlayerView.swift +601 -0
- package/ios/Plugin/VideoPlayer/Models/Video.swift +28 -0
- package/ios/Plugin/VideoPlayer/Models/VideoModel.swift +42 -0
- package/package.json +92 -0
- package/readme.md +190 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CapacitorVideoPlayerPlugin.swift
|
|
3
|
+
// Plugin
|
|
4
|
+
//
|
|
5
|
+
// Created by Quéau Jean Pierre on 30/05/2021.
|
|
6
|
+
// Copyright © 2021 Max Lynch. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
extension CapacitorVideoPlayerPlugin {
|
|
12
|
+
|
|
13
|
+
// MARK: - getURLFromFilePath
|
|
14
|
+
|
|
15
|
+
// swiftlint:disable cyclomatic_complexity
|
|
16
|
+
// swiftlint:disable function_body_length
|
|
17
|
+
func getURLFromFilePath(filePath: String) -> [String: Any] {
|
|
18
|
+
var dict: [String: Any] = [:]
|
|
19
|
+
dict["message"] = ""
|
|
20
|
+
let docPath: String =
|
|
21
|
+
NSSearchPathForDirectoriesInDomains(.documentDirectory,
|
|
22
|
+
.userDomainMask,
|
|
23
|
+
true)[0]
|
|
24
|
+
let appPath: String =
|
|
25
|
+
NSSearchPathForDirectoriesInDomains(.applicationDirectory,
|
|
26
|
+
.userDomainMask,
|
|
27
|
+
true)[0]
|
|
28
|
+
|
|
29
|
+
if String(filePath.prefix(4)) == "http" {
|
|
30
|
+
if let url = URL(string: filePath) {
|
|
31
|
+
dict["url"] = url
|
|
32
|
+
return dict
|
|
33
|
+
} else {
|
|
34
|
+
dict["message"] = "cannot convert filePath in URL"
|
|
35
|
+
return dict
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if String(filePath.prefix(13)) == "public/assets" {
|
|
39
|
+
if let appFolder = Bundle.main.resourceURL {
|
|
40
|
+
dict["url"] = appFolder.appendingPathComponent(filePath)
|
|
41
|
+
return dict
|
|
42
|
+
} else {
|
|
43
|
+
dict["message"] = "did not find appFolder"
|
|
44
|
+
return dict
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if String(filePath.prefix(11)) == "application" {
|
|
48
|
+
let path: String = String(filePath.dropFirst(12))
|
|
49
|
+
let vPath: String = docPath.appendingFormat("/\(path)")
|
|
50
|
+
if !isFileExists(filePath: vPath) {
|
|
51
|
+
print("*** file does not exist at path \n \(vPath) \n***")
|
|
52
|
+
let info: [String: Any] = ["dismiss": true]
|
|
53
|
+
self.notifyListeners("jeepCapVideoPlayerExit", data: info, retainUntilConsumed: true)
|
|
54
|
+
dict["message"] = "file does not exist"
|
|
55
|
+
return dict
|
|
56
|
+
}
|
|
57
|
+
dict["url"] = URL(fileURLWithPath: vPath)
|
|
58
|
+
return dict
|
|
59
|
+
}
|
|
60
|
+
if String(filePath.prefix(29)) == "file:///var/mobile/Containers" {
|
|
61
|
+
|
|
62
|
+
// get the appId from the appPath
|
|
63
|
+
let pathArray = appPath.components(separatedBy: "Application")
|
|
64
|
+
let appId: String = pathArray[1].replacingOccurrences(of: "/", with: "")
|
|
65
|
+
// remove the appId from the given filePath and replace it with the current appId
|
|
66
|
+
let fPathArray = filePath.components(separatedBy: "Application")
|
|
67
|
+
if let uPath = URL(string: pathArray[0]) {
|
|
68
|
+
let fPath = (uPath.appendingPathComponent("Application")
|
|
69
|
+
.appendingPathComponent(appId)
|
|
70
|
+
.appendingPathComponent(
|
|
71
|
+
String(fPathArray[1].dropFirst(38)))
|
|
72
|
+
).absoluteString
|
|
73
|
+
if !isFileExists(filePath: fPath) {
|
|
74
|
+
print("*** file does not exist at path \n \(fPath) \n***")
|
|
75
|
+
let info: [String: Any] = ["dismiss": true]
|
|
76
|
+
self.notifyListeners("jeepCapVideoPlayerExit", data: info,
|
|
77
|
+
retainUntilConsumed: true)
|
|
78
|
+
dict["message"] = "file does not exist"
|
|
79
|
+
return dict
|
|
80
|
+
}
|
|
81
|
+
dict["url"] = URL(fileURLWithPath: fPath)
|
|
82
|
+
} else {
|
|
83
|
+
dict["message"] = "file path not correct"
|
|
84
|
+
}
|
|
85
|
+
return dict
|
|
86
|
+
}
|
|
87
|
+
if String(filePath.prefix(19)) == "file:///var/mobile/" {
|
|
88
|
+
let pathArray = appPath.components(separatedBy: "Containers")
|
|
89
|
+
let fPathArray = filePath.components(separatedBy: "mobile/")
|
|
90
|
+
|
|
91
|
+
if let uPath = URL(string: pathArray[0]) {
|
|
92
|
+
let fPath = (uPath.appendingPathComponent(
|
|
93
|
+
String(fPathArray[1]))
|
|
94
|
+
).absoluteString
|
|
95
|
+
if !isFileExists(filePath: fPath) {
|
|
96
|
+
print("*** file does not exist at path \n \(fPath) \n***")
|
|
97
|
+
let info: [String: Any] = ["dismiss": true]
|
|
98
|
+
self.notifyListeners("jeepCapVideoPlayerExit", data: info,
|
|
99
|
+
retainUntilConsumed: true)
|
|
100
|
+
dict["message"] = "file does not exist"
|
|
101
|
+
return dict
|
|
102
|
+
}
|
|
103
|
+
dict["url"] = URL(fileURLWithPath: fPath)
|
|
104
|
+
} else {
|
|
105
|
+
dict["message"] = "file path not correct"
|
|
106
|
+
}
|
|
107
|
+
return dict
|
|
108
|
+
}
|
|
109
|
+
dict["message"] = "filePath not implemented"
|
|
110
|
+
return dict
|
|
111
|
+
}
|
|
112
|
+
// swiftlint:enable function_body_length
|
|
113
|
+
// swiftlint:enable cyclomatic_complexity
|
|
114
|
+
|
|
115
|
+
// MARK: - isFileExists
|
|
116
|
+
|
|
117
|
+
func isFileExists(filePath: String) -> Bool {
|
|
118
|
+
var ret: Bool = false
|
|
119
|
+
let fileManager = FileManager.default
|
|
120
|
+
if fileManager.fileExists(atPath: filePath) {
|
|
121
|
+
ret = true
|
|
122
|
+
}
|
|
123
|
+
return ret
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CapacitorVideoPlayerPlugin.Fullscreen.swift
|
|
3
|
+
// Plugin
|
|
4
|
+
//
|
|
5
|
+
// Created by Quéau Jean Pierre on 30/05/2021.
|
|
6
|
+
// Copyright © 2021 Max Lynch. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import Capacitor
|
|
11
|
+
import AVKit
|
|
12
|
+
|
|
13
|
+
extension CapacitorVideoPlayerPlugin {
|
|
14
|
+
|
|
15
|
+
// MARK: - createVideoPlayerFullScreenView
|
|
16
|
+
|
|
17
|
+
// swiftlint:disable function_body_length
|
|
18
|
+
// swiftlint:disable function_parameter_count
|
|
19
|
+
func createVideoPlayerFullscreenView(
|
|
20
|
+
call: CAPPluginCall, videoUrl: URL, rate: Float,
|
|
21
|
+
exitOnEnd: Bool, loopOnEnd: Bool, pipEnabled: Bool,
|
|
22
|
+
backModeEnabled: Bool, showControls: Bool,
|
|
23
|
+
displayMode: String,
|
|
24
|
+
subTitleUrl: URL?, subTitleLanguage: String?,
|
|
25
|
+
subTitleOptions: [String: Any]?,
|
|
26
|
+
headers: [String: String]?, title: String?,
|
|
27
|
+
smallTitle: String?, artwork: String?) {
|
|
28
|
+
DispatchQueue.main.async { [weak self] in
|
|
29
|
+
let playerId: String = self?.fsPlayerId ?? "fullscreen"
|
|
30
|
+
if let fullscreenView = self?.implementation
|
|
31
|
+
.createFullscreenPlayer(
|
|
32
|
+
playerId: playerId, videoUrl: videoUrl,
|
|
33
|
+
rate: rate, exitOnEnd: exitOnEnd, loopOnEnd: loopOnEnd,
|
|
34
|
+
pipEnabled: pipEnabled,
|
|
35
|
+
showControls: showControls,
|
|
36
|
+
displayMode: displayMode,
|
|
37
|
+
subTitleUrl: subTitleUrl,
|
|
38
|
+
language: subTitleLanguage, headers: headers, options: subTitleOptions,
|
|
39
|
+
title: title, smallTitle: smallTitle, artwork: artwork) {
|
|
40
|
+
self?.videoPlayerFullScreenView = fullscreenView
|
|
41
|
+
if backModeEnabled {
|
|
42
|
+
self?.bgPlayer = self?.videoPlayerFullScreenView?
|
|
43
|
+
.videoPlayer.player
|
|
44
|
+
}
|
|
45
|
+
guard let videoPlayer: AVPlayerViewController =
|
|
46
|
+
self?.videoPlayerFullScreenView?.videoPlayer else {
|
|
47
|
+
let error: String = "No videoPlayer available"
|
|
48
|
+
print(error)
|
|
49
|
+
call.resolve([ "result": false, "method": "createVideoPlayerFullScreenView",
|
|
50
|
+
"message": error])
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
videoPlayer.delegate = self
|
|
54
|
+
self?.bridge?.viewController?.present(
|
|
55
|
+
videoPlayer, animated: true, completion: {
|
|
56
|
+
if backModeEnabled {
|
|
57
|
+
// add audio session
|
|
58
|
+
self?.audioSession = AVAudioSession.sharedInstance()
|
|
59
|
+
// Set the audio session category, mode, and options.
|
|
60
|
+
do {
|
|
61
|
+
try self?.audioSession?
|
|
62
|
+
.setCategory(.playback,
|
|
63
|
+
mode: .moviePlayback,
|
|
64
|
+
options: [])
|
|
65
|
+
try self?.audioSession?.setActive(true)
|
|
66
|
+
call.resolve([
|
|
67
|
+
"result": true,
|
|
68
|
+
"method": "createVideoPlayerFullScreenView",
|
|
69
|
+
"value": true])
|
|
70
|
+
return
|
|
71
|
+
} catch let error as NSError {
|
|
72
|
+
print("Unable to activate audio session: \(error.localizedDescription)")
|
|
73
|
+
call.resolve([
|
|
74
|
+
"result": false,
|
|
75
|
+
"method": "createVideoPlayerFullScreenView",
|
|
76
|
+
"message": error.localizedDescription])
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
call.resolve([
|
|
81
|
+
"result": true,
|
|
82
|
+
"method": "createVideoPlayerFullScreenView",
|
|
83
|
+
"value": true])
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// swiftlint:enable function_parameter_count
|
|
92
|
+
// swiftlint:enable function_body_length
|
|
93
|
+
|
|
94
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CapacitorVideoPlayerPlugin.Notifications.swift
|
|
3
|
+
// Plugin
|
|
4
|
+
//
|
|
5
|
+
// Created by Quéau Jean Pierre on 30/05/2021.
|
|
6
|
+
// Copyright © 2021 Max Lynch. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import MediaPlayer
|
|
11
|
+
|
|
12
|
+
// MARK: - Handle Notifications
|
|
13
|
+
|
|
14
|
+
extension CapacitorVideoPlayerPlugin {
|
|
15
|
+
|
|
16
|
+
// MARK: - playerItemPlay
|
|
17
|
+
|
|
18
|
+
@objc func playerItemPlay(notification: Notification) {
|
|
19
|
+
guard let info = notification.userInfo as? [String: Any] else { return }
|
|
20
|
+
DispatchQueue.main.async {
|
|
21
|
+
self.notifyListeners("jeepCapVideoPlayerPlay", data: info, retainUntilConsumed: true)
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// MARK: - playerItemPause
|
|
27
|
+
|
|
28
|
+
@objc func playerItemPause(notification: Notification) {
|
|
29
|
+
guard let info = notification.userInfo as? [String: Any] else { return }
|
|
30
|
+
DispatchQueue.main.async {
|
|
31
|
+
self.notifyListeners("jeepCapVideoPlayerPause", data: info, retainUntilConsumed: true)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// MARK: - playerItemEnd
|
|
37
|
+
|
|
38
|
+
@objc func playerItemEnd(notification: Notification) {
|
|
39
|
+
guard let info = notification.userInfo as? [String: Any] else { return }
|
|
40
|
+
DispatchQueue.main.async {
|
|
41
|
+
self.notifyListeners("jeepCapVideoPlayerEnded", data: info, retainUntilConsumed: true)
|
|
42
|
+
if self.mode == "fullscreen" {
|
|
43
|
+
self.playerFullscreenExit()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// MARK: - playerItemReady
|
|
51
|
+
|
|
52
|
+
@objc func playerItemReady(notification: Notification) {
|
|
53
|
+
guard let info = notification.userInfo as? [String: Any] else { return }
|
|
54
|
+
guard let playerId = info["fromPlayerId"] as? String else { return}
|
|
55
|
+
DispatchQueue.main.async {
|
|
56
|
+
self.notifyListeners("jeepCapVideoPlayerReady", data: info, retainUntilConsumed: true)
|
|
57
|
+
if self.mode == "fullscreen" && playerId == self.fsPlayerId {
|
|
58
|
+
if let vPFSV = self.videoPlayerFullScreenView {
|
|
59
|
+
vPFSV.play()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// MARK: - playerFullscreenDismiss
|
|
67
|
+
|
|
68
|
+
@objc func playerFullscreenDismiss(notification: Notification) {
|
|
69
|
+
|
|
70
|
+
var currentTime: Double = 0.0
|
|
71
|
+
if let playerView = self.videoPlayerFullScreenView {
|
|
72
|
+
currentTime = playerView.getRealCurrentTime()
|
|
73
|
+
}
|
|
74
|
+
let info: [String: Any] = ["dismiss": true, "currentTime": currentTime]
|
|
75
|
+
DispatchQueue.main.async {
|
|
76
|
+
if self.mode == "fullscreen" {
|
|
77
|
+
if let vPFSV = self.videoPlayerFullScreenView {
|
|
78
|
+
vPFSV.pause()
|
|
79
|
+
}
|
|
80
|
+
self.playerFullscreenExit()
|
|
81
|
+
}
|
|
82
|
+
self.notifyListeners("jeepCapVideoPlayerExit", data: info, retainUntilConsumed: true)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// MARK: - playerFullscreenExit
|
|
88
|
+
|
|
89
|
+
func playerFullscreenExit() {
|
|
90
|
+
if let vPFSV = self.videoPlayerFullScreenView {
|
|
91
|
+
vPFSV.removeObservers()
|
|
92
|
+
self.terminateNowPlayingInfo()
|
|
93
|
+
vPFSV.videoPlayer.player = nil
|
|
94
|
+
vPFSV.player = nil
|
|
95
|
+
/*
|
|
96
|
+
if self.displayMode == "landscape" {
|
|
97
|
+
vPFSV.videoPlayer = PortraitAVPlayerController()
|
|
98
|
+
} else if self.displayMode == "portrait" {
|
|
99
|
+
vPFSV.videoPlayer = LandscapeAVPlayerController()
|
|
100
|
+
} else {
|
|
101
|
+
vPFSV.videoPlayer = AllOrientationAVPlayerController()
|
|
102
|
+
}
|
|
103
|
+
*/
|
|
104
|
+
self.videoPlayerFullScreenView = nil
|
|
105
|
+
}
|
|
106
|
+
if let viewController = self.bridge?.viewController {
|
|
107
|
+
viewController.dismiss(animated: true, completion: {
|
|
108
|
+
if self.backModeEnabled {
|
|
109
|
+
if let audioSession = self.audioSession {
|
|
110
|
+
do {
|
|
111
|
+
try audioSession.setActive(false)
|
|
112
|
+
self.audioSession = nil
|
|
113
|
+
} catch {
|
|
114
|
+
let error: String = "playerFullscreenExit: Failed to deactivate audio session category"
|
|
115
|
+
print(error)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private func terminateNowPlayingInfo() {
|
|
124
|
+
if let vPFSV = self.videoPlayerFullScreenView {
|
|
125
|
+
if let token = vPFSV.periodicTimeObserver {
|
|
126
|
+
vPFSV.player?.removeTimeObserver(token)
|
|
127
|
+
vPFSV.periodicTimeObserver = nil
|
|
128
|
+
}
|
|
129
|
+
let rcc = MPRemoteCommandCenter.shared()
|
|
130
|
+
rcc.changePlaybackPositionCommand.isEnabled = false
|
|
131
|
+
rcc.playCommand.isEnabled = false
|
|
132
|
+
rcc.pauseCommand.isEnabled = false
|
|
133
|
+
rcc.skipForwardCommand.isEnabled = false
|
|
134
|
+
rcc.skipBackwardCommand.isEnabled = false
|
|
135
|
+
MPNowPlayingInfoCenter.default().nowPlayingInfo = [:]
|
|
136
|
+
MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CapacitorVideoPlayerPlugin.Observers.swift
|
|
3
|
+
// Plugin
|
|
4
|
+
//
|
|
5
|
+
// Created by Quéau Jean Pierre on 30/05/2021.
|
|
6
|
+
// Copyright © 2021 Max Lynch. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import UIKit
|
|
11
|
+
import AVFoundation
|
|
12
|
+
|
|
13
|
+
extension CapacitorVideoPlayerPlugin {
|
|
14
|
+
|
|
15
|
+
// MARK: - Add Observers
|
|
16
|
+
|
|
17
|
+
// swiftlint:disable function_body_length
|
|
18
|
+
@objc func addObserversToNotificationCenter() {
|
|
19
|
+
// add Observers
|
|
20
|
+
|
|
21
|
+
playObserver = NotificationCenter.default
|
|
22
|
+
.addObserver(forName: .playerItemPlay, object: nil, queue: nil,
|
|
23
|
+
using: playerItemPlay)
|
|
24
|
+
pauseObserver = NotificationCenter.default
|
|
25
|
+
.addObserver(forName: .playerItemPause, object: nil,
|
|
26
|
+
queue: nil, using: playerItemPause)
|
|
27
|
+
endObserver = NotificationCenter.default
|
|
28
|
+
.addObserver(forName: .playerItemEnd, object: nil, queue: nil,
|
|
29
|
+
using: playerItemEnd)
|
|
30
|
+
readyObserver = NotificationCenter.default
|
|
31
|
+
.addObserver(forName: .playerItemReady, object: nil,
|
|
32
|
+
queue: nil, using: playerItemReady)
|
|
33
|
+
fsDismissObserver = NotificationCenter.default
|
|
34
|
+
.addObserver(forName: .playerFullscreenDismiss, object: nil,
|
|
35
|
+
queue: nil, using: playerFullscreenDismiss)
|
|
36
|
+
vpInternalObserver = NotificationCenter.default
|
|
37
|
+
.addObserver(forName: .videoPathInternalReady, object: nil,
|
|
38
|
+
queue: nil, using: videoPathInternalReady)
|
|
39
|
+
|
|
40
|
+
backgroundObserver =
|
|
41
|
+
NotificationCenter.default.addObserver(
|
|
42
|
+
forName: UIApplication.didEnterBackgroundNotification,
|
|
43
|
+
object: nil, queue: nil) { (_) in
|
|
44
|
+
if self.backModeEnabled {
|
|
45
|
+
isInBackgroundMode = true
|
|
46
|
+
if !isInPIPMode &&
|
|
47
|
+
self.videoPlayerFullScreenView != nil {
|
|
48
|
+
self.videoPlayerFullScreenView?
|
|
49
|
+
.videoPlayer.player = nil
|
|
50
|
+
|
|
51
|
+
if let playerItem = self.videoPlayerFullScreenView?
|
|
52
|
+
.playerItem {
|
|
53
|
+
self.videoTrackEnable(playerItem: playerItem,
|
|
54
|
+
enable: false)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
if self.videoPlayerFullScreenView != nil {
|
|
59
|
+
|
|
60
|
+
self.videoPlayerFullScreenView?
|
|
61
|
+
.videoPlayer.player?.pause()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
foregroundObserver =
|
|
66
|
+
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil,
|
|
67
|
+
queue: OperationQueue.main) { (_) in
|
|
68
|
+
|
|
69
|
+
if self.backModeEnabled {
|
|
70
|
+
isInBackgroundMode = false
|
|
71
|
+
if !isInPIPMode && self.bgPlayer != nil &&
|
|
72
|
+
self.videoPlayerFullScreenView != nil {
|
|
73
|
+
//enable video track
|
|
74
|
+
if let playerItem =
|
|
75
|
+
self.videoPlayerFullScreenView?.playerItem {
|
|
76
|
+
self.videoTrackEnable(playerItem: playerItem,
|
|
77
|
+
enable: true)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self.videoPlayerFullScreenView?
|
|
81
|
+
.videoPlayer.player = self.bgPlayer
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
if self.videoPlayerFullScreenView != nil {
|
|
85
|
+
|
|
86
|
+
if let playerItem =
|
|
87
|
+
self.videoPlayerFullScreenView?.playerItem {
|
|
88
|
+
self.videoTrackEnable(playerItem: playerItem,
|
|
89
|
+
enable: true)
|
|
90
|
+
}
|
|
91
|
+
self.videoPlayerFullScreenView?
|
|
92
|
+
.videoPlayer.player?.play()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// swiftlint:enable function_body_length
|
|
99
|
+
|
|
100
|
+
// MARK: - videoTrackEnable
|
|
101
|
+
|
|
102
|
+
func videoTrackEnable(playerItem: AVPlayerItem, enable: Bool) {
|
|
103
|
+
let tracks = playerItem.tracks
|
|
104
|
+
for playerItemTrack in tracks {
|
|
105
|
+
// Find the video tracks.
|
|
106
|
+
if let mediaType = playerItemTrack.assetTrack?.mediaType {
|
|
107
|
+
if mediaType == AVMediaType.video {
|
|
108
|
+
// Enable/Disable the track.
|
|
109
|
+
playerItemTrack.isEnabled = enable
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// MARK: - videoPathInternalReady
|
|
117
|
+
|
|
118
|
+
// swiftlint:disable function_body_length
|
|
119
|
+
func videoPathInternalReady(notification: Notification) {
|
|
120
|
+
self.bridge?.viewController?.dismiss(animated: true, completion: {
|
|
121
|
+
})
|
|
122
|
+
guard let info = notification.userInfo as? [String: Any]
|
|
123
|
+
else { return }
|
|
124
|
+
guard let videoUrl = info["videoUrl"] as? URL else {
|
|
125
|
+
NotificationCenter.default.post(
|
|
126
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
guard let videoRate = info["videoRate"] as? Float else {
|
|
130
|
+
NotificationCenter.default.post(
|
|
131
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
guard let exitOnEnd = info["exitOnEnd"] as? Bool else {
|
|
135
|
+
NotificationCenter.default.post(
|
|
136
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
guard let loopOnEnd = info["loopOnEnd"] as? Bool else {
|
|
140
|
+
NotificationCenter.default.post(
|
|
141
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
guard let pipEnabled = info["pipEnabled"] as? Bool else {
|
|
145
|
+
NotificationCenter.default.post(
|
|
146
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
guard let showControls = info["showControls"] as? Bool else {
|
|
150
|
+
NotificationCenter.default.post(
|
|
151
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
guard let displayMode = info["displayMode"] as? String else {
|
|
155
|
+
NotificationCenter.default.post(
|
|
156
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
guard let backModeEnabled = info["backModeEnabled"] as? Bool else {
|
|
160
|
+
NotificationCenter.default.post(
|
|
161
|
+
name: .playerFullscreenDismiss, object: nil)
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
guard let call = self.call else { return }
|
|
165
|
+
|
|
166
|
+
self.createVideoPlayerFullscreenView(
|
|
167
|
+
call: call, videoUrl: videoUrl,
|
|
168
|
+
rate: videoRate, exitOnEnd: exitOnEnd,
|
|
169
|
+
loopOnEnd: loopOnEnd, pipEnabled: pipEnabled,
|
|
170
|
+
backModeEnabled: backModeEnabled,
|
|
171
|
+
showControls: showControls,
|
|
172
|
+
displayMode: displayMode,
|
|
173
|
+
subTitleUrl: nil, subTitleLanguage: nil,
|
|
174
|
+
subTitleOptions: nil, headers: nil,
|
|
175
|
+
title: nil, smallTitle: nil, artwork: nil)
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
// swiftlint:enable function_body_length
|
|
179
|
+
|
|
180
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>FMWK</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
+
<key>NSPrincipalClass</key>
|
|
22
|
+
<string></string>
|
|
23
|
+
</dict>
|
|
24
|
+
</plist>
|