Skip to content
This repository was archived by the owner on Feb 10, 2026. It is now read-only.

Commit a31f3ec

Browse files
committed
Fix android plugin
1 parent d33ffe9 commit a31f3ec

4 files changed

Lines changed: 63 additions & 124 deletions

File tree

internal/fishjam-chat/app.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,6 @@
7070
"enableVoIPBackgroundMode": true,
7171
"supportsPictureInPicture": true,
7272
"broadcastExtensionDisplayName": "Fishjam Screen Broadcast"
73-
},
74-
"livestream": {
75-
"android": {
76-
"enableScreensharing": true,
77-
"supportsPictureInPicture": true
78-
},
79-
"ios": {
80-
"enableScreensharing": true,
81-
"supportsPictureInPicture": true
82-
}
8373
}
8474
}
8575
],

packages/react-native-client/plugin/src/types.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,5 @@ export type FishjamPluginOptions =
1414
broadcastExtensionTargetName?: string;
1515
broadcastExtensionDisplayName?: string;
1616
};
17-
livestream?: {
18-
android?: {
19-
enableScreensharing?: boolean;
20-
supportsPictureInPicture?: boolean;
21-
};
22-
ios?: {
23-
enableScreensharing?: boolean;
24-
supportsPictureInPicture?: boolean;
25-
};
26-
};
2717
}
2818
| undefined;

packages/react-native-client/plugin/src/withFishjam.ts

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,107 +3,9 @@ import { withFishjamAndroid } from './withFishjamAndroid';
33
import { FishjamPluginOptions } from './types';
44
import withFishjamIos from './withFishjamIos';
55

6-
/**
7-
* Main Fishjam Expo config plugin.
8-
*
9-
* This plugin configures both iOS and Android platforms for Fishjam video calls
10-
* and optionally for livestreaming functionality.
11-
*
12-
* ## Basic Usage (Video Calls)
13-
*
14-
* ```json
15-
* {
16-
* "plugins": [
17-
* [
18-
* "@fishjam-cloud/react-native-client",
19-
* {
20-
* "android": {
21-
* "enableForegroundService": true,
22-
* "supportsPictureInPicture": true
23-
* },
24-
* "ios": {
25-
* "enableScreensharing": true,
26-
* "enableVoIPBackgroundMode": true,
27-
* "supportsPictureInPicture": true
28-
* }
29-
* }
30-
* ]
31-
* ]
32-
* }
33-
* ```
34-
*
35-
* ## Livestreaming Support
36-
*
37-
* If you're using the livestream functionality (WHIP/WHEP), add the `livestream` configuration.
38-
* This will automatically configure the underlying `react-native-whip-whep` package:
39-
*
40-
* ```json
41-
* {
42-
* "plugins": [
43-
* [
44-
* "@fishjam-cloud/react-native-client",
45-
* {
46-
* "android": {
47-
* "enableForegroundService": true,
48-
* "supportsPictureInPicture": true
49-
* },
50-
* "ios": {
51-
* "enableScreensharing": true,
52-
* "enableVoIPBackgroundMode": true,
53-
* "supportsPictureInPicture": true
54-
* },
55-
* "livestream": {
56-
* "android": {
57-
* "enableScreensharing": true,
58-
* "supportsPictureInPicture": true
59-
* },
60-
* "ios": {
61-
* "enableScreensharing": true,
62-
* "supportsPictureInPicture": true
63-
* }
64-
* }
65-
* }
66-
* ]
67-
* ]
68-
* }
69-
* ```
70-
*
71-
* The `livestream` configuration adds:
72-
* - **Android**: ScreenCaptureService for screen sharing in livestreams
73-
* - **iOS**: Broadcast extension for screen sharing in livestreams
74-
*
75-
* @param config - Expo config object
76-
* @param options - Plugin configuration options
77-
* @returns Modified config object
78-
*/
796
const withFishjam: ConfigPlugin<FishjamPluginOptions> = (config, options) => {
807
config = withFishjamAndroid(config, options);
818
config = withFishjamIos(config, options);
82-
83-
if (options?.livestream) {
84-
try {
85-
const withWhipWhep =
86-
// eslint-disable-next-line @typescript-eslint/no-require-imports
87-
require('react-native-whip-whep/plugin/build/withWhipWhep').default;
88-
89-
// Fishjam's iOS screensharing is enabled, disable whip-whep's screensharing
90-
// This ensures only one broadcast extension is created (Fishjam's FishjamScreenBroadcastExtension)
91-
// to avoid duplicate broadcast extension targets in the Xcode project
92-
if (options?.ios?.enableScreensharing) {
93-
options.livestream.ios = {
94-
...options.livestream.ios,
95-
enableScreensharing: false,
96-
};
97-
}
98-
99-
config = withWhipWhep(config, options.livestream);
100-
} catch {
101-
console.warn(
102-
'[Fishjam] react-native-whip-whep plugin not found. Livestream configuration will be skipped.',
103-
);
104-
}
105-
}
106-
1079
return config;
10810
};
10911

packages/react-native-client/plugin/src/withFishjamAndroid.ts

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const withFishjamForegroundService: ConfigPlugin<FishjamPluginOptions> = (
1818
const mainApplication = getMainApplicationOrThrow(configuration.modResults);
1919
mainApplication.service = mainApplication.service || [];
2020

21-
const newService = {
21+
const fishjamService = {
2222
$: {
2323
'android:name':
2424
'io.fishjam.reactnative.foregroundService.FishjamForegroundService',
@@ -27,14 +27,70 @@ const withFishjamForegroundService: ConfigPlugin<FishjamPluginOptions> = (
2727
},
2828
};
2929

30-
const existingServiceIndex = mainApplication.service.findIndex(
31-
(service) => service.$['android:name'] === newService.$['android:name'],
30+
const whipWhepService = {
31+
$: {
32+
'android:name':
33+
'com.swmansion.reactnativeclient.foregroundService.ScreenCaptureService',
34+
'android:foregroundServiceType': 'mediaProjection',
35+
'android:stopWithTask': 'true',
36+
},
37+
};
38+
39+
// Add Fishjam service
40+
const existingFishjamServiceIndex = mainApplication.service.findIndex(
41+
(service) => service.$['android:name'] === fishjamService.$['android:name'],
42+
);
43+
44+
if (existingFishjamServiceIndex !== -1) {
45+
mainApplication.service[existingFishjamServiceIndex] = fishjamService;
46+
} else {
47+
mainApplication.service.push(fishjamService);
48+
}
49+
50+
// Add WhipWhep service
51+
const existingWhipWhepServiceIndex = mainApplication.service.findIndex(
52+
(service) => service.$['android:name'] === whipWhepService.$['android:name'],
3253
);
3354

34-
if (existingServiceIndex !== -1) {
35-
mainApplication.service[existingServiceIndex] = newService;
55+
if (existingWhipWhepServiceIndex !== -1) {
56+
mainApplication.service[existingWhipWhepServiceIndex] = whipWhepService;
3657
} else {
37-
mainApplication.service.push(newService);
58+
mainApplication.service.push(whipWhepService);
59+
}
60+
61+
return configuration;
62+
});
63+
64+
const withFishjamForegroundServicePermission: ConfigPlugin<FishjamPluginOptions> = (
65+
config,
66+
props,
67+
) =>
68+
withAndroidManifest(config, (configuration) => {
69+
if (!props?.android?.enableForegroundService) {
70+
return configuration;
71+
}
72+
73+
const mainApplication = configuration.modResults;
74+
if (!mainApplication.manifest) {
75+
return configuration;
76+
}
77+
78+
if (!mainApplication.manifest['uses-permission']) {
79+
mainApplication.manifest['uses-permission'] = [];
80+
}
81+
82+
const permissions = mainApplication.manifest['uses-permission'];
83+
84+
const hasForegroundServicePermission = permissions.some(
85+
(perm) => perm.$?.['android:name'] === 'android.permission.FOREGROUND_SERVICE',
86+
);
87+
88+
if (!hasForegroundServicePermission) {
89+
permissions.push({
90+
$: {
91+
'android:name': 'android.permission.FOREGROUND_SERVICE',
92+
},
93+
});
3894
}
3995

4096
return configuration;
@@ -61,6 +117,7 @@ export const withFishjamAndroid: ConfigPlugin<FishjamPluginOptions> = (
61117
config,
62118
props,
63119
) => {
120+
config = withFishjamForegroundServicePermission(config, props);
64121
config = withFishjamForegroundService(config, props);
65122
config = withFishjamPictureInPicture(config, props);
66123
return config;

0 commit comments

Comments
 (0)