@capgo/capacitor-jw-player 0.0.1 → 0.0.12

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.
@@ -13,6 +13,8 @@ Pod::Spec.new do |s|
13
13
  s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
14
  s.ios.deployment_target = '14.0'
15
15
  s.dependency 'Capacitor'
16
- s.dependency 'JWPlayerKit'
16
+ s.dependency 'JWPlayerKit', '>= 4.0.0'
17
+ s.dependency 'google-cast-sdk', '>= 4.8.1'
18
+ s.dependency 'Protobuf', '>= 3.13'
17
19
  s.swift_version = '5.1'
18
20
  end
package/Package.swift CHANGED
@@ -1,6 +1,11 @@
1
1
  // swift-tools-version: 5.9
2
2
  import PackageDescription
3
3
 
4
+ struct GoogleCastMetadata {
5
+ static let version: String = "4.8.3"
6
+ static let checksum: String = "bc2c3c2434ef2895a0388ac3f16932242d3d3ac11805f810dbe7d7bce3bb27f6"
7
+ }
8
+
4
9
  let package = Package(
5
10
  name: "CapgoCapacitorJwPlayer",
6
11
  platforms: [.iOS(.v14)],
@@ -10,8 +15,8 @@ let package = Package(
10
15
  targets: ["JwPlayerPlugin"])
11
16
  ],
12
17
  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"))
18
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "7.2.0"),
19
+ .package(url: "https://github.com/jwplayer/JWPlayerKit-package.git", .upToNextMajor(from: "4.22.0"))
15
20
  ],
16
21
  targets: [
17
22
  .target(
@@ -22,6 +27,11 @@ let package = Package(
22
27
  .product(name: "JWPlayerKit", package: "JWPlayerKit-package")
23
28
  ],
24
29
  path: "ios/Sources/JwPlayerPlugin"),
30
+ .binaryTarget(
31
+ name: "GoogleCast",
32
+ url: "https://dl.google.com/dl/chromecast/sdk/ios/GoogleCastSDK-ios-\(GoogleCastMetadata.version)_dynamic.xcframework.zip",
33
+ checksum: GoogleCastMetadata.checksum
34
+ ),
25
35
  .testTarget(
26
36
  name: "JwPlayerPluginTests",
27
37
  dependencies: ["JwPlayerPlugin"],
package/README.md CHANGED
@@ -27,6 +27,21 @@ npm install @capgo/capacitor-jw-player
27
27
  npx cap sync
28
28
  ```
29
29
 
30
+ ## Android
31
+
32
+ Edit `build.gradle` in order for the plugin to work:
33
+ ```gradle
34
+ allprojects {
35
+ repositories {
36
+ google()
37
+ mavenCentral()
38
+ maven {
39
+ url 'https://mvn.jwplayer.com/content/repositories/releases/'
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
30
45
  ## Usage Examples
31
46
 
32
47
  ### Basic Setup and Playback
@@ -217,14 +232,14 @@ Initialize the JW Player
217
232
  ### play(...)
218
233
 
219
234
  ```typescript
220
- play(options: { mediaUrl: string; mediaType: 'video' | 'playlist'; }) => Promise<void>
235
+ play(options: { mediaUrl: string; mediaType: 'video' | 'playlist'; autostart?: boolean; }) => Promise<void>
221
236
  ```
222
237
 
223
238
  Play a video
224
239
 
225
- | Param | Type | Description |
226
- | ------------- | -------------------------------------------------------------------- | ------------------------------- |
227
- | **`options`** | <code>{ mediaUrl: string; mediaType: 'video' \| 'playlist'; }</code> | - The options for the JW Player |
240
+ | Param | Type | Description |
241
+ | ------------- | ----------------------------------------------------------------------------------------- | ------------------------------- |
242
+ | **`options`** | <code>{ mediaUrl: string; mediaType: 'video' \| 'playlist'; autostart?: boolean; }</code> | - The options for the JW Player |
228
243
 
229
244
  --------------------
230
245
 
@@ -62,6 +62,7 @@ dependencies {
62
62
 
63
63
  implementation "com.jwplayer:jwplayer-core:$jwPlayerVersion"
64
64
  implementation "com.jwplayer:jwplayer-common:$jwPlayerVersion"
65
+ implementation "com.jwplayer:jwplayer-chromecast:$jwPlayerVersion"
65
66
 
66
67
  implementation "androidx.media3:media3-common:$media3ExoVersion"
67
68
  implementation "androidx.media3:media3-exoplayer:$media3ExoVersion"
@@ -14,6 +14,11 @@
14
14
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
15
15
 
16
16
  <application>
17
+
18
+ <meta-data
19
+ android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
20
+ android:value="ee.forgr.capacitor_jw_player.CastOptionsProvider" />
21
+
17
22
  <activity
18
23
  android:name=".PlayerActivity"
19
24
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
@@ -0,0 +1,30 @@
1
+ package ee.forgr.capacitor_jw_player;
2
+
3
+ import android.content.Context;
4
+ import androidx.annotation.NonNull;
5
+ import com.google.android.gms.cast.CastMediaControlIntent;
6
+ import com.google.android.gms.cast.LaunchOptions;
7
+ import com.google.android.gms.cast.framework.CastOptions;
8
+ import com.google.android.gms.cast.framework.OptionsProvider;
9
+ import com.google.android.gms.cast.framework.SessionProvider;
10
+ import java.util.List;
11
+ import java.util.Locale;
12
+
13
+ public class CastOptionsProvider implements OptionsProvider {
14
+
15
+ @NonNull
16
+ @Override
17
+ public CastOptions getCastOptions(@NonNull Context context) {
18
+ LaunchOptions launchOptions = new LaunchOptions.Builder().setLocale(Locale.US).build();
19
+
20
+ return new CastOptions.Builder()
21
+ .setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)
22
+ .setLaunchOptions(launchOptions)
23
+ .build();
24
+ }
25
+
26
+ @Override
27
+ public List<SessionProvider> getAdditionalSessionProviders(Context context) {
28
+ return null;
29
+ }
30
+ }
@@ -2,23 +2,22 @@ package ee.forgr.capacitor_jw_player;
2
2
 
3
3
  import android.content.Intent;
4
4
  import android.util.Log;
5
-
6
5
  import com.getcapacitor.JSArray;
7
6
  import com.getcapacitor.JSObject;
8
7
  import com.getcapacitor.Plugin;
9
8
  import com.getcapacitor.PluginCall;
10
9
  import com.getcapacitor.PluginMethod;
11
10
  import com.getcapacitor.annotation.CapacitorPlugin;
11
+ import com.google.android.gms.cast.framework.CastContext;
12
12
  import com.jwplayer.pub.api.JWPlayer;
13
13
  import com.jwplayer.pub.api.configuration.PlayerConfig;
14
14
  import com.jwplayer.pub.api.license.LicenseUtil;
15
- import com.jwplayer.pub.api.media.playlists.PlaylistItem;
16
15
  import com.jwplayer.pub.api.media.audio.AudioTrack;
17
16
  import com.jwplayer.pub.api.media.captions.Caption;
18
-
17
+ import com.jwplayer.pub.api.media.playlists.PlaylistItem;
19
18
  import java.lang.ref.WeakReference;
20
- import java.util.List;
21
19
  import java.util.ArrayList;
20
+ import java.util.List;
22
21
 
23
22
  @CapacitorPlugin(name = "JwPlayer")
24
23
  public class JwPlayerPlugin extends Plugin {
@@ -54,6 +53,7 @@ public class JwPlayerPlugin extends Plugin {
54
53
  public void play(PluginCall call) {
55
54
  String mediaUrl = call.getString("mediaUrl");
56
55
  String mediaType = call.getString("mediaType");
56
+ boolean autostart = Boolean.TRUE.equals(call.getBoolean("autostart", false));
57
57
 
58
58
  if (mediaUrl == null || mediaUrl.isEmpty()) {
59
59
  call.reject("mediaUrl is required for play");
@@ -69,10 +69,11 @@ public class JwPlayerPlugin extends Plugin {
69
69
  Intent intent = new Intent(getContext(), PlayerActivity.class);
70
70
  intent.putExtra(PlayerActivity.EXTRA_MEDIA_URL, mediaUrl);
71
71
  intent.putExtra(PlayerActivity.EXTRA_MEDIA_TYPE, mediaType);
72
+ intent.putExtra(PlayerActivity.AUTOSTART, autostart);
72
73
  getActivity().startActivity(intent);
73
74
 
74
75
  // We resolve immediately, actual playback state comes via events
75
- call.resolve();
76
+ call.resolve();
76
77
  }
77
78
 
78
79
  @PluginMethod
@@ -89,7 +90,7 @@ public class JwPlayerPlugin extends Plugin {
89
90
  @PluginMethod
90
91
  public void resume(PluginCall call) {
91
92
  Log.d(TAG, "Resume called");
92
- if (staticPlayerInstance != null) {
93
+ if (staticPlayerInstance != null) {
93
94
  staticPlayerInstance.play();
94
95
  call.resolve();
95
96
  } else {
@@ -100,15 +101,15 @@ public class JwPlayerPlugin extends Plugin {
100
101
  @PluginMethod
101
102
  public void stop(PluginCall call) {
102
103
  Log.d(TAG, "Stop called");
103
- if (staticPlayerInstance != null) {
104
+ if (staticPlayerInstance != null) {
104
105
  staticPlayerInstance.stop();
105
- // Consider finishing PlayerActivity here? Maybe PlayerActivity should finish itself on stop.
106
+ // Consider finishing PlayerActivity here? Maybe PlayerActivity should finish itself on stop.
106
107
  call.resolve();
107
108
  } else {
108
109
  call.reject("Player not active");
109
110
  }
110
111
  }
111
-
112
+
112
113
  @PluginMethod
113
114
  public void seekTo(PluginCall call) {
114
115
  Double time = call.getDouble("time");
@@ -116,14 +117,14 @@ public class JwPlayerPlugin extends Plugin {
116
117
  call.reject("time parameter is required");
117
118
  return;
118
119
  }
119
- if (staticPlayerInstance != null) {
120
+ if (staticPlayerInstance != null) {
120
121
  staticPlayerInstance.seek(time);
121
122
  call.resolve();
122
123
  } else {
123
124
  call.reject("Player not active");
124
125
  }
125
126
  }
126
-
127
+
127
128
  @PluginMethod
128
129
  public void setVolume(PluginCall call) {
129
130
  Double volume = call.getDouble("volume"); // JW Player Android uses 0-100
@@ -131,9 +132,9 @@ public class JwPlayerPlugin extends Plugin {
131
132
  call.reject("volume parameter is required");
132
133
  return;
133
134
  }
134
- if (staticPlayerInstance != null) {
135
+ if (staticPlayerInstance != null) {
135
136
  // Cast the result to int
136
- staticPlayerInstance.setVolume((int) (volume.floatValue() * 100));
137
+ staticPlayerInstance.setVolume((int) (volume.floatValue() * 100));
137
138
  call.resolve();
138
139
  } else {
139
140
  call.reject("Player not active");
@@ -147,15 +148,15 @@ public class JwPlayerPlugin extends Plugin {
147
148
  call.reject("speed parameter is required");
148
149
  return;
149
150
  }
150
- if (staticPlayerInstance != null) {
151
+ if (staticPlayerInstance != null) {
151
152
  staticPlayerInstance.setPlaybackRate(speed.floatValue());
152
153
  call.resolve();
153
154
  } else {
154
155
  call.reject("Player not active");
155
156
  }
156
157
  }
157
-
158
- @PluginMethod
158
+
159
+ @PluginMethod
159
160
  public void getPosition(PluginCall call) {
160
161
  if (staticPlayerInstance != null) {
161
162
  JSObject ret = new JSObject();
@@ -178,7 +179,7 @@ public class JwPlayerPlugin extends Plugin {
178
179
  call.reject("Player not active", "-1"); // Return -1 or similar on error
179
180
  }
180
181
  }
181
-
182
+
182
183
  @PluginMethod
183
184
  public void loadPlaylist(PluginCall call) {
184
185
  String playlistUrl = call.getString("playlistUrl");
@@ -189,16 +190,14 @@ public class JwPlayerPlugin extends Plugin {
189
190
  if (staticPlayerInstance != null) {
190
191
  Log.d(TAG, "Loading playlist from URL: " + playlistUrl);
191
192
  // Use PlayerConfig with a single playlist item URL
192
- PlaylistItem playlistItem = new PlaylistItem.Builder()
193
- .file(playlistUrl)
194
- .build();
193
+ PlaylistItem playlistItem = new PlaylistItem.Builder().file(playlistUrl).build();
195
194
  List<PlaylistItem> playlist = new ArrayList<>();
196
195
  playlist.add(playlistItem);
197
196
  PlayerConfig config = new PlayerConfig.Builder()
198
- .playlist(playlist)
199
- // Autostart false when just loading?
200
- .autostart(false)
201
- .build();
197
+ .playlist(playlist)
198
+ // Autostart false when just loading?
199
+ .autostart(false)
200
+ .build();
202
201
  staticPlayerInstance.setup(config); // Use setup for subsequent loads
203
202
  call.resolve();
204
203
  } else {
@@ -230,7 +229,7 @@ public class JwPlayerPlugin extends Plugin {
230
229
  if (!playlist.isEmpty()) {
231
230
  Log.d(TAG, "Loading playlist with " + playlist.size() + " items");
232
231
  // Use PlayerConfig for loading multiple items too
233
- PlayerConfig config = new PlayerConfig.Builder()
232
+ PlayerConfig config = new PlayerConfig.Builder()
234
233
  .playlist(playlist)
235
234
  .autostart(false) // Or true depending on desired behavior
236
235
  .build();
@@ -388,7 +387,7 @@ public class JwPlayerPlugin extends Plugin {
388
387
  }
389
388
  }
390
389
 
391
- // --- Static methods for PlayerActivity Communication ---
390
+ // --- Static methods for PlayerActivity Communication ---
392
391
 
393
392
  public static void setStaticPlayerInstance(JWPlayer player) {
394
393
  Log.d(TAG, "Setting static player instance: " + (player != null));
@@ -403,7 +402,7 @@ public class JwPlayerPlugin extends Plugin {
403
402
  plugin.notifyListeners("playerDismissed", null);
404
403
  }
405
404
  }
406
-
405
+
407
406
  public static void notifyPipChanged(boolean isInPip) {
408
407
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
409
408
  if (plugin != null) {
@@ -430,8 +429,8 @@ public class JwPlayerPlugin extends Plugin {
430
429
  plugin.notifyListeners(type, data);
431
430
  }
432
431
  }
433
-
434
- public static void notifyWarning(String type, String message) {
432
+
433
+ public static void notifyWarning(String type, String message) {
435
434
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
436
435
  if (plugin != null) {
437
436
  JSObject data = new JSObject();
@@ -441,26 +440,26 @@ public class JwPlayerPlugin extends Plugin {
441
440
  }
442
441
 
443
442
  public static void notifyPlaylistItem(int index, PlaylistItem item) {
444
- JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
443
+ JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
445
444
  if (plugin != null) {
446
445
  JSObject data = new JSObject();
447
446
  data.put("index", index);
448
447
  if (item != null) {
449
- data.put("title", item.getTitle());
450
- // data.put("file", item.getFile()); // Be careful with accessing file directly
448
+ data.put("title", item.getTitle());
449
+ // data.put("file", item.getFile()); // Be careful with accessing file directly
451
450
  }
452
451
  plugin.notifyListeners("playlistItem", data);
453
452
  }
454
453
  }
455
-
454
+
456
455
  public static void notifyPlaylistComplete() {
457
456
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
458
457
  if (plugin != null) {
459
458
  plugin.notifyListeners("complete", null); // Maybe playlistComplete event?
460
459
  }
461
460
  }
462
-
463
- public static void notifyPause(String reason) {
461
+
462
+ public static void notifyPause(String reason) {
464
463
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
465
464
  if (plugin != null) {
466
465
  JSObject data = new JSObject();
@@ -468,62 +467,67 @@ public class JwPlayerPlugin extends Plugin {
468
467
  plugin.notifyListeners("pause", data);
469
468
  }
470
469
  }
471
-
470
+
472
471
  public static void notifyPlay(String reason) {
473
472
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
474
473
  if (plugin != null) {
475
474
  JSObject data = new JSObject();
476
- data.put("reason", reason); // Android uses enum names
475
+ data.put("reason", reason); // Android uses enum names
477
476
  plugin.notifyListeners("play", data);
478
477
  }
479
478
  }
480
-
481
- public static void notifyComplete() {
479
+
480
+ public static void notifyComplete() {
482
481
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
483
482
  if (plugin != null) {
484
483
  plugin.notifyListeners("complete", null);
485
484
  }
486
485
  }
487
-
488
- public static void notifySeek(double position, double offset) {
486
+
487
+ public static void notifySeek(double position, double offset) {
489
488
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
490
489
  if (plugin != null) {
491
- JSObject data = new JSObject();
492
- data.put("position", position);
493
- data.put("offset", offset);
490
+ JSObject data = new JSObject();
491
+ data.put("position", position);
492
+ data.put("offset", offset);
494
493
  plugin.notifyListeners("seek", data);
495
494
  }
496
495
  }
497
-
498
- public static void notifySeeked() {
496
+
497
+ public static void notifySeeked() {
499
498
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
500
499
  if (plugin != null) {
501
500
  plugin.notifyListeners("seeked", null);
502
501
  }
503
502
  }
504
-
505
- public static void notifyTime(double position, double duration) {
503
+
504
+ public static void notifyTime(double position, double duration) {
506
505
  JwPlayerPlugin plugin = staticPluginRef != null ? staticPluginRef.get() : null;
507
506
  if (plugin != null) {
508
- JSObject data = new JSObject();
509
- data.put("position", position);
510
- data.put("duration", duration);
507
+ JSObject data = new JSObject();
508
+ data.put("position", position);
509
+ data.put("duration", duration);
511
510
  plugin.notifyListeners("time", data);
512
511
  }
513
512
  }
514
-
513
+
515
514
  // Helper to map Android state enum to iOS-like integers
516
515
  private int mapPlayerStateToInt(com.jwplayer.pub.api.PlayerState state) {
517
516
  switch (state) {
518
- case IDLE: return 0;
519
- case BUFFERING: return 1;
520
- case PLAYING: return 2;
521
- case PAUSED: return 3;
522
- case COMPLETE: return 4;
523
- default: return -1; // Unknown
517
+ case IDLE:
518
+ return 0;
519
+ case BUFFERING:
520
+ return 1;
521
+ case PLAYING:
522
+ return 2;
523
+ case PAUSED:
524
+ return 3;
525
+ case COMPLETE:
526
+ return 4;
527
+ default:
528
+ return -1; // Unknown
524
529
  }
525
530
  }
526
-
527
531
  // TODO: Implement other methods like loadPlaylist, getAudioTracks, setAudioTrack, getCaptions, setCaptions etc.
528
532
  // These will require more complex communication with the PlayerActivity or direct player interaction.
529
533
  }