unified-video-framework 1.0.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/.github/workflows/ci.yml +253 -0
- package/ANDROID_TV_IMPLEMENTATION.md +313 -0
- package/COMPLETION_STATUS.md +165 -0
- package/CONTRIBUTING.md +376 -0
- package/FINAL_STATUS_REPORT.md +170 -0
- package/FRAMEWORK_REVIEW.md +247 -0
- package/IMPROVEMENTS_SUMMARY.md +168 -0
- package/LICENSE +21 -0
- package/NATIVE_APP_INTEGRATION_GUIDE.md +903 -0
- package/PAYWALL_RENTAL_FLOW.md +499 -0
- package/PLATFORM_SETUP_GUIDE.md +1636 -0
- package/README.md +315 -0
- package/RUN_LOCALLY.md +151 -0
- package/apps/demo/cast-sender-min.html +173 -0
- package/apps/demo/custom-player.html +883 -0
- package/apps/demo/demo.html +990 -0
- package/apps/demo/enhanced-player.html +3556 -0
- package/apps/demo/index.html +159 -0
- package/apps/rental-api/.env.example +24 -0
- package/apps/rental-api/README.md +23 -0
- package/apps/rental-api/migrations/001_init.sql +35 -0
- package/apps/rental-api/migrations/002_videos.sql +10 -0
- package/apps/rental-api/migrations/003_add_gateway_subref.sql +4 -0
- package/apps/rental-api/migrations/004_update_gateways.sql +4 -0
- package/apps/rental-api/migrations/005_seed_demo_video.sql +5 -0
- package/apps/rental-api/package-lock.json +2045 -0
- package/apps/rental-api/package.json +33 -0
- package/apps/rental-api/scripts/run-migration.js +42 -0
- package/apps/rental-api/scripts/update-video-currency.js +21 -0
- package/apps/rental-api/scripts/update-video-price.js +19 -0
- package/apps/rental-api/src/config.ts +14 -0
- package/apps/rental-api/src/db.ts +10 -0
- package/apps/rental-api/src/routes/cashfree.ts +167 -0
- package/apps/rental-api/src/routes/pesapal.ts +92 -0
- package/apps/rental-api/src/routes/rentals.ts +242 -0
- package/apps/rental-api/src/routes/webhooks.ts +73 -0
- package/apps/rental-api/src/server.ts +41 -0
- package/apps/rental-api/src/services/entitlements.ts +45 -0
- package/apps/rental-api/src/services/payments.ts +22 -0
- package/apps/rental-api/tsconfig.json +17 -0
- package/check-urls.ps1 +74 -0
- package/comparison-report.md +181 -0
- package/docs/PAYWALL.md +95 -0
- package/docs/PLAYER_UI_VISIBILITY.md +431 -0
- package/docs/README.md +7 -0
- package/docs/SYSTEM_ARCHITECTURE.md +612 -0
- package/docs/VDOCIPHER_CLONE_REQUIREMENTS.md +403 -0
- package/examples/android/JavaSampleApp/MainActivity.java +641 -0
- package/examples/android/JavaSampleApp/activity_main.xml +226 -0
- package/examples/android/SampleApp/MainActivity.kt +430 -0
- package/examples/ios/SampleApp/ViewController.swift +337 -0
- package/examples/ios/SwiftUISampleApp/ContentView.swift +304 -0
- package/iOS_IMPLEMENTATION_OPTIONS.md +470 -0
- package/ios/UnifiedVideoPlayer/UnifiedVideoPlayer.podspec +33 -0
- package/jest.config.js +33 -0
- package/jitpack.yml +5 -0
- package/lerna.json +35 -0
- package/package.json +69 -0
- package/packages/PLATFORM_STATUS.md +163 -0
- package/packages/android/build.gradle +135 -0
- package/packages/android/src/main/AndroidManifest.xml +36 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/PlayerConfiguration.java +221 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/UnifiedVideoPlayer.java +1037 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/UnifiedVideoPlayer.kt +707 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/analytics/AnalyticsProvider.java +9 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/cast/CastManager.java +141 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/cast/CastOptionsProvider.java +29 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/overlay/WatermarkOverlayView.java +88 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/pip/PipActionReceiver.java +33 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/services/PlaybackService.java +110 -0
- package/packages/android/src/main/java/com/unifiedvideo/player/services/PlayerHolder.java +19 -0
- package/packages/core/package.json +34 -0
- package/packages/core/src/BasePlayer.ts +250 -0
- package/packages/core/src/VideoPlayer.ts +237 -0
- package/packages/core/src/VideoPlayerFactory.ts +145 -0
- package/packages/core/src/index.ts +20 -0
- package/packages/core/src/interfaces/IVideoPlayer.ts +184 -0
- package/packages/core/src/interfaces.ts +240 -0
- package/packages/core/src/utils/EventEmitter.ts +66 -0
- package/packages/core/src/utils/PlatformDetector.ts +300 -0
- package/packages/core/tsconfig.json +20 -0
- package/packages/enact/package.json +51 -0
- package/packages/enact/src/VideoPlayer.js +365 -0
- package/packages/enact/src/adapters/TizenAdapter.js +354 -0
- package/packages/enact/src/index.js +82 -0
- package/packages/ios/BUILD_INSTRUCTIONS.md +108 -0
- package/packages/ios/FIX_EMBED_ISSUE.md +142 -0
- package/packages/ios/GETTING_STARTED.md +100 -0
- package/packages/ios/Package.swift +35 -0
- package/packages/ios/README.md +84 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Analytics/AnalyticsEmitter.swift +26 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/DRM/FairPlayDRMManager.swift +102 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Info.plist +24 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Remote/RemoteCommandCenter.swift +109 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/UnifiedVideoPlayer.swift +811 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/UnifiedVideoPlayerView.swift +640 -0
- package/packages/ios/Sources/UnifiedVideoPlayer/Utilities/Color+Hex.swift +36 -0
- package/packages/ios/UnifiedVideoPlayer.podspec +27 -0
- package/packages/ios/UnifiedVideoPlayer.xcodeproj/project.pbxproj +385 -0
- package/packages/ios/build_framework.sh +55 -0
- package/packages/react-native/android/src/main/java/com/unifiedvideo/UnifiedVideoPlayerModule.kt +482 -0
- package/packages/react-native/ios/UnifiedVideoPlayer.swift +436 -0
- package/packages/react-native/package.json +51 -0
- package/packages/react-native/src/ReactNativePlayer.tsx +423 -0
- package/packages/react-native/src/VideoPlayer.tsx +224 -0
- package/packages/react-native/src/index.ts +28 -0
- package/packages/react-native/src/utils/EventEmitter.ts +66 -0
- package/packages/react-native/tsconfig.json +31 -0
- package/packages/roku/components/UnifiedVideoPlayer.brs +400 -0
- package/packages/roku/package.json +44 -0
- package/packages/roku/source/VideoPlayer.brs +231 -0
- package/packages/roku/source/main.brs +28 -0
- package/packages/web/GETTING_STARTED.md +292 -0
- package/packages/web/jest.config.js +28 -0
- package/packages/web/jest.setup.ts +110 -0
- package/packages/web/package.json +50 -0
- package/packages/web/src/SecureVideoPlayer.ts +1164 -0
- package/packages/web/src/WebPlayer.ts +3110 -0
- package/packages/web/src/__tests__/WebPlayer.test.ts +314 -0
- package/packages/web/src/index.ts +14 -0
- package/packages/web/src/paywall/PaywallController.ts +215 -0
- package/packages/web/src/react/WebPlayerView.tsx +177 -0
- package/packages/web/tsconfig.json +23 -0
- package/packages/web/webpack.config.js +45 -0
- package/server.js +131 -0
- package/server.py +84 -0
- package/test-urls.ps1 +97 -0
- package/test-video-urls.ps1 +87 -0
- package/tsconfig.json +39 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# 📱 iOS Implementation Options for Unified Video Framework
|
|
2
|
+
|
|
3
|
+
You have **5 different ways** to implement the video player on iOS, depending on your project requirements:
|
|
4
|
+
|
|
5
|
+
## 1. ✅ Native iOS (Pure Swift/Objective-C)
|
|
6
|
+
**Best for:** Native iOS apps, maximum performance, full platform control
|
|
7
|
+
|
|
8
|
+
### Swift Implementation
|
|
9
|
+
```swift
|
|
10
|
+
// VideoPlayerViewController.swift
|
|
11
|
+
import UIKit
|
|
12
|
+
import AVFoundation
|
|
13
|
+
import AVKit
|
|
14
|
+
|
|
15
|
+
class VideoPlayerViewController: UIViewController {
|
|
16
|
+
private var player: AVPlayer?
|
|
17
|
+
private var playerLayer: AVPlayerLayer?
|
|
18
|
+
private var playerViewController: AVPlayerViewController?
|
|
19
|
+
|
|
20
|
+
override func viewDidLoad() {
|
|
21
|
+
super.viewDidLoad()
|
|
22
|
+
setupPlayer()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private func setupPlayer() {
|
|
26
|
+
// Initialize player with URL
|
|
27
|
+
guard let url = URL(string: "https://example.com/video.m3u8") else { return }
|
|
28
|
+
|
|
29
|
+
player = AVPlayer(url: url)
|
|
30
|
+
|
|
31
|
+
// Option 1: Custom player view
|
|
32
|
+
playerLayer = AVPlayerLayer(player: player)
|
|
33
|
+
playerLayer?.frame = view.bounds
|
|
34
|
+
playerLayer?.videoGravity = .resizeAspect
|
|
35
|
+
view.layer.addSublayer(playerLayer!)
|
|
36
|
+
|
|
37
|
+
// Option 2: Using AVPlayerViewController
|
|
38
|
+
// playerViewController = AVPlayerViewController()
|
|
39
|
+
// playerViewController?.player = player
|
|
40
|
+
// present(playerViewController!, animated: true) {
|
|
41
|
+
// self.player?.play()
|
|
42
|
+
// }
|
|
43
|
+
|
|
44
|
+
// Add controls
|
|
45
|
+
addCustomControls()
|
|
46
|
+
|
|
47
|
+
// Start playback
|
|
48
|
+
player?.play()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private func addCustomControls() {
|
|
52
|
+
// Add play/pause button
|
|
53
|
+
let playButton = UIButton(frame: CGRect(x: 20, y: view.bounds.height - 100, width: 60, height: 60))
|
|
54
|
+
playButton.setTitle("▶️", for: .normal)
|
|
55
|
+
playButton.addTarget(self, action: #selector(togglePlayPause), for: .touchUpInside)
|
|
56
|
+
view.addSubview(playButton)
|
|
57
|
+
|
|
58
|
+
// Add progress slider
|
|
59
|
+
let slider = UISlider(frame: CGRect(x: 100, y: view.bounds.height - 80, width: view.bounds.width - 120, height: 40))
|
|
60
|
+
slider.addTarget(self, action: #selector(sliderValueChanged(_:)), for: .valueChanged)
|
|
61
|
+
view.addSubview(slider)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@objc private func togglePlayPause() {
|
|
65
|
+
if player?.rate == 0 {
|
|
66
|
+
player?.play()
|
|
67
|
+
} else {
|
|
68
|
+
player?.pause()
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@objc private func sliderValueChanged(_ slider: UISlider) {
|
|
73
|
+
let seconds = Double(slider.value) * (player?.currentItem?.duration.seconds ?? 0)
|
|
74
|
+
let time = CMTime(seconds: seconds, preferredTimescale: 1000)
|
|
75
|
+
player?.seek(to: time)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Objective-C Implementation
|
|
81
|
+
```objc
|
|
82
|
+
// VideoPlayerViewController.m
|
|
83
|
+
#import <AVFoundation/AVFoundation.h>
|
|
84
|
+
#import <AVKit/AVKit.h>
|
|
85
|
+
|
|
86
|
+
@interface VideoPlayerViewController ()
|
|
87
|
+
@property (nonatomic, strong) AVPlayer *player;
|
|
88
|
+
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
|
|
89
|
+
@end
|
|
90
|
+
|
|
91
|
+
@implementation VideoPlayerViewController
|
|
92
|
+
|
|
93
|
+
- (void)viewDidLoad {
|
|
94
|
+
[super viewDidLoad];
|
|
95
|
+
[self setupPlayer];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
- (void)setupPlayer {
|
|
99
|
+
NSURL *videoURL = [NSURL URLWithString:@"https://example.com/video.m3u8"];
|
|
100
|
+
self.player = [AVPlayer playerWithURL:videoURL];
|
|
101
|
+
|
|
102
|
+
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
|
|
103
|
+
self.playerLayer.frame = self.view.bounds;
|
|
104
|
+
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
|
|
105
|
+
[self.view.layer addSublayer:self.playerLayer];
|
|
106
|
+
|
|
107
|
+
[self.player play];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Installation Steps:
|
|
114
|
+
```bash
|
|
115
|
+
# No additional dependencies needed - uses native iOS frameworks
|
|
116
|
+
# Simply add to your Xcode project
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 2. 🌐 WebView Implementation
|
|
122
|
+
**Best for:** Web-based content, existing web player, hybrid apps
|
|
123
|
+
|
|
124
|
+
```swift
|
|
125
|
+
// WebViewPlayerViewController.swift
|
|
126
|
+
import UIKit
|
|
127
|
+
import WebKit
|
|
128
|
+
|
|
129
|
+
class WebViewPlayerViewController: UIViewController, WKNavigationDelegate {
|
|
130
|
+
private var webView: WKWebView!
|
|
131
|
+
|
|
132
|
+
override func viewDidLoad() {
|
|
133
|
+
super.viewDidLoad()
|
|
134
|
+
setupWebView()
|
|
135
|
+
loadVideoPlayer()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private func setupWebView() {
|
|
139
|
+
let configuration = WKWebViewConfiguration()
|
|
140
|
+
configuration.allowsInlineMediaPlayback = true
|
|
141
|
+
configuration.mediaTypesRequiringUserActionForPlayback = []
|
|
142
|
+
|
|
143
|
+
webView = WKWebView(frame: view.bounds, configuration: configuration)
|
|
144
|
+
webView.navigationDelegate = self
|
|
145
|
+
view.addSubview(webView)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private func loadVideoPlayer() {
|
|
149
|
+
// Option 1: Load remote player
|
|
150
|
+
if let url = URL(string: "https://yoursite.com/player.html") {
|
|
151
|
+
webView.load(URLRequest(url: url))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Option 2: Load local HTML
|
|
155
|
+
let html = """
|
|
156
|
+
<!DOCTYPE html>
|
|
157
|
+
<html>
|
|
158
|
+
<head>
|
|
159
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
160
|
+
<style>
|
|
161
|
+
body { margin: 0; padding: 0; }
|
|
162
|
+
video { width: 100%; height: 100vh; }
|
|
163
|
+
</style>
|
|
164
|
+
</head>
|
|
165
|
+
<body>
|
|
166
|
+
<video controls autoplay>
|
|
167
|
+
<source src="https://example.com/video.mp4" type="video/mp4">
|
|
168
|
+
</video>
|
|
169
|
+
<script src="unified-video-web.js"></script>
|
|
170
|
+
<script>
|
|
171
|
+
const player = new UnifiedVideoPlayer();
|
|
172
|
+
player.initialize('video');
|
|
173
|
+
</script>
|
|
174
|
+
</body>
|
|
175
|
+
</html>
|
|
176
|
+
"""
|
|
177
|
+
webView.loadHTMLString(html, baseURL: nil)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 3. 🎭 React Native Implementation
|
|
185
|
+
**Best for:** Cross-platform apps, JavaScript developers, code reuse
|
|
186
|
+
|
|
187
|
+
```jsx
|
|
188
|
+
// Already covered in your example
|
|
189
|
+
// This is useful when you want to share code between iOS and Android
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 4. 🔥 Flutter Implementation
|
|
195
|
+
**Best for:** Cross-platform with Dart, Material Design, high performance
|
|
196
|
+
|
|
197
|
+
```dart
|
|
198
|
+
// VideoPlayerScreen.dart
|
|
199
|
+
import 'package:flutter/material.dart';
|
|
200
|
+
import 'package:video_player/video_player.dart';
|
|
201
|
+
import 'package:chewie/chewie.dart';
|
|
202
|
+
|
|
203
|
+
class VideoPlayerScreen extends StatefulWidget {
|
|
204
|
+
@override
|
|
205
|
+
_VideoPlayerScreenState createState() => _VideoPlayerScreenState();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
|
|
209
|
+
VideoPlayerController? _videoPlayerController;
|
|
210
|
+
ChewieController? _chewieController;
|
|
211
|
+
|
|
212
|
+
@override
|
|
213
|
+
void initState() {
|
|
214
|
+
super.initState();
|
|
215
|
+
initializePlayer();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
Future<void> initializePlayer() async {
|
|
219
|
+
_videoPlayerController = VideoPlayerController.network(
|
|
220
|
+
'https://example.com/video.m3u8',
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
await _videoPlayerController!.initialize();
|
|
224
|
+
|
|
225
|
+
_chewieController = ChewieController(
|
|
226
|
+
videoPlayerController: _videoPlayerController!,
|
|
227
|
+
autoPlay: true,
|
|
228
|
+
looping: false,
|
|
229
|
+
showControls: true,
|
|
230
|
+
materialProgressColors: ChewieProgressColors(
|
|
231
|
+
playedColor: Colors.red,
|
|
232
|
+
handleColor: Colors.blue,
|
|
233
|
+
backgroundColor: Colors.grey,
|
|
234
|
+
bufferedColor: Colors.lightGreen,
|
|
235
|
+
),
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
setState(() {});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@override
|
|
242
|
+
Widget build(BuildContext context) {
|
|
243
|
+
return Scaffold(
|
|
244
|
+
appBar: AppBar(title: Text('Video Player')),
|
|
245
|
+
body: Center(
|
|
246
|
+
child: _chewieController != null
|
|
247
|
+
? Chewie(controller: _chewieController!)
|
|
248
|
+
: CircularProgressIndicator(),
|
|
249
|
+
),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@override
|
|
254
|
+
void dispose() {
|
|
255
|
+
_videoPlayerController?.dispose();
|
|
256
|
+
_chewieController?.dispose();
|
|
257
|
+
super.dispose();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Installation:
|
|
263
|
+
```yaml
|
|
264
|
+
# pubspec.yaml
|
|
265
|
+
dependencies:
|
|
266
|
+
video_player: ^2.7.0
|
|
267
|
+
chewie: ^1.7.0
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 5. 🏗️ Unity Implementation
|
|
273
|
+
**Best for:** Games, 3D apps, AR/VR experiences
|
|
274
|
+
|
|
275
|
+
```csharp
|
|
276
|
+
// VideoPlayerController.cs
|
|
277
|
+
using UnityEngine;
|
|
278
|
+
using UnityEngine.Video;
|
|
279
|
+
|
|
280
|
+
public class VideoPlayerController : MonoBehaviour
|
|
281
|
+
{
|
|
282
|
+
private VideoPlayer videoPlayer;
|
|
283
|
+
private RenderTexture renderTexture;
|
|
284
|
+
|
|
285
|
+
void Start()
|
|
286
|
+
{
|
|
287
|
+
// Create VideoPlayer component
|
|
288
|
+
videoPlayer = gameObject.AddComponent<VideoPlayer>();
|
|
289
|
+
|
|
290
|
+
// Set video URL
|
|
291
|
+
videoPlayer.url = "https://example.com/video.mp4";
|
|
292
|
+
|
|
293
|
+
// Configure player
|
|
294
|
+
videoPlayer.playOnAwake = false;
|
|
295
|
+
videoPlayer.renderMode = VideoRenderMode.RenderTexture;
|
|
296
|
+
|
|
297
|
+
// Create render texture
|
|
298
|
+
renderTexture = new RenderTexture(1920, 1080, 16);
|
|
299
|
+
videoPlayer.targetTexture = renderTexture;
|
|
300
|
+
|
|
301
|
+
// Apply to UI or 3D object
|
|
302
|
+
GetComponent<Renderer>().material.mainTexture = renderTexture;
|
|
303
|
+
|
|
304
|
+
// Play video
|
|
305
|
+
videoPlayer.Play();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
public void PlayPause()
|
|
309
|
+
{
|
|
310
|
+
if (videoPlayer.isPlaying)
|
|
311
|
+
videoPlayer.Pause();
|
|
312
|
+
else
|
|
313
|
+
videoPlayer.Play();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 📊 Comparison Matrix
|
|
321
|
+
|
|
322
|
+
| Feature | Native iOS | WebView | React Native | Flutter | Unity |
|
|
323
|
+
|---------|-----------|---------|--------------|---------|--------|
|
|
324
|
+
| **Performance** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
|
|
325
|
+
| **Development Speed** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
|
|
326
|
+
| **Cross-Platform** | ❌ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
|
|
327
|
+
| **Native Features** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
|
|
328
|
+
| **Custom UI** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
|
329
|
+
| **DRM Support** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
|
|
330
|
+
| **Learning Curve** | Medium | Easy | Medium | Medium | Hard |
|
|
331
|
+
| **App Size** | Small | Small | Large | Medium | Large |
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 🎯 When to Use Each Approach
|
|
336
|
+
|
|
337
|
+
### Choose **Native iOS** if:
|
|
338
|
+
- ✅ Building iOS-only app
|
|
339
|
+
- ✅ Need maximum performance
|
|
340
|
+
- ✅ Require deep iOS integration
|
|
341
|
+
- ✅ Want smallest app size
|
|
342
|
+
- ✅ Need advanced DRM (FairPlay)
|
|
343
|
+
|
|
344
|
+
### Choose **WebView** if:
|
|
345
|
+
- ✅ Already have web player
|
|
346
|
+
- ✅ Want quick implementation
|
|
347
|
+
- ✅ Need to maintain single codebase
|
|
348
|
+
- ✅ Content is web-based
|
|
349
|
+
|
|
350
|
+
### Choose **React Native** if:
|
|
351
|
+
- ✅ Building for iOS and Android
|
|
352
|
+
- ✅ Team knows JavaScript/React
|
|
353
|
+
- ✅ Want to share code between platforms
|
|
354
|
+
- ✅ Need hot reload for development
|
|
355
|
+
|
|
356
|
+
### Choose **Flutter** if:
|
|
357
|
+
- ✅ Want beautiful UI out of the box
|
|
358
|
+
- ✅ Building for multiple platforms
|
|
359
|
+
- ✅ Team knows Dart
|
|
360
|
+
- ✅ Need high performance cross-platform
|
|
361
|
+
|
|
362
|
+
### Choose **Unity** if:
|
|
363
|
+
- ✅ Building game or 3D app
|
|
364
|
+
- ✅ Need AR/VR features
|
|
365
|
+
- ✅ Want 360° video support
|
|
366
|
+
- ✅ Already using Unity
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 🚀 Quick Start Commands
|
|
371
|
+
|
|
372
|
+
### Native iOS (Swift)
|
|
373
|
+
```bash
|
|
374
|
+
# Create new Xcode project
|
|
375
|
+
# File > New > Project > iOS App
|
|
376
|
+
# Add VideoPlayerViewController.swift to project
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### WebView
|
|
380
|
+
```bash
|
|
381
|
+
# Add to existing iOS project
|
|
382
|
+
# No additional setup needed
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### React Native
|
|
386
|
+
```bash
|
|
387
|
+
npx react-native init VideoApp
|
|
388
|
+
cd VideoApp
|
|
389
|
+
npm install react-native-video
|
|
390
|
+
cd ios && pod install
|
|
391
|
+
npx react-native run-ios
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Flutter
|
|
395
|
+
```bash
|
|
396
|
+
flutter create video_app
|
|
397
|
+
cd video_app
|
|
398
|
+
flutter pub add video_player chewie
|
|
399
|
+
flutter run
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Unity
|
|
403
|
+
```bash
|
|
404
|
+
# Download Unity Hub
|
|
405
|
+
# Create new 3D project
|
|
406
|
+
# Import Video Player package
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 📦 Framework Integration
|
|
412
|
+
|
|
413
|
+
To integrate the Unified Video Framework with any of these approaches:
|
|
414
|
+
|
|
415
|
+
### 1. Native iOS Integration
|
|
416
|
+
```swift
|
|
417
|
+
// UnifiedVideoPlayer.swift
|
|
418
|
+
import UnifiedVideoCore
|
|
419
|
+
|
|
420
|
+
class UnifiedVideoPlayer {
|
|
421
|
+
private let corePlayer = UnifiedCore.Player()
|
|
422
|
+
|
|
423
|
+
func initialize(view: UIView) {
|
|
424
|
+
corePlayer.attachToView(view)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
func load(url: String) {
|
|
428
|
+
corePlayer.load(MediaSource(url: url))
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 2. Bridge Pattern for Cross-Platform
|
|
434
|
+
```swift
|
|
435
|
+
// UnifiedVideoBridge.swift
|
|
436
|
+
@objc(UnifiedVideoBridge)
|
|
437
|
+
class UnifiedVideoBridge: NSObject {
|
|
438
|
+
@objc func initialize(_ config: [String: Any]) {
|
|
439
|
+
// Initialize core player
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
@objc func load(_ source: [String: Any]) {
|
|
443
|
+
// Load video source
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 💡 Best Practices
|
|
451
|
+
|
|
452
|
+
1. **For Enterprise Apps**: Use Native iOS for best control
|
|
453
|
+
2. **For Startups**: Use React Native or Flutter for faster time-to-market
|
|
454
|
+
3. **For Media Companies**: Native iOS with custom controls
|
|
455
|
+
4. **For Education/Training**: WebView for easy content updates
|
|
456
|
+
5. **For Gaming**: Unity with video textures
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 📚 Additional Resources
|
|
461
|
+
|
|
462
|
+
- [AVFoundation Documentation](https://developer.apple.com/av-foundation/)
|
|
463
|
+
- [React Native Video](https://github.com/react-native-video/react-native-video)
|
|
464
|
+
- [Flutter Video Player](https://pub.dev/packages/video_player)
|
|
465
|
+
- [Unity Video Player](https://docs.unity3d.com/Manual/VideoPlayer.html)
|
|
466
|
+
- [WKWebView Guide](https://developer.apple.com/documentation/webkit/wkwebview)
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
Choose the approach that best fits your project requirements, team expertise, and timeline!
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Pod::Spec.new do |s|
|
|
2
|
+
s.name = 'UnifiedVideoPlayer'
|
|
3
|
+
s.version = '0.1.0'
|
|
4
|
+
s.summary = 'Unified video player SDK for iOS (HLS, FairPlay DRM, PiP, AirPlay, Remote Command Center).'
|
|
5
|
+
s.description = <<-DESC
|
|
6
|
+
A unified, embeddable iOS video player SDK powered by AVPlayer.
|
|
7
|
+
Features:
|
|
8
|
+
- HLS playback with robust event API
|
|
9
|
+
- Subtitles/audio track selection
|
|
10
|
+
- Picture-in-Picture and AirPlay support
|
|
11
|
+
- FairPlay DRM (SPC/CKC) integration hooks
|
|
12
|
+
- Remote Command Center & Now Playing
|
|
13
|
+
- Background audio
|
|
14
|
+
DESC
|
|
15
|
+
s.homepage = 'https://github.com/your-org/unified-video-framework'
|
|
16
|
+
s.license = { :type => 'MIT' }
|
|
17
|
+
s.author = { 'Your Company' => 'support@example.com' }
|
|
18
|
+
s.source = { :git => 'https://github.com/your-org/unified-video-framework-ios.git', :tag => s.version.to_s }
|
|
19
|
+
s.platform = :ios, '12.0'
|
|
20
|
+
s.swift_version = '5.8'
|
|
21
|
+
|
|
22
|
+
# This podspec lives next to the Sources directory
|
|
23
|
+
s.source_files = 'Sources/**/*.{swift,h,m}'
|
|
24
|
+
|
|
25
|
+
s.frameworks = 'AVFoundation', 'AVKit', 'MediaPlayer'
|
|
26
|
+
s.requires_arc = true
|
|
27
|
+
|
|
28
|
+
s.pod_target_xcconfig = {
|
|
29
|
+
'OTHER_SWIFT_FLAGS' => '$(inherited) -DUNIFIED_VIDEO_PLAYER',
|
|
30
|
+
'SWIFT_OPTIMIZATION_LEVEL' => '$(inherited)'
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'jsdom',
|
|
4
|
+
roots: ['<rootDir>/packages'],
|
|
5
|
+
testMatch: [
|
|
6
|
+
'**/__tests__/**/*.+(ts|tsx|js)',
|
|
7
|
+
'**/?(*.)+(spec|test).+(ts|tsx|js)'
|
|
8
|
+
],
|
|
9
|
+
transform: {
|
|
10
|
+
'^.+\\.(ts|tsx)$': 'ts-jest'
|
|
11
|
+
},
|
|
12
|
+
collectCoverageFrom: [
|
|
13
|
+
'packages/*/src/**/*.{ts,tsx}',
|
|
14
|
+
'!packages/*/src/**/*.d.ts',
|
|
15
|
+
'!packages/*/src/**/index.ts',
|
|
16
|
+
'!packages/*/src/**/*.stories.tsx'
|
|
17
|
+
],
|
|
18
|
+
moduleNameMapper: {
|
|
19
|
+
'@unified-video/core': '<rootDir>/packages/core/src',
|
|
20
|
+
'@unified-video/web': '<rootDir>/packages/web/src',
|
|
21
|
+
'@unified-video/react-native': '<rootDir>/packages/react-native/src',
|
|
22
|
+
'@unified-video/enact': '<rootDir>/packages/enact/src',
|
|
23
|
+
'@unified-video/roku': '<rootDir>/packages/roku/src'
|
|
24
|
+
},
|
|
25
|
+
coverageThreshold: {
|
|
26
|
+
global: {
|
|
27
|
+
branches: 70,
|
|
28
|
+
functions: 70,
|
|
29
|
+
lines: 70,
|
|
30
|
+
statements: 70
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
package/jitpack.yml
ADDED
package/lerna.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"npmClient": "npm",
|
|
4
|
+
"packages": [
|
|
5
|
+
"packages/*",
|
|
6
|
+
"apps/*"
|
|
7
|
+
],
|
|
8
|
+
"command": {
|
|
9
|
+
"bootstrap": {
|
|
10
|
+
"hoist": true,
|
|
11
|
+
"noCi": false,
|
|
12
|
+
"npmClientArgs": ["--no-package-lock"]
|
|
13
|
+
},
|
|
14
|
+
"publish": {
|
|
15
|
+
"conventionalCommits": true,
|
|
16
|
+
"message": "chore(release): publish %v",
|
|
17
|
+
"registry": "https://registry.npmjs.org",
|
|
18
|
+
"allowBranch": ["main", "master"]
|
|
19
|
+
},
|
|
20
|
+
"version": {
|
|
21
|
+
"allowBranch": ["main", "master"],
|
|
22
|
+
"conventionalCommits": true,
|
|
23
|
+
"createRelease": "github",
|
|
24
|
+
"exact": false,
|
|
25
|
+
"message": "chore(release): version %v"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"ignoreChanges": [
|
|
29
|
+
"**/dist/**",
|
|
30
|
+
"**/node_modules/**",
|
|
31
|
+
"**/test/**",
|
|
32
|
+
"**/*.md",
|
|
33
|
+
"**/package-lock.json"
|
|
34
|
+
]
|
|
35
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "unified-video-framework",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more",
|
|
5
|
+
"private": false,
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"packages/*",
|
|
8
|
+
"apps/*",
|
|
9
|
+
"tools/*"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"postinstall": "npm run build:core",
|
|
13
|
+
"bootstrap": "lerna bootstrap --legacy-peer-deps",
|
|
14
|
+
"build": "npm run build:core && npm run build:web && npm run build:rental-api",
|
|
15
|
+
"build:core": "cd packages/core && npm run build",
|
|
16
|
+
"build:web": "cd packages/web && npm run build",
|
|
17
|
+
"build:rental-api": "cd apps/rental-api && npm run build",
|
|
18
|
+
"start:rental-api": "cd apps/rental-api && npm start",
|
|
19
|
+
"dev:rental-api": "cd apps/rental-api && npm run dev",
|
|
20
|
+
"build:react-native": "cd packages/react-native && npm run build",
|
|
21
|
+
"build:enact": "cd packages/enact && npm run build",
|
|
22
|
+
"build:all": "lerna run build --stream",
|
|
23
|
+
"clean": "lerna clean",
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"test:coverage": "jest --coverage",
|
|
26
|
+
"test:watch": "jest --watch",
|
|
27
|
+
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
|
|
28
|
+
"type-check": "tsc --noEmit",
|
|
29
|
+
"publish": "lerna publish",
|
|
30
|
+
"dev": "lerna run dev --parallel",
|
|
31
|
+
"serve:demo": "node server.js",
|
|
32
|
+
"docs": "typedoc --out docs packages/core/src"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^18.0.0",
|
|
36
|
+
"@types/react": "^18.0.0",
|
|
37
|
+
"@types/react-native": "^0.70.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
39
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
40
|
+
"eslint": "^8.0.0",
|
|
41
|
+
"lerna": "^6.0.0",
|
|
42
|
+
"prettier": "^2.8.0",
|
|
43
|
+
"typescript": "^4.9.0",
|
|
44
|
+
"typedoc": "^0.23.0",
|
|
45
|
+
"webpack": "^5.75.0",
|
|
46
|
+
"webpack-cli": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/your-org/unified-video-framework.git"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"video",
|
|
54
|
+
"player",
|
|
55
|
+
"streaming",
|
|
56
|
+
"cross-platform",
|
|
57
|
+
"react-native",
|
|
58
|
+
"enact",
|
|
59
|
+
"smart-tv",
|
|
60
|
+
"tizen",
|
|
61
|
+
"webos",
|
|
62
|
+
"roku",
|
|
63
|
+
"drm",
|
|
64
|
+
"hls",
|
|
65
|
+
"dash"
|
|
66
|
+
],
|
|
67
|
+
"author": "Your Company",
|
|
68
|
+
"license": "MIT"
|
|
69
|
+
}
|