@stream-io/video-react-native-sdk 1.41.0 → 1.43.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt +79 -54
  3. package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioManagerUtil.kt +6 -2
  4. package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +3 -3
  5. package/dist/commonjs/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
  6. package/dist/commonjs/components/Participant/FloatingParticipantView/index.js.map +1 -1
  7. package/dist/commonjs/contexts/ThemeContext.js +10 -0
  8. package/dist/commonjs/contexts/ThemeContext.js.map +1 -1
  9. package/dist/commonjs/hooks/index.js +11 -0
  10. package/dist/commonjs/hooks/index.js.map +1 -1
  11. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +73 -0
  12. package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -1
  13. package/dist/commonjs/hooks/useAudioDeviceStatus.js +76 -0
  14. package/dist/commonjs/hooks/useAudioDeviceStatus.js.map +1 -0
  15. package/dist/commonjs/hooks/useScreenShareButton.js.map +1 -1
  16. package/dist/commonjs/modules/call-manager/CallManager.js +94 -47
  17. package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
  18. package/dist/commonjs/providers/NoiseCancellation/lib.js.map +1 -1
  19. package/dist/commonjs/providers/StreamCall/AudioInterruptionTracer.js.map +1 -1
  20. package/dist/commonjs/utils/internal/callingx/callingx.js +0 -7
  21. package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -1
  22. package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -2
  23. package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +1 -1
  24. package/dist/commonjs/version.js +1 -1
  25. package/dist/module/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
  26. package/dist/module/components/Participant/FloatingParticipantView/index.js.map +1 -1
  27. package/dist/module/contexts/ThemeContext.js +10 -0
  28. package/dist/module/contexts/ThemeContext.js.map +1 -1
  29. package/dist/module/hooks/index.js +1 -0
  30. package/dist/module/hooks/index.js.map +1 -1
  31. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +73 -0
  32. package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -1
  33. package/dist/module/hooks/useAudioDeviceStatus.js +71 -0
  34. package/dist/module/hooks/useAudioDeviceStatus.js.map +1 -0
  35. package/dist/module/hooks/useScreenShareButton.js.map +1 -1
  36. package/dist/module/modules/call-manager/CallManager.js +94 -47
  37. package/dist/module/modules/call-manager/CallManager.js.map +1 -1
  38. package/dist/module/providers/NoiseCancellation/lib.js.map +1 -1
  39. package/dist/module/providers/StreamCall/AudioInterruptionTracer.js.map +1 -1
  40. package/dist/module/utils/internal/callingx/callingx.js +0 -7
  41. package/dist/module/utils/internal/callingx/callingx.js.map +1 -1
  42. package/dist/module/utils/push/setupCallingExpEvents.js +0 -2
  43. package/dist/module/utils/push/setupCallingExpEvents.js.map +1 -1
  44. package/dist/module/version.js +1 -1
  45. package/dist/typescript/components/Participant/FloatingParticipantView/index.d.ts.map +1 -1
  46. package/dist/typescript/contexts/ThemeContext.d.ts +10 -1
  47. package/dist/typescript/contexts/ThemeContext.d.ts.map +1 -1
  48. package/dist/typescript/hooks/index.d.ts +1 -0
  49. package/dist/typescript/hooks/index.d.ts.map +1 -1
  50. package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +1 -1
  51. package/dist/typescript/hooks/useAudioDeviceStatus.d.ts +21 -0
  52. package/dist/typescript/hooks/useAudioDeviceStatus.d.ts.map +1 -0
  53. package/dist/typescript/hooks/useScreenShareButton.d.ts +2 -1
  54. package/dist/typescript/hooks/useScreenShareButton.d.ts.map +1 -1
  55. package/dist/typescript/modules/call-manager/CallManager.d.ts +25 -11
  56. package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
  57. package/dist/typescript/modules/call-manager/types.d.ts +29 -3
  58. package/dist/typescript/modules/call-manager/types.d.ts.map +1 -1
  59. package/dist/typescript/providers/NoiseCancellation/lib.d.ts.map +1 -1
  60. package/dist/typescript/providers/StreamCall/AudioInterruptionTracer.d.ts.map +1 -1
  61. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  62. package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -1
  63. package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -1
  64. package/dist/typescript/version.d.ts +1 -1
  65. package/expo-config-plugin/dist/index.js +2 -0
  66. package/expo-config-plugin/dist/withAndroidMessagingService.js +313 -0
  67. package/expo-config-plugin/dist/withIosScreenCapture/addBroadcastExtensionXcodeTarget.js +84 -2
  68. package/expo-config-plugin/dist/withIosScreenCapture/withPlistUpdates.js +3 -6
  69. package/expo-config-plugin/dist/withIosScreenCapture/withTarget.js +6 -4
  70. package/expo-config-plugin/static/AudioUploader.swift +230 -0
  71. package/expo-config-plugin/static/SampleHandler.swift +67 -14
  72. package/ios/StreamInCallManager.m +7 -0
  73. package/ios/StreamInCallManager.swift +258 -15
  74. package/ios/StreamVideoReactNative.m +15 -5
  75. package/package.json +27 -25
  76. package/src/components/Call/RingingCallContent/OutgoingCall.tsx +1 -2
  77. package/src/components/Participant/FloatingParticipantView/index.tsx +1 -4
  78. package/src/contexts/ThemeContext.tsx +10 -1
  79. package/src/hooks/index.ts +1 -0
  80. package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +95 -0
  81. package/src/hooks/useAudioDeviceStatus.ts +90 -0
  82. package/src/hooks/useScreenShareButton.ts +2 -1
  83. package/src/modules/call-manager/CallManager.ts +123 -66
  84. package/src/modules/call-manager/native-module.d.ts +14 -7
  85. package/src/modules/call-manager/types.ts +30 -3
  86. package/src/providers/NoiseCancellation/lib.ts +1 -2
  87. package/src/providers/StreamCall/AudioInterruptionTracer.tsx +1 -2
  88. package/src/utils/StreamVideoRN/types.ts +1 -3
  89. package/src/utils/internal/callingx/callingx.ts +0 -8
  90. package/src/utils/push/setupCallingExpEvents.ts +0 -2
  91. package/src/version.ts +1 -1
  92. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -68
  93. package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  94. package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -63
  95. package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
  96. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
  97. package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
  98. package/src/utils/internal/callingx/audioSessionPromise.ts +0 -65
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FIREBASE_DEP_MARKER = exports.FIREBASE_BOM_FALLBACK_VERSION = exports.FIREBASE_MESSAGING_ARTIFACT = exports.STREAM_DEFAULT_SERVICE = exports.GENERATED_SERVICE_CLASS_NAME = exports.EXPO_NOTIFICATIONS_SERVICE = void 0;
37
+ exports.updateManifest = updateManifest;
38
+ exports.buildServiceSource = buildServiceSource;
39
+ exports.validateBaseClass = validateBaseClass;
40
+ exports.resolveBaseClass = resolveBaseClass;
41
+ exports.isExpoNotificationsInstalled = isExpoNotificationsInstalled;
42
+ exports.getGeneratedServiceFqcn = getGeneratedServiceFqcn;
43
+ exports.addFirebaseMessagingDependency = addFirebaseMessagingDependency;
44
+ exports.resolveFirebaseBomVersion = resolveFirebaseBomVersion;
45
+ const config_plugins_1 = require("@expo/config-plugins");
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const GENERATED_SERVICE_CLASS_NAME = 'StreamVideoMessagingService';
49
+ exports.GENERATED_SERVICE_CLASS_NAME = GENERATED_SERVICE_CLASS_NAME;
50
+ const STREAM_DEFAULT_SERVICE = 'io.getstream.rn.callingx.StreamMessagingService';
51
+ exports.STREAM_DEFAULT_SERVICE = STREAM_DEFAULT_SERVICE;
52
+ /** React Native Firebase's own FCM service. */
53
+ const RN_FIREBASE_SERVICE = 'io.invertase.firebase.messaging.ReactNativeFirebaseMessagingService';
54
+ /** expo-notifications' FCM service — the default base auto-detected when installed. */
55
+ const EXPO_NOTIFICATIONS_SERVICE = 'expo.modules.notifications.service.ExpoFirebaseMessagingService';
56
+ exports.EXPO_NOTIFICATIONS_SERVICE = EXPO_NOTIFICATIONS_SERVICE;
57
+ const EXPO_NOTIFICATIONS_PACKAGE = 'expo-notifications';
58
+ const MESSAGING_EVENT_ACTION = 'com.google.firebase.MESSAGING_EVENT';
59
+ /**
60
+ * The generated service lives in the `:app` module, which only has
61
+ * firebase-messaging on its *runtime* classpath (via callingx / RNFB /
62
+ * expo-notifications `implementation` deps). We add it as `compileOnly` so the
63
+ * app can compile a `FirebaseMessagingService` subclass. The runtime artifact is
64
+ * still supplied by those modules, so this avoids a version conflict.
65
+ */
66
+ const FIREBASE_MESSAGING_ARTIFACT = 'com.google.firebase:firebase-messaging';
67
+ exports.FIREBASE_MESSAGING_ARTIFACT = FIREBASE_MESSAGING_ARTIFACT;
68
+ /**
69
+ * Fallback Firebase BOM version, used only when the live BOM cannot be resolved
70
+ * from @react-native-firebase/app. This is the BOM shipped by the minimum RNFB
71
+ * version we support: @stream-io/react-native-callingx declares a
72
+ * `@react-native-firebase/* >= 23.0.0` peer dependency, and RNFB `23.0.0` pins
73
+ * firebase-bom `34.0.0`. Keep in sync with that peer floor.
74
+ */
75
+ const FIREBASE_BOM_FALLBACK_VERSION = '34.0.0';
76
+ exports.FIREBASE_BOM_FALLBACK_VERSION = FIREBASE_BOM_FALLBACK_VERSION;
77
+ /** Stable comment used to detect (and avoid duplicating) our gradle injection. */
78
+ const FIREBASE_DEP_MARKER = '// Added by @stream-io/video-react-native-sdk for the generated FCM messaging service';
79
+ exports.FIREBASE_DEP_MARKER = FIREBASE_DEP_MARKER;
80
+ function getAndroidPackage(config) {
81
+ const modResults = config.modResults;
82
+ const pkg = config.android?.package ?? modResults?.manifest?.$?.package;
83
+ if (!pkg) {
84
+ throw new Error('[StreamVideo] Unable to resolve the Android package name required to generate ' +
85
+ 'the FCM messaging service. Set "android.package" in your app config.');
86
+ }
87
+ return pkg;
88
+ }
89
+ function getGeneratedServiceFqcn(androidPackage) {
90
+ return `${androidPackage}.${GENERATED_SERVICE_CLASS_NAME}`;
91
+ }
92
+ function validateBaseClass(baseClass) {
93
+ if (typeof baseClass !== 'string' || baseClass.trim().length === 0) {
94
+ throw new Error('[StreamVideo] "androidMessagingServiceBaseClass" must be a non-empty string.');
95
+ }
96
+ if (!baseClass.includes('.')) {
97
+ throw new Error(`[StreamVideo] "androidMessagingServiceBaseClass" must be a fully-qualified class name ` +
98
+ `including its package (e.g. "expo.modules.notifications.service.ExpoFirebaseMessagingService"), ` +
99
+ `received "${baseClass}".`);
100
+ }
101
+ }
102
+ function isExpoNotificationsInstalled(projectRoot) {
103
+ return isPackageUsedByApp(EXPO_NOTIFICATIONS_PACKAGE, projectRoot);
104
+ }
105
+ /**
106
+ * Whether `packageName` belongs to this app's own dependency graph.
107
+ *
108
+ * Deliberately avoids `require.resolve`, which walks up the directory tree: in a
109
+ * workspace that also finds packages hoisted to the repo root by a *sibling*
110
+ * app. Those are not linked into this app's Android build, so extending their
111
+ * service generates Kotlin that cannot compile.
112
+ */
113
+ function isPackageUsedByApp(packageName, projectRoot) {
114
+ if (!projectRoot) {
115
+ // No project context to scope the lookup to; plain resolution is all we have.
116
+ try {
117
+ require.resolve(`${packageName}/package.json`);
118
+ return true;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
124
+ try {
125
+ const appPackageJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
126
+ // Only runtime dependencies: a devDependency is not linked into the build.
127
+ if (packageName in { ...appPackageJson?.dependencies }) {
128
+ return true;
129
+ }
130
+ }
131
+ catch {
132
+ // Unreadable app package.json: fall through to the filesystem check.
133
+ }
134
+ return fs.existsSync(path.join(projectRoot, 'node_modules', packageName, 'package.json'));
135
+ }
136
+ function resolveBaseClass(value, projectRoot) {
137
+ if (value === null) {
138
+ return undefined;
139
+ }
140
+ if (typeof value === 'string') {
141
+ validateBaseClass(value);
142
+ return value;
143
+ }
144
+ return isExpoNotificationsInstalled(projectRoot)
145
+ ? EXPO_NOTIFICATIONS_SERVICE
146
+ : undefined;
147
+ }
148
+ /** Kotlin source for the generated messaging service. */
149
+ function buildServiceSource(androidPackage, baseClassFqcn) {
150
+ const simpleName = baseClassFqcn.split('.').pop();
151
+ const shouldForwardNewToken = baseClassFqcn !== RN_FIREBASE_SERVICE;
152
+ const onNewToken = shouldForwardNewToken
153
+ ? `
154
+ override fun onNewToken(token: String) {
155
+ super.onNewToken(token)
156
+ // Keep Stream's device registration working under a non-RNFirebase base.
157
+ StreamMessagingHelper.forwardNewToken(token)
158
+ }
159
+ `
160
+ : '';
161
+ return `package ${androidPackage}
162
+
163
+ import android.annotation.SuppressLint
164
+ import com.google.firebase.messaging.RemoteMessage
165
+ import io.getstream.rn.callingx.StreamMessagingHelper
166
+ import ${baseClassFqcn}
167
+
168
+ /**
169
+ * AUTO-GENERATED by the @stream-io/video-react-native-sdk Expo config plugin.
170
+ * Do not edit — this file is regenerated on every \`expo prebuild\`.
171
+ *
172
+ * Extends the app-declared FCM service (${baseClassFqcn}) and injects Stream
173
+ * Video incoming-call (\`call.ring\`) handling. Stream's default
174
+ * ${STREAM_DEFAULT_SERVICE} is removed from the merged manifest so this class is
175
+ * the single FirebaseMessagingService for the app.
176
+ */
177
+ @SuppressLint("MissingFirebaseInstanceTokenRefresh")
178
+ class ${GENERATED_SERVICE_CLASS_NAME} : ${simpleName}() {
179
+ override fun onMessageReceived(remoteMessage: RemoteMessage) {
180
+ if (StreamMessagingHelper.isStreamCallRing(remoteMessage)) {
181
+ StreamMessagingHelper.handleMessage(applicationContext, remoteMessage)
182
+ return
183
+ }
184
+ super.onMessageReceived(remoteMessage)
185
+ }
186
+ ${onNewToken}}
187
+ `;
188
+ }
189
+ function updateManifest(androidManifest, generatedFqcn, baseClassFqcn) {
190
+ const manifest = androidManifest.manifest;
191
+ if (!manifest ||
192
+ !Array.isArray(manifest.application) ||
193
+ !manifest.application[0]) {
194
+ throw new Error('[StreamVideo] Malformed AndroidManifest.xml: missing <application> element.');
195
+ }
196
+ manifest.$ = manifest.$ ?? {};
197
+ manifest.$['xmlns:tools'] =
198
+ manifest.$['xmlns:tools'] ?? 'http://schemas.android.com/tools';
199
+ // Services whose registration we strip so the generated service is the only
200
+ // MESSAGING_EVENT handler: Stream's default (from react-native-callingx) and
201
+ // the base class (its logic still runs — the generated service subclasses it).
202
+ const servicesToRemove = [
203
+ ...new Set([STREAM_DEFAULT_SERVICE, baseClassFqcn]),
204
+ ];
205
+ const application = manifest.application[0];
206
+ const existing = application.service ?? [];
207
+ // Drop our own previously-added entries so re-runs don't duplicate them.
208
+ const services = existing.filter((service) => {
209
+ const name = service?.$?.['android:name'];
210
+ return name !== generatedFqcn && !servicesToRemove.includes(name ?? '');
211
+ });
212
+ // The generated service becomes the single com.google.firebase.MESSAGING_EVENT handler.
213
+ services.push({
214
+ $: {
215
+ 'android:name': generatedFqcn,
216
+ 'android:exported': 'false',
217
+ },
218
+ 'intent-filter': [
219
+ {
220
+ action: [{ $: { 'android:name': MESSAGING_EVENT_ACTION } }],
221
+ },
222
+ ],
223
+ });
224
+ // Remove the competing services so they don't win FCM delivery. `tools:node`
225
+ // is not part of the strict typing but is valid manifest merger syntax.
226
+ for (const name of servicesToRemove) {
227
+ services.push({
228
+ $: {
229
+ 'android:name': name,
230
+ 'tools:node': 'remove',
231
+ },
232
+ });
233
+ }
234
+ application.service = services;
235
+ return androidManifest;
236
+ }
237
+ const withGeneratedMessagingServiceFile = (config, value) => {
238
+ return (0, config_plugins_1.withDangerousMod)(config, [
239
+ 'android',
240
+ (dangerousConfig) => {
241
+ const baseClassFqcn = resolveBaseClass(value, dangerousConfig.modRequest.projectRoot);
242
+ if (!baseClassFqcn) {
243
+ return dangerousConfig;
244
+ }
245
+ const androidPackage = getAndroidPackage(dangerousConfig);
246
+ const packagePath = androidPackage.replace(/\./g, path.sep);
247
+ const javaDir = path.join(dangerousConfig.modRequest.platformProjectRoot, 'app', 'src', 'main', 'java', packagePath);
248
+ fs.mkdirSync(javaDir, { recursive: true });
249
+ const destPath = path.join(javaDir, `${GENERATED_SERVICE_CLASS_NAME}.kt`);
250
+ fs.writeFileSync(destPath, buildServiceSource(androidPackage, baseClassFqcn), 'utf8');
251
+ return dangerousConfig;
252
+ },
253
+ ]);
254
+ };
255
+ const withMessagingServiceManifest = (config, value) => {
256
+ return (0, config_plugins_1.withAndroidManifest)(config, (androidConfig) => {
257
+ const baseClassFqcn = resolveBaseClass(value, androidConfig.modRequest.projectRoot);
258
+ if (!baseClassFqcn) {
259
+ return androidConfig;
260
+ }
261
+ const androidPackage = getAndroidPackage(androidConfig);
262
+ androidConfig.modResults = updateManifest(androidConfig.modResults, getGeneratedServiceFqcn(androidPackage), baseClassFqcn);
263
+ return androidConfig;
264
+ });
265
+ };
266
+ function resolveFirebaseBomVersion(projectRoot) {
267
+ try {
268
+ const pkgPath = require.resolve('@react-native-firebase/app/package.json', projectRoot ? { paths: [projectRoot] } : undefined);
269
+ const pkg = require(pkgPath);
270
+ const bom = pkg?.sdkVersions?.android?.firebase;
271
+ return typeof bom === 'string' && bom.length > 0 ? bom : undefined;
272
+ }
273
+ catch {
274
+ return undefined;
275
+ }
276
+ }
277
+ const DEPENDENCIES_BLOCK = /dependencies\s*\{/;
278
+ function addFirebaseMessagingDependency(contents, bomVersion) {
279
+ if (contents.includes(FIREBASE_DEP_MARKER)) {
280
+ return contents;
281
+ }
282
+ if (!DEPENDENCIES_BLOCK.test(contents)) {
283
+ throw new Error('[StreamVideo] Could not find a "dependencies { }" block in the app build.gradle ' +
284
+ 'to add the firebase-messaging compile dependency for the generated FCM service.');
285
+ }
286
+ const lines = ` ${FIREBASE_DEP_MARKER}\n` +
287
+ ` compileOnly(platform("com.google.firebase:firebase-bom:${bomVersion ?? FIREBASE_BOM_FALLBACK_VERSION}"))\n` +
288
+ ` compileOnly("${FIREBASE_MESSAGING_ARTIFACT}")`;
289
+ return contents.replace(DEPENDENCIES_BLOCK, (match) => `${match}\n${lines}`);
290
+ }
291
+ const withMessagingServiceGradle = (config, value) => {
292
+ return (0, config_plugins_1.withAppBuildGradle)(config, (gradleConfig) => {
293
+ const baseClassFqcn = resolveBaseClass(value, gradleConfig.modRequest.projectRoot);
294
+ if (!baseClassFqcn) {
295
+ return gradleConfig;
296
+ }
297
+ const bomVersion = resolveFirebaseBomVersion(gradleConfig.modRequest.projectRoot);
298
+ gradleConfig.modResults.contents = addFirebaseMessagingDependency(gradleConfig.modResults.contents, bomVersion);
299
+ return gradleConfig;
300
+ });
301
+ };
302
+ const withAndroidMessagingService = (config, props) => {
303
+ // The messaging-service override only matters for the ringing flow, skip it otherwise.
304
+ if (!props?.ringing) {
305
+ return config;
306
+ }
307
+ const value = props?.androidMessagingServiceBaseClass;
308
+ let updated = withGeneratedMessagingServiceFile(config, value);
309
+ updated = withMessagingServiceManifest(updated, value);
310
+ updated = withMessagingServiceGradle(updated, value);
311
+ return updated;
312
+ };
313
+ exports.default = withAndroidMessagingService;
@@ -33,8 +33,88 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveDeploymentTarget = exports.MIN_DEPLOYMENT_TARGET = void 0;
36
37
  exports.default = addBroadcastExtensionXcodeTarget;
37
38
  const util = __importStar(require("util"));
39
+ /**
40
+ * The lowest iOS version the broadcast extension is built for.
41
+ */
42
+ exports.MIN_DEPLOYMENT_TARGET = '15.0';
43
+ /**
44
+ * A plain dotted version number, for example `15` or `16.4`. Anything else
45
+ * (`$(inherited)`, `16.4beta`) is not comparable and must not be adopted:
46
+ * `Number.parseInt` would silently accept a trailing suffix.
47
+ */
48
+ const VERSION_PATTERN = /^\d+(?:\.\d+)*$/;
49
+ /**
50
+ * Returns true when `candidate` is a higher iOS version than `current`.
51
+ * Values that are not plain version numbers are treated as not higher.
52
+ */
53
+ const isHigherVersion = (candidate, current) => {
54
+ if (!VERSION_PATTERN.test(candidate)) {
55
+ return false;
56
+ }
57
+ const parse = (value) => value.split('.').map((part) => Number.parseInt(part, 10));
58
+ const parsedCandidate = parse(candidate);
59
+ const parsedCurrent = parse(current);
60
+ const length = Math.max(parsedCandidate.length, parsedCurrent.length);
61
+ for (let index = 0; index < length; index++) {
62
+ const left = parsedCandidate[index] ?? 0;
63
+ const right = parsedCurrent[index] ?? 0;
64
+ if (left !== right) {
65
+ return left > right;
66
+ }
67
+ }
68
+ return false;
69
+ };
70
+ /**
71
+ * Deployment targets declared by the host app target and by the project itself.
72
+ *
73
+ * Scoped to those two on purpose. `pbxXCBuildConfigurationSection()` also
74
+ * returns configurations belonging to unrelated targets (widgets, share or
75
+ * notification-service extensions), and adopting the highest of those could make
76
+ * the broadcast extension require a newer iOS than the app it ships inside,
77
+ * which would silently drop screen share on devices in between.
78
+ */
79
+ const collectHostDeploymentTargets = (proj) => {
80
+ const configurations = (proj.pbxXCBuildConfigurationSection?.() ??
81
+ {});
82
+ const configurationLists = (proj.pbxXCConfigurationList?.() ?? {});
83
+ const listUuids = [
84
+ proj.getFirstTarget?.()?.firstTarget?.buildConfigurationList,
85
+ proj.getFirstProject?.()?.firstProject?.buildConfigurationList,
86
+ ].filter((uuid) => typeof uuid === 'string');
87
+ const values = [];
88
+ for (const listUuid of listUuids) {
89
+ const entries = configurationLists[listUuid]?.buildConfigurations ?? [];
90
+ for (const entry of entries) {
91
+ const value = configurations[entry?.value]?.buildSettings?.IPHONEOS_DEPLOYMENT_TARGET;
92
+ if (value === undefined || value === null) {
93
+ continue;
94
+ }
95
+ values.push(String(value).replace(/"/g, '').trim());
96
+ }
97
+ }
98
+ return values;
99
+ };
100
+ /**
101
+ * Resolves the deployment target to use for the broadcast extension.
102
+ *
103
+ * The extension mirrors the highest deployment target of its host app, so it
104
+ * never requires a newer iOS than the app itself and it satisfies the minimum
105
+ * the toolchain accepts (Xcode 27 rejects anything below 15.0). The value only
106
+ * ever moves up from {@link MIN_DEPLOYMENT_TARGET}.
107
+ */
108
+ const resolveDeploymentTarget = (proj) => {
109
+ let resolved = exports.MIN_DEPLOYMENT_TARGET;
110
+ for (const candidate of collectHostDeploymentTargets(proj)) {
111
+ if (isHigherVersion(candidate, resolved)) {
112
+ resolved = candidate;
113
+ }
114
+ }
115
+ return resolved;
116
+ };
117
+ exports.resolveDeploymentTarget = resolveDeploymentTarget;
38
118
  function addBroadcastExtensionXcodeTarget(proj, { appName, extensionName, extensionBundleIdentifier, currentProjectVersion, marketingVersion, developmentTeamId, }) {
39
119
  const targets = proj.getFirstProject().firstProject.targets ?? [];
40
120
  if (targets.length > 0 &&
@@ -50,6 +130,7 @@ function addBroadcastExtensionXcodeTarget(proj, { appName, extensionName, extens
50
130
  marketingVersion,
51
131
  extensionName,
52
132
  appName,
133
+ developmentTeamId,
53
134
  });
54
135
  const productFile = addProductFile(proj, extensionName, groupName);
55
136
  const target = addToPbxNativeTargetSection(proj, {
@@ -74,7 +155,7 @@ function addBroadcastExtensionXcodeTarget(proj, { appName, extensionName, extens
74
155
  });
75
156
  addPbxGroup(proj, productFile);
76
157
  }
77
- const addXCConfigurationList = (proj, { extensionBundleIdentifier, currentProjectVersion, marketingVersion, extensionName, }) => {
158
+ const addXCConfigurationList = (proj, { extensionBundleIdentifier, currentProjectVersion, marketingVersion, extensionName, developmentTeamId, }) => {
78
159
  const commonBuildSettings = {
79
160
  CLANG_ANALYZER_NONNULL: 'YES',
80
161
  CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: 'YES_AGGRESSIVE',
@@ -86,12 +167,13 @@ const addXCConfigurationList = (proj, { extensionBundleIdentifier, currentProjec
86
167
  CODE_SIGN_ENTITLEMENTS: `${extensionName}/${extensionName}.entitlements`,
87
168
  CODE_SIGN_STYLE: 'Automatic',
88
169
  CURRENT_PROJECT_VERSION: currentProjectVersion,
170
+ DEVELOPMENT_TEAM: developmentTeamId,
89
171
  GCC_C_LANGUAGE_STANDARD: 'gnu11',
90
172
  GENERATE_INFOPLIST_FILE: 'YES',
91
173
  INFOPLIST_FILE: `${extensionName}/Info.plist`,
92
174
  INFOPLIST_KEY_CFBundleDisplayName: `${extensionName}`,
93
175
  INFOPLIST_KEY_NSHumanReadableCopyright: quoted(''),
94
- IPHONEOS_DEPLOYMENT_TARGET: '14.0',
176
+ IPHONEOS_DEPLOYMENT_TARGET: (0, exports.resolveDeploymentTarget)(proj),
95
177
  LD_RUNPATH_SEARCH_PATHS: quoted('$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks'),
96
178
  MARKETING_VERSION: marketingVersion,
97
179
  MTL_FAST_MATH: 'YES',
@@ -6,8 +6,7 @@ exports.default = withPlistUpdates;
6
6
  // adds the app group identifier to the app's entitlements file
7
7
  const withAppEntitlements = (configuration) => {
8
8
  return (0, config_plugins_1.withEntitlementsPlist)(configuration, (config) => {
9
- const appGroupIdentifier = `group.${config.ios
10
- .bundleIdentifier}.appgroup`;
9
+ const appGroupIdentifier = `group.${config.ios.bundleIdentifier}.appgroup`;
11
10
  config.modResults['com.apple.security.application-groups'] = [
12
11
  appGroupIdentifier,
13
12
  ];
@@ -16,10 +15,8 @@ const withAppEntitlements = (configuration) => {
16
15
  };
17
16
  const withInfoPlistRTC = (configuration) => {
18
17
  return (0, config_plugins_1.withInfoPlist)(configuration, (config) => {
19
- const appGroupIdentifier = `group.${config.ios
20
- .bundleIdentifier}.appgroup`;
21
- const extensionBundleIdentifier = `${config.ios
22
- .bundleIdentifier}.broadcast`;
18
+ const appGroupIdentifier = `group.${config.ios.bundleIdentifier}.appgroup`;
19
+ const extensionBundleIdentifier = `${config.ios.bundleIdentifier}.broadcast`;
23
20
  config.modResults.RTCAppGroupIdentifier = appGroupIdentifier;
24
21
  config.modResults.RTCScreenSharingExtension = extensionBundleIdentifier;
25
22
  if (!config.modResults.UIBackgroundModes) {
@@ -46,8 +46,7 @@ const withTarget = (configuration, props) => {
46
46
  return (0, config_plugins_1.withXcodeProject)(configuration, (config) => {
47
47
  const appName = config.modRequest.projectName;
48
48
  const extensionName = 'broadcast';
49
- const extensionBundleIdentifier = `${config.ios
50
- .bundleIdentifier}.broadcast`;
49
+ const extensionBundleIdentifier = `${config.ios.bundleIdentifier}.broadcast`;
51
50
  const currentProjectVersion = config.ios.buildNumber || '1';
52
51
  const marketingVersion = config.version;
53
52
  const proj = config.modResults;
@@ -63,8 +62,7 @@ const withTarget = (configuration, props) => {
63
62
  marketingVersion,
64
63
  developmentTeamId,
65
64
  });
66
- const appGroupIdentifier = `group.${config.ios
67
- .bundleIdentifier}.appgroup`;
65
+ const appGroupIdentifier = `group.${config.ios.bundleIdentifier}.appgroup`;
68
66
  const extensionRootPath = path.join(config.modRequest.platformProjectRoot, 'broadcast');
69
67
  addBroadcastEntitlementsFile({
70
68
  proj,
@@ -103,6 +101,7 @@ const addBroadcastSourceFiles = ({ proj, extensionRootPath, appGroupIdentifier,
103
101
  fs.copyFileSync(path.join(__dirname, '..', '..', 'static', 'Atomic.swift'), path.join(extensionRootPath, 'Atomic.swift'));
104
102
  fs.copyFileSync(path.join(__dirname, '..', '..', 'static', 'DarwinNotificationCenter.swift'), path.join(extensionRootPath, 'DarwinNotificationCenter.swift'));
105
103
  fs.copyFileSync(path.join(__dirname, '..', '..', 'static', 'SampleUploader.swift'), path.join(extensionRootPath, 'SampleUploader.swift'));
104
+ fs.copyFileSync(path.join(__dirname, '..', '..', 'static', 'AudioUploader.swift'), path.join(extensionRootPath, 'AudioUploader.swift'));
106
105
  fs.copyFileSync(path.join(__dirname, '..', '..', 'static', 'SocketConnection.swift'), path.join(extensionRootPath, 'SocketConnection.swift'));
107
106
  // Update app group bundle id in SampleHandler code
108
107
  const code = fs.readFileSync(path.join(extensionRootPath, 'SampleHandler.swift'), { encoding: 'utf-8' });
@@ -126,6 +125,9 @@ const addBroadcastSourceFiles = ({ proj, extensionRootPath, appGroupIdentifier,
126
125
  proj.addSourceFile('SampleUploader.swift', {
127
126
  target: targetUuid,
128
127
  }, groupUuid);
128
+ proj.addSourceFile('AudioUploader.swift', {
129
+ target: targetUuid,
130
+ }, groupUuid);
129
131
  proj.addSourceFile('SocketConnection.swift', {
130
132
  target: targetUuid,
131
133
  }, groupUuid);