bitmovin-player-react-native 1.19.0 → 1.21.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/CHANGELOG.md +42 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +4 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +43 -6
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +2 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +59 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/RNPictureInPictureHandler.kt +81 -1
- package/build/components/PlayerView/events.d.ts +0 -4
- package/build/components/PlayerView/events.d.ts.map +1 -1
- package/build/components/PlayerView/events.js.map +1 -1
- package/build/components/PlayerView/nativeEvents.d.ts +0 -4
- package/build/components/PlayerView/nativeEvents.d.ts.map +1 -1
- package/build/components/PlayerView/nativeEvents.js.map +1 -1
- package/build/events.d.ts +99 -6
- package/build/events.d.ts.map +1 -1
- package/build/events.js.map +1 -1
- package/build/mediaControlConfig.d.ts +0 -2
- package/build/mediaControlConfig.d.ts.map +1 -1
- package/build/mediaControlConfig.js.map +1 -1
- package/build/modules/PlayerModule.d.ts +4 -0
- package/build/modules/PlayerModule.d.ts.map +1 -1
- package/build/modules/PlayerModule.js.map +1 -1
- package/build/player.d.ts +7 -0
- package/build/player.d.ts.map +1 -1
- package/build/player.js +13 -0
- package/build/player.js.map +1 -1
- package/build/tweaksConfig.d.ts +0 -13
- package/build/tweaksConfig.d.ts.map +1 -1
- package/build/tweaksConfig.js.map +1 -1
- package/ios/PlayerModule.swift +5 -0
- package/ios/RCTConvert+BitmovinPlayer.swift +0 -5
- package/ios/RNBitmovinPlayer.podspec +1 -1
- package/package.json +3 -2
- package/plugin/build/withAppGradleDependencies.js +90 -31
- package/plugin/build/withBitmovinIosConfig.js +3 -2
- package/plugin/src/withAppGradleDependencies.ts +157 -39
- package/plugin/src/withBitmovinIosConfig.ts +4 -2
- package/scripts/test-with-app-gradle-dependencies.js +150 -0
- package/src/components/PlayerView/events.ts +0 -4
- package/src/components/PlayerView/nativeEvents.ts +0 -4
- package/src/events.ts +98 -6
- package/src/mediaControlConfig.ts +0 -2
- package/src/modules/PlayerModule.ts +5 -0
- package/src/player.ts +16 -0
- package/src/tweaksConfig.ts +0 -13
|
@@ -9,16 +9,138 @@ export type PluginProps = {
|
|
|
9
9
|
dependencies?: string[];
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
const DEFAULT_SPACING = ' ';
|
|
13
|
+
|
|
12
14
|
const defaultProps: PluginProps = {
|
|
13
|
-
spacing:
|
|
15
|
+
spacing: DEFAULT_SPACING,
|
|
14
16
|
dependencies: [],
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
const CORE_LIBRARY_DESUGARING_DEPENDENCY =
|
|
20
|
+
"coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'";
|
|
21
|
+
const CORE_LIBRARY_DESUGARING_ARTIFACT = 'com.android.tools:desugar_jdk_libs';
|
|
22
|
+
|
|
23
|
+
const hasCoreLibraryDesugaringEnabled = (contents: string) =>
|
|
24
|
+
/^\s*(?:set)?CoreLibraryDesugaringEnabled\b.*?\btrue\b/m.test(contents);
|
|
25
|
+
|
|
26
|
+
const escapeRegExp = (value: string) =>
|
|
27
|
+
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
28
|
+
|
|
29
|
+
const hasGradleDependencyDeclaration = (
|
|
30
|
+
contents: string,
|
|
31
|
+
dependency: string,
|
|
32
|
+
configuration?: string,
|
|
33
|
+
allowVersionSuffix = false
|
|
34
|
+
) => {
|
|
35
|
+
const dependencyPattern = escapeRegExp(dependency);
|
|
36
|
+
const configurationPattern = configuration
|
|
37
|
+
? escapeRegExp(configuration)
|
|
38
|
+
: '[A-Za-z_][\\w.-]*';
|
|
39
|
+
const versionSuffixPattern = allowVersionSuffix ? `(?::[^'"]*)?` : '';
|
|
40
|
+
const declarationPattern = new RegExp(
|
|
41
|
+
`^${configurationPattern}\\s*(?:\\(\\s*)?['"]${dependencyPattern}${versionSuffixPattern}['"]`
|
|
42
|
+
);
|
|
43
|
+
let nestedBlockDepth = 0;
|
|
44
|
+
|
|
45
|
+
return contents.split('\n').some((line) => {
|
|
46
|
+
const trimmedLine = line.trim();
|
|
47
|
+
if (trimmedLine.startsWith('//')) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (/^dependencies\s*\{$/.test(trimmedLine)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isTopLevelDependency =
|
|
56
|
+
nestedBlockDepth === 0 && declarationPattern.test(trimmedLine);
|
|
57
|
+
const openBlockCount = (trimmedLine.match(/\{/g) || []).length;
|
|
58
|
+
const closeBlockCount = (trimmedLine.match(/\}/g) || []).length;
|
|
59
|
+
nestedBlockDepth += openBlockCount - closeBlockCount;
|
|
60
|
+
|
|
61
|
+
return isTopLevelDependency;
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Matches any pinned version of the desugaring artifact so an existing
|
|
66
|
+
// declaration is never duplicated, even when it pins a different version.
|
|
67
|
+
const hasCoreLibraryDesugaringDependency = (contents: string) =>
|
|
68
|
+
hasGradleDependencyDeclaration(
|
|
69
|
+
contents,
|
|
70
|
+
CORE_LIBRARY_DESUGARING_ARTIFACT,
|
|
71
|
+
'coreLibraryDesugaring',
|
|
72
|
+
true
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const replaceDisabledCoreLibraryDesugaringSettings = (contents: string) =>
|
|
76
|
+
contents
|
|
77
|
+
.replace(
|
|
78
|
+
/^(\s*)setCoreLibraryDesugaringEnabled\s*\(\s*false\s*\)/gm,
|
|
79
|
+
'$1setCoreLibraryDesugaringEnabled(true)'
|
|
80
|
+
)
|
|
81
|
+
.replace(
|
|
82
|
+
/^(\s*)coreLibraryDesugaringEnabled(\s*=\s*)false\b/gm,
|
|
83
|
+
'$1coreLibraryDesugaringEnabled$2true'
|
|
84
|
+
)
|
|
85
|
+
.replace(
|
|
86
|
+
/^(\s*)coreLibraryDesugaringEnabled(\s+)false\b/gm,
|
|
87
|
+
'$1coreLibraryDesugaringEnabled$2true'
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const ensureCoreLibraryDesugaringCompileOptions = (
|
|
91
|
+
contents: string,
|
|
92
|
+
spacing: string,
|
|
93
|
+
androidBlockStart: number,
|
|
94
|
+
androidPosition: number
|
|
95
|
+
) => {
|
|
96
|
+
const androidBlock = contents.slice(androidBlockStart, androidPosition);
|
|
97
|
+
const updatedAndroidBlock =
|
|
98
|
+
replaceDisabledCoreLibraryDesugaringSettings(androidBlock);
|
|
99
|
+
const updatedContents = [
|
|
100
|
+
contents.slice(0, androidBlockStart),
|
|
101
|
+
updatedAndroidBlock,
|
|
102
|
+
contents.slice(androidPosition),
|
|
103
|
+
].join('');
|
|
104
|
+
const updatedAndroidPosition =
|
|
105
|
+
androidPosition + updatedAndroidBlock.length - androidBlock.length;
|
|
106
|
+
|
|
107
|
+
if (hasCoreLibraryDesugaringEnabled(updatedAndroidBlock)) {
|
|
108
|
+
return updatedContents;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const compileOptionsRelativeStart = updatedAndroidBlock.search(
|
|
112
|
+
/^[^\S\r\n]*compileOptions\s*\{$/m
|
|
113
|
+
);
|
|
114
|
+
if (compileOptionsRelativeStart === -1) {
|
|
115
|
+
const compileOptions = [
|
|
116
|
+
`${spacing}compileOptions {`,
|
|
117
|
+
`${spacing}${spacing}setCoreLibraryDesugaringEnabled(true)`,
|
|
118
|
+
`${spacing}}`,
|
|
119
|
+
'',
|
|
120
|
+
].join('\n');
|
|
121
|
+
return [
|
|
122
|
+
updatedContents.slice(0, updatedAndroidPosition),
|
|
123
|
+
compileOptions,
|
|
124
|
+
updatedContents.slice(updatedAndroidPosition),
|
|
125
|
+
].join('');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const compileOptionsStart = androidBlockStart + compileOptionsRelativeStart;
|
|
129
|
+
const compileOptionsLineEnd =
|
|
130
|
+
updatedContents.indexOf('\n', compileOptionsStart) + 1;
|
|
131
|
+
return [
|
|
132
|
+
updatedContents.slice(0, compileOptionsLineEnd),
|
|
133
|
+
`${spacing}${spacing}setCoreLibraryDesugaringEnabled(true)\n`,
|
|
134
|
+
updatedContents.slice(compileOptionsLineEnd),
|
|
135
|
+
].join('');
|
|
136
|
+
};
|
|
137
|
+
|
|
17
138
|
const withAppGradleDependencies: ConfigPlugin<PluginProps> = (
|
|
18
139
|
config,
|
|
19
140
|
props: PluginProps
|
|
20
141
|
) => {
|
|
21
142
|
const combinedProps = { ...defaultProps, ...(props || {}) };
|
|
143
|
+
const spacing = combinedProps.spacing || DEFAULT_SPACING;
|
|
22
144
|
config = withAppBuildGradle(config, (config) => {
|
|
23
145
|
if (config.modResults.language !== 'groovy') {
|
|
24
146
|
WarningAggregator.addWarningAndroid(
|
|
@@ -28,16 +150,6 @@ const withAppGradleDependencies: ConfigPlugin<PluginProps> = (
|
|
|
28
150
|
return config;
|
|
29
151
|
}
|
|
30
152
|
|
|
31
|
-
const deduplicatedDependencies = Array.from(
|
|
32
|
-
new Set(combinedProps.dependencies)
|
|
33
|
-
);
|
|
34
|
-
const filteredDependencies = deduplicatedDependencies.filter((dep) => {
|
|
35
|
-
return config.modResults.contents.indexOf(dep) === -1;
|
|
36
|
-
});
|
|
37
|
-
if (filteredDependencies.length === 0) {
|
|
38
|
-
return config;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
153
|
const androidBlockStart =
|
|
42
154
|
config.modResults.contents.search(/^android \{$/m);
|
|
43
155
|
if (androidBlockStart === -1) {
|
|
@@ -56,21 +168,6 @@ const withAppGradleDependencies: ConfigPlugin<PluginProps> = (
|
|
|
56
168
|
);
|
|
57
169
|
return config;
|
|
58
170
|
}
|
|
59
|
-
const androidPosition = androidBlockStart + androidBlockEnd;
|
|
60
|
-
const compileOptions = [];
|
|
61
|
-
compileOptions.push(`${combinedProps.spacing}compileOptions {`);
|
|
62
|
-
compileOptions.push('\n');
|
|
63
|
-
compileOptions.push(
|
|
64
|
-
`${combinedProps.spacing}setCoreLibraryDesugaringEnabled(true)`
|
|
65
|
-
);
|
|
66
|
-
compileOptions.push('\n');
|
|
67
|
-
compileOptions.push(`${combinedProps.spacing}}`);
|
|
68
|
-
compileOptions.push('\n');
|
|
69
|
-
config.modResults.contents = [
|
|
70
|
-
config.modResults.contents.slice(0, androidPosition),
|
|
71
|
-
...compileOptions,
|
|
72
|
-
config.modResults.contents.slice(androidPosition),
|
|
73
|
-
].join('');
|
|
74
171
|
|
|
75
172
|
const dependenciesBlockStart =
|
|
76
173
|
config.modResults.contents.search(/^dependencies \{$/m);
|
|
@@ -92,22 +189,43 @@ const withAppGradleDependencies: ConfigPlugin<PluginProps> = (
|
|
|
92
189
|
);
|
|
93
190
|
return config;
|
|
94
191
|
}
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
192
|
+
const androidPosition = androidBlockStart + androidBlockEnd;
|
|
193
|
+
config.modResults.contents = ensureCoreLibraryDesugaringCompileOptions(
|
|
194
|
+
config.modResults.contents,
|
|
195
|
+
spacing,
|
|
196
|
+
androidBlockStart,
|
|
197
|
+
androidPosition
|
|
100
198
|
);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
199
|
+
|
|
200
|
+
const updatedDependenciesBlockStart =
|
|
201
|
+
config.modResults.contents.search(/^dependencies \{$/m);
|
|
202
|
+
const updatedFromDependencies = config.modResults.contents.substring(
|
|
203
|
+
updatedDependenciesBlockStart
|
|
204
|
+
);
|
|
205
|
+
const updatedDependenciesBlockEnd = updatedFromDependencies.search(/^\}$/m);
|
|
206
|
+
const position =
|
|
207
|
+
updatedDependenciesBlockStart + updatedDependenciesBlockEnd;
|
|
208
|
+
const dependenciesBlock = config.modResults.contents.slice(
|
|
209
|
+
updatedDependenciesBlockStart,
|
|
210
|
+
position
|
|
211
|
+
);
|
|
212
|
+
const dependencyDeclarations = [
|
|
213
|
+
...(!hasCoreLibraryDesugaringDependency(dependenciesBlock)
|
|
214
|
+
? [`${spacing}${CORE_LIBRARY_DESUGARING_DEPENDENCY}`]
|
|
215
|
+
: []),
|
|
216
|
+
...Array.from(new Set(combinedProps.dependencies))
|
|
217
|
+
.filter(
|
|
218
|
+
(dependency) =>
|
|
219
|
+
!hasGradleDependencyDeclaration(dependenciesBlock, dependency)
|
|
220
|
+
)
|
|
221
|
+
.map((dependency) => `${spacing}implementation '${dependency}'`),
|
|
222
|
+
];
|
|
223
|
+
if (dependencyDeclarations.length === 0) {
|
|
224
|
+
return config;
|
|
225
|
+
}
|
|
108
226
|
config.modResults.contents = [
|
|
109
227
|
config.modResults.contents.slice(0, position),
|
|
110
|
-
|
|
228
|
+
`\n${dependencyDeclarations.join('\n')}\n`,
|
|
111
229
|
config.modResults.contents.slice(position),
|
|
112
230
|
].join('');
|
|
113
231
|
return config;
|
|
@@ -61,10 +61,12 @@ const withBitmovinIosConfig: ConfigPlugin<BitmovinConfigOptions> = (
|
|
|
61
61
|
delete config.modResults['BitmovinPlayerOfflineSupportEnabled'];
|
|
62
62
|
}
|
|
63
63
|
if (googleCastConfig?.ios != null) {
|
|
64
|
+
const defaultLocalNetworkUsageDescription =
|
|
65
|
+
'${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
|
|
64
66
|
const localNetworkUsageDescription =
|
|
65
|
-
typeof googleCastConfig?.ios === 'object'
|
|
67
|
+
(typeof googleCastConfig?.ios === 'object'
|
|
66
68
|
? googleCastConfig?.ios?.localNetworkUsageDescription
|
|
67
|
-
:
|
|
69
|
+
: undefined) ?? defaultLocalNetworkUsageDescription;
|
|
68
70
|
|
|
69
71
|
config.modResults['BitmovinPlayerGoogleCastApplicationId'] =
|
|
70
72
|
googleCastAppId;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const assert = require('node:assert/strict');
|
|
2
|
+
|
|
3
|
+
const withAppGradleDependencies =
|
|
4
|
+
require('../plugin/build/withAppGradleDependencies').default;
|
|
5
|
+
|
|
6
|
+
const desugaringDependency =
|
|
7
|
+
"coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'";
|
|
8
|
+
const featureDependency = 'com.example:feature:1.0';
|
|
9
|
+
|
|
10
|
+
const countOccurrences = (contents, needle) =>
|
|
11
|
+
contents.split(needle).length - 1;
|
|
12
|
+
|
|
13
|
+
const applyPlugin = async (contents, props = {}) => {
|
|
14
|
+
const config = withAppGradleDependencies(
|
|
15
|
+
{ name: 'test-app', slug: 'test-app' },
|
|
16
|
+
props
|
|
17
|
+
);
|
|
18
|
+
const appBuildGradleMod = config.mods?.android?.appBuildGradle;
|
|
19
|
+
assert.equal(typeof appBuildGradleMod, 'function');
|
|
20
|
+
|
|
21
|
+
const result = await appBuildGradleMod({
|
|
22
|
+
...config,
|
|
23
|
+
modResults: {
|
|
24
|
+
language: 'groovy',
|
|
25
|
+
contents,
|
|
26
|
+
},
|
|
27
|
+
modRequest: {
|
|
28
|
+
projectRoot: process.cwd(),
|
|
29
|
+
platform: 'android',
|
|
30
|
+
modName: 'appBuildGradle',
|
|
31
|
+
introspect: true,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return result.modResults.contents;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const gradle = ({
|
|
39
|
+
android = " namespace 'com.example'",
|
|
40
|
+
dependencies = '',
|
|
41
|
+
}) => `plugins {
|
|
42
|
+
id 'com.android.application'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
android {
|
|
46
|
+
${android}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
dependencies {
|
|
50
|
+
implementation 'com.facebook.react:react-android'
|
|
51
|
+
${dependencies}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const tests = [];
|
|
56
|
+
|
|
57
|
+
const test = (name, run) => {
|
|
58
|
+
tests.push({ name, run });
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
test('adds desugaring when no feature dependencies are requested', async () => {
|
|
62
|
+
const result = await applyPlugin(gradle({}));
|
|
63
|
+
|
|
64
|
+
assert.match(result, /setCoreLibraryDesugaringEnabled\(true\)/);
|
|
65
|
+
assert.ok(result.includes(desugaringDependency));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('inserts desugaring inside existing compileOptions with surrounding whitespace', async () => {
|
|
69
|
+
const result = await applyPlugin(
|
|
70
|
+
gradle({
|
|
71
|
+
android: ` namespace 'com.example'
|
|
72
|
+
|
|
73
|
+
compileOptions {
|
|
74
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
75
|
+
}`,
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
assert.equal(countOccurrences(result, 'compileOptions {'), 1);
|
|
80
|
+
assert.match(
|
|
81
|
+
result,
|
|
82
|
+
/compileOptions \{\n setCoreLibraryDesugaringEnabled\(true\)\n sourceCompatibility/
|
|
83
|
+
);
|
|
84
|
+
assert.doesNotMatch(
|
|
85
|
+
result,
|
|
86
|
+
/namespace 'com\.example'\n\n setCoreLibraryDesugaringEnabled/
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('does not duplicate existing desugaring dependency', async () => {
|
|
91
|
+
const result = await applyPlugin(
|
|
92
|
+
gradle({
|
|
93
|
+
android: ` namespace 'com.example'
|
|
94
|
+
compileOptions {
|
|
95
|
+
setCoreLibraryDesugaringEnabled(true)
|
|
96
|
+
}`,
|
|
97
|
+
dependencies:
|
|
98
|
+
" coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'",
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
assert.equal(
|
|
103
|
+
countOccurrences(
|
|
104
|
+
result,
|
|
105
|
+
"coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs"
|
|
106
|
+
),
|
|
107
|
+
1
|
|
108
|
+
);
|
|
109
|
+
assert.doesNotMatch(result, /desugar_jdk_libs:2\.1\.5/);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('ignores comments and constraints when checking feature dependencies', async () => {
|
|
113
|
+
const result = await applyPlugin(
|
|
114
|
+
gradle({
|
|
115
|
+
dependencies: ` // ${featureDependency} is added by the plugin
|
|
116
|
+
constraints {
|
|
117
|
+
implementation('${featureDependency}') {
|
|
118
|
+
because 'pins the version when another dependency requests it'
|
|
119
|
+
}
|
|
120
|
+
}`,
|
|
121
|
+
}),
|
|
122
|
+
{ dependencies: [featureDependency] }
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
assert.match(result, /implementation 'com\.example:feature:1\.0'/);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const run = async () => {
|
|
129
|
+
const failures = [];
|
|
130
|
+
|
|
131
|
+
for (const { name, run } of tests) {
|
|
132
|
+
try {
|
|
133
|
+
await run();
|
|
134
|
+
console.log(`PASS ${name}`);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
failures.push({ name, error });
|
|
137
|
+
console.error(`FAIL ${name}`);
|
|
138
|
+
console.error(error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (failures.length > 0) {
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
run().catch((error) => {
|
|
148
|
+
console.error(error);
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
});
|
|
@@ -247,8 +247,6 @@ export type PlayerViewEvents = {
|
|
|
247
247
|
onPictureInPictureEnter?: (event: PictureInPictureEnterEvent) => void;
|
|
248
248
|
/**
|
|
249
249
|
* Event emitted when the player entered Picture in Picture mode.
|
|
250
|
-
*
|
|
251
|
-
* @platform iOS
|
|
252
250
|
*/
|
|
253
251
|
onPictureInPictureEntered?: (event: PictureInPictureEnteredEvent) => void;
|
|
254
252
|
/**
|
|
@@ -257,8 +255,6 @@ export type PlayerViewEvents = {
|
|
|
257
255
|
onPictureInPictureExit?: (event: PictureInPictureExitEvent) => void;
|
|
258
256
|
/**
|
|
259
257
|
* Event emitted when the player exited Picture in Picture mode.
|
|
260
|
-
*
|
|
261
|
-
* @platform iOS
|
|
262
258
|
*/
|
|
263
259
|
onPictureInPictureExited?: (event: PictureInPictureExitedEvent) => void;
|
|
264
260
|
/**
|
|
@@ -262,8 +262,6 @@ export type NativePlayerViewEvents = {
|
|
|
262
262
|
}) => void;
|
|
263
263
|
/**
|
|
264
264
|
* Event emitted when the player entered Picture in Picture mode.
|
|
265
|
-
*
|
|
266
|
-
* @platform iOS
|
|
267
265
|
*/
|
|
268
266
|
onBmpPictureInPictureEntered?: (event: {
|
|
269
267
|
nativeEvent: PictureInPictureEnteredEvent;
|
|
@@ -276,8 +274,6 @@ export type NativePlayerViewEvents = {
|
|
|
276
274
|
}) => void;
|
|
277
275
|
/**
|
|
278
276
|
* Event emitted when the player exited Picture in Picture mode.
|
|
279
|
-
*
|
|
280
|
-
* @platform iOS
|
|
281
277
|
*/
|
|
282
278
|
onBmpPictureInPictureExited?: (event: {
|
|
283
279
|
nativeEvent: PictureInPictureExitedEvent;
|
package/src/events.ts
CHANGED
|
@@ -383,14 +383,14 @@ export type PictureInPictureExitEvent = Event;
|
|
|
383
383
|
/**
|
|
384
384
|
* Emitted when the player has finished entering Picture in Picture mode on iOS.
|
|
385
385
|
*
|
|
386
|
-
* @platform iOS
|
|
386
|
+
* @platform iOS, Android
|
|
387
387
|
*/
|
|
388
388
|
export type PictureInPictureEnteredEvent = Event;
|
|
389
389
|
|
|
390
390
|
/**
|
|
391
391
|
* Emitted when the player has finished exiting Picture in Picture mode on iOS.
|
|
392
392
|
*
|
|
393
|
-
* @platform iOS
|
|
393
|
+
* @platform iOS, Android
|
|
394
394
|
*/
|
|
395
395
|
export type PictureInPictureExitedEvent = Event;
|
|
396
396
|
|
|
@@ -746,6 +746,70 @@ export interface PlaybackSpeedChangedEvent extends Event {
|
|
|
746
746
|
to: number;
|
|
747
747
|
}
|
|
748
748
|
|
|
749
|
+
/**
|
|
750
|
+
* The `line` field of a {@link SubtitleCueLayout}.
|
|
751
|
+
*
|
|
752
|
+
* `{ value: 'auto' }` defers placement to the renderer.
|
|
753
|
+
* `{ value: number; unit: 'percent' }` places the cue as a percentage of the viewport.
|
|
754
|
+
* `{ value: number; unit: 'line' }` places the cue by counting rendered text-line slots.
|
|
755
|
+
*
|
|
756
|
+
* @platform Android
|
|
757
|
+
*/
|
|
758
|
+
export type SubtitleCueLayoutLine =
|
|
759
|
+
| { value: 'auto' }
|
|
760
|
+
| { value: number; unit: 'line' | 'percent' };
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Normalized cue-box geometry.
|
|
764
|
+
*
|
|
765
|
+
* Values reflect native cue data including platform defaults, not only explicitly authored
|
|
766
|
+
* subtitle settings. Omitted fields were not set or not applicable for this cue.
|
|
767
|
+
*
|
|
768
|
+
* @platform Android
|
|
769
|
+
*/
|
|
770
|
+
export interface SubtitleCueLayout {
|
|
771
|
+
/**
|
|
772
|
+
* Cue position on the axis perpendicular to the text flow.
|
|
773
|
+
*
|
|
774
|
+
* For horizontal captions this controls vertical placement:
|
|
775
|
+
* - `{ value: 85, unit: 'percent' }` — 85% down the viewport.
|
|
776
|
+
* - `{ value: 12, unit: 'line' }` — 12 rendered text-line slots from the edge.
|
|
777
|
+
* - `{ value: 'auto' }` — renderer chooses placement.
|
|
778
|
+
*
|
|
779
|
+
* For vertical captions this controls horizontal placement.
|
|
780
|
+
*/
|
|
781
|
+
line?: SubtitleCueLayoutLine;
|
|
782
|
+
/**
|
|
783
|
+
* Which edge of the cue box is anchored at `line`.
|
|
784
|
+
*
|
|
785
|
+
* Does not control text alignment inside the box; see `textAlign` for that.
|
|
786
|
+
*/
|
|
787
|
+
lineAlign?: 'start' | 'center' | 'end';
|
|
788
|
+
/**
|
|
789
|
+
* Cue box position as a percentage of the viewport on the axis orthogonal to `line`.
|
|
790
|
+
*
|
|
791
|
+
* `'auto'` defers to the renderer.
|
|
792
|
+
*/
|
|
793
|
+
position?: number | 'auto';
|
|
794
|
+
/**
|
|
795
|
+
* Which edge of the cue box is anchored at `position`.
|
|
796
|
+
*/
|
|
797
|
+
positionAlign?: 'line-left' | 'center' | 'line-right' | 'auto';
|
|
798
|
+
/**
|
|
799
|
+
* Width of the cue box as a percentage of the viewport dimension in the writing direction.
|
|
800
|
+
*/
|
|
801
|
+
size?: number;
|
|
802
|
+
/**
|
|
803
|
+
* Text alignment inside the cue box.
|
|
804
|
+
*/
|
|
805
|
+
textAlign?: 'start' | 'center' | 'end' | 'left' | 'right';
|
|
806
|
+
/**
|
|
807
|
+
* Writing direction of the cue text; affects how `line`, `position`, and `size` are interpreted.
|
|
808
|
+
* When absent, the cue uses the default horizontal writing direction.
|
|
809
|
+
*/
|
|
810
|
+
writingMode?: 'vertical-lr' | 'vertical-rl';
|
|
811
|
+
}
|
|
812
|
+
|
|
749
813
|
/**
|
|
750
814
|
* Emitted when a subtitle entry transitions into the active status.
|
|
751
815
|
*/
|
|
@@ -759,13 +823,27 @@ export interface CueEnterEvent extends Event {
|
|
|
759
823
|
*/
|
|
760
824
|
end: number;
|
|
761
825
|
/**
|
|
762
|
-
*
|
|
826
|
+
* Plain-text content of this subtitle.
|
|
763
827
|
*/
|
|
764
828
|
text?: string;
|
|
765
829
|
/**
|
|
766
|
-
* Data URI for image data
|
|
830
|
+
* Data URI for image subtitle data.
|
|
767
831
|
*/
|
|
768
832
|
image?: string;
|
|
833
|
+
/**
|
|
834
|
+
* HTML cue text, which may include styling generated by the native SDK.
|
|
835
|
+
*
|
|
836
|
+
* Treat as renderer input, not plain text.
|
|
837
|
+
*
|
|
838
|
+
* @platform Android
|
|
839
|
+
*/
|
|
840
|
+
html?: string;
|
|
841
|
+
/**
|
|
842
|
+
* Normalized cue-box geometry.
|
|
843
|
+
*
|
|
844
|
+
* @platform Android
|
|
845
|
+
*/
|
|
846
|
+
layout?: SubtitleCueLayout;
|
|
769
847
|
}
|
|
770
848
|
|
|
771
849
|
/**
|
|
@@ -781,13 +859,27 @@ export interface CueExitEvent extends Event {
|
|
|
781
859
|
*/
|
|
782
860
|
end: number;
|
|
783
861
|
/**
|
|
784
|
-
*
|
|
862
|
+
* Plain-text content of this subtitle.
|
|
785
863
|
*/
|
|
786
864
|
text?: string;
|
|
787
865
|
/**
|
|
788
|
-
* Data URI for image data
|
|
866
|
+
* Data URI for image subtitle data.
|
|
789
867
|
*/
|
|
790
868
|
image?: string;
|
|
869
|
+
/**
|
|
870
|
+
* HTML cue text, which may include styling generated by the native SDK.
|
|
871
|
+
*
|
|
872
|
+
* Treat as renderer input, not plain text.
|
|
873
|
+
*
|
|
874
|
+
* @platform Android
|
|
875
|
+
*/
|
|
876
|
+
html?: string;
|
|
877
|
+
/**
|
|
878
|
+
* Normalized cue-box geometry.
|
|
879
|
+
*
|
|
880
|
+
* @platform Android
|
|
881
|
+
*/
|
|
882
|
+
layout?: SubtitleCueLayout;
|
|
791
883
|
}
|
|
792
884
|
|
|
793
885
|
/**
|
|
@@ -13,8 +13,6 @@ export interface MediaControlConfig {
|
|
|
13
13
|
* For a detailed list of the supported features in the **default behavior**,
|
|
14
14
|
* check the **Default Supported Features** section.
|
|
15
15
|
*
|
|
16
|
-
* @remarks Enabling this flag will automatically treat {@link TweaksConfig.updatesNowPlayingInfoCenter} as `false`.
|
|
17
|
-
*
|
|
18
16
|
* ## Limitations
|
|
19
17
|
* ---
|
|
20
18
|
* - Android: If an app creates multiple player instances, the player shown in media controls is the latest one created having media controls enabled.
|
|
@@ -152,6 +152,11 @@ declare class PlayerModule extends NativeModule<PlayerModuleEvents> {
|
|
|
152
152
|
*/
|
|
153
153
|
isAirPlayAvailable(nativeId: string): Promise<boolean | null>;
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Display the AirPlay route selection menu for nativeId's player (iOS only).
|
|
157
|
+
*/
|
|
158
|
+
showAirPlayTargetPicker(nativeId: string): Promise<void>;
|
|
159
|
+
|
|
155
160
|
/**
|
|
156
161
|
* Resolve nativeId's cast availability state.
|
|
157
162
|
*/
|
package/src/player.ts
CHANGED
|
@@ -395,6 +395,22 @@ export class Player extends NativeInstance<PlayerConfig> {
|
|
|
395
395
|
return (await PlayerModule.isAirPlayAvailable(this.nativeId)) ?? false;
|
|
396
396
|
};
|
|
397
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Displays the system AirPlay route selection menu, allowing the user to pick
|
|
400
|
+
* an AirPlay target for the current playback.
|
|
401
|
+
*
|
|
402
|
+
* @platform iOS
|
|
403
|
+
*/
|
|
404
|
+
showAirPlayTargetPicker = () => {
|
|
405
|
+
if (Platform.OS !== 'ios' || Platform.isTV) {
|
|
406
|
+
console.warn(
|
|
407
|
+
`[Player ${this.nativeId}] Method showAirPlayTargetPicker is only available on iOS (not Android/tvOS).`
|
|
408
|
+
);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
void PlayerModule.showAirPlayTargetPicker(this.nativeId);
|
|
412
|
+
};
|
|
413
|
+
|
|
398
414
|
/**
|
|
399
415
|
* @returns The currently selected audio track or `null`.
|
|
400
416
|
*/
|
package/src/tweaksConfig.ts
CHANGED
|
@@ -174,19 +174,6 @@ export interface TweaksConfig {
|
|
|
174
174
|
* @platform Android
|
|
175
175
|
*/
|
|
176
176
|
enableDrmLicenseRenewRetry?: boolean;
|
|
177
|
-
/**
|
|
178
|
-
* Determines whether `AVKit` should update Now Playing information automatically when using System UI.
|
|
179
|
-
*
|
|
180
|
-
* - If set to `false`, the automatic updates of Now Playing Info sent by `AVKit` are disabled.
|
|
181
|
-
* This prevents interference with manual updates you may want to perform.
|
|
182
|
-
* - If set to `true`, the default behaviour is maintained, allowing `AVKit` to handle Now Playing updates.
|
|
183
|
-
*
|
|
184
|
-
* Default is `true`.
|
|
185
|
-
*
|
|
186
|
-
* @deprecated To enable the Now Playing information use {@link MediaControlConfig.isEnabled}
|
|
187
|
-
* @platform iOS
|
|
188
|
-
*/
|
|
189
|
-
updatesNowPlayingInfoCenter?: boolean;
|
|
190
177
|
|
|
191
178
|
/**
|
|
192
179
|
* When switching between video formats (eg: adapting between video qualities)
|