@jwplayer/jwplayer-react-native 1.0.3 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -9
- package/RNJWPlayer.podspec +2 -2
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
- package/android/build.gradle +10 -3
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +279 -434
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +86 -33
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +7 -1
- package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +39 -2
- package/badges/version.svg +1 -1
- package/index.d.ts +21 -2
- package/index.js +38 -2
- package/ios/RNJWPlayer/RNJWPlayerView.swift +56 -6
- package/ios/RNJWPlayer/RNJWPlayerViewController.swift +14 -4
- package/ios/RNJWPlayer/RNJWPlayerViewManager.m +4 -1
- package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +222 -167
- package/ios/RNJWPlayer.xcodeproj/project.pbxproj +4 -2
- package/package.json +1 -1
- package/jwplayer-jwplayer-react-native-1.0.3.tgz +0 -0
|
@@ -40,6 +40,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
|
|
|
40
40
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
41
41
|
import com.facebook.react.bridge.ReadableArray;
|
|
42
42
|
import com.facebook.react.bridge.ReadableMap;
|
|
43
|
+
import com.facebook.react.bridge.ReadableType;
|
|
43
44
|
import com.facebook.react.bridge.WritableArray;
|
|
44
45
|
import com.facebook.react.bridge.WritableMap;
|
|
45
46
|
import com.facebook.react.common.MapBuilder;
|
|
@@ -156,6 +157,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
156
157
|
VideoPlayerEvents.OnCaptionsListListener,
|
|
157
158
|
VideoPlayerEvents.OnCaptionsChangedListener,
|
|
158
159
|
VideoPlayerEvents.OnMetaListener,
|
|
160
|
+
VideoPlayerEvents.PlaylistItemCallbackListener,
|
|
159
161
|
|
|
160
162
|
CastingEvents.OnCastListener,
|
|
161
163
|
|
|
@@ -236,6 +238,9 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
236
238
|
private MediaServiceController mMediaServiceController;
|
|
237
239
|
private PipHandlerReceiver mReceiver = null;
|
|
238
240
|
|
|
241
|
+
// Add completion handler field
|
|
242
|
+
PlaylistItemDecision itemUpdatePromise = null;
|
|
243
|
+
|
|
239
244
|
private void doBindService() {
|
|
240
245
|
if (mMediaServiceController != null) {
|
|
241
246
|
if (!isBackgroundAudioServiceRunning()) {
|
|
@@ -379,6 +384,9 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
379
384
|
mActivity.getLifecycle().removeObserver(lifecycleObserver);
|
|
380
385
|
mPlayer.deregisterActivityForPip();
|
|
381
386
|
|
|
387
|
+
// Remove playlist item callback listener
|
|
388
|
+
mPlayer.removePlaylistItemCallbackListener();
|
|
389
|
+
|
|
382
390
|
mPlayer.removeListeners(this,
|
|
383
391
|
// VideoPlayerEvents
|
|
384
392
|
EventType.READY,
|
|
@@ -456,7 +464,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
456
464
|
}
|
|
457
465
|
}
|
|
458
466
|
|
|
459
|
-
public void setupPlayerView(Boolean backgroundAudioEnabled) {
|
|
467
|
+
public void setupPlayerView(Boolean backgroundAudioEnabled, Boolean playlistItemCallbackEnabled) {
|
|
460
468
|
if (mPlayer != null) {
|
|
461
469
|
|
|
462
470
|
mPlayer.addListeners(this,
|
|
@@ -470,6 +478,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
470
478
|
EventType.SETUP_ERROR,
|
|
471
479
|
EventType.BUFFER,
|
|
472
480
|
EventType.TIME,
|
|
481
|
+
EventType.AUDIO_TRACKS,
|
|
482
|
+
EventType.AUDIO_TRACK_CHANGED,
|
|
473
483
|
EventType.PLAYLIST,
|
|
474
484
|
EventType.PLAYLIST_ITEM,
|
|
475
485
|
EventType.PLAYLIST_COMPLETE,
|
|
@@ -519,9 +529,33 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
519
529
|
} else {
|
|
520
530
|
mPlayer.setFullscreenHandler(new fullscreenHandler());
|
|
521
531
|
}
|
|
522
|
-
|
|
523
532
|
mPlayer.allowBackgroundAudio(backgroundAudioEnabled);
|
|
533
|
+
|
|
534
|
+
if (playlistItemCallbackEnabled) {
|
|
535
|
+
mPlayer.setPlaylistItemCallbackListener(this);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
public void resolveNextPlaylistItem(ReadableMap playlistItem) {
|
|
541
|
+
if (itemUpdatePromise == null) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (playlistItem == null) {
|
|
546
|
+
itemUpdatePromise.continuePlayback();
|
|
547
|
+
itemUpdatePromise = null;
|
|
548
|
+
return;
|
|
524
549
|
}
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
PlaylistItem updatedPlaylistItem = Util.getPlaylistItem(playlistItem);
|
|
553
|
+
itemUpdatePromise.modify(updatedPlaylistItem);
|
|
554
|
+
} catch (Exception exception) {
|
|
555
|
+
itemUpdatePromise.continuePlayback();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
itemUpdatePromise = null;
|
|
525
559
|
}
|
|
526
560
|
|
|
527
561
|
/**
|
|
@@ -625,6 +659,18 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
625
659
|
return delegate;
|
|
626
660
|
}
|
|
627
661
|
|
|
662
|
+
@Override
|
|
663
|
+
public void onBeforeNextPlaylistItem(PlaylistItemDecision playlistItemDecision, PlaylistItem nextItem, int indexOfNextItem) {
|
|
664
|
+
WritableMap event = Arguments.createMap();
|
|
665
|
+
Gson gson = new Gson();
|
|
666
|
+
event.putString("message", "onBeforeNextPlaylistItem");
|
|
667
|
+
event.putInt("index", indexOfNextItem);
|
|
668
|
+
event.putString("playlistItem", gson.toJson(nextItem));
|
|
669
|
+
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topBeforeNextPlaylistItem", event);
|
|
670
|
+
|
|
671
|
+
itemUpdatePromise = playlistItemDecision;
|
|
672
|
+
}
|
|
673
|
+
|
|
628
674
|
private class fullscreenHandler implements FullscreenHandler {
|
|
629
675
|
ViewGroup mPlayerViewContainer = (ViewGroup) mPlayerView.getParent();
|
|
630
676
|
private View mDecorView;
|
|
@@ -901,7 +947,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
901
947
|
return differences.size() == 1 && differences.containsKey(keyName);
|
|
902
948
|
}
|
|
903
949
|
|
|
904
|
-
boolean playlistNotTheSame(ReadableMap prop) {
|
|
950
|
+
private boolean playlistNotTheSame(ReadableMap prop) {
|
|
905
951
|
return prop.hasKey("playlist") && mPlaylistProp != prop.getArray("playlist") && !Arrays
|
|
906
952
|
.deepEquals(new ReadableArray[]{mPlaylistProp}, new ReadableArray[]{prop.getArray("playlist")});
|
|
907
953
|
}
|
|
@@ -913,6 +959,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
913
959
|
JSONObject obj;
|
|
914
960
|
PlayerConfig jwConfig = null;
|
|
915
961
|
Boolean forceLegacy = prop.hasKey("forceLegacyConfig") ? prop.getBoolean("forceLegacyConfig") : false;
|
|
962
|
+
Boolean playlistItemCallbackEnabled = prop.hasKey("playlistItemCallbackEnabled") ? prop.getBoolean("playlistItemCallbackEnabled") : false;
|
|
916
963
|
Boolean isJwConfig = false;
|
|
917
964
|
if (!forceLegacy) {
|
|
918
965
|
try {
|
|
@@ -1019,9 +1066,11 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1019
1066
|
ReadableArray uiGroupsArray = prop.getArray("hideUIGroups");
|
|
1020
1067
|
UiConfig.Builder hideConfigBuilder = new UiConfig.Builder().displayAllControls();
|
|
1021
1068
|
for (int i = 0; i < uiGroupsArray.size(); i++) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1069
|
+
if (uiGroupsArray.getType(i) == ReadableType.String) {
|
|
1070
|
+
UiGroup uiGroup = GROUP_TYPES.get(uiGroupsArray.getString(i));
|
|
1071
|
+
if (uiGroup != null) {
|
|
1072
|
+
hideConfigBuilder.hide(uiGroup);
|
|
1073
|
+
}
|
|
1025
1074
|
}
|
|
1026
1075
|
}
|
|
1027
1076
|
UiConfig hideJwControlbarUiConfig = hideConfigBuilder.build();
|
|
@@ -1046,7 +1095,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1046
1095
|
addView(mPlayerView);
|
|
1047
1096
|
|
|
1048
1097
|
// Ensure we have a valid state before applying to the player
|
|
1049
|
-
registry.setCurrentState(
|
|
1098
|
+
registry.setCurrentState(registry.getCurrentState()); // This is a hack to ensure player and view know the lifecycle state
|
|
1050
1099
|
|
|
1051
1100
|
mPlayer = mPlayerView.getPlayer(this);
|
|
1052
1101
|
|
|
@@ -1150,7 +1199,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1150
1199
|
backgroundAudioEnabled = prop.getBoolean("backgroundAudioEnabled");
|
|
1151
1200
|
}
|
|
1152
1201
|
|
|
1153
|
-
setupPlayerView(backgroundAudioEnabled);
|
|
1202
|
+
setupPlayerView(backgroundAudioEnabled, playlistItemCallbackEnabled);
|
|
1154
1203
|
|
|
1155
1204
|
if (backgroundAudioEnabled) {
|
|
1156
1205
|
audioManager = (AudioManager) simpleContext.getSystemService(Context.AUDIO_SERVICE);
|
|
@@ -1312,7 +1361,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1312
1361
|
public void onAdLoaded(AdLoadedEvent adLoadedEvent) {
|
|
1313
1362
|
WritableMap event = Arguments.createMap();
|
|
1314
1363
|
event.putString("message", "onAdEvent");
|
|
1315
|
-
event.
|
|
1364
|
+
event.putInt("client", Util.getAdEventClientValue(adLoadedEvent));
|
|
1316
1365
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1317
1366
|
}
|
|
1318
1367
|
|
|
@@ -1320,7 +1369,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1320
1369
|
public void onAdLoadedXml(AdLoadedXmlEvent adLoadedXmlEvent) {
|
|
1321
1370
|
WritableMap event = Arguments.createMap();
|
|
1322
1371
|
event.putString("message", "onAdEvent");
|
|
1323
|
-
event.
|
|
1372
|
+
event.putInt("client", Util.getAdEventClientValue(adLoadedXmlEvent));
|
|
1324
1373
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1325
1374
|
}
|
|
1326
1375
|
|
|
@@ -1329,7 +1378,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1329
1378
|
WritableMap event = Arguments.createMap();
|
|
1330
1379
|
event.putString("message", "onAdEvent");
|
|
1331
1380
|
event.putString("reason", adPauseEvent.getAdPauseReason().toString());
|
|
1332
|
-
event.putInt("
|
|
1381
|
+
event.putInt("client", Util.getAdEventClientValue(adPauseEvent));
|
|
1382
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypePause));
|
|
1333
1383
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1334
1384
|
}
|
|
1335
1385
|
|
|
@@ -1338,7 +1388,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1338
1388
|
WritableMap event = Arguments.createMap();
|
|
1339
1389
|
event.putString("message", "onAdEvent");
|
|
1340
1390
|
event.putString("reason", adPlayEvent.getAdPlayReason().toString());
|
|
1341
|
-
event.putInt("
|
|
1391
|
+
event.putInt("client", Util.getAdEventClientValue(adPlayEvent));
|
|
1392
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypePlay));
|
|
1342
1393
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1343
1394
|
}
|
|
1344
1395
|
|
|
@@ -1346,8 +1397,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1346
1397
|
public void onAdBreakEnd(AdBreakEndEvent adBreakEndEvent) {
|
|
1347
1398
|
WritableMap event = Arguments.createMap();
|
|
1348
1399
|
event.putString("message", "onAdEvent");
|
|
1349
|
-
event.
|
|
1350
|
-
event.putInt("type", Util.
|
|
1400
|
+
event.putInt("client", Util.getAdEventClientValue(adBreakEndEvent));
|
|
1401
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakEnd));
|
|
1351
1402
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1352
1403
|
}
|
|
1353
1404
|
|
|
@@ -1355,8 +1406,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1355
1406
|
public void onAdBreakStart(AdBreakStartEvent adBreakStartEvent) {
|
|
1356
1407
|
WritableMap event = Arguments.createMap();
|
|
1357
1408
|
event.putString("message", "onAdEvent");
|
|
1358
|
-
event.
|
|
1359
|
-
event.putInt("type", Util.
|
|
1409
|
+
event.putInt("client", Util.getAdEventClientValue(adBreakStartEvent));
|
|
1410
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakStart));
|
|
1360
1411
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1361
1412
|
}
|
|
1362
1413
|
|
|
@@ -1364,7 +1415,7 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1364
1415
|
public void onAdBreakIgnored(AdBreakIgnoredEvent adBreakIgnoredEvent) {
|
|
1365
1416
|
WritableMap event = Arguments.createMap();
|
|
1366
1417
|
event.putString("message", "onAdEvent");
|
|
1367
|
-
event.
|
|
1418
|
+
event.putInt("client", Util.getAdEventClientValue(adBreakIgnoredEvent));
|
|
1368
1419
|
// missing type code
|
|
1369
1420
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1370
1421
|
}
|
|
@@ -1373,8 +1424,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1373
1424
|
public void onAdClick(AdClickEvent adClickEvent) {
|
|
1374
1425
|
WritableMap event = Arguments.createMap();
|
|
1375
1426
|
event.putString("message", "onAdEvent");
|
|
1376
|
-
event.
|
|
1377
|
-
event.putInt("type", Util.
|
|
1427
|
+
event.putInt("client", Util.getAdEventClientValue(adClickEvent));
|
|
1428
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeClicked));
|
|
1378
1429
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1379
1430
|
}
|
|
1380
1431
|
|
|
@@ -1382,7 +1433,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1382
1433
|
public void onAdCompanions(AdCompanionsEvent adCompanionsEvent) {
|
|
1383
1434
|
WritableMap event = Arguments.createMap();
|
|
1384
1435
|
event.putString("message", "onAdEvent");
|
|
1385
|
-
event.putInt("
|
|
1436
|
+
event.putInt("client", Util.getAdEventClientValue(adCompanionsEvent));
|
|
1437
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeCompanion));
|
|
1386
1438
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1387
1439
|
}
|
|
1388
1440
|
|
|
@@ -1390,8 +1442,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1390
1442
|
public void onAdComplete(AdCompleteEvent adCompleteEvent) {
|
|
1391
1443
|
WritableMap event = Arguments.createMap();
|
|
1392
1444
|
event.putString("message", "onAdEvent");
|
|
1393
|
-
event.
|
|
1394
|
-
event.putInt("type", Util.
|
|
1445
|
+
event.putInt("client", Util.getAdEventClientValue(adCompleteEvent));
|
|
1446
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeComplete));
|
|
1395
1447
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1396
1448
|
}
|
|
1397
1449
|
|
|
@@ -1419,8 +1471,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1419
1471
|
public void onAdImpression(AdImpressionEvent adImpressionEvent) {
|
|
1420
1472
|
WritableMap event = Arguments.createMap();
|
|
1421
1473
|
event.putString("message", "onAdEvent");
|
|
1422
|
-
event.
|
|
1423
|
-
event.putInt("type", Util.
|
|
1474
|
+
event.putInt("client", Util.getAdEventClientValue(adImpressionEvent));
|
|
1475
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeImpression));
|
|
1424
1476
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1425
1477
|
}
|
|
1426
1478
|
|
|
@@ -1428,8 +1480,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1428
1480
|
public void onAdMeta(AdMetaEvent adMetaEvent) {
|
|
1429
1481
|
WritableMap event = Arguments.createMap();
|
|
1430
1482
|
event.putString("message", "onAdEvent");
|
|
1431
|
-
event.
|
|
1432
|
-
event.putInt("type", Util.
|
|
1483
|
+
event.putInt("client", Util.getAdEventClientValue(adMetaEvent));
|
|
1484
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeMeta));
|
|
1433
1485
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1434
1486
|
}
|
|
1435
1487
|
|
|
@@ -1437,8 +1489,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1437
1489
|
public void onAdRequest(AdRequestEvent adRequestEvent) {
|
|
1438
1490
|
WritableMap event = Arguments.createMap();
|
|
1439
1491
|
event.putString("message", "onAdEvent");
|
|
1440
|
-
event.
|
|
1441
|
-
event.putInt("type", Util.
|
|
1492
|
+
event.putInt("client", Util.getAdEventClientValue(adRequestEvent));
|
|
1493
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeRequest));
|
|
1442
1494
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1443
1495
|
}
|
|
1444
1496
|
|
|
@@ -1446,8 +1498,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1446
1498
|
public void onAdSchedule(AdScheduleEvent adScheduleEvent) {
|
|
1447
1499
|
WritableMap event = Arguments.createMap();
|
|
1448
1500
|
event.putString("message", "onAdEvent");
|
|
1449
|
-
event.
|
|
1450
|
-
event.putInt("type", Util.
|
|
1501
|
+
event.putInt("client", Util.getAdEventClientValue(adScheduleEvent));
|
|
1502
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeSchedule));
|
|
1451
1503
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1452
1504
|
}
|
|
1453
1505
|
|
|
@@ -1455,8 +1507,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1455
1507
|
public void onAdSkipped(AdSkippedEvent adSkippedEvent) {
|
|
1456
1508
|
WritableMap event = Arguments.createMap();
|
|
1457
1509
|
event.putString("message", "onAdEvent");
|
|
1458
|
-
event.
|
|
1459
|
-
event.putInt("type", Util.
|
|
1510
|
+
event.putInt("client", Util.getAdEventClientValue(adSkippedEvent));
|
|
1511
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeSkipped));
|
|
1460
1512
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1461
1513
|
}
|
|
1462
1514
|
|
|
@@ -1464,7 +1516,8 @@ public class RNJWPlayerView extends RelativeLayout implements
|
|
|
1464
1516
|
public void onAdStarted(AdStartedEvent adStartedEvent) {
|
|
1465
1517
|
WritableMap event = Arguments.createMap();
|
|
1466
1518
|
event.putString("message", "onAdEvent");
|
|
1467
|
-
event.putInt("
|
|
1519
|
+
event.putInt("client", Util.getAdEventClientValue(adStartedEvent));
|
|
1520
|
+
event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeStarted));
|
|
1468
1521
|
getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
|
|
1469
1522
|
}
|
|
1470
1523
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
package com.jwplayer.rnjwplayer;
|
|
3
2
|
|
|
4
3
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
@@ -41,6 +40,9 @@ public class RNJWPlayerViewManager extends SimpleViewManager<RNJWPlayerView> {
|
|
|
41
40
|
|
|
42
41
|
@ReactProp(name = "controls")
|
|
43
42
|
public void setControls(RNJWPlayerView view, Boolean controls) {
|
|
43
|
+
if (view == null || view.mPlayerView == null) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
44
46
|
view.mPlayerView.getPlayer().setControls(controls);
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -171,6 +173,10 @@ public class RNJWPlayerViewManager extends SimpleViewManager<RNJWPlayerView> {
|
|
|
171
173
|
MapBuilder.of(
|
|
172
174
|
"phasedRegistrationNames",
|
|
173
175
|
MapBuilder.of("bubbled", "onLoaded")))
|
|
176
|
+
.put("topBeforeNextPlaylistItem",
|
|
177
|
+
MapBuilder.of(
|
|
178
|
+
"phasedRegistrationNames",
|
|
179
|
+
MapBuilder.of("bubbled", "onBeforeNextPlaylistItem")))
|
|
174
180
|
.build();
|
|
175
181
|
}
|
|
176
182
|
|
|
@@ -9,6 +9,8 @@ import android.webkit.URLUtil;
|
|
|
9
9
|
import com.facebook.react.bridge.ReadableArray;
|
|
10
10
|
import com.facebook.react.bridge.ReadableMap;
|
|
11
11
|
import com.jwplayer.pub.api.JsonHelper;
|
|
12
|
+
import com.jwplayer.pub.api.configuration.ads.AdvertisingConfig;
|
|
13
|
+
import com.jwplayer.pub.api.events.Event;
|
|
12
14
|
import com.jwplayer.pub.api.media.ads.AdBreak;
|
|
13
15
|
import com.jwplayer.pub.api.media.captions.Caption;
|
|
14
16
|
import com.jwplayer.pub.api.media.captions.CaptionType;
|
|
@@ -253,7 +255,42 @@ public class Util {
|
|
|
253
255
|
}
|
|
254
256
|
|
|
255
257
|
// Method to get the event type value
|
|
256
|
-
public static int
|
|
258
|
+
public static int getAdEventTypeValue(AdEventType eventType) {
|
|
257
259
|
return eventType.getValue();
|
|
258
260
|
}
|
|
259
|
-
|
|
261
|
+
|
|
262
|
+
public enum AdEventClient {
|
|
263
|
+
JWAdEventClientJWPlayer(0),
|
|
264
|
+
JWAdEventClientGoogleIMA(1),
|
|
265
|
+
JWAdEventClientGoogleIMADAI(2),
|
|
266
|
+
JWAdEventClientUnknown(3);
|
|
267
|
+
|
|
268
|
+
private final int value;
|
|
269
|
+
|
|
270
|
+
AdEventClient(int value) {
|
|
271
|
+
this.value = value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public int getValue() {
|
|
275
|
+
return value;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
public static int getAdEventClientValue(Event adEvent) {
|
|
280
|
+
AdvertisingConfig adConfig = adEvent.getPlayer().getConfig().getAdvertisingConfig();
|
|
281
|
+
if (adConfig == null) {
|
|
282
|
+
return AdEventClient.JWAdEventClientUnknown.getValue();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
switch (adConfig.getAdClient()) {
|
|
286
|
+
case IMA:
|
|
287
|
+
return AdEventClient.JWAdEventClientGoogleIMA.getValue();
|
|
288
|
+
case IMA_DAI:
|
|
289
|
+
return AdEventClient.JWAdEventClientGoogleIMADAI.getValue();
|
|
290
|
+
case VAST:
|
|
291
|
+
return AdEventClient.JWAdEventClientJWPlayer.getValue();
|
|
292
|
+
default:
|
|
293
|
+
return AdEventClient.JWAdEventClientUnknown.getValue();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
package/badges/version.svg
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="version: 1.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="version: 1.1.1"><title>version: 1.1.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="90" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="39" height="20" fill="#007ec6"/><rect width="90" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">1.1.1</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="290">1.1.1</text></g></svg>
|
package/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ declare module "@jwplayer/jwplayer-react-native" {
|
|
|
6
6
|
pid?: string;
|
|
7
7
|
mute?: boolean;
|
|
8
8
|
forceLegacyConfig?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* If true, `onBeforeNextPlaylistItem` MUST be impelemented with `player.resolveNextPlaylistItem()` called in the callback or content will hang
|
|
11
|
+
*/
|
|
12
|
+
playlistItemCallbackEnabled?: boolean;
|
|
9
13
|
useTextureView?: boolean;
|
|
10
14
|
autostart?: boolean;
|
|
11
15
|
nextupoffset?: string | number; // String with % or number
|
|
@@ -518,7 +522,7 @@ declare module "@jwplayer/jwplayer-react-native" {
|
|
|
518
522
|
adErrorCode?: number; // Android only
|
|
519
523
|
}
|
|
520
524
|
interface AdEventProps {
|
|
521
|
-
client
|
|
525
|
+
client: number;
|
|
522
526
|
reason?: string;
|
|
523
527
|
type: number;
|
|
524
528
|
}
|
|
@@ -570,6 +574,7 @@ declare module "@jwplayer/jwplayer-react-native" {
|
|
|
570
574
|
onCaptionsList?: (event: BaseEvent<CaptionsListEventProps>) => void;
|
|
571
575
|
onAudioTracks?: () => void;
|
|
572
576
|
shouldComponentUpdate?: (nextProps: any, nextState: any) => boolean;
|
|
577
|
+
onBeforeNextPlaylistItem?: (event: BaseEvent<PlaylistItemEventProps>) => void;
|
|
573
578
|
}
|
|
574
579
|
|
|
575
580
|
export default class JWPlayer extends React.Component<PropsType> {
|
|
@@ -586,7 +591,16 @@ declare module "@jwplayer/jwplayer-react-native" {
|
|
|
586
591
|
setControls(show: boolean): void;
|
|
587
592
|
setLockScreenControls(show: boolean): void;
|
|
588
593
|
seekTo(time: number): void;
|
|
589
|
-
|
|
594
|
+
/**
|
|
595
|
+
* Side load playlist items into an already setup player
|
|
596
|
+
* @param playlistItems `PlaylistItem` or `JwPlaylistItem`
|
|
597
|
+
*/
|
|
598
|
+
loadPlaylist(playlistItems: PlaylistItem[] | JwPlaylistItem[]): void;
|
|
599
|
+
/**
|
|
600
|
+
* Side load playlist via URL into an already setup player
|
|
601
|
+
* @param playlistUrl URL for playlist to load (format for response: json)
|
|
602
|
+
*/
|
|
603
|
+
loadPlaylistWithUrl(playlistUrl: string): void;
|
|
590
604
|
setFullscreen(fullScreen: boolean): void;
|
|
591
605
|
position(): Promise<number>;
|
|
592
606
|
setUpCastController(): void;
|
|
@@ -601,5 +615,10 @@ declare module "@jwplayer/jwplayer-react-native" {
|
|
|
601
615
|
setCurrentCaptions(index: number): void;
|
|
602
616
|
getCurrentCaptions(): Promise<number | null>;
|
|
603
617
|
setVisibility(visibility: boolean, controls: JWControlType[]): void;
|
|
618
|
+
/**
|
|
619
|
+
* Only called inside `onBeforeNextPlaylistItem` callback, and once per callback
|
|
620
|
+
* @param playlistItem `PlaylistItem` or `JwPlaylistItem`
|
|
621
|
+
*/
|
|
622
|
+
resolveNextPlaylistItem(playlistItem: PlaylistItem | JwPlaylistItem): void;
|
|
604
623
|
}
|
|
605
624
|
}
|
package/index.js
CHANGED
|
@@ -174,6 +174,12 @@ export default class JWPlayer extends Component {
|
|
|
174
174
|
config: PropTypes.shape({
|
|
175
175
|
license: PropTypes.string.isRequired,
|
|
176
176
|
forceLegacyConfig: PropTypes.bool,
|
|
177
|
+
/**
|
|
178
|
+
* Only enable if you are prepared to implement `onBeforeNextPlaylistItem` on the JS side
|
|
179
|
+
* And resolve the promise with `resolveNextPlaylistItem` inside the callback
|
|
180
|
+
* Otherwise, the player will not proceed to the next item
|
|
181
|
+
*/
|
|
182
|
+
playlistItemCallbackEnabled: PropTypes.bool,
|
|
177
183
|
backgroundAudioEnabled: PropTypes.bool,
|
|
178
184
|
category: PropTypes.oneOf([
|
|
179
185
|
'Ambient',
|
|
@@ -374,6 +380,16 @@ export default class JWPlayer extends Component {
|
|
|
374
380
|
onCaptionsChanged: PropTypes.func,
|
|
375
381
|
onCaptionsList: PropTypes.func,
|
|
376
382
|
onAudioTracks: PropTypes.func,
|
|
383
|
+
/**
|
|
384
|
+
* Callback that is fired when the player is about to play the next playlist item.
|
|
385
|
+
* Indented to be paired with `playlistItemCallbackEnabled` prop
|
|
386
|
+
*
|
|
387
|
+
* Android will only fire after index 0 (starting at index 1)
|
|
388
|
+
*
|
|
389
|
+
* iOS will fire all playlist items (including index 0)
|
|
390
|
+
*/
|
|
391
|
+
onBeforeNextPlaylistItem: PropTypes.func,
|
|
392
|
+
resolveNextPlaylistItem: PropTypes.func
|
|
377
393
|
};
|
|
378
394
|
|
|
379
395
|
constructor(props) {
|
|
@@ -381,8 +397,7 @@ export default class JWPlayer extends Component {
|
|
|
381
397
|
|
|
382
398
|
this._playerId = playerId++;
|
|
383
399
|
this.ref_key = `${RCT_RNJWPLAYER_REF}-${this._playerId}`;
|
|
384
|
-
|
|
385
|
-
this.quite();
|
|
400
|
+
|
|
386
401
|
}
|
|
387
402
|
|
|
388
403
|
shouldComponentUpdate(nextProps, nextState) {
|
|
@@ -520,6 +535,11 @@ export default class JWPlayer extends Component {
|
|
|
520
535
|
RNJWPlayerManager.loadPlaylist(this.getRNJWPlayerBridgeHandle(), playlistItems);
|
|
521
536
|
}
|
|
522
537
|
|
|
538
|
+
loadPlaylistWithUrl(playlistUrl) {
|
|
539
|
+
if (RNJWPlayerManager)
|
|
540
|
+
RNJWPlayerManager.loadPlaylistWithUrl(this.getRNJWPlayerBridgeHandle(), playlistUrl);
|
|
541
|
+
}
|
|
542
|
+
|
|
523
543
|
setFullscreen(fullscreen) {
|
|
524
544
|
if (RNJWPlayerManager)
|
|
525
545
|
RNJWPlayerManager.setFullscreen(
|
|
@@ -707,6 +727,22 @@ export default class JWPlayer extends Component {
|
|
|
707
727
|
}
|
|
708
728
|
}
|
|
709
729
|
|
|
730
|
+
/**
|
|
731
|
+
* Only to be called in the onBeforeNextPlaylistItem callback.
|
|
732
|
+
* If called outside of the callback, it will not have any effect.
|
|
733
|
+
*
|
|
734
|
+
* Can only be called once inside the onBeforeNextPlaylistItem callback.
|
|
735
|
+
* @param {PlaylistItem | JwPlaylistItem} playlistItem
|
|
736
|
+
*/
|
|
737
|
+
resolveNextPlaylistItem(playlistItem) {
|
|
738
|
+
if (RNJWPlayerManager) {
|
|
739
|
+
RNJWPlayerManager.resolveNextPlaylistItem(
|
|
740
|
+
this.getRNJWPlayerBridgeHandle(),
|
|
741
|
+
playlistItem
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
710
746
|
getRNJWPlayerBridgeHandle() {
|
|
711
747
|
return findNodeHandle(this[this.ref_key]);
|
|
712
748
|
}
|
|
@@ -16,7 +16,12 @@ import JWPlayerKit
|
|
|
16
16
|
import GoogleCast
|
|
17
17
|
#endif
|
|
18
18
|
|
|
19
|
-
class RNJWPlayerView
|
|
19
|
+
class RNJWPlayerView: UIView, JWPlayerDelegate, JWPlayerStateDelegate,
|
|
20
|
+
JWAdDelegate, JWAVDelegate, JWPlayerViewDelegate,
|
|
21
|
+
JWPlayerViewControllerFullScreenDelegate, JWPlayerViewControllerUIDelegate,
|
|
22
|
+
JWPlayerViewControllerRelatedDelegate, JWDRMContentKeyDataSource,
|
|
23
|
+
JWTimeEventListener, AVPictureInPictureControllerDelegate
|
|
24
|
+
{
|
|
20
25
|
|
|
21
26
|
// MARK: - RNJWPlayer allocation
|
|
22
27
|
|
|
@@ -41,6 +46,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
41
46
|
var castController: JWCastController!
|
|
42
47
|
var isCasting: Bool = false
|
|
43
48
|
var availableDevices: [AnyObject]!
|
|
49
|
+
var onBeforeNextPlaylistItemCompletion: ((JWPlayerItem?) -> ())?
|
|
44
50
|
|
|
45
51
|
@objc var onBuffer: RCTDirectEventBlock?
|
|
46
52
|
@objc var onUpdateBuffer: RCTDirectEventBlock?
|
|
@@ -87,6 +93,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
87
93
|
@objc var onCastingFailed: RCTDirectEventBlock?
|
|
88
94
|
@objc var onCaptionsChanged: RCTDirectEventBlock?
|
|
89
95
|
@objc var onCaptionsList: RCTDirectEventBlock?
|
|
96
|
+
@objc var onBeforeNextPlaylistItem: RCTDirectEventBlock?
|
|
90
97
|
|
|
91
98
|
init() {
|
|
92
99
|
super.init(frame: CGRect(x: 20, y: 0, width: UIScreen.main.bounds.width - 40, height: 300))
|
|
@@ -283,6 +290,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
283
290
|
|
|
284
291
|
func setNewConfig(config: [String : Any]) {
|
|
285
292
|
let forceLegacyConfig = config["forceLegacyConfig"] as? Bool?
|
|
293
|
+
let playlistItemCallback = config["playlistItemCallbackEnabled"] as? Bool?
|
|
286
294
|
let data:Data! = try? JSONSerialization.data(withJSONObject: config, options:.prettyPrinted)
|
|
287
295
|
let jwConfig = try? JWJSONParser.config(from:data)
|
|
288
296
|
|
|
@@ -348,6 +356,11 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
348
356
|
self.setupPlayerViewController(config: config, playerConfig: jwConfig!)
|
|
349
357
|
}
|
|
350
358
|
}
|
|
359
|
+
|
|
360
|
+
if playlistItemCallback == true {
|
|
361
|
+
self.setupPlaylistItemCallback()
|
|
362
|
+
}
|
|
363
|
+
|
|
351
364
|
} catch {
|
|
352
365
|
print(error)
|
|
353
366
|
}
|
|
@@ -362,6 +375,47 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
362
375
|
}
|
|
363
376
|
}
|
|
364
377
|
|
|
378
|
+
func setupPlaylistItemCallback() {
|
|
379
|
+
playerViewController.player.setPlaylistItemCallback { [weak self] item, index, completion in
|
|
380
|
+
print("setPlaylistItemCallback called with index \(index)")
|
|
381
|
+
guard let self = self else {
|
|
382
|
+
print("setPlaylistItemCallback: self is nil, resuming normally")
|
|
383
|
+
completion(item)
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if let onBeforeNextPlaylistItem = self.onBeforeNextPlaylistItem {
|
|
388
|
+
print("Storing completion handler and triggering onBeforeNextPlaylistItem")
|
|
389
|
+
// Store the completion handler first, before any other operations
|
|
390
|
+
self.onBeforeNextPlaylistItemCompletion = completion
|
|
391
|
+
print("Completion handler stored: \(self.onBeforeNextPlaylistItemCompletion != nil)")
|
|
392
|
+
|
|
393
|
+
do {
|
|
394
|
+
let data = try JSONSerialization.data(withJSONObject: item.toJSONObject(), options: [.prettyPrinted])
|
|
395
|
+
let jsonString = String(data: data, encoding: .utf8) ?? "{}"
|
|
396
|
+
|
|
397
|
+
print("Triggering onBeforeNextPlaylistItem with index \(index)")
|
|
398
|
+
print("Completion handler before event: \(self.onBeforeNextPlaylistItemCompletion != nil)")
|
|
399
|
+
|
|
400
|
+
// Pass the playlist item to the React Native side
|
|
401
|
+
onBeforeNextPlaylistItem([
|
|
402
|
+
"playlistItem": jsonString,
|
|
403
|
+
"index": index
|
|
404
|
+
])
|
|
405
|
+
print("Completion handler after event: \(self.onBeforeNextPlaylistItemCompletion != nil)")
|
|
406
|
+
|
|
407
|
+
} catch {
|
|
408
|
+
print("Error serializing playlist item: \(error)")
|
|
409
|
+
self.onBeforeNextPlaylistItemCompletion?(item) // Call completion handler directly on error
|
|
410
|
+
self.onBeforeNextPlaylistItemCompletion = nil
|
|
411
|
+
}
|
|
412
|
+
} else {
|
|
413
|
+
print("No onBeforeNextPlaylistItem handler set, calling completion directly")
|
|
414
|
+
completion(item)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
365
419
|
// MARK: - RNJWPlayer styling
|
|
366
420
|
|
|
367
421
|
func colorWithHexString(hex:String!) -> UIColor! {
|
|
@@ -1231,10 +1285,6 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
1231
1285
|
func jwplayerContentDidComplete(_ player:JWPlayer) {
|
|
1232
1286
|
self.onComplete?([:])
|
|
1233
1287
|
}
|
|
1234
|
-
|
|
1235
|
-
func jwplayerContentIsBuffering(_ player: any JWPlayerKit.JWPlayer) {
|
|
1236
|
-
|
|
1237
|
-
}
|
|
1238
1288
|
|
|
1239
1289
|
func jwplayer(_ player:JWPlayer, didLoadPlaylistItem item:JWPlayerItem, at index:UInt) {
|
|
1240
1290
|
// var sourceDict: [String: Any] = [:]
|
|
@@ -1384,7 +1434,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
|
|
|
1384
1434
|
// MARK: - JWPlayer Ad Delegate
|
|
1385
1435
|
|
|
1386
1436
|
func jwplayer(_ player:JWPlayer, adEvent event:JWAdEvent) {
|
|
1387
|
-
self.onAdEvent?(["client": event.client, "type": event.type])
|
|
1437
|
+
self.onAdEvent?(["client": event.client.rawValue, "type": event.type.rawValue])
|
|
1388
1438
|
}
|
|
1389
1439
|
|
|
1390
1440
|
// MARK: - JWPlayer AV Delegate
|