@fishjam-cloud/react-native-client 0.2.0 → 0.2.2
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/README.md +21 -8
- package/android/build.gradle +5 -3
- 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 +14 -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 +870 -0
- package/android/src/main/java/io/fishjam/reactnative/RNFishjamClientModule.kt +370 -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/expo-module.config.json +17 -0
- package/ios/RNFishjamClient.podspec +30 -0
- package/ios/RNFishjamClientModule.swift +2 -2
- package/package.json +10 -7
- 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
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.2",
|
|
4
4
|
"description": "A React Native client for Fishjam Cloud",
|
|
5
5
|
"author": "Fishjam Cloud Team",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"bugs": {
|
|
32
32
|
"url": "https://github.com/fishjam-cloud/mobile-client-sdk/issues"
|
|
33
33
|
},
|
|
34
|
-
"homepage": "https://
|
|
34
|
+
"homepage": "https://fishjam.io",
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"registry": "https://registry.npmjs.org/",
|
|
37
37
|
"access": "public"
|
|
@@ -78,12 +78,15 @@
|
|
|
78
78
|
"testEnvironment": "jsdom"
|
|
79
79
|
},
|
|
80
80
|
"files": [
|
|
81
|
-
"build
|
|
82
|
-
"ios/*.swift",
|
|
83
|
-
"android/src",
|
|
81
|
+
"build/**",
|
|
84
82
|
"android/build.gradle",
|
|
85
|
-
"
|
|
83
|
+
"android/src/**",
|
|
84
|
+
"ios/*.swift",
|
|
85
|
+
"ios/RNFishjamClient.podspec",
|
|
86
|
+
"plugin/build/**",
|
|
86
87
|
"app.plugin.js",
|
|
87
|
-
"
|
|
88
|
+
"expo-module.config.json",
|
|
89
|
+
"README.md",
|
|
90
|
+
"!**/node_modules"
|
|
88
91
|
]
|
|
89
92
|
}
|
|
@@ -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, { android: { enableForegroundService } }) => {
|
|
27
|
+
if (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;
|