@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.
- package/CHANGELOG.md +40 -0
- package/android/src/main/java/com/streamvideo/reactnative/audio/AudioDeviceManager.kt +79 -54
- package/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioManagerUtil.kt +6 -2
- package/android/src/main/java/com/streamvideo/reactnative/callmanager/StreamInCallManagerModule.kt +3 -3
- package/dist/commonjs/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
- package/dist/commonjs/components/Participant/FloatingParticipantView/index.js.map +1 -1
- package/dist/commonjs/contexts/ThemeContext.js +10 -0
- package/dist/commonjs/contexts/ThemeContext.js.map +1 -1
- package/dist/commonjs/hooks/index.js +11 -0
- package/dist/commonjs/hooks/index.js.map +1 -1
- package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js +73 -0
- package/dist/commonjs/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -1
- package/dist/commonjs/hooks/useAudioDeviceStatus.js +76 -0
- package/dist/commonjs/hooks/useAudioDeviceStatus.js.map +1 -0
- package/dist/commonjs/hooks/useScreenShareButton.js.map +1 -1
- package/dist/commonjs/modules/call-manager/CallManager.js +94 -47
- package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
- package/dist/commonjs/providers/NoiseCancellation/lib.js.map +1 -1
- package/dist/commonjs/providers/StreamCall/AudioInterruptionTracer.js.map +1 -1
- package/dist/commonjs/utils/internal/callingx/callingx.js +0 -7
- package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -1
- package/dist/commonjs/utils/push/setupCallingExpEvents.js +0 -2
- package/dist/commonjs/utils/push/setupCallingExpEvents.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/module/components/Call/RingingCallContent/OutgoingCall.js.map +1 -1
- package/dist/module/components/Participant/FloatingParticipantView/index.js.map +1 -1
- package/dist/module/contexts/ThemeContext.js +10 -0
- package/dist/module/contexts/ThemeContext.js.map +1 -1
- package/dist/module/hooks/index.js +1 -0
- package/dist/module/hooks/index.js.map +1 -1
- package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js +73 -0
- package/dist/module/hooks/push/useCallingExpWithCallingStateEffect.js.map +1 -1
- package/dist/module/hooks/useAudioDeviceStatus.js +71 -0
- package/dist/module/hooks/useAudioDeviceStatus.js.map +1 -0
- package/dist/module/hooks/useScreenShareButton.js.map +1 -1
- package/dist/module/modules/call-manager/CallManager.js +94 -47
- package/dist/module/modules/call-manager/CallManager.js.map +1 -1
- package/dist/module/providers/NoiseCancellation/lib.js.map +1 -1
- package/dist/module/providers/StreamCall/AudioInterruptionTracer.js.map +1 -1
- package/dist/module/utils/internal/callingx/callingx.js +0 -7
- package/dist/module/utils/internal/callingx/callingx.js.map +1 -1
- package/dist/module/utils/push/setupCallingExpEvents.js +0 -2
- package/dist/module/utils/push/setupCallingExpEvents.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/typescript/components/Participant/FloatingParticipantView/index.d.ts.map +1 -1
- package/dist/typescript/contexts/ThemeContext.d.ts +10 -1
- package/dist/typescript/contexts/ThemeContext.d.ts.map +1 -1
- package/dist/typescript/hooks/index.d.ts +1 -0
- package/dist/typescript/hooks/index.d.ts.map +1 -1
- package/dist/typescript/hooks/push/useCallingExpWithCallingStateEffect.d.ts.map +1 -1
- package/dist/typescript/hooks/useAudioDeviceStatus.d.ts +21 -0
- package/dist/typescript/hooks/useAudioDeviceStatus.d.ts.map +1 -0
- package/dist/typescript/hooks/useScreenShareButton.d.ts +2 -1
- package/dist/typescript/hooks/useScreenShareButton.d.ts.map +1 -1
- package/dist/typescript/modules/call-manager/CallManager.d.ts +25 -11
- package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
- package/dist/typescript/modules/call-manager/types.d.ts +29 -3
- package/dist/typescript/modules/call-manager/types.d.ts.map +1 -1
- package/dist/typescript/providers/NoiseCancellation/lib.d.ts.map +1 -1
- package/dist/typescript/providers/StreamCall/AudioInterruptionTracer.d.ts.map +1 -1
- package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
- package/dist/typescript/utils/internal/callingx/callingx.d.ts.map +1 -1
- package/dist/typescript/utils/push/setupCallingExpEvents.d.ts.map +1 -1
- package/dist/typescript/version.d.ts +1 -1
- package/expo-config-plugin/dist/index.js +2 -0
- package/expo-config-plugin/dist/withAndroidMessagingService.js +313 -0
- package/expo-config-plugin/dist/withIosScreenCapture/addBroadcastExtensionXcodeTarget.js +84 -2
- package/expo-config-plugin/dist/withIosScreenCapture/withPlistUpdates.js +3 -6
- package/expo-config-plugin/dist/withIosScreenCapture/withTarget.js +6 -4
- package/expo-config-plugin/static/AudioUploader.swift +230 -0
- package/expo-config-plugin/static/SampleHandler.swift +67 -14
- package/ios/StreamInCallManager.m +7 -0
- package/ios/StreamInCallManager.swift +258 -15
- package/ios/StreamVideoReactNative.m +15 -5
- package/package.json +27 -25
- package/src/components/Call/RingingCallContent/OutgoingCall.tsx +1 -2
- package/src/components/Participant/FloatingParticipantView/index.tsx +1 -4
- package/src/contexts/ThemeContext.tsx +10 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/push/useCallingExpWithCallingStateEffect.ts +95 -0
- package/src/hooks/useAudioDeviceStatus.ts +90 -0
- package/src/hooks/useScreenShareButton.ts +2 -1
- package/src/modules/call-manager/CallManager.ts +123 -66
- package/src/modules/call-manager/native-module.d.ts +14 -7
- package/src/modules/call-manager/types.ts +30 -3
- package/src/providers/NoiseCancellation/lib.ts +1 -2
- package/src/providers/StreamCall/AudioInterruptionTracer.tsx +1 -2
- package/src/utils/StreamVideoRN/types.ts +1 -3
- package/src/utils/internal/callingx/callingx.ts +0 -8
- package/src/utils/push/setupCallingExpEvents.ts +0 -2
- package/src/version.ts +1 -1
- package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js +0 -68
- package/dist/commonjs/utils/internal/callingx/audioSessionPromise.js.map +0 -1
- package/dist/module/utils/internal/callingx/audioSessionPromise.js +0 -63
- package/dist/module/utils/internal/callingx/audioSessionPromise.js.map +0 -1
- package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts +0 -16
- package/dist/typescript/utils/internal/callingx/audioSessionPromise.d.ts.map +0 -1
- 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:
|
|
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
|
-
|
|
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);
|