@capgo/capacitor-jw-player 0.0.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.
Files changed (33) hide show
  1. package/CapgoCapacitorJwPlayer.podspec +18 -0
  2. package/Package.swift +30 -0
  3. package/README.md +493 -0
  4. package/android/build.gradle +83 -0
  5. package/android/src/main/AndroidManifest.xml +37 -0
  6. package/android/src/main/java/ee/forgr/capacitor_jw_player/JwPlayerPlugin.java +529 -0
  7. package/android/src/main/java/ee/forgr/capacitor_jw_player/PlayerActivity.java +469 -0
  8. package/android/src/main/res/.gitkeep +0 -0
  9. package/android/src/main/res/drawable/close_button_background.xml +5 -0
  10. package/android/src/main/res/layout/activity_player.xml +28 -0
  11. package/android/src/main/res/values/colors.xml +16 -0
  12. package/android/src/main/res/values/strings.xml +3 -0
  13. package/android/src/main/res/values/styles.xml +32 -0
  14. package/dist/docs.json +459 -0
  15. package/dist/esm/definitions.d.ts +156 -0
  16. package/dist/esm/definitions.js +2 -0
  17. package/dist/esm/definitions.js.map +1 -0
  18. package/dist/esm/index.d.ts +4 -0
  19. package/dist/esm/index.js +7 -0
  20. package/dist/esm/index.js.map +1 -0
  21. package/dist/esm/web.d.ts +57 -0
  22. package/dist/esm/web.js +65 -0
  23. package/dist/esm/web.js.map +1 -0
  24. package/dist/plugin.cjs.js +79 -0
  25. package/dist/plugin.cjs.js.map +1 -0
  26. package/dist/plugin.js +82 -0
  27. package/dist/plugin.js.map +1 -0
  28. package/ios/Sources/JwPlayerPlugin/JwPlayer.swift +24 -0
  29. package/ios/Sources/JwPlayerPlugin/JwPlayerPlugin.swift +749 -0
  30. package/ios/Sources/JwPlayerPlugin/LinkedList.swift +219 -0
  31. package/ios/Sources/JwPlayerPlugin/VideosToPlay.swift +56 -0
  32. package/ios/Tests/JwPlayerPluginTests/JwPlayerPluginTests.swift +15 -0
  33. package/package.json +80 -0
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapgoCapacitorJwPlayer'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '14.0'
15
+ s.dependency 'Capacitor'
16
+ s.dependency 'JWPlayerKit'
17
+ s.swift_version = '5.1'
18
+ end
package/Package.swift ADDED
@@ -0,0 +1,30 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapgoCapacitorJwPlayer",
6
+ platforms: [.iOS(.v14)],
7
+ products: [
8
+ .library(
9
+ name: "CapgoCapacitorJwPlayer",
10
+ targets: ["JwPlayerPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0"),
14
+ .package(url: "https://github.com/jwplayer/JWPlayerKit-package.git", .upToNextMajor(from: "4.21.3"))
15
+ ],
16
+ targets: [
17
+ .target(
18
+ name: "JwPlayerPlugin",
19
+ dependencies: [
20
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
21
+ .product(name: "Cordova", package: "capacitor-swift-pm"),
22
+ .product(name: "JWPlayerKit", package: "JWPlayerKit-package")
23
+ ],
24
+ path: "ios/Sources/JwPlayerPlugin"),
25
+ .testTarget(
26
+ name: "JwPlayerPluginTests",
27
+ dependencies: ["JwPlayerPlugin"],
28
+ path: "ios/Tests/JwPlayerPluginTests")
29
+ ]
30
+ )
package/README.md ADDED
@@ -0,0 +1,493 @@
1
+ # @capgo/capacitor-jw-player
2
+ <a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
3
+
4
+ <div align="center">
5
+ <h2><a href="https://capgo.app/?ref=plugin"> ➡️ Get Instant updates for your App with Capgo 🚀</a></h2>
6
+ <h2><a href="https://capgo.app/consulting/?ref=plugin"> Fix your annoying bug now, Hire a Capacitor expert 💪</a></h2>
7
+ </div>
8
+
9
+ WIP: do not use it yet it's in dev
10
+
11
+ Play videos from jwplayer.com with a fullscreen player interface. The plugin provides a comprehensive API for controlling JW Player playback, playlists, and tracks.
12
+
13
+ ## Key Features
14
+
15
+ - Always fullscreen player
16
+ - Supports both single videos and playlists
17
+ - Complete control over playback (play, pause, seek, etc.)
18
+ - Audio track selection
19
+ - Caption/subtitle support
20
+ - Event listeners for player state changes
21
+ Playes videos from jwplayer.com
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ npm install @capgo/capacitor-jw-player
27
+ npx cap sync
28
+ ```
29
+
30
+ ## Usage Examples
31
+
32
+ ### Basic Setup and Playback
33
+
34
+ ```typescript
35
+ import { JwPlayer } from '@capgo/capacitor-jw-player';
36
+
37
+ // Initialize the player with your license key
38
+ await JwPlayer.initialize({
39
+ licenseKey: 'YOUR_JW_PLAYER_LICENSE_KEY'
40
+ });
41
+
42
+ // Play a video
43
+ await JwPlayer.play({
44
+ mediaUrl: 'https://example.com/video.mp4',
45
+ mediaType: 'video'
46
+ });
47
+
48
+ // Play a playlist
49
+ await JwPlayer.play({
50
+ mediaUrl: 'https://cdn.jwplayer.com/v2/playlists/PLAYLIST_ID',
51
+ mediaType: 'playlist'
52
+ });
53
+ ```
54
+
55
+ ### Playback Controls
56
+
57
+ ```typescript
58
+ // Pause playback
59
+ await JwPlayer.pause();
60
+
61
+ // Resume playback
62
+ // Note: No need to call play() again with the URL, it resumes current content
63
+ await JwPlayer.play();
64
+
65
+ // Seek to a specific position (in seconds)
66
+ await JwPlayer.seekTo({ time: 30 });
67
+
68
+ // Set volume (0.0 to 1.0)
69
+ await JwPlayer.setVolume({ volume: 0.5 });
70
+
71
+ // Change playback speed
72
+ await JwPlayer.setSpeed({ speed: 1.5 });
73
+
74
+ // Stop and release the player
75
+ await JwPlayer.stop();
76
+ ```
77
+
78
+ ### Working with Playlists
79
+
80
+ ```typescript
81
+ // Load a playlist by URL
82
+ await JwPlayer.loadPlaylist({
83
+ playlistUrl: 'https://cdn.jwplayer.com/v2/playlists/PLAYLIST_ID'
84
+ });
85
+
86
+ // Load a playlist with custom items
87
+ await JwPlayer.loadPlaylistWithItems({
88
+ playlist: [
89
+ { file: 'https://example.com/video1.mp4', title: 'Video 1' },
90
+ { file: 'https://example.com/video2.mp4', title: 'Video 2' }
91
+ ]
92
+ });
93
+
94
+ // Jump to a specific item in the playlist
95
+ await JwPlayer.setPlaylistIndex({ index: 2 });
96
+
97
+ // Get information about the current playlist
98
+ const playlistInfo = await JwPlayer.currentPlaylist();
99
+ console.log(playlistInfo.playlist);
100
+ ```
101
+
102
+ ### Audio and Caption Tracks
103
+
104
+ ```typescript
105
+ // Get available audio tracks
106
+ const { tracks } = await JwPlayer.getAudioTracks();
107
+ console.log('Available audio tracks:', tracks);
108
+
109
+ // Get current audio track
110
+ const { index } = await JwPlayer.getCurrentAudioTrack();
111
+ console.log('Current audio track index:', index);
112
+
113
+ // Set audio track
114
+ await JwPlayer.setCurrentAudioTrack({ index: 1 });
115
+
116
+ // Get available captions
117
+ const { captions } = await JwPlayer.getCaptions();
118
+ console.log('Available captions:', captions);
119
+
120
+ // Set captions track (0 is usually "Off")
121
+ await JwPlayer.setCurrentCaptions({ index: 1 });
122
+ ```
123
+
124
+ ### Event Listeners
125
+
126
+ ```typescript
127
+ import { JwPlayer } from '@capgo/capacitor-jw-player';
128
+
129
+ // Listen for player ready event
130
+ JwPlayer.addListener('ready', () => {
131
+ console.log('Player is ready');
132
+ });
133
+
134
+ // Listen for playback state changes
135
+ JwPlayer.addListener('play', () => {
136
+ console.log('Playback started');
137
+ });
138
+
139
+ JwPlayer.addListener('pause', (data) => {
140
+ console.log('Playback paused, reason:', data.reason);
141
+ });
142
+
143
+ JwPlayer.addListener('complete', () => {
144
+ console.log('Playback completed');
145
+ });
146
+
147
+ // Listen for time updates
148
+ JwPlayer.addListener('time', (data) => {
149
+ console.log(`Position: ${data.position}, Duration: ${data.duration}`);
150
+ });
151
+
152
+ // Listen for playlist changes
153
+ JwPlayer.addListener('playlist', (data) => {
154
+ console.log(`Playlist loaded with ${data.playlistSize} items`);
155
+ });
156
+
157
+ JwPlayer.addListener('playlistItem', (data) => {
158
+ console.log(`Now playing item at index ${data.index}`);
159
+ });
160
+
161
+ // Listen for errors
162
+ JwPlayer.addListener('error', (data) => {
163
+ console.error('Player error:', data.message);
164
+ });
165
+
166
+ // Clean up listeners when done
167
+ function cleanup() {
168
+ JwPlayer.removeAllListeners();
169
+ }
170
+ ```
171
+
172
+ ## API
173
+
174
+ <docgen-index>
175
+
176
+ * [`initialize(...)`](#initialize)
177
+ * [`play(...)`](#play)
178
+ * [`pause()`](#pause)
179
+ * [`resume()`](#resume)
180
+ * [`stop()`](#stop)
181
+ * [`seekTo(...)`](#seekto)
182
+ * [`setVolume(...)`](#setvolume)
183
+ * [`getPosition()`](#getposition)
184
+ * [`getState()`](#getstate)
185
+ * [`setSpeed(...)`](#setspeed)
186
+ * [`setPlaylistIndex(...)`](#setplaylistindex)
187
+ * [`loadPlaylist(...)`](#loadplaylist)
188
+ * [`loadPlaylistWithItems(...)`](#loadplaylistwithitems)
189
+ * [`getAudioTracks()`](#getaudiotracks)
190
+ * [`getCurrentAudioTrack()`](#getcurrentaudiotrack)
191
+ * [`setCurrentAudioTrack(...)`](#setcurrentaudiotrack)
192
+ * [`getCaptions()`](#getcaptions)
193
+ * [`getCurrentCaptions()`](#getcurrentcaptions)
194
+ * [`setCurrentCaptions(...)`](#setcurrentcaptions)
195
+ * [`currentPlaylist()`](#currentplaylist)
196
+
197
+ </docgen-index>
198
+
199
+ <docgen-api>
200
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
201
+
202
+ ### initialize(...)
203
+
204
+ ```typescript
205
+ initialize(options: { licenseKey: string; }) => Promise<void>
206
+ ```
207
+
208
+ Initialize the JW Player
209
+
210
+ | Param | Type | Description |
211
+ | ------------- | ------------------------------------ | ------------------------------- |
212
+ | **`options`** | <code>{ licenseKey: string; }</code> | - The options for the JW Player |
213
+
214
+ --------------------
215
+
216
+
217
+ ### play(...)
218
+
219
+ ```typescript
220
+ play(options: { mediaUrl: string; mediaType: 'video' | 'playlist'; }) => Promise<void>
221
+ ```
222
+
223
+ Play a video
224
+
225
+ | Param | Type | Description |
226
+ | ------------- | -------------------------------------------------------------------- | ------------------------------- |
227
+ | **`options`** | <code>{ mediaUrl: string; mediaType: 'video' \| 'playlist'; }</code> | - The options for the JW Player |
228
+
229
+ --------------------
230
+
231
+
232
+ ### pause()
233
+
234
+ ```typescript
235
+ pause() => Promise<void>
236
+ ```
237
+
238
+ Pause the currently playing media
239
+
240
+ --------------------
241
+
242
+
243
+ ### resume()
244
+
245
+ ```typescript
246
+ resume() => Promise<void>
247
+ ```
248
+
249
+ Resume the currently paused media
250
+
251
+ --------------------
252
+
253
+
254
+ ### stop()
255
+
256
+ ```typescript
257
+ stop() => Promise<void>
258
+ ```
259
+
260
+ Stop the currently playing media
261
+
262
+ --------------------
263
+
264
+
265
+ ### seekTo(...)
266
+
267
+ ```typescript
268
+ seekTo(options: { time: number; }) => Promise<void>
269
+ ```
270
+
271
+ Seek to a specific position in the currently playing media
272
+
273
+ | Param | Type | Description |
274
+ | ------------- | ------------------------------ | --------------------- |
275
+ | **`options`** | <code>{ time: number; }</code> | - Options for seeking |
276
+
277
+ --------------------
278
+
279
+
280
+ ### setVolume(...)
281
+
282
+ ```typescript
283
+ setVolume(options: { volume: number; }) => Promise<void>
284
+ ```
285
+
286
+ Set the volume level
287
+
288
+ | Param | Type | Description |
289
+ | ------------- | -------------------------------- | ---------------------------- |
290
+ | **`options`** | <code>{ volume: number; }</code> | - Options for setting volume |
291
+
292
+ --------------------
293
+
294
+
295
+ ### getPosition()
296
+
297
+ ```typescript
298
+ getPosition() => Promise<{ position: number; }>
299
+ ```
300
+
301
+ Get the current position in the media
302
+
303
+ **Returns:** <code>Promise&lt;{ position: number; }&gt;</code>
304
+
305
+ --------------------
306
+
307
+
308
+ ### getState()
309
+
310
+ ```typescript
311
+ getState() => Promise<{ state: number; }>
312
+ ```
313
+
314
+ Get the current player state
315
+
316
+ **Returns:** <code>Promise&lt;{ state: number; }&gt;</code>
317
+
318
+ --------------------
319
+
320
+
321
+ ### setSpeed(...)
322
+
323
+ ```typescript
324
+ setSpeed(options: { speed: number; }) => Promise<void>
325
+ ```
326
+
327
+ Set the playback speed
328
+
329
+ | Param | Type | Description |
330
+ | ------------- | ------------------------------- | --------------------------- |
331
+ | **`options`** | <code>{ speed: number; }</code> | - Options for setting speed |
332
+
333
+ --------------------
334
+
335
+
336
+ ### setPlaylistIndex(...)
337
+
338
+ ```typescript
339
+ setPlaylistIndex(options: { index: number; }) => Promise<void>
340
+ ```
341
+
342
+ Set the current item in the playlist by index
343
+
344
+ | Param | Type | Description |
345
+ | ------------- | ------------------------------- | ----------------------------------- |
346
+ | **`options`** | <code>{ index: number; }</code> | - Options for setting playlist item |
347
+
348
+ --------------------
349
+
350
+
351
+ ### loadPlaylist(...)
352
+
353
+ ```typescript
354
+ loadPlaylist(options: { playlistUrl: string; }) => Promise<void>
355
+ ```
356
+
357
+ Load a playlist
358
+
359
+ | Param | Type | Description |
360
+ | ------------- | ------------------------------------- | -------------------------------- |
361
+ | **`options`** | <code>{ playlistUrl: string; }</code> | - Options for loading a playlist |
362
+
363
+ --------------------
364
+
365
+
366
+ ### loadPlaylistWithItems(...)
367
+
368
+ ```typescript
369
+ loadPlaylistWithItems(options: { playlist: any[]; }) => Promise<void>
370
+ ```
371
+
372
+ Load a playlist with items
373
+
374
+ | Param | Type | Description |
375
+ | ------------- | --------------------------------- | -------------------------------- |
376
+ | **`options`** | <code>{ playlist: any[]; }</code> | - Options for loading a playlist |
377
+
378
+ --------------------
379
+
380
+
381
+ ### getAudioTracks()
382
+
383
+ ```typescript
384
+ getAudioTracks() => Promise<{ tracks: any[]; }>
385
+ ```
386
+
387
+ Get available audio tracks
388
+
389
+ **Returns:** <code>Promise&lt;{ tracks: any[]; }&gt;</code>
390
+
391
+ --------------------
392
+
393
+
394
+ ### getCurrentAudioTrack()
395
+
396
+ ```typescript
397
+ getCurrentAudioTrack() => Promise<{ index: number; }>
398
+ ```
399
+
400
+ Get the current audio track
401
+
402
+ **Returns:** <code>Promise&lt;{ index: number; }&gt;</code>
403
+
404
+ --------------------
405
+
406
+
407
+ ### setCurrentAudioTrack(...)
408
+
409
+ ```typescript
410
+ setCurrentAudioTrack(options: { index: number; }) => Promise<void>
411
+ ```
412
+
413
+ Set the current audio track
414
+
415
+ | Param | Type | Description |
416
+ | ------------- | ------------------------------- | --------------------------------- |
417
+ | **`options`** | <code>{ index: number; }</code> | - Options for setting audio track |
418
+
419
+ --------------------
420
+
421
+
422
+ ### getCaptions()
423
+
424
+ ```typescript
425
+ getCaptions() => Promise<{ captions: any[]; }>
426
+ ```
427
+
428
+ Get the available captions/subtitles
429
+
430
+ **Returns:** <code>Promise&lt;{ captions: any[]; }&gt;</code>
431
+
432
+ --------------------
433
+
434
+
435
+ ### getCurrentCaptions()
436
+
437
+ ```typescript
438
+ getCurrentCaptions() => Promise<{ index: number; }>
439
+ ```
440
+
441
+ Get the current captions/subtitles track
442
+
443
+ **Returns:** <code>Promise&lt;{ index: number; }&gt;</code>
444
+
445
+ --------------------
446
+
447
+
448
+ ### setCurrentCaptions(...)
449
+
450
+ ```typescript
451
+ setCurrentCaptions(options: { index: number; }) => Promise<void>
452
+ ```
453
+
454
+ Set the current captions/subtitles track
455
+
456
+ | Param | Type | Description |
457
+ | ------------- | ------------------------------- | ------------------------------------ |
458
+ | **`options`** | <code>{ index: number; }</code> | - Options for setting captions track |
459
+
460
+ --------------------
461
+
462
+
463
+ ### currentPlaylist()
464
+
465
+ ```typescript
466
+ currentPlaylist() => Promise<any>
467
+ ```
468
+
469
+ Get the current playlist
470
+
471
+ **Returns:** <code>Promise&lt;any&gt;</code>
472
+
473
+ --------------------
474
+
475
+ </docgen-api>
476
+
477
+ ## Event Listeners
478
+
479
+ The plugin emits the following events that you can listen for:
480
+
481
+ | Event | Description | Data |
482
+ | ----- | ----------- | ---- |
483
+ | `ready` | Player is ready to use | None |
484
+ | `play` | Playback has started | None |
485
+ | `pause` | Playback is paused | `{ reason: number }` |
486
+ | `complete` | Playback of the current item is complete | None |
487
+ | `time` | Playback time has updated | `{ position: number, duration: number }` |
488
+ | `setupError` | Error during setup | `{ code: number, message: string }` |
489
+ | `error` | General playback error | `{ code: number, message: string }` |
490
+ | `warning` | Player warning | `{ code: number, message: string }` |
491
+ | `playlist` | Playlist has been loaded | `{ playlistSize: number }` |
492
+ | `playlistItem` | Current playlist item has changed | `{ index: number, file: string, title: string }` |
493
+ | `playerDismissed` | Player has been closed/dismissed | None |
@@ -0,0 +1,83 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.7.2'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace "ee.forgr.capacitor_jw_player"
22
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ maven {
49
+ url 'https://mvn.jwplayer.com/content/repositories/releases/'
50
+ }
51
+ }
52
+
53
+ def jwPlayerVersion = "4.19.0"
54
+ def media3ExoVersion = "1.1.1"
55
+
56
+ dependencies {
57
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
58
+ implementation project(':capacitor-android')
59
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
60
+
61
+ implementation 'com.google.android.material:material:1.12.0'
62
+
63
+ implementation "com.jwplayer:jwplayer-core:$jwPlayerVersion"
64
+ implementation "com.jwplayer:jwplayer-common:$jwPlayerVersion"
65
+
66
+ implementation "androidx.media3:media3-common:$media3ExoVersion"
67
+ implementation "androidx.media3:media3-exoplayer:$media3ExoVersion"
68
+ implementation "androidx.media3:media3-exoplayer-dash:$media3ExoVersion"
69
+ implementation "androidx.media3:media3-exoplayer-hls:$media3ExoVersion"
70
+ implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3ExoVersion"
71
+ implementation "androidx.media3:media3-ui:$media3ExoVersion"
72
+
73
+ implementation 'com.squareup.picasso:picasso:2.71828'
74
+ implementation 'androidx.viewpager2:viewpager2:1.0.0'
75
+ implementation 'com.android.volley:volley:1.2.1'
76
+ implementation 'androidx.recyclerview:recyclerview:1.3.0'
77
+ implementation 'androidx.mediarouter:mediarouter:1.4.0'
78
+ implementation 'androidx.media:media:1.6.0'
79
+
80
+ testImplementation "junit:junit:$junitVersion"
81
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
82
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
83
+ }
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ xmlns:tools="http://schemas.android.com/tools"
4
+ package="ee.forgr.capacitor_jw_player"
5
+ tools:overrideLibrary="com.longtailvideo.jwplayer">
6
+
7
+ <!-- Core Permissions -->
8
+ <uses-permission android:name="android.permission.INTERNET" />
9
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
10
+
11
+ <!-- Background Playback / Notifications -->
12
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
13
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
14
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
15
+
16
+ <application>
17
+ <activity
18
+ android:name=".PlayerActivity"
19
+ android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
20
+ android:theme="@style/JWPlayerTheme"
21
+ android:supportsPictureInPicture="true"
22
+ android:autoRemoveFromRecents="false"
23
+ android:excludeFromRecents="false"
24
+ />
25
+ <!-- Changed from AppCompat.NoActionBar to JWPlayerTheme -->
26
+
27
+ <!-- JW Player Media Service for background audio/notifications -->
28
+ <service
29
+ android:name="com.jwplayer.pub.api.background.MediaService"
30
+ android:foregroundServiceType="mediaPlayback"
31
+ android:exported="false">
32
+ <intent-filter>
33
+ <action android:name="android.intent.action.MEDIA_BUTTON" />
34
+ </intent-filter>
35
+ </service>
36
+ </application>
37
+ </manifest>