{"id":18465172,"url":"https://github.com/fishjam-dev/react-native-client-sdk","last_synced_at":"2025-04-08T08:31:49.196Z","repository":{"id":164303903,"uuid":"639739884","full_name":"fishjam-dev/react-native-client-sdk","owner":"fishjam-dev","description":"React Native client library for Fishjam.","archived":false,"fork":false,"pushed_at":"2024-05-20T12:44:05.000Z","size":8502,"stargazers_count":5,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-05-20T14:42:23.972Z","etag":null,"topics":["android","fishjam","ios","react-native","video","webrtc"],"latest_commit_sha":null,"homepage":"https://github.com/fishjam-dev/fishjam","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fishjam-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-12T05:55:26.000Z","updated_at":"2024-05-20T14:42:30.475Z","dependencies_parsed_at":"2023-12-18T14:32:07.969Z","dependency_job_id":"2398d63a-9bda-4ae4-b197-f011fdb5b3f0","html_url":"https://github.com/fishjam-dev/react-native-client-sdk","commit_stats":null,"previous_names":["fishjam-dev/react-native-client-sdk","jellyfish-dev/react-native-client-sdk"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fishjam-dev%2Freact-native-client-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fishjam-dev%2Freact-native-client-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fishjam-dev%2Freact-native-client-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fishjam-dev%2Freact-native-client-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fishjam-dev","download_url":"https://codeload.github.com/fishjam-dev/react-native-client-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247804550,"owners_count":20999010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","fishjam","ios","react-native","video","webrtc"],"created_at":"2024-11-06T09:12:14.006Z","updated_at":"2025-04-08T08:31:46.765Z","avatar_url":"https://github.com/fishjam-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-native-client\n\nreact-native-client is a React Native wrapper for\n[android-client](https://github.com/fishjam-dev/android-client-sdk) and\n[ios-client](https://github.com/fishjam-dev/ios-client-sdk). It allows you to\nquickly and easily create a mobile client app in React Native for a\n[Fishjam](https://github.com/fishjam-dev/fishjam) server.\n\n# Documentation\n\nAPI documentation is available\n[here](https://fishjam-dev.github.io/react-native-client-sdk/)\n\n# Installation\n\nFirstly install `react-native-client` with `yarn` or `npm`\n\n```\nyarn add @fishjam-dev/react-native-client\n```\n\nor\n\n```\nnpm install @fishjam-dev/react-native-client\n```\n\n### Expo plugin\n\nIf you're using development builds with `eas build` or bare workflow you can try\nusing expo plugin to do the configuration below for you. Simply run:\n\n```\nexpo install @fishjam-dev/react-native-client\n```\n\nAdd plugin to your `app.json` if it's not already added:\n\n```json\n{\n  \"expo\": {\n    \"name\": \"example\",\n    ...\n    \"plugins\": [\n      \"@fishjam-dev/react-native-client\"\n    ]\n  }\n}\n```\n\nIf you want to use screensharing feature, enable the following flag:\n\n```json\n{\n  \"expo\": {\n    \"name\": \"example\",\n    ...\n    \"plugins\": [\n      [\n        \"@fishjam-dev/react-native-client\",\n        {\n          \"setUpScreensharing\": true,\n        }\n      ]\n    ]\n  }\n}\n```\n\nOn bare workflow run `expo prebuild` to configure the app, then run\n`pod install`. On development build `eas build` should take care of it.\n\n### Android\n\n1. Add camera and microphone permissions to your `AndroidManifest.xml`.\n2. Rebuild the app. That's it!\n\n### iOS\n\nOn iOS installation is a bit more complicated, because you need to setup a\nscreen broadcast app extension for screensharing.\n\n1. Add camera and microphone permissions to your main `Info.plist`.\n   ```xml\n   \u003ckey\u003eNSCameraUsageDescription\u003c/key\u003e\n   \u003cstring\u003eAllow $(PRODUCT_NAME) to use the camera\u003c/string\u003e\n   \u003ckey\u003eNSMicrophoneUsageDescription\u003c/key\u003e\n   \u003cstring\u003eAllow $(PRODUCT_NAME) to use the microphone\u003c/string\u003e\n   ```\n2. We recommend adding `audio` background mode in `Info.plist` so that the app\n   doesn't disconnect when it's in background:\n\n```xml\n\t\u003ckey\u003eUIBackgroundModes\u003c/key\u003e\n  \u003carray\u003e\n    \u003cstring\u003eaudio\u003c/string\u003e\n  \u003c/array\u003e\n```\n\n2. Open your `\u003cyour-project\u003e.xcworkspace` in Xcode\n3. Create new Broadcast Upload Extension. Select File → New → Target... →\n   Broadcast Upload Extension → Next. Choose the name for the new target, select\n   Swift language and deselect \"Include UI Extension\".\n\n   ![New target config](./.github/images/xcode1.png)\n\n   Press Finish. In the next alert xcode will ask you if you want to activate\n   the new scheme - press Cancel.\n\n4. Configure app group. Go to \"Signing \u0026 Capabilities\" tab, click \"+ Capability\"\n   button in upper left corner and select \"App Groups\".\n\n   ![App groups config](./.github/images/xcode2.png)\n\n   Then in the \"App Groups\" add a new group or select existing. Usually group\n   name has format `group.\u003cyour-bundle-identifier\u003e`. Verify that both app and\n   extension targets have app group and dev team set correctly.\n\n5. A new folder with app extension should appear on the left with contents like\n   this:\n\n   ![App extension files](./.github/images/xcode3.png)\n\n   Replace `SampleHandler.swift` with `MembraneBroadcastSampleHandler.swift` and\n   this code:\n\n   ```swift\n   import Foundation\n   import MembraneRTC\n   import os.log\n   import ReplayKit\n   import WebRTC\n\n\n   /// App Group used by the extension to exchange buffers with the target application\n   let appGroup = \"{{GROUP_IDENTIFIER}}\"\n\n   let logger = OSLog(subsystem: \"{{BUNDLE_IDENTIFIER}}.MembraneBroadcastSampleHandler\", category: \"Broadcaster\")\n\n   /// An example `SampleHandler` utilizing `BroadcastSampleSource` from `MembraneRTC` sending broadcast samples and necessary notification enabling device's screencast.\n   class MembraneBroadcastSampleHandler: RPBroadcastSampleHandler {\n       let broadcastSource = BroadcastSampleSource(appGroup: appGroup)\n       var started: Bool = false\n\n\n       override func broadcastStarted(withSetupInfo _: [String: NSObject]?) {\n           started = broadcastSource.connect()\n\n           guard started else {\n               os_log(\"failed to connect with ipc server\", log: logger, type: .debug)\n\n               super.finishBroadcastWithError(NSError(domain: \"\", code: 0, userInfo: nil))\n\n               return\n           }\n\n           broadcastSource.started()\n       }\n\n       override func broadcastPaused() {\n           broadcastSource.paused()\n       }\n\n       override func broadcastResumed() {\n           broadcastSource.resumed()\n       }\n\n       override func broadcastFinished() {\n           broadcastSource.finished()\n       }\n\n       override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {\n           guard started else {\n               return\n           }\n\n           broadcastSource.processFrame(sampleBuffer: sampleBuffer, ofType: sampleBufferType)\n       }\n   }\n   ```\n\n   Replace `{{GROUP_IDENTIFIER}}` and `{{BUNDLE_IDENTIFIER}}` with your group\n   identifier and bundle identifier respectively.\n\n6. In project's Podfile add the following code:\n   ```rb\n   target 'MembraneScreenBroadcastExtension' do\n     pod 'MembraneRTC/Broadcast'\n   end\n   ```\n   \u003e This new dependency should be added outside of your application target.\n   \u003e Example\n   \u003e\n   \u003e ```rb\n   \u003e target 'ReactNativeMembraneExample' do\n   \u003e  ...\n   \u003e end\n   \u003e\n   \u003e target 'MembraneScreenBroadcastExtension' do\n   \u003e  pod 'MembraneRTC/Broadcast'\n   \u003e end\n   \u003e ```\n7. Run `pod install` in your `ios/` directory\n8. Add the following constants in your Info.plist:\n   ```xml\n   \u003ckey\u003eAppGroupName\u003c/key\u003e\n   \u003cstring\u003e{{GROUP_IDENTIFIER}}\u003c/string\u003e\n   \u003ckey\u003eScreencastExtensionBundleId\u003c/key\u003e\n   \u003cstring\u003e{{BUNDLE_IDENTIFIER}}.MembraneBroadcastSampleHandler\u003c/string\u003e\n   ```\n   Replace `{{GROUP_IDENTIFIER}}` and `{{BUNDLE_IDENTIFIER}}` with your group\n   identifier and bundle identifier respectively.\n9. Rebuild the app and enjoy!\n\n# Example\n\nWe strongly recommend checking out our example app that implements a basic video\nroom client. To run the app:\n\n1. Go to Membrane's server demo repo:\n   https://github.com/fishjam-dev/fishjam-videoroom. Follow instructions there\n   to setup and run demo server.\n2. Clone the repo\n3. ```\n   cd example\n   yarn\n   ```\n4. In App.ts replace server url with your server's url.\n5. `yarn run android` or `yarn run ios` or run project from Android Studio /\n   Xcode just like every RN project. Note that simulators won't work, you have\n   to test on real device for camera and screensharing to run.\n\n# Usage\n\n\u003e [!IMPORTANT] Since version 7.4.0, you need to call function\n\u003e `initializeWebRTC()` once in your app before using any other functionality.\n\nStart with connecting to the membrane webrtc server. Use `useWebRTC()` hook to\nmanage connection:\n\n```ts\nconst { connect, disconnect, error } = useWebRTC();\n```\n\nConnect to the server and join the room using the `connect` function. Use user\nmetadata to pass things like usernames etc. to the server. You can also pass\nconnection params that will be sent to the socket when establishing the\nconnection tries.\n\n```ts\nconst startServerConnection = () =\u003e {\n  try {\n    await connect('https://example.com', \"Annie's room\", {\n      endpointMetadata: {\n        displayName: 'Annie',\n      },\n      connectionParams: {\n        token: 'TOKEN',\n      },\n    });\n  } catch (e) {\n    console.log('error!');\n  }\n};\n```\n\nRemember to gracefully disconnect from the server using the `disconnect()`\nfunction:\n\n```ts\nconst stopServerConnection = () =\u003e {\n  await disconnect();\n};\n```\n\nAlso handle errors properly, for example when internet connection fails or\nserver is down:\n\n```ts\nuseEffect(() =\u003e {\n  if (error) console.log('error: ', e);\n}, [error]);\n```\n\nStart the device's camera and microphone using `useCamera()` and\n`useMicrophone()` hooks. Use `videoTrackMetadata` and `audioTrackMetadata`\noptions to send metadata about the tracks (for example whether it's a camera or\nscreencast track).\n\n```ts\nconst { startCamera } = useCamera();\nconst { startMicrophone } = useMicrophone();\n\nawait startCamera({\n  quality: VideoQuality.HD_169,\n  videoTrackMetadata: { active: true, type: 'camera' },\n});\nawait startMicrophone({ audioTrackMetadata: { active: true, type: 'audio' } });\n```\n\nFor more options and functions to control the camera and microphone see the API\ndocumentation.\n\nIf you have the connection set up, then use `useEndpoints()` hook to track the\nother endpoints in the room. One of the endpoints will be a local participant\n(the one who's using the device). When endpoints is added or removed because an\nuser joins or leaves the room, the endpoints will be updated automatically.\nSimply call the hook like this:\n\n```ts\nconst endpoints = useEndpoints();\n```\n\nWhen you have the endpoints all that's left is to render their video tracks. Use\n`\u003cVideoRendererView /\u003e` component like this:\n\n```ts\n{\n  endpoint.videoTracks.map((track) =\u003e (\n    \u003cVideoRendererView trackId={track.id} /\u003e\n  ));\n}\n```\n\nYou can style the views to lay out them however you'd like, basic animations\nshould work too.\n\nThere are also some simple hooks for toggling camera, microphone and\nscreensharing. Use them like this:\n\n```ts\nconst { isCameraOn, toggleCamera } = useCameraState();\nconst { isMicrophoneOn, toggleMicrophone } = useMicrophoneState();\n```\n\nFor screencasting use `useScreencast()` hook. The local endpoint will have a new\nvideo track which you can render just like an ordinary video track with\n\u003cVideoRendererView /\u003e:\n\n```ts\nconst { isScreencastOn, toggleScreencast } = useScreencast();\n...\ntoggleScreencast({screencastMetadata: { displayName: \"Annie's desktop\" }});\n```\n\nUse track metadata to differentiate between video and screencast tracks.\n\n### Android foreground service\n\nIn order for the call to continue running when app is in background, you need to\nset up and start a foreground service. You can use a 3rd party library for this,\nfor example [notifee](https://notifee.app/).\n\nIn `AndroidManifest.xml` specify necessary permissions:\n\n```xml\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION\" /\u003e\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_CAMERA\" /\u003e\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_MICROPHONE\" /\u003e\n```\n\nAnd add foreground service:\n\n```xml\n\u003capplication\n...\n\u003e\n  ...\n  \u003cservice\n    android:name=\"app.notifee.core.ForegroundService\"\n    android:foregroundServiceType=\"mediaProjection|camera|microphone\" /\u003e\n\u003c/application\u003e\n```\n\nThen to start the foreground service:\n\n```ts\nimport notifee, { AndroidImportance } from '@notifee/react-native';\n\nconst startForegroundService = async () =\u003e {\n  if (Platform.OS === 'android') {\n    const channelId = await notifee.createChannel({\n      id: 'video_call',\n      name: 'Video call',\n      lights: false,\n      vibration: false,\n      importance: AndroidImportance.DEFAULT,\n    });\n\n    await notifee.displayNotification({\n      title: 'Your video call is ongoing',\n      body: 'Tap to return to the call.',\n      android: {\n        channelId,\n        asForegroundService: true,\n        ongoing: true,\n        pressAction: {\n          id: 'default',\n        },\n      },\n    });\n  }\n};\n```\n\nDon't forget to also stop the service when the call has ended:\n\n```ts\nnotifee.stopForegroundService();\n```\n\nAlso add this code in your `index.js` to register the service:\n\n```js\nnotifee.registerForegroundService((notification) =\u003e {\n  return new Promise(() =\u003e {});\n});\n```\n\n### Developing\n\nRun `./scripts/init.sh` in the main directory to install swift-format and set up\ngit hooks.\n\nTo release a new version of the lib just run `yarn release`, follow the prompts\nto bump version, make tags, commits and upload to npm. To release a new version\nof the example app on Android install fastlane, get upload key password and\nfirebase auth json from the devs, update `~/.gradle/gradle.properties` like\nthis:\n\n```\nMEMBRANE_UPLOAD_STORE_FILE=my-upload-key.keystore\nMEMBRANE_UPLOAD_KEY_ALIAS=my-key-alias\nMEMBRANE_UPLOAD_STORE_PASSWORD=********\nMEMBRANE_UPLOAD_KEY_PASSWORD=********\n```\n\nand run `yarn releaseAppAndroid` from the main directory.\n\nTo release a new version of the example app on iOS install fastlane, get added\nto swmansion app store account and run `yarn releaseAppIos` from the main\ndirectory.\n\nPro tip: when developing, set the backend url in `.env.development`.\n\n## Credits\n\nThis project has been built and is maintained thanks to the support from\n[dscout](https://dscout.com/) and [Software Mansion](https://swmansion.com).\n\n\u003cimg alt=\"dscout\" height=\"100\" src=\"./.github/images/dscout_logo.png\"/\u003e\n\u003cimg alt=\"Software Mansion\" src=\"https://logo.swmansion.com/logo?color=white\u0026variant=desktop\u0026width=150\u0026tag=react-native-reanimated-github\"/\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffishjam-dev%2Freact-native-client-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffishjam-dev%2Freact-native-client-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffishjam-dev%2Freact-native-client-sdk/lists"}