@fishjam-cloud/react-native-client 0.2.1 → 0.2.3
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/android/build.gradle +1 -1
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/io/fishjam/reactnative/AudioDeviceKind.kt +34 -0
- package/android/src/main/java/io/fishjam/reactnative/AudioSwitchManager.kt +61 -0
- package/android/src/main/java/io/fishjam/reactnative/EmitableEvents.kt +15 -0
- package/android/src/main/java/io/fishjam/reactnative/Errors.kt +31 -0
- package/android/src/main/java/io/fishjam/reactnative/FishjamForegroundService.kt +90 -0
- package/android/src/main/java/io/fishjam/reactnative/RNFishjamClient.kt +883 -0
- package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +371 -0
- package/android/src/main/java/io/fishjam/reactnative/Utils.kt +11 -0
- package/android/src/main/java/io/fishjam/reactnative/VideoPreviewView.kt +40 -0
- package/android/src/main/java/io/fishjam/reactnative/VideoPreviewViewModule.kt +17 -0
- package/android/src/main/java/io/fishjam/reactnative/VideoRendererView.kt +58 -0
- package/android/src/main/java/io/fishjam/reactnative/VideoRendererViewModule.kt +25 -0
- package/android/src/main/java/io/fishjam/reactnative/VideoView.kt +77 -0
- package/build/RNFishjamClientModule.d.ts +2 -0
- package/build/RNFishjamClientModule.d.ts.map +1 -1
- package/build/RNFishjamClientModule.js +2 -1
- package/build/RNFishjamClientModule.js.map +1 -1
- package/build/common/client.d.ts +4 -1
- package/build/common/client.d.ts.map +1 -1
- package/build/common/client.js +4 -1
- package/build/common/client.js.map +1 -1
- package/build/common/metadata.d.ts +1 -0
- package/build/common/metadata.d.ts.map +1 -1
- package/build/common/metadata.js +1 -0
- package/build/common/metadata.js.map +1 -1
- package/build/common/webRTC.d.ts +2 -0
- package/build/common/webRTC.d.ts.map +1 -1
- package/build/common/webRTC.js +2 -0
- package/build/common/webRTC.js.map +1 -1
- package/build/components/VideoPreviewView.d.ts +6 -3
- package/build/components/VideoPreviewView.d.ts.map +1 -1
- package/build/components/VideoPreviewView.js +5 -0
- package/build/components/VideoPreviewView.js.map +1 -1
- package/build/components/VideoRendererView.d.ts +5 -3
- package/build/components/VideoRendererView.d.ts.map +1 -1
- package/build/components/VideoRendererView.js +4 -0
- package/build/components/VideoRendererView.js.map +1 -1
- package/build/hooks/useAudioSettings.d.ts +15 -0
- package/build/hooks/useAudioSettings.d.ts.map +1 -1
- package/build/hooks/useAudioSettings.js +15 -13
- package/build/hooks/useAudioSettings.js.map +1 -1
- package/build/hooks/useBandwidthEstimation.d.ts +2 -0
- package/build/hooks/useBandwidthEstimation.d.ts.map +1 -1
- package/build/hooks/useBandwidthEstimation.js +2 -0
- package/build/hooks/useBandwidthEstimation.js.map +1 -1
- package/build/hooks/useCamera.d.ts +45 -1
- package/build/hooks/useCamera.d.ts.map +1 -1
- package/build/hooks/useCamera.js +45 -37
- package/build/hooks/useCamera.js.map +1 -1
- package/build/hooks/useFishjamEvent.d.ts +1 -0
- package/build/hooks/useFishjamEvent.d.ts.map +1 -1
- package/build/hooks/useFishjamEvent.js +3 -4
- package/build/hooks/useFishjamEvent.js.map +1 -1
- package/build/hooks/useMicrophone.d.ts +4 -0
- package/build/hooks/useMicrophone.d.ts.map +1 -1
- package/build/hooks/useMicrophone.js +8 -4
- package/build/hooks/useMicrophone.js.map +1 -1
- package/build/hooks/useParticipants.d.ts +2 -0
- package/build/hooks/useParticipants.d.ts.map +1 -1
- package/build/hooks/useParticipants.js +2 -0
- package/build/hooks/useParticipants.js.map +1 -1
- package/build/hooks/useReconnection.d.ts +6 -0
- package/build/hooks/useReconnection.d.ts.map +1 -1
- package/build/hooks/useReconnection.js +6 -0
- package/build/hooks/useReconnection.js.map +1 -1
- package/build/hooks/useScreencast.d.ts +22 -3
- package/build/hooks/useScreencast.d.ts.map +1 -1
- package/build/hooks/useScreencast.js +30 -22
- package/build/hooks/useScreencast.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/stats/useRTCStatistics.d.ts +1 -0
- package/build/stats/useRTCStatistics.d.ts.map +1 -1
- package/build/stats/useRTCStatistics.js +1 -0
- package/build/stats/useRTCStatistics.js.map +1 -1
- package/build/types.d.ts +6 -0
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/build/utils/errorListener.d.ts +2 -0
- package/build/utils/errorListener.d.ts.map +1 -0
- package/build/utils/errorListener.js +16 -0
- package/build/utils/errorListener.js.map +1 -0
- package/build/utils/foregroundService.d.ts +2 -0
- package/build/utils/foregroundService.d.ts.map +1 -1
- package/build/utils/foregroundService.js +2 -0
- package/build/utils/foregroundService.js.map +1 -1
- package/ios/Events.swift +1 -0
- package/ios/RNFishjamClient.podspec +1 -1
- package/ios/RNFishjamClient.swift +14 -0
- package/package.json +7 -6
- package/plugin/broadcastExtensionFiles/FishjamBroadcastSampleHandler.swift +50 -0
- package/plugin/broadcastExtensionFiles/FishjamScreenBroadcastExtension.entitlements +10 -0
- package/plugin/broadcastExtensionFiles/Info.plist +27 -0
- package/plugin/build/types.d.ts +9 -0
- package/plugin/build/types.js +2 -0
- package/plugin/build/withFishjam.d.ts +4 -0
- package/plugin/build/withFishjam.js +13 -0
- package/plugin/build/withFishjamAndroid.d.ts +3 -0
- package/plugin/build/withFishjamAndroid.js +32 -0
- package/plugin/build/withFishjamIos.d.ts +9 -0
- package/plugin/build/withFishjamIos.js +222 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ReceivableEvents } from '../hooks/useFishjamEvent';
|
|
2
|
+
import { nativeModuleEventEmitter } from '../RNFishjamClientModule';
|
|
3
|
+
export const initializeWarningListener = () => {
|
|
4
|
+
if (!__DEV__) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
nativeModuleEventEmitter.addListener(ReceivableEvents.Warning, ({ message }) => {
|
|
9
|
+
console.warn(message);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.error(`Failed to start warning listener: ${error?.message ?? ''}`);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=errorListener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorListener.js","sourceRoot":"","sources":["../../src/utils/errorListener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,EAAE;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,wBAAwB,CAAC,WAAW,CAClC,gBAAgB,CAAC,OAAO,EACxB,CAAC,EAAE,OAAO,EAAuB,EAAE,EAAE;YACnC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,KAAK,EAAE,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { ReceivableEvents } from '../hooks/useFishjamEvent';\nimport { nativeModuleEventEmitter } from '../RNFishjamClientModule';\n\nexport const initializeWarningListener = () => {\n if (!__DEV__) {\n return;\n }\n try {\n nativeModuleEventEmitter.addListener(\n ReceivableEvents.Warning,\n ({ message }: { message: string }) => {\n console.warn(message);\n },\n );\n } catch (error) {\n console.error(`Failed to start warning listener: ${error?.message ?? ''}`);\n }\n};\n"]}
|
|
@@ -18,6 +18,7 @@ import { ForegroundServiceOptions } from '../types';
|
|
|
18
18
|
```
|
|
19
19
|
<service android:name="io.fishjam.reactnative.FishjamForegroundService" android:foregroundServiceType="camera|microphone|mediaProjection"/>
|
|
20
20
|
```
|
|
21
|
+
* @category Screenshare
|
|
21
22
|
*/
|
|
22
23
|
export declare const startForegroundService: (options: ForegroundServiceOptions) => void;
|
|
23
24
|
/**
|
|
@@ -25,6 +26,7 @@ export declare const startForegroundService: (options: ForegroundServiceOptions)
|
|
|
25
26
|
* @see {@link startForegroundService} for further information.
|
|
26
27
|
*
|
|
27
28
|
* Does nothing on other platforms.
|
|
29
|
+
* @category Screenshare
|
|
28
30
|
*/
|
|
29
31
|
export declare const stopForegroundService: () => void;
|
|
30
32
|
//# sourceMappingURL=foregroundService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foregroundService.d.ts","sourceRoot":"","sources":["../../src/utils/foregroundService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"foregroundService.d.ts","sourceRoot":"","sources":["../../src/utils/foregroundService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;MAoBM;AACN,eAAO,MAAM,sBAAsB,YAAa,wBAAwB,SAKvE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,YAKjC,CAAC"}
|
|
@@ -19,6 +19,7 @@ import RNFishjamClientModule from '../RNFishjamClientModule';
|
|
|
19
19
|
```
|
|
20
20
|
<service android:name="io.fishjam.reactnative.FishjamForegroundService" android:foregroundServiceType="camera|microphone|mediaProjection"/>
|
|
21
21
|
```
|
|
22
|
+
* @category Screenshare
|
|
22
23
|
*/
|
|
23
24
|
export const startForegroundService = (options) => {
|
|
24
25
|
if (Platform.OS !== 'android') {
|
|
@@ -31,6 +32,7 @@ export const startForegroundService = (options) => {
|
|
|
31
32
|
* @see {@link startForegroundService} for further information.
|
|
32
33
|
*
|
|
33
34
|
* Does nothing on other platforms.
|
|
35
|
+
* @category Screenshare
|
|
34
36
|
*/
|
|
35
37
|
export const stopForegroundService = () => {
|
|
36
38
|
if (Platform.OS !== 'android') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foregroundService.js","sourceRoot":"","sources":["../../src/utils/foregroundService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAG7D
|
|
1
|
+
{"version":3,"file":"foregroundService.js","sourceRoot":"","sources":["../../src/utils/foregroundService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;;MAoBM;AACN,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAiC,EAAE,EAAE;IAC1E,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,qBAAqB,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACxC,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,qBAAqB,CAAC,qBAAqB,EAAE,CAAC;AAChD,CAAC,CAAC","sourcesContent":["import { Platform } from 'react-native';\nimport RNFishjamClientModule from '../RNFishjamClientModule';\nimport { ForegroundServiceOptions } from '../types';\n\n/**\n * Launches a foreground service on Android.\n * Does nothing on other platforms.\n * \n * @remarks\n * You must have have the following permissions enabled before calling this function:\n * @example\n ```\n \"android.permission.FOREGROUND_SERVICE\"\n \"android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION\"\n \"android.permission.FOREGROUND_SERVICE_CAMERA\"\n \"android.permission.FOREGROUND_SERVICE_MICROPHONE\"\n \"android.permission.POST_NOTIFICATIONS\"\n *```\n * as well as FishjamForegroundService in your AndroidManifest:\n * @example\n ```\n <service android:name=\"io.fishjam.reactnative.FishjamForegroundService\" android:foregroundServiceType=\"camera|microphone|mediaProjection\"/>\n ```\n * @category Screenshare\n */\nexport const startForegroundService = (options: ForegroundServiceOptions) => {\n if (Platform.OS !== 'android') {\n return;\n }\n RNFishjamClientModule.startForegroundService(options);\n};\n\n/**\n * Stops previously launched Android foreground service.\n * @see {@link startForegroundService} for further information.\n *\n * Does nothing on other platforms.\n * @category Screenshare\n */\nexport const stopForegroundService = () => {\n if (Platform.OS !== 'android') {\n return;\n }\n RNFishjamClientModule.stopForegroundService();\n};\n"]}
|
package/ios/Events.swift
CHANGED
|
@@ -13,6 +13,8 @@ class RNFishjamClient: FishjamClientListener {
|
|
|
13
13
|
var isScreencastOn = false
|
|
14
14
|
var isConnected = false
|
|
15
15
|
|
|
16
|
+
private var isCameraInitialized = false
|
|
17
|
+
|
|
16
18
|
var connectPromise: Promise? = nil
|
|
17
19
|
|
|
18
20
|
var videoSimulcastConfig: SimulcastConfig = SimulcastConfig()
|
|
@@ -211,14 +213,22 @@ class RNFishjamClient: FishjamClientListener {
|
|
|
211
213
|
isCameraOn = false
|
|
212
214
|
isScreencastOn = false
|
|
213
215
|
isConnected = false
|
|
216
|
+
isCameraInitialized = false
|
|
214
217
|
RNFishjamClient.fishjamClient?.leave()
|
|
215
218
|
}
|
|
216
219
|
|
|
217
220
|
func startCamera(config: CameraConfig) throws {
|
|
218
221
|
try ensureCreated()
|
|
222
|
+
|
|
223
|
+
guard !isCameraInitialized else {
|
|
224
|
+
emit(warning: "Camera already started. You may only call startCamera once before leaveRoom is called.")
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
219
228
|
let cameraTrack = try createCameraTrack(config: config)
|
|
220
229
|
setCameraTrackState(cameraTrack, enabled: config.cameraEnabled)
|
|
221
230
|
emitEndpoints()
|
|
231
|
+
isCameraInitialized = true
|
|
222
232
|
}
|
|
223
233
|
|
|
224
234
|
private func createCameraTrack(config: CameraConfig) throws -> LocalVideoTrack {
|
|
@@ -667,6 +677,10 @@ class RNFishjamClient: FishjamClientListener {
|
|
|
667
677
|
sendEvent(name, data)
|
|
668
678
|
}
|
|
669
679
|
|
|
680
|
+
func emit(warning: String) {
|
|
681
|
+
emitEvent(name: EmitableEvents.Warning, data: ["message": warning])
|
|
682
|
+
}
|
|
683
|
+
|
|
670
684
|
func emitEndpoints() {
|
|
671
685
|
let eventName = EmitableEvents.PeersUpdate
|
|
672
686
|
let EndpointsUpdateMap = [eventName: (try? getPeers()) ?? []]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fishjam-cloud/react-native-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "A React Native client for Fishjam Cloud",
|
|
5
5
|
"author": "Fishjam Cloud Team",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"MembraneWebRTC",
|
|
28
28
|
"fishjam"
|
|
29
29
|
],
|
|
30
|
-
"repository": "
|
|
30
|
+
"repository": "github:fishjam-cloud/mobile-client-sdk",
|
|
31
31
|
"bugs": {
|
|
32
32
|
"url": "https://github.com/fishjam-cloud/mobile-client-sdk/issues"
|
|
33
33
|
},
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/lodash": "^4.17.7",
|
|
47
47
|
"@types/phoenix": "^1.6.5",
|
|
48
48
|
"@types/promise-fs": "^2.1.2",
|
|
49
|
-
"@types/react": "^18.3.
|
|
49
|
+
"@types/react": "^18.3.7",
|
|
50
50
|
"expo": "^51.0.32",
|
|
51
51
|
"expo-module-scripts": "^3.5.2",
|
|
52
52
|
"expo-modules-core": "^1.12.24",
|
|
@@ -78,12 +78,13 @@
|
|
|
78
78
|
"testEnvironment": "jsdom"
|
|
79
79
|
},
|
|
80
80
|
"files": [
|
|
81
|
-
"build
|
|
81
|
+
"build/**",
|
|
82
82
|
"android/build.gradle",
|
|
83
|
-
"android/src
|
|
83
|
+
"android/src/**",
|
|
84
84
|
"ios/*.swift",
|
|
85
85
|
"ios/RNFishjamClient.podspec",
|
|
86
|
-
"plugin/build
|
|
86
|
+
"plugin/build/**",
|
|
87
|
+
"plugin/broadcastExtensionFiles/**",
|
|
87
88
|
"app.plugin.js",
|
|
88
89
|
"expo-module.config.json",
|
|
89
90
|
"README.md",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import FishjamCloudClient
|
|
2
|
+
import Foundation
|
|
3
|
+
import ReplayKit
|
|
4
|
+
import WebRTC
|
|
5
|
+
import os.log
|
|
6
|
+
|
|
7
|
+
/// App Group used by the extension to exchange buffers with the target application
|
|
8
|
+
let appGroup = "{{GROUP_IDENTIFIER}}"
|
|
9
|
+
|
|
10
|
+
let logger = OSLog(subsystem: "{{BUNDLE_IDENTIFIER}}.FishjamBroadcastSampleHandler", category: "Broadcaster")
|
|
11
|
+
|
|
12
|
+
/// An example `SampleHandler` utilizing `BroadcastSampleSource` from `MembraneRTC` sending broadcast samples and necessary notification enabling device's screencast.
|
|
13
|
+
class FishjamBroadcastSampleHandler: RPBroadcastSampleHandler {
|
|
14
|
+
let broadcastSource = BroadcastSampleSource(appGroup: appGroup)
|
|
15
|
+
var started: Bool = false
|
|
16
|
+
|
|
17
|
+
override func broadcastStarted(withSetupInfo _: [String: NSObject]?) {
|
|
18
|
+
started = broadcastSource.connect()
|
|
19
|
+
|
|
20
|
+
guard started else {
|
|
21
|
+
os_log("failed to connect with ipc server", log: logger, type: .debug)
|
|
22
|
+
|
|
23
|
+
super.finishBroadcastWithError(NSError(domain: "", code: 0, userInfo: nil))
|
|
24
|
+
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
broadcastSource.started()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override func broadcastPaused() {
|
|
32
|
+
broadcastSource.paused()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override func broadcastResumed() {
|
|
36
|
+
broadcastSource.resumed()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override func broadcastFinished() {
|
|
40
|
+
broadcastSource.finished()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
|
|
44
|
+
guard started else {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
broadcastSource.processFrame(sampleBuffer: sampleBuffer, ofType: sampleBufferType)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>com.apple.security.application-groups</key>
|
|
6
|
+
<array>
|
|
7
|
+
<string>{{GROUP_IDENTIFIER}}</string>
|
|
8
|
+
</array>
|
|
9
|
+
</dict>
|
|
10
|
+
</plist>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDisplayName</key>
|
|
6
|
+
<string>FishjamScreenBroadcast</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleName</key>
|
|
12
|
+
<string>$(PRODUCT_NAME)</string>
|
|
13
|
+
<key>CFBundlePackageType</key>
|
|
14
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
15
|
+
<key>CFBundleVersion</key>
|
|
16
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
17
|
+
<key>NSExtension</key>
|
|
18
|
+
<dict>
|
|
19
|
+
<key>NSExtensionPointIdentifier</key>
|
|
20
|
+
<string>com.apple.broadcast-services-upload</string>
|
|
21
|
+
<key>NSExtensionPrincipalClass</key>
|
|
22
|
+
<string>$(PRODUCT_MODULE_NAME).FishjamBroadcastSampleHandler</string>
|
|
23
|
+
<key>RPBroadcastProcessMode</key>
|
|
24
|
+
<string>RPBroadcastProcessModeSampleBuffer</string>
|
|
25
|
+
</dict>
|
|
26
|
+
</dict>
|
|
27
|
+
</plist>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const withFishjamAndroid_1 = require("./withFishjamAndroid");
|
|
7
|
+
const withFishjamIos_1 = __importDefault(require("./withFishjamIos"));
|
|
8
|
+
const withFishjam = (config, options) => {
|
|
9
|
+
(0, withFishjamAndroid_1.withFishjamAndroid)(config, options);
|
|
10
|
+
(0, withFishjamIos_1.default)(config, options);
|
|
11
|
+
return config;
|
|
12
|
+
};
|
|
13
|
+
exports.default = withFishjam;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withFishjamAndroid = void 0;
|
|
4
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
5
|
+
const Manifest_1 = require("@expo/config-plugins/build/android/Manifest");
|
|
6
|
+
const withFishjamForegroundService = (config) => {
|
|
7
|
+
return (0, config_plugins_1.withAndroidManifest)(config, async (config) => {
|
|
8
|
+
const mainApplication = (0, Manifest_1.getMainApplicationOrThrow)(config.modResults);
|
|
9
|
+
mainApplication.service = mainApplication.service || [];
|
|
10
|
+
const newService = {
|
|
11
|
+
$: {
|
|
12
|
+
'android:name': 'io.fishjam.reactnative.FishjamForegroundService',
|
|
13
|
+
'android:foregroundServiceType': 'camera|microphone|mediaProjection',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const existingServiceIndex = mainApplication.service.findIndex((service) => service.$['android:name'] === newService.$['android:name']);
|
|
17
|
+
if (existingServiceIndex !== -1) {
|
|
18
|
+
mainApplication.service[existingServiceIndex] = newService;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
mainApplication.service.push(newService);
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
const withFishjamAndroid = (config, props) => {
|
|
27
|
+
if (props?.android?.enableForegroundService) {
|
|
28
|
+
config = withFishjamForegroundService(config);
|
|
29
|
+
}
|
|
30
|
+
return config;
|
|
31
|
+
};
|
|
32
|
+
exports.withFishjamAndroid = withFishjamAndroid;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import { FishjamPluginOptions } from './types';
|
|
3
|
+
export declare const SBE_PODFILE_SNIPPET = "\ntarget 'FishjamScreenBroadcastExtension' do\n pod 'FishjamCloudClient/Broadcast'\nend";
|
|
4
|
+
/**
|
|
5
|
+
* Applies screen sharing plugin if enabled. In order for screensharing to work, we need to copy extension files to your iOS project.
|
|
6
|
+
* Allows for dynamically changing deploymentTarget.
|
|
7
|
+
*/
|
|
8
|
+
declare const withFishjamIos: ConfigPlugin<FishjamPluginOptions>;
|
|
9
|
+
export default withFishjamIos;
|
|
@@ -0,0 +1,222 @@
|
|
|
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 (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.SBE_PODFILE_SNIPPET = void 0;
|
|
27
|
+
// ios-related code was mostly copied from OneSignal expo plugin: https://github.com/OneSignal/onesignal-expo-plugin/blob/main/onesignal/withOneSignalIos.ts
|
|
28
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
29
|
+
const fs = __importStar(require("promise-fs"));
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
const SBE_TARGET_NAME = 'FishjamScreenBroadcastExtension';
|
|
32
|
+
exports.SBE_PODFILE_SNIPPET = `
|
|
33
|
+
target '${SBE_TARGET_NAME}' do
|
|
34
|
+
pod 'FishjamCloudClient/Broadcast'
|
|
35
|
+
end`;
|
|
36
|
+
const TARGETED_DEVICE_FAMILY = `"1,2"`;
|
|
37
|
+
const IPHONEOS_DEPLOYMENT_TARGET = '13.4';
|
|
38
|
+
const GROUP_IDENTIFIER_TEMPLATE_REGEX = /{{GROUP_IDENTIFIER}}/gm;
|
|
39
|
+
const BUNDLE_IDENTIFIER_TEMPLATE_REGEX = /{{BUNDLE_IDENTIFIER}}/gm;
|
|
40
|
+
/**
|
|
41
|
+
* A helper function for updating a value in a file for given regex
|
|
42
|
+
*/
|
|
43
|
+
async function updateFileWithRegex(iosPath, fileName, regex, value) {
|
|
44
|
+
const filePath = `${iosPath}/${SBE_TARGET_NAME}/${fileName}`;
|
|
45
|
+
let file = await fs.readFile(filePath, { encoding: 'utf-8' });
|
|
46
|
+
file = file.replace(regex, value);
|
|
47
|
+
await fs.writeFile(filePath, file);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Inserts a required target to Podfile.
|
|
51
|
+
* This is needed to provide the dependency of FishjamCloudClient/Broadcast to the extension.
|
|
52
|
+
*/
|
|
53
|
+
async function updatePodfile(iosPath) {
|
|
54
|
+
let matches;
|
|
55
|
+
try {
|
|
56
|
+
const podfile = await fs.readFile(`${iosPath}/Podfile`, {
|
|
57
|
+
encoding: 'utf-8',
|
|
58
|
+
});
|
|
59
|
+
matches = podfile.match(exports.SBE_PODFILE_SNIPPET);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
console.error('Error reading from Podfile: ', e);
|
|
63
|
+
}
|
|
64
|
+
if (matches) {
|
|
65
|
+
console.log(`${SBE_TARGET_NAME} target already added to Podfile. Skipping...`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
fs.appendFile(`${iosPath}/Podfile`, exports.SBE_PODFILE_SNIPPET);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.error('Error writing to Podfile: ', e);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Adds "App Group" permission
|
|
77
|
+
* App Group allow your app and the FishjamScreenBroadcastExtension to communicate with each other.
|
|
78
|
+
*/
|
|
79
|
+
const withAppGroupPermissions = (config) => {
|
|
80
|
+
const APP_GROUP_KEY = 'com.apple.security.application-groups';
|
|
81
|
+
return (0, config_plugins_1.withEntitlementsPlist)(config, (newConfig) => {
|
|
82
|
+
if (!Array.isArray(newConfig.modResults[APP_GROUP_KEY])) {
|
|
83
|
+
newConfig.modResults[APP_GROUP_KEY] = [];
|
|
84
|
+
}
|
|
85
|
+
const modResultsArray = newConfig.modResults[APP_GROUP_KEY];
|
|
86
|
+
const entitlement = `group.${newConfig?.ios?.bundleIdentifier || ''}`;
|
|
87
|
+
if (modResultsArray.indexOf(entitlement) !== -1) {
|
|
88
|
+
return newConfig;
|
|
89
|
+
}
|
|
90
|
+
modResultsArray.push(entitlement);
|
|
91
|
+
return newConfig;
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Adds constants to Info.plist
|
|
96
|
+
* In other to dynamically retreive extension's bundleId and group name we need to store it in Info.plist.
|
|
97
|
+
*/
|
|
98
|
+
const withInfoPlistConstants = (config) => {
|
|
99
|
+
return (0, config_plugins_1.withInfoPlist)(config, (config) => {
|
|
100
|
+
const bundleIdentifier = config.ios?.bundleIdentifier || '';
|
|
101
|
+
config.modResults['AppGroupName'] = `group.${bundleIdentifier}`;
|
|
102
|
+
config.modResults['ScreencastExtensionBundleId'] =
|
|
103
|
+
`${bundleIdentifier}.${SBE_TARGET_NAME}`;
|
|
104
|
+
return config;
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Updates and copies required extension files.
|
|
109
|
+
* Our extension needs to be properly setup inside the XCode project. In order to do that we need to copy the files and update the pbxproj.
|
|
110
|
+
*/
|
|
111
|
+
const withFishjamSBE = (config, options) => {
|
|
112
|
+
return (0, config_plugins_1.withXcodeProject)(config, async (props) => {
|
|
113
|
+
const appName = props.modRequest.projectName || '';
|
|
114
|
+
const iosPath = props.modRequest.platformProjectRoot;
|
|
115
|
+
const bundleIdentifier = props.ios?.bundleIdentifier;
|
|
116
|
+
const xcodeProject = props.modResults;
|
|
117
|
+
const pluginDir = require.resolve('@fishjam-cloud/react-native-client/package.json');
|
|
118
|
+
const extensionSourceDir = path.join(pluginDir, '../plugin/broadcastExtensionFiles/');
|
|
119
|
+
await updatePodfile(iosPath);
|
|
120
|
+
const projPath = `${iosPath}/${appName}.xcodeproj/project.pbxproj`;
|
|
121
|
+
const extFiles = [
|
|
122
|
+
'FishjamBroadcastSampleHandler.swift',
|
|
123
|
+
`${SBE_TARGET_NAME}.entitlements`,
|
|
124
|
+
`Info.plist`,
|
|
125
|
+
];
|
|
126
|
+
await xcodeProject.parse(async function (err) {
|
|
127
|
+
if (err) {
|
|
128
|
+
console.error(`Error parsing iOS project: ${JSON.stringify(err)}`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (xcodeProject.pbxTargetByName(`"${SBE_TARGET_NAME}"`)) {
|
|
132
|
+
console.log(`${SBE_TARGET_NAME} already exists in project. Skipping...`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
// copy extension files
|
|
137
|
+
await fs.mkdir(`${iosPath}/${SBE_TARGET_NAME}`, { recursive: true });
|
|
138
|
+
for (let i = 0; i < extFiles.length; i++) {
|
|
139
|
+
const extFile = extFiles[i];
|
|
140
|
+
const targetFile = `${iosPath}/${SBE_TARGET_NAME}/${extFile}`;
|
|
141
|
+
await fs.copyFile(`${extensionSourceDir}${extFile}`, targetFile);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (e) {
|
|
145
|
+
console.error('Error copying extension files: ', e);
|
|
146
|
+
}
|
|
147
|
+
// update extension files
|
|
148
|
+
await updateFileWithRegex(iosPath, `${SBE_TARGET_NAME}.entitlements`, GROUP_IDENTIFIER_TEMPLATE_REGEX, `group.${bundleIdentifier}`);
|
|
149
|
+
await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', GROUP_IDENTIFIER_TEMPLATE_REGEX, `group.${bundleIdentifier}`);
|
|
150
|
+
await updateFileWithRegex(iosPath, 'FishjamBroadcastSampleHandler.swift', BUNDLE_IDENTIFIER_TEMPLATE_REGEX, bundleIdentifier || '');
|
|
151
|
+
// Create new PBXGroup for the extension
|
|
152
|
+
const extGroup = xcodeProject.addPbxGroup(extFiles, SBE_TARGET_NAME, SBE_TARGET_NAME);
|
|
153
|
+
// Add the new PBXGroup to the top level group. This makes the
|
|
154
|
+
// files / folder appear in the file explorer in Xcode.
|
|
155
|
+
const groups = xcodeProject.hash.project.objects['PBXGroup'];
|
|
156
|
+
Object.keys(groups).forEach(function (key) {
|
|
157
|
+
if (groups[key].name === undefined) {
|
|
158
|
+
xcodeProject.addToPbxGroup(extGroup.uuid, key);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
// WORK AROUND for codeProject.addTarget BUG
|
|
162
|
+
// Xcode projects don't contain these if there is only one target
|
|
163
|
+
// An upstream fix should be made to the code referenced in this link:
|
|
164
|
+
// - https://github.com/apache/cordova-node-xcode/blob/8b98cabc5978359db88dc9ff2d4c015cba40f150/lib/pbxProject.js#L860
|
|
165
|
+
const projObjects = xcodeProject.hash.project.objects;
|
|
166
|
+
projObjects['PBXTargetDependency'] =
|
|
167
|
+
projObjects['PBXTargetDependency'] || {};
|
|
168
|
+
projObjects['PBXContainerItemProxy'] =
|
|
169
|
+
projObjects['PBXTargetDependency'] || {};
|
|
170
|
+
// Add the SBE target
|
|
171
|
+
// This adds PBXTargetDependency and PBXContainerItemProxy for you
|
|
172
|
+
const sbeTarget = xcodeProject.addTarget(SBE_TARGET_NAME, 'app_extension', SBE_TARGET_NAME, `${bundleIdentifier}.${SBE_TARGET_NAME}`);
|
|
173
|
+
// Add build phases to the new target
|
|
174
|
+
xcodeProject.addBuildPhase(['FishjamBroadcastSampleHandler.swift'], 'PBXSourcesBuildPhase', 'Sources', sbeTarget.uuid);
|
|
175
|
+
xcodeProject.addBuildPhase([], 'PBXResourcesBuildPhase', 'Resources', sbeTarget.uuid);
|
|
176
|
+
xcodeProject.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', sbeTarget.uuid);
|
|
177
|
+
xcodeProject.addFramework('ReplayKit.framework', {
|
|
178
|
+
target: sbeTarget.uuid,
|
|
179
|
+
});
|
|
180
|
+
// Edit the Deployment info of the new Target, only IphoneOS and Targeted Device Family
|
|
181
|
+
// However, can be more
|
|
182
|
+
const configurations = xcodeProject.pbxXCBuildConfigurationSection();
|
|
183
|
+
for (const key in configurations) {
|
|
184
|
+
if (typeof configurations[key].buildSettings !== 'undefined' &&
|
|
185
|
+
configurations[key].buildSettings.PRODUCT_NAME ===
|
|
186
|
+
`"${SBE_TARGET_NAME}"`) {
|
|
187
|
+
const buildSettingsObj = configurations[key].buildSettings;
|
|
188
|
+
buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET =
|
|
189
|
+
options?.ios?.iphoneDeploymentTarget ?? IPHONEOS_DEPLOYMENT_TARGET;
|
|
190
|
+
buildSettingsObj.TARGETED_DEVICE_FAMILY = TARGETED_DEVICE_FAMILY;
|
|
191
|
+
buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `${SBE_TARGET_NAME}/${SBE_TARGET_NAME}.entitlements`;
|
|
192
|
+
buildSettingsObj.CODE_SIGN_STYLE = 'Automatic';
|
|
193
|
+
buildSettingsObj.INFOPLIST_FILE = `${SBE_TARGET_NAME}/Info.plist`;
|
|
194
|
+
buildSettingsObj.SWIFT_VERSION = '5.0';
|
|
195
|
+
buildSettingsObj.MARKETING_VERSION = '1.0.0';
|
|
196
|
+
buildSettingsObj.CURRENT_PROJECT_VERSION = '1';
|
|
197
|
+
buildSettingsObj.ENABLE_BITCODE = 'NO';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
await fs.writeFile(projPath, xcodeProject.writeSync());
|
|
201
|
+
});
|
|
202
|
+
return props;
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Applies screen sharing plugin if enabled. In order for screensharing to work, we need to copy extension files to your iOS project.
|
|
207
|
+
* Allows for dynamically changing deploymentTarget.
|
|
208
|
+
*/
|
|
209
|
+
const withFishjamIos = (config, props) => {
|
|
210
|
+
if (props?.ios?.enableScreensharing) {
|
|
211
|
+
withAppGroupPermissions(config);
|
|
212
|
+
withInfoPlistConstants(config);
|
|
213
|
+
withFishjamSBE(config, props);
|
|
214
|
+
}
|
|
215
|
+
(0, config_plugins_1.withPodfileProperties)(config, (config) => {
|
|
216
|
+
config.modResults['ios.deploymentTarget'] =
|
|
217
|
+
props?.ios?.iphoneDeploymentTarget ?? IPHONEOS_DEPLOYMENT_TARGET;
|
|
218
|
+
return config;
|
|
219
|
+
});
|
|
220
|
+
return config;
|
|
221
|
+
};
|
|
222
|
+
exports.default = withFishjamIos;
|