@jwplayer/jwplayer-react-native 1.2.0 → 1.3.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 +114 -21
- package/RNJWPlayer.podspec +1 -1
- package/android/build.gradle +31 -5
- package/android/src/ima/java/com/jwplayer/rnjwplayer/ImaHelper.java +143 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +41 -129
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +19 -4
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +385 -105
- package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +13 -1
- package/android/src/noima/java/com/jwplayer/rnjwplayer/ImaHelper.java +24 -0
- package/badges/version.svg +1 -1
- package/docs/CONFIG-REFERENCE.md +747 -0
- package/docs/MIGRATION-GUIDE.md +617 -0
- package/docs/PLATFORM-DIFFERENCES.md +693 -0
- package/docs/props.md +15 -3
- package/index.d.ts +207 -249
- package/ios/RNJWPlayer/RNJWPlayerView.swift +278 -21
- package/ios/RNJWPlayer/RNJWPlayerViewController.swift +33 -16
- package/package.json +2 -2
- package/types/advertising.d.ts +514 -0
- package/types/index.d.ts +21 -0
- package/types/legacy.d.ts +82 -0
- package/types/platform-specific.d.ts +641 -0
- package/types/playlist.d.ts +410 -0
- package/types/unified-config.d.ts +591 -0
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/docs/types.md +0 -254
|
@@ -2,21 +2,13 @@ package com.jwplayer.rnjwplayer;
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.ReadableArray;
|
|
4
4
|
import com.facebook.react.bridge.ReadableMap;
|
|
5
|
-
import com.google.ads.interactivemedia.v3.api.FriendlyObstruction;
|
|
6
|
-
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
|
|
7
|
-
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
|
|
8
5
|
import com.jwplayer.pub.api.configuration.ads.AdRules;
|
|
9
6
|
import com.jwplayer.pub.api.configuration.ads.AdvertisingConfig;
|
|
10
7
|
import com.jwplayer.pub.api.configuration.ads.VastAdvertisingConfig;
|
|
11
|
-
import com.jwplayer.pub.api.configuration.ads.dai.ImaDaiAdvertisingConfig;
|
|
12
|
-
import com.jwplayer.pub.api.configuration.ads.ima.ImaAdvertisingConfig;
|
|
13
8
|
import com.jwplayer.pub.api.media.ads.AdBreak;
|
|
14
|
-
import com.jwplayer.pub.api.media.ads.dai.ImaDaiSettings;
|
|
15
9
|
|
|
16
10
|
import java.util.ArrayList;
|
|
17
|
-
import java.util.HashMap;
|
|
18
11
|
import java.util.List;
|
|
19
|
-
import java.util.Map;
|
|
20
12
|
import java.util.Objects;
|
|
21
13
|
|
|
22
14
|
public class RNJWPlayerAds {
|
|
@@ -27,103 +19,43 @@ public class RNJWPlayerAds {
|
|
|
27
19
|
return null;
|
|
28
20
|
}
|
|
29
21
|
|
|
30
|
-
|
|
22
|
+
// Check both "client" (JWPlayer JSON format) and "adClient" (RN wrapper format)
|
|
23
|
+
String adClientType = null;
|
|
24
|
+
if (ads.hasKey("adClient")) {
|
|
25
|
+
adClientType = ads.getString("adClient");
|
|
26
|
+
} else if (ads.hasKey("client")) {
|
|
27
|
+
adClientType = ads.getString("client");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Validate client type exists and is not null
|
|
31
|
+
if (adClientType == null) {
|
|
32
|
+
throw new IllegalArgumentException("Missing required 'adClient' or 'client' field in advertising config");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Normalize to lowercase for case-insensitive matching
|
|
36
|
+
adClientType = adClientType.toLowerCase();
|
|
37
|
+
|
|
31
38
|
switch (adClientType) {
|
|
32
39
|
case "ima":
|
|
33
|
-
|
|
34
|
-
return configureImaAdvertising(ads);
|
|
35
|
-
} catch (Exception e) {
|
|
36
|
-
throw new RuntimeException(e);
|
|
37
|
-
}
|
|
40
|
+
case "googima": // Support legacy "googima" format
|
|
38
41
|
case "ima_dai":
|
|
42
|
+
// Delegate to ImaHelper (implementation selected by Gradle)
|
|
43
|
+
// Note: Only parse adSchedule for regular IMA, not for DAI (ads are embedded in stream)
|
|
44
|
+
List<AdBreak> adSchedule = ("ima".equals(adClientType) || "googima".equals(adClientType))
|
|
45
|
+
? getAdSchedule(ads)
|
|
46
|
+
: new ArrayList<>();
|
|
39
47
|
try {
|
|
40
|
-
return
|
|
41
|
-
} catch (
|
|
42
|
-
|
|
48
|
+
return ImaHelper.configureImaOrDai(ads, adSchedule);
|
|
49
|
+
} catch (RuntimeException e) {
|
|
50
|
+
// IMA not enabled - log error and return null (graceful degradation)
|
|
51
|
+
android.util.Log.e("RNJWPlayerAds", "Failed to configure IMA ads: " + e.getMessage());
|
|
52
|
+
return null;
|
|
43
53
|
}
|
|
44
54
|
default: // Defaulting to VAST
|
|
45
55
|
return configureVastAdvertising(ads);
|
|
46
56
|
}
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
// Configure IMA Advertising
|
|
50
|
-
private static ImaAdvertisingConfig configureImaAdvertising(ReadableMap ads) throws Exception {
|
|
51
|
-
if (!BuildConfig.USE_IMA) {
|
|
52
|
-
throw new Exception("Error: Google ads services is not installed. Add RNJWPlayerUseGoogleIMA = true to your app/build.gradle ext {}");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
ImaAdvertisingConfig.Builder builder = new ImaAdvertisingConfig.Builder();
|
|
56
|
-
|
|
57
|
-
List<AdBreak> adScheduleList = getAdSchedule(ads);
|
|
58
|
-
builder.schedule(adScheduleList);
|
|
59
|
-
|
|
60
|
-
if (ads.hasKey("imaSettings")) {
|
|
61
|
-
builder.imaSdkSettings(getImaSettings(Objects.requireNonNull(ads.getMap("imaSettings"))));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// companionSlots
|
|
65
|
-
|
|
66
|
-
return builder.build();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Configure IMA DAI Advertising
|
|
70
|
-
private static ImaDaiAdvertisingConfig configureImaDaiAdvertising(ReadableMap ads) throws Exception {
|
|
71
|
-
if (!BuildConfig.USE_IMA) {
|
|
72
|
-
throw new Exception("Error: Google ads services is not installed. Add RNJWPlayerUseGoogleIMA = true to your app/build.gradle ext {}");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
ImaDaiAdvertisingConfig.Builder builder = new ImaDaiAdvertisingConfig.Builder();
|
|
76
|
-
|
|
77
|
-
if (ads.hasKey("imaSettings")) {
|
|
78
|
-
builder.imaSdkSettings(getImaSettings(Objects.requireNonNull(ads.getMap("imaSettings"))));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (ads.hasKey("imaDaiSettings")) {
|
|
82
|
-
builder.imaDaiSettings(getImaDaiSettings(Objects.requireNonNull(ads.getMap("imaDaiSettings"))));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return builder.build();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// You'll need to implement this method based on how you pass ImaDaiSettings from React Native
|
|
89
|
-
private static ImaDaiSettings getImaDaiSettings(ReadableMap imaDaiSettingsMap) {
|
|
90
|
-
String videoId = imaDaiSettingsMap.hasKey("videoId") ? imaDaiSettingsMap.getString("videoId") : null;
|
|
91
|
-
String cmsId = imaDaiSettingsMap.hasKey("cmsId") ? imaDaiSettingsMap.getString("cmsId") : null;
|
|
92
|
-
String assetKey = imaDaiSettingsMap.hasKey("assetKey") ? imaDaiSettingsMap.getString("assetKey") : null;
|
|
93
|
-
String apiKey = imaDaiSettingsMap.hasKey("apiKey") ? imaDaiSettingsMap.getString("apiKey") : null;
|
|
94
|
-
|
|
95
|
-
// Extracting adTagParameters from imaDaiSettingsMap if present
|
|
96
|
-
Map<String, String> adTagParameters = null;
|
|
97
|
-
if (imaDaiSettingsMap.hasKey("adTagParameters") && imaDaiSettingsMap.getMap("adTagParameters") != null) {
|
|
98
|
-
adTagParameters = new HashMap<>();
|
|
99
|
-
ReadableMap adTagParamsMap = imaDaiSettingsMap.getMap("adTagParameters");
|
|
100
|
-
for (Map.Entry<String, Object> entry : adTagParamsMap.toHashMap().entrySet()) {
|
|
101
|
-
if (entry.getValue() instanceof String) {
|
|
102
|
-
adTagParameters.put(entry.getKey(), (String) entry.getValue());
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Handling streamType
|
|
108
|
-
ImaDaiSettings.StreamType streamType = ImaDaiSettings.StreamType.HLS; // Default to HLS
|
|
109
|
-
if (imaDaiSettingsMap.hasKey("streamType")) {
|
|
110
|
-
String streamTypeStr = imaDaiSettingsMap.getString("streamType");
|
|
111
|
-
if ("DASH".equalsIgnoreCase(streamTypeStr)) {
|
|
112
|
-
streamType = ImaDaiSettings.StreamType.DASH;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// Create ImaDaiSettings based on the provided values
|
|
116
|
-
ImaDaiSettings imaDaiSettings = (assetKey != null) ?
|
|
117
|
-
new ImaDaiSettings(assetKey, streamType, apiKey) :
|
|
118
|
-
new ImaDaiSettings(videoId, cmsId, streamType, apiKey);
|
|
119
|
-
|
|
120
|
-
if (adTagParameters != null) {
|
|
121
|
-
imaDaiSettings.setAdTagParameters(adTagParameters);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return imaDaiSettings;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
59
|
// Configure VAST Advertising
|
|
128
60
|
private static VastAdvertisingConfig configureVastAdvertising(ReadableMap ads) {
|
|
129
61
|
VastAdvertisingConfig.Builder builder = new VastAdvertisingConfig.Builder();
|
|
@@ -154,9 +86,23 @@ public class RNJWPlayerAds {
|
|
|
154
86
|
|
|
155
87
|
private static List<AdBreak> getAdSchedule(ReadableMap ads) {
|
|
156
88
|
List<AdBreak> adScheduleList = new ArrayList<>();
|
|
89
|
+
|
|
90
|
+
// Check if adSchedule exists
|
|
91
|
+
if (!ads.hasKey("adSchedule")) {
|
|
92
|
+
return adScheduleList; // Return empty list
|
|
93
|
+
}
|
|
94
|
+
|
|
157
95
|
ReadableArray adSchedule = ads.getArray("adSchedule");
|
|
96
|
+
if (adSchedule == null) {
|
|
97
|
+
return adScheduleList; // Return empty list if null
|
|
98
|
+
}
|
|
99
|
+
|
|
158
100
|
for (int i = 0; i < adSchedule.size(); i++) {
|
|
159
101
|
ReadableMap adBreakProp = adSchedule.getMap(i);
|
|
102
|
+
// Skip null entries in the adSchedule array
|
|
103
|
+
if (adBreakProp == null) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
160
106
|
String offset = adBreakProp.hasKey("offset") ? adBreakProp.getString("offset") : "pre";
|
|
161
107
|
if (adBreakProp.hasKey("tag")) {
|
|
162
108
|
AdBreak adBreak = new AdBreak.Builder()
|
|
@@ -202,38 +148,4 @@ public class RNJWPlayerAds {
|
|
|
202
148
|
return AdRules.RULES_START_ON_SEEK_NONE;
|
|
203
149
|
}
|
|
204
150
|
|
|
205
|
-
// public static List<FriendlyObstruction> getFriendlyObstructions(ReadableArray obstructionsArray) {
|
|
206
|
-
// List<FriendlyObstruction> obstructions = new ArrayList<>();
|
|
207
|
-
// // Example: Parse and create FriendlyObstruction objects from obstructionsArray
|
|
208
|
-
// return obstructions;
|
|
209
|
-
// }
|
|
210
|
-
|
|
211
|
-
public static ImaSdkSettings getImaSettings(ReadableMap imaSettingsMap) {
|
|
212
|
-
ImaSdkSettings settings = ImaSdkFactory.getInstance().createImaSdkSettings();
|
|
213
|
-
|
|
214
|
-
if (imaSettingsMap.hasKey("maxRedirects")) {
|
|
215
|
-
settings.setMaxRedirects(imaSettingsMap.getInt("maxRedirects"));
|
|
216
|
-
}
|
|
217
|
-
if (imaSettingsMap.hasKey("language")) {
|
|
218
|
-
settings.setLanguage(imaSettingsMap.getString("language"));
|
|
219
|
-
}
|
|
220
|
-
if (imaSettingsMap.hasKey("ppid")) {
|
|
221
|
-
settings.setPpid(imaSettingsMap.getString("ppid"));
|
|
222
|
-
}
|
|
223
|
-
if (imaSettingsMap.hasKey("playerType")) {
|
|
224
|
-
settings.setPlayerType(imaSettingsMap.getString("playerType"));
|
|
225
|
-
}
|
|
226
|
-
if (imaSettingsMap.hasKey("playerVersion")) {
|
|
227
|
-
settings.setPlayerVersion(imaSettingsMap.getString("playerVersion"));
|
|
228
|
-
}
|
|
229
|
-
if (imaSettingsMap.hasKey("sessionId")) {
|
|
230
|
-
settings.setSessionId(imaSettingsMap.getString("sessionId"));
|
|
231
|
-
}
|
|
232
|
-
if (imaSettingsMap.hasKey("debugMode")) {
|
|
233
|
-
settings.setDebugMode(imaSettingsMap.getBoolean("debugMode"));
|
|
234
|
-
}
|
|
235
|
-
// Add other settings as needed
|
|
236
|
-
|
|
237
|
-
return settings;
|
|
238
|
-
}
|
|
239
151
|
}
|
|
@@ -434,12 +434,27 @@ public class RNJWPlayerModule extends ReactContextBaseJavaModule {
|
|
|
434
434
|
|
|
435
435
|
@ReactMethod
|
|
436
436
|
/**
|
|
437
|
-
*
|
|
438
|
-
*
|
|
437
|
+
* Reconfigures or recreates the player with a new configuration.
|
|
438
|
+
*
|
|
439
|
+
* This method intelligently determines whether to:
|
|
440
|
+
* 1. Reconfigure the existing player (preferred, ~90% of cases)
|
|
441
|
+
* 2. Recreate the player (only when necessary, e.g., license changes)
|
|
442
|
+
*
|
|
443
|
+
* Note: Despite the name "recreate", this method usually does NOT recreate the player.
|
|
444
|
+
* It follows the JWPlayer SDK's design intent of reusing player instances via setup() calls.
|
|
445
|
+
*
|
|
446
|
+
* This provides API parity with iOS while being more efficient on Android.
|
|
439
447
|
*/
|
|
440
448
|
public void recreatePlayerWithConfig(final int reactTag, final ReadableMap config) {
|
|
441
|
-
|
|
442
|
-
|
|
449
|
+
new Handler(Looper.getMainLooper()).post(() -> {
|
|
450
|
+
RNJWPlayerView playerView = getPlayerView(reactTag);
|
|
451
|
+
if (playerView != null) {
|
|
452
|
+
// Delegate to setConfig() which intelligently handles reconfiguration vs recreation
|
|
453
|
+
playerView.setConfig(config);
|
|
454
|
+
} else {
|
|
455
|
+
Log.e("RNJWPlayer", "recreatePlayerWithConfig: Player view not found for tag " + reactTag);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
443
458
|
}
|
|
444
459
|
|
|
445
460
|
private int stateToInt(PlayerState playerState) {
|