snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
6
ios/.xcode.env
Normal file
@@ -0,0 +1,6 @@
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
|
||||
. ${THIS_DIR}/../node_modules/react-native/scripts/find-node-for-xcode.sh
|
||||
|
||||
export NODE_BINARY=$(command -v node)
|
||||
export ENTRY_FILE="${PROJECT_DIR}/../../index.ios.js"
|
||||
165
ios/Podfile
Normal file
@@ -0,0 +1,165 @@
|
||||
# Resolve react_native_pods.rb with node to allow for hoisting.
|
||||
require Pod::Executable.execute_command('node', ['-p',
|
||||
'require.resolve(
|
||||
"react-native/scripts/react_native_pods.rb",
|
||||
{paths: [process.argv[1]]},
|
||||
)', __dir__]).strip
|
||||
|
||||
platform :ios, '15.1'
|
||||
workspace 'jitsi-meet'
|
||||
|
||||
ENV['RCT_NEW_ARCH_ENABLED'] = '1'
|
||||
ENV['RCT_HERMES_V1_ENABLED'] = '0'
|
||||
|
||||
# Build RN deps and Core from source so we don't depend on the prebuilt RN xcframeworks.
|
||||
ENV['RCT_USE_RN_DEP'] = '0'
|
||||
ENV['RCT_USE_PREBUILT_RNCORE'] = '0'
|
||||
|
||||
# hermes-engine bakes an absolute path into HERMES_CLI_PATH, which makes the
|
||||
# Podfile.lock SPEC CHECKSUM differ on every machine. Rewrite it to a relative
|
||||
# path so the lockfile is portable (e.g. `pod install --deployment` in CI).
|
||||
module HermesCliPathRelativizer
|
||||
def store_attribute(name, value, platform_name = nil)
|
||||
if name == :user_target_xcconfig &&
|
||||
value.is_a?(Hash) &&
|
||||
value['HERMES_CLI_PATH'] &&
|
||||
self.name.to_s.start_with?('hermes-engine')
|
||||
value = value.merge(
|
||||
'HERMES_CLI_PATH' => '${REACT_NATIVE_PATH}/../hermes-compiler/hermesc/osx-bin/hermesc'
|
||||
)
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
Pod::Specification.prepend(HermesCliPathRelativizer)
|
||||
|
||||
install! 'cocoapods', :deterministic_uuids => false
|
||||
|
||||
def cocoa_utilities
|
||||
pod 'CocoaLumberjack', '3.7.4'
|
||||
end
|
||||
|
||||
# Giphy is excluded from iOS autolinking to keep it out of the lite SDK,
|
||||
# but the full SDK needs its TurboModule spec
|
||||
# and we re-add it to autolinking.json so react native codegen generates it.
|
||||
def include_giphy_in_codegen!
|
||||
require 'json'
|
||||
autolinking_json = File.join(
|
||||
Pod::Config.instance.installation_root.to_s,
|
||||
'build/generated/autolinking/autolinking.json'
|
||||
)
|
||||
return unless File.exist?(autolinking_json)
|
||||
|
||||
json = JSON.parse(File.read(autolinking_json))
|
||||
giphy_root = File.expand_path('../node_modules/@giphy/react-native-sdk', __dir__)
|
||||
json['dependencies'] ||= {}
|
||||
json['dependencies']['@giphy/react-native-sdk'] = {
|
||||
'name' => '@giphy/react-native-sdk',
|
||||
'root' => giphy_root,
|
||||
'platforms' => {
|
||||
'ios' => {
|
||||
'podspecPath' => File.join(giphy_root, 'giphy-react-native-sdk.podspec'),
|
||||
'scriptPhases' => [],
|
||||
'configurations' => []
|
||||
}
|
||||
}
|
||||
}
|
||||
File.write(autolinking_json, JSON.pretty_generate(json))
|
||||
end
|
||||
|
||||
target 'JitsiMeet' do
|
||||
project 'app/app.xcodeproj'
|
||||
|
||||
pod 'Firebase/Analytics', '~> 8.0'
|
||||
pod 'Firebase/Crashlytics', '~> 8.0'
|
||||
end
|
||||
|
||||
target 'JitsiMeetSDK' do
|
||||
project 'sdk/sdk.xcodeproj'
|
||||
|
||||
# React Native and its dependencies
|
||||
#
|
||||
|
||||
config = use_native_modules!
|
||||
include_giphy_in_codegen!
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
||||
)
|
||||
|
||||
# We use auto linking, but some dependencies are excluded from the lite build
|
||||
# (see react-native.config.js) so we add them here.
|
||||
|
||||
pod 'giphy-react-native-sdk', :path => '../node_modules/@giphy/react-native-sdk'
|
||||
pod 'RNCalendarEvents', :path => '../node_modules/react-native-calendar-events'
|
||||
pod 'RNGoogleSignin', :path => '../node_modules/@react-native-google-signin/google-signin'
|
||||
|
||||
# Native pod dependencies
|
||||
#
|
||||
|
||||
cocoa_utilities
|
||||
pod 'ObjectiveDropboxOfficial', '6.2.3'
|
||||
end
|
||||
|
||||
target 'JitsiMeetSDKLite' do
|
||||
project 'sdk/sdk.xcodeproj'
|
||||
|
||||
# This is a more lightweight target, which removes some functionality.
|
||||
# Check the react-native.config.js for the list of excluded packages.
|
||||
|
||||
# React Native and its dependencies
|
||||
#
|
||||
|
||||
config = use_native_modules!
|
||||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
# An absolute path to your application root.
|
||||
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
||||
)
|
||||
|
||||
# Native pod dependencies
|
||||
#
|
||||
|
||||
cocoa_utilities
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
|
||||
react_native_post_install(
|
||||
installer,
|
||||
use_native_modules![:reactNativePath],
|
||||
:mac_catalyst_enabled => false,
|
||||
# :ccache_enabled => true
|
||||
)
|
||||
installer.pods_project.targets.each do |target|
|
||||
# https://github.com/CocoaPods/CocoaPods/issues/11402
|
||||
if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
end
|
||||
end
|
||||
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['SUPPORTS_MACCATALYST'] = 'NO'
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.1'
|
||||
config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -no-verify-emitted-module-interface'
|
||||
end
|
||||
end
|
||||
|
||||
# Patch SocketRocket to support TLS 1.3
|
||||
%x(patch Pods/SocketRocket/SocketRocket/SRSecurityPolicy.m -N < patches/ws-tls13.diff)
|
||||
|
||||
# GiphyUISDK.xcframework already embeds libwebp; Giphy's podspec also
|
||||
# declares libwebp as a dependency, which makes CocoaPods statically link
|
||||
# libwebp into JitsiMeetSDK as well. The two copies trigger a duplicate
|
||||
# `PodsDummy_libwebp` warning at runtime. Drop the redundant link.
|
||||
['Pods-JitsiMeetSDK', 'Pods-JitsiMeet'].each do |aggregate_name|
|
||||
Dir.glob("Pods/Target Support Files/#{aggregate_name}/*.xcconfig").each do |path|
|
||||
contents = File.read(path)
|
||||
patched = contents.gsub(/ -l"?libwebp"?/, '')
|
||||
File.write(path, patched) if patched != contents
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
3717
ios/Podfile.lock
Normal file
3
ios/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Jitsi Meet SDK for iOS
|
||||
|
||||
This document has been moved to [The Handbook](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-ios-sdk).
|
||||
47
ios/app/PrivacyInfo.xcprivacy
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>C617.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>1C8F.1</string>
|
||||
<string>C56D.1</string>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>35F9.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>85F4.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
18
ios/app/app.entitlements
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:alpha.jitsi.net</string>
|
||||
<string>applinks:beta.meet.jit.si</string>
|
||||
<string>applinks:meet.jit.si</string>
|
||||
</array>
|
||||
<key>com.apple.developer.siri</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
846
ios/app/app.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,846 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 60;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.storyboard */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */; };
|
||||
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */; };
|
||||
4341A9062CF0D63200940D93 /* hermes.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4341A9052CF0D63200940D93 /* hermes.xcframework */; };
|
||||
4341A9072CF0D63200940D93 /* hermes.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4341A9052CF0D63200940D93 /* hermes.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
4E90F9402632D1AB001102D4 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E90F93F2632D1AB001102D4 /* Atomic.swift */; };
|
||||
4EB06024260E026600F524C5 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EC49B8625BED71300E76218 /* ReplayKit.framework */; };
|
||||
4EB06027260E026600F524C5 /* SampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06026260E026600F524C5 /* SampleHandler.swift */; };
|
||||
4EB0602B260E026600F524C5 /* JitsiMeetBroadcastExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB06039260E09D000F524C5 /* SocketConnection.swift */; };
|
||||
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */; };
|
||||
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB0603B260E09D000F524C5 /* SampleUploader.swift */; };
|
||||
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */; };
|
||||
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */; };
|
||||
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; };
|
||||
DEA9F28A258A6EA800D4CD74 /* JitsiMeetSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
DED016F128ECBC9D009D5E8D /* WebRTC.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */; };
|
||||
DED016F228ECBC9D009D5E8D /* WebRTC.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FD572B9827EDF32300A800FB /* GiphyUISDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD572B9727EDF32300A800FB /* GiphyUISDK.xcframework */; };
|
||||
FD572B9927EDF32300A800FB /* GiphyUISDK.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FD572B9727EDF32300A800FB /* GiphyUISDK.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
4EB06029260E026600F524C5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 4EB06022260E026600F524C5;
|
||||
remoteInfo = "JitsiMeetBroadcast Extension";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
0B26BE701EC5BC3C00EEFB41 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
DEA9F28A258A6EA800D4CD74 /* JitsiMeetSDK.framework in Embed Frameworks */,
|
||||
4341A9072CF0D63200940D93 /* hermes.xcframework in Embed Frameworks */,
|
||||
FD572B9927EDF32300A800FB /* GiphyUISDK.xcframework in Embed Frameworks */,
|
||||
DED016F228ECBC9D009D5E8D /* WebRTC.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Watch Content";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EC49B9025BED71300E76218 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
4EB0602B260E026600F524C5 /* JitsiMeetBroadcastExtension.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.framework"; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* jitsi-meet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "jitsi-meet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = src/Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.release.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.release.xcconfig"; sourceTree = "<group>"; };
|
||||
4341A9052CF0D63200940D93 /* hermes.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = hermes.xcframework; path = "../Pods/hermes-engine/destroot/Library/Frameworks/universal/hermesvm.xcframework"; sourceTree = "<group>"; };
|
||||
4E90F93F2632D1AB001102D4 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
|
||||
4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = JitsiMeetBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4EB06026260E026600F524C5 /* SampleHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleHandler.swift; sourceTree = "<group>"; };
|
||||
4EB06028260E026600F524C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4EB06032260E08CC00F524C5 /* extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = extension.entitlements; sourceTree = "<group>"; };
|
||||
4EB06039260E09D000F524C5 /* SocketConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketConnection.swift; sourceTree = "<group>"; };
|
||||
4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarwinNotificationCenter.swift; sourceTree = "<group>"; };
|
||||
4EB0603B260E09D000F524C5 /* SampleUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUploader.swift; sourceTree = "<group>"; };
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JitsiMeet.debug.xcconfig"; path = "Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app.entitlements; sourceTree = "<group>"; };
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE050388256E904600DEE3A5 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/apple/WebRTC.xcframework"; sourceTree = "<group>"; };
|
||||
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = ../Pods/JitsiWebRTC/WebRTC.xcframework; sourceTree = "<group>"; };
|
||||
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WebRTC.xcframework; path = "../../node_modules/react-native-webrtc/ios/WebRTC.xcframework"; sourceTree = "<group>"; };
|
||||
FD572B9727EDF32300A800FB /* GiphyUISDK.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:925PGC4MV7:Giphy, Inc."; lastKnownFileType = wrapper.xcframework; name = GiphyUISDK.xcframework; path = ../Pods/Giphy/GiphySDK/GiphyUISDK.xcframework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DED016F128ECBC9D009D5E8D /* WebRTC.xcframework in Frameworks */,
|
||||
DEA9F289258A6EA800D4CD74 /* JitsiMeetSDK.framework in Frameworks */,
|
||||
FD572B9827EDF32300A800FB /* GiphyUISDK.xcframework in Frameworks */,
|
||||
2681BB562C7A0B42CFBA6719 /* libPods-JitsiMeet.a in Frameworks */,
|
||||
4341A9062CF0D63200940D93 /* hermes.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EB06020260E026600F524C5 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4EB06024260E026600F524C5 /* ReplayKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0B26BE711EC5BC4D00EEFB41 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4341A9052CF0D63200940D93 /* hermes.xcframework */,
|
||||
DED016F028ECBC9D009D5E8D /* WebRTC.xcframework */,
|
||||
FD572B9727EDF32300A800FB /* GiphyUISDK.xcframework */,
|
||||
DEA9F288258A6EA800D4CD74 /* JitsiMeetSDK.framework */,
|
||||
DE050388256E904600DEE3A5 /* WebRTC.xcframework */,
|
||||
0B26BE6D1EC5BC3C00EEFB41 /* JitsiMeet.framework */,
|
||||
DEFDBBDB25656E3B00344B23 /* WebRTC.xcframework */,
|
||||
0BD6B4361EF82A6B00D1F4CD /* WebRTC.framework */,
|
||||
4EC49B8625BED71300E76218 /* ReplayKit.framework */,
|
||||
D6152FF9E9F7B0E86F70A21D /* libPods-JitsiMeet.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13B07FAE1A68108700A75B9A /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DEA0B7132D7EF7590062A9F6 /* AppDelegate.swift */,
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||
DEA0B7112D7EF16E0062A9F6 /* ViewController.swift */,
|
||||
);
|
||||
path = src;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EB06032260E08CC00F524C5 /* extension.entitlements */,
|
||||
4EB06026260E026600F524C5 /* SampleHandler.swift */,
|
||||
4EB0603B260E09D000F524C5 /* SampleUploader.swift */,
|
||||
4EB06039260E09D000F524C5 /* SocketConnection.swift */,
|
||||
4EB0603A260E09D000F524C5 /* DarwinNotificationCenter.swift */,
|
||||
4E90F93F2632D1AB001102D4 /* Atomic.swift */,
|
||||
4EB06028260E026600F524C5 /* Info.plist */,
|
||||
);
|
||||
indentWidth = 4;
|
||||
name = "JitsiMeetBroadcast Extension";
|
||||
path = "broadcast-extension";
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 4;
|
||||
};
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B3B083EB1D4955FF0069CEE7 /* app.entitlements */,
|
||||
0B26BE711EC5BC4D00EEFB41 /* Frameworks */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
13B07FAE1A68108700A75B9A /* src */,
|
||||
4EB06025260E026600F524C5 /* JitsiMeetBroadcast Extension */,
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */,
|
||||
5C1BE20ECD5DEEB48FED90B5 /* PrivacyInfo.xcprivacy */,
|
||||
DEAC44E22E97D2C200AD7BEE /* Recovered References */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
};
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* jitsi-meet.app */,
|
||||
4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CDD71F5E1157E9F283DF92A8 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */,
|
||||
3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = ../Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DEAC44E22E97D2C200AD7BEE /* Recovered References */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.storyboard */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
13B07F861A680F5B00A75B9A /* JitsiMeet */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "JitsiMeet" */;
|
||||
buildPhases = (
|
||||
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */,
|
||||
0BBA83C41EC9F7600075A103 /* Run React packager */,
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
0B26BE701EC5BC3C00EEFB41 /* Embed Frameworks */,
|
||||
0BEA5C491F7B8F73000D0AB4 /* Embed Watch Content */,
|
||||
4EC49B9025BED71300E76218 /* Embed App Extensions */,
|
||||
4E81688528A408E600F8FA9E /* Update App Entitlements */,
|
||||
DE11877A21EE09640078D059 /* Setup Google reverse URL handler */,
|
||||
0BB7DA181EC9E695007AAE98 /* Adjust ATS */,
|
||||
DE4F6D6E22005C0400DE699E /* Setup Dropbox */,
|
||||
E9D850368D253EFA8AB3B8D1 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
4EB0602A260E026600F524C5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = JitsiMeet;
|
||||
productName = "Jitsi Meet";
|
||||
productReference = 13B07F961A680F5B00A75B9A /* jitsi-meet.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
4EB06022260E026600F524C5 /* JitsiMeetBroadcastExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4EB0602C260E026700F524C5 /* Build configuration list for PBXNativeTarget "JitsiMeetBroadcastExtension" */;
|
||||
buildPhases = (
|
||||
4EB0601F260E026600F524C5 /* Sources */,
|
||||
4EB06020260E026600F524C5 /* Frameworks */,
|
||||
4EB06021260E026600F524C5 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = JitsiMeetBroadcastExtension;
|
||||
productName = "JitsiMeetBroadcast Extension";
|
||||
productReference = 4EB06023260E026600F524C5 /* JitsiMeetBroadcastExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
83CBB9F71A601CBA00E9B192 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = Jitsi;
|
||||
TargetAttributes = {
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1620;
|
||||
SystemCapabilities = {
|
||||
com.apple.SafariKeychain = {
|
||||
enabled = 1;
|
||||
};
|
||||
com.apple.Siri = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
4EB06022260E026600F524C5 = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
|
||||
compatibilityVersion = "Xcode 12.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 83CBB9F61A601CBA00E9B192;
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* JitsiMeet */,
|
||||
4EB06022260E026600F524C5 /* JitsiMeetBroadcastExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
13B07F8E1A680F5B00A75B9A /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.storyboard in Resources */,
|
||||
361974E2A13624D7735D619D /* PrivacyInfo.xcprivacy in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EB06021260E026600F524C5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
0BB7DA181EC9E695007AAE98 /* Adjust ATS */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH,
|
||||
);
|
||||
name = "Adjust ATS";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../scripts/fixup-ats.sh\n";
|
||||
};
|
||||
0BBA83C41EC9F7600075A103 /* Run React packager */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run React packager";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../scripts/run-packager.sh\n";
|
||||
};
|
||||
4E81688528A408E600F8FA9E /* Update App Entitlements */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
$PROJECT_DIR/app.entitlements,
|
||||
);
|
||||
name = "Update App Entitlements";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "#if test \"$PRODUCT_BUNDLE_IDENTIFIER\" = \"com.atlassian.JitsiMeet.ios\"; then\n# ENTITLEMENTS_PLIST=\"$PROJECT_DIR/app.entitlements\"\n# \n# /usr/libexec/PlistBuddy -c \"Add :com.apple.developer.avfoundation.multitasking-camera-access bool 1\" $ENTITLEMENTS_PLIST\n#fi\n";
|
||||
};
|
||||
69BC5020DBE393B56BD76636 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-JitsiMeet-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
DE11877A21EE09640078D059 /* Setup Google reverse URL handler */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH,
|
||||
);
|
||||
name = "Setup Google reverse URL handler";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "GOOGLE_PLIST_NAME=\"GoogleService-Info.plist\"\nGOOGLE_PLIST=\"$PROJECT_DIR/$GOOGLE_PLIST_NAME\"\nBUILD_APP_DIR=\"$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app\"\nINFO_PLIST=\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\n\nif [[ -f $GOOGLE_PLIST ]]; then\n cp $GOOGLE_PLIST \"$BUILD_APP_DIR/$GOOGLE_PLIST_NAME\"\n REVERSED_CLIENT_ID=$(/usr/libexec/PlistBuddy -c \"Print :REVERSED_CLIENT_ID:\" $GOOGLE_PLIST)\n /usr/libexec/PlistBuddy -c \"Set :CFBundleURLTypes:1:CFBundleURLSchemes:0 $REVERSED_CLIENT_ID\" $INFO_PLIST\nfi\n";
|
||||
};
|
||||
DE4F6D6E22005C0400DE699E /* Setup Dropbox */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH,
|
||||
);
|
||||
name = "Setup Dropbox";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "INFO_PLIST=\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\nDROPBOX_KEY_FILE=\"$PROJECT_DIR/dropbox.key\"\n\nif [[ -f $DROPBOX_KEY_FILE ]]; then\n /usr/libexec/PlistBuddy -c \"Delete :LSApplicationQueriesSchemes\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes array\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes:0 string 'dbapi-2'\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :LSApplicationQueriesSchemes:1 string 'dbapi-8-emm'\" $INFO_PLIST\n\n DROPBOX_KEY=$(head -n 1 $DROPBOX_KEY_FILE)\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLName string dropbox\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLSchemes array\" $INFO_PLIST\n /usr/libexec/PlistBuddy -c \"Add :CFBundleURLTypes:2:CFBundleURLSchemes:0 string $DROPBOX_KEY\" $INFO_PLIST\nfi\n";
|
||||
};
|
||||
E9D850368D253EFA8AB3B8D1 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JitsiMeet/Pods-JitsiMeet-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
13B07F871A680F5B00A75B9A /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DEA0B7122D7EF16E0062A9F6 /* ViewController.swift in Sources */,
|
||||
DEA0B7142D7EF7590062A9F6 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
4EB0601F260E026600F524C5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4EB0603C260E09D000F524C5 /* SocketConnection.swift in Sources */,
|
||||
4EB0603E260E09D000F524C5 /* SampleUploader.swift in Sources */,
|
||||
4EB0603D260E09D000F524C5 /* DarwinNotificationCenter.swift in Sources */,
|
||||
4EB06027260E026600F524C5 /* SampleHandler.swift in Sources */,
|
||||
4E90F9402632D1AB001102D4 /* Atomic.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
4EB0602A260E026600F524C5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 4EB06022260E026600F524C5 /* JitsiMeetBroadcastExtension */;
|
||||
targetProxy = 4EB06029260E026600F524C5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
13B07FB21A68108700A75B9A /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
13B07F941A680F5B00A75B9A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 756FCE06C08D9B947653C98A /* Pods-JitsiMeet.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDebug;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
INFOPLIST_FILE = src/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
|
||||
PRODUCT_NAME = "jitsi-meet";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3E0F4ED943C0B12BE77F6B45 /* Pods-JitsiMeet.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIconRelease;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = app.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
INFOPLIST_FILE = src/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet;
|
||||
PRODUCT_NAME = "jitsi-meet";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_VERSION = 6.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
4EB0602D260E026700F524C5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "broadcast-extension/extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "broadcast-extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.broadcast.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4EB0602E260E026700F524C5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = "broadcast-extension/extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = FC967L3QRG;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = "broadcast-extension/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.jitsi.meet.broadcast.extension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
83CBBA201A601CBA00E9B192 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CC = "";
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CXX = "";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD = "";
|
||||
LDPLUSPLUS = "";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
USE_HERMES = true;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
83CBBA211A601CBA00E9B192 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CC = "";
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CXX = "";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
|
||||
LD = "";
|
||||
LDPLUSPLUS = "";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(inherited)",
|
||||
"-DRCT_REMOVE_LEGACY_ARCH=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "JitsiMeet" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
13B07F941A680F5B00A75B9A /* Debug */,
|
||||
13B07F951A680F5B00A75B9A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4EB0602C260E026700F524C5 /* Build configuration list for PBXNativeTarget "JitsiMeetBroadcastExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
4EB0602D260E026700F524C5 /* Debug */,
|
||||
4EB0602E260E026700F524C5 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
83CBBA201A601CBA00E9B192 /* Debug */,
|
||||
83CBBA211A601CBA00E9B192 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
}
|
||||
101
ios/app/app.xcodeproj/xcshareddata/xcschemes/JitsiMeet.xcscheme
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "NO"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0BD906E41EC0C00300C8C18E"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDK"
|
||||
ReferencedContainer = "container:../sdk/sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "jitsi-meet.app"
|
||||
BlueprintName = "JitsiMeet"
|
||||
ReferencedContainer = "container:app.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
30
ios/app/broadcast-extension/Atomic.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@propertyWrapper
|
||||
struct Atomic<Value> {
|
||||
|
||||
private var value: Value
|
||||
private let lock = NSLock()
|
||||
|
||||
init(wrappedValue value: Value) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
var wrappedValue: Value {
|
||||
get { return load() }
|
||||
set { store(newValue: newValue) }
|
||||
}
|
||||
|
||||
func load() -> Value {
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return value
|
||||
}
|
||||
|
||||
mutating func store(newValue: Value) {
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
value = newValue
|
||||
}
|
||||
}
|
||||
37
ios/app/broadcast-extension/DarwinNotificationCenter.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
enum DarwinNotification: String {
|
||||
case broadcastStarted = "iOS_BroadcastStarted"
|
||||
case broadcastStopped = "iOS_BroadcastStopped"
|
||||
}
|
||||
|
||||
class DarwinNotificationCenter {
|
||||
|
||||
static var shared = DarwinNotificationCenter()
|
||||
|
||||
private var notificationCenter: CFNotificationCenter
|
||||
|
||||
init() {
|
||||
notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()
|
||||
}
|
||||
|
||||
func postNotification(_ name: DarwinNotification) {
|
||||
CFNotificationCenterPostNotification(notificationCenter, CFNotificationName(rawValue: name.rawValue as CFString), nil, nil, true)
|
||||
}
|
||||
}
|
||||
35
ios/app/broadcast-extension/Info.plist
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Jitsi Meet Broadcast Extension</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.broadcast-services-upload</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SampleHandler</string>
|
||||
<key>RPBroadcastProcessMode</key>
|
||||
<string>RPBroadcastProcessModeSampleBuffer</string>
|
||||
</dict>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
116
ios/app/broadcast-extension/SampleHandler.swift
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import ReplayKit
|
||||
|
||||
private enum Constants {
|
||||
// the App Group ID value that the app and the broadcast extension targets are setup with. It differs for each app.
|
||||
static let appGroupIdentifier = "group.org.jitsi.meet.appgroup"
|
||||
}
|
||||
|
||||
class SampleHandler: RPBroadcastSampleHandler {
|
||||
|
||||
private var clientConnection: SocketConnection?
|
||||
private var uploader: SampleUploader?
|
||||
|
||||
private var frameCount: Int = 0
|
||||
|
||||
var socketFilePath: String {
|
||||
let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
|
||||
|
||||
return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
if let connection = SocketConnection(filePath: socketFilePath) {
|
||||
clientConnection = connection
|
||||
setupConnection()
|
||||
|
||||
uploader = SampleUploader(connection: connection)
|
||||
}
|
||||
}
|
||||
|
||||
override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
|
||||
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
|
||||
print("broadcast started")
|
||||
|
||||
frameCount = 0
|
||||
|
||||
DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
|
||||
openConnection()
|
||||
}
|
||||
|
||||
override func broadcastPaused() {
|
||||
// User has requested to pause the broadcast. Samples will stop being delivered.
|
||||
}
|
||||
|
||||
override func broadcastResumed() {
|
||||
// User has requested to resume the broadcast. Samples delivery will resume.
|
||||
}
|
||||
|
||||
override func broadcastFinished() {
|
||||
// User has requested to finish the broadcast.
|
||||
DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
|
||||
clientConnection?.close()
|
||||
}
|
||||
|
||||
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
|
||||
switch sampleBufferType {
|
||||
case RPSampleBufferType.video:
|
||||
// very simple mechanism for adjusting frame rate by using every third frame
|
||||
frameCount += 1
|
||||
if frameCount % 3 == 0 {
|
||||
uploader?.send(sample: sampleBuffer)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension SampleHandler {
|
||||
|
||||
func setupConnection() {
|
||||
clientConnection?.didClose = { [weak self] error in
|
||||
print("client connection did close \(String(describing: error))")
|
||||
|
||||
if let error = error {
|
||||
self?.finishBroadcastWithError(error)
|
||||
} else {
|
||||
// the displayed failure message is more user friendly when using NSError instead of Error
|
||||
let JMScreenSharingStopped = 10001
|
||||
let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: "Screen sharing stopped"])
|
||||
self?.finishBroadcastWithError(customError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openConnection() {
|
||||
let queue = DispatchQueue(label: "broadcast.connectTimer")
|
||||
let timer = DispatchSource.makeTimerSource(queue: queue)
|
||||
timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
|
||||
timer.setEventHandler { [weak self] in
|
||||
guard self?.clientConnection?.open() == true else {
|
||||
return
|
||||
}
|
||||
|
||||
timer.cancel()
|
||||
}
|
||||
|
||||
timer.resume()
|
||||
}
|
||||
}
|
||||
154
ios/app/broadcast-extension/SampleUploader.swift
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import ReplayKit
|
||||
|
||||
private enum Constants {
|
||||
static let bufferMaxLength = 10240
|
||||
}
|
||||
|
||||
class SampleUploader {
|
||||
|
||||
private static var imageContext = CIContext(options: nil)
|
||||
|
||||
@Atomic private var isReady: Bool = false
|
||||
private var connection: SocketConnection
|
||||
|
||||
private var dataToSend: Data?
|
||||
private var byteIndex = 0
|
||||
|
||||
private let serialQueue: DispatchQueue
|
||||
|
||||
init(connection: SocketConnection) {
|
||||
self.connection = connection
|
||||
self.serialQueue = DispatchQueue(label: "org.jitsi.meet.broadcast.sampleUploader")
|
||||
|
||||
setupConnection()
|
||||
}
|
||||
|
||||
@discardableResult func send(sample buffer: CMSampleBuffer) -> Bool {
|
||||
guard isReady == true else {
|
||||
return false
|
||||
}
|
||||
|
||||
isReady = false
|
||||
|
||||
dataToSend = prepare(sample: buffer)
|
||||
byteIndex = 0
|
||||
|
||||
serialQueue.async { [weak self] in
|
||||
self?.sendDataChunk()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private extension SampleUploader {
|
||||
|
||||
func setupConnection() {
|
||||
connection.didOpen = { [weak self] in
|
||||
self?.isReady = true
|
||||
}
|
||||
connection.streamHasSpaceAvailable = { [weak self] in
|
||||
self?.serialQueue.async {
|
||||
self?.isReady = !(self?.sendDataChunk() ?? true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult func sendDataChunk() -> Bool {
|
||||
guard let dataToSend = dataToSend else {
|
||||
return false
|
||||
}
|
||||
|
||||
var bytesLeft = dataToSend.count - byteIndex
|
||||
var length = bytesLeft > Constants.bufferMaxLength ? Constants.bufferMaxLength : bytesLeft
|
||||
|
||||
length = dataToSend[byteIndex..<(byteIndex + length)].withUnsafeBytes {
|
||||
guard let ptr = $0.bindMemory(to: UInt8.self).baseAddress else {
|
||||
return 0
|
||||
}
|
||||
|
||||
return connection.writeToStream(buffer: ptr, maxLength: length)
|
||||
}
|
||||
|
||||
if length > 0 {
|
||||
byteIndex += length
|
||||
bytesLeft -= length
|
||||
|
||||
if bytesLeft == 0 {
|
||||
self.dataToSend = nil
|
||||
byteIndex = 0
|
||||
}
|
||||
} else {
|
||||
print("writeBufferToStream failure")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func prepare(sample buffer: CMSampleBuffer) -> Data? {
|
||||
guard let imageBuffer = CMSampleBufferGetImageBuffer(buffer) else {
|
||||
print("image buffer not available")
|
||||
return nil
|
||||
}
|
||||
|
||||
CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
|
||||
|
||||
let scaleFactor = 2.0
|
||||
let width = CVPixelBufferGetWidth(imageBuffer)/Int(scaleFactor)
|
||||
let height = CVPixelBufferGetHeight(imageBuffer)/Int(scaleFactor)
|
||||
let orientation = CMGetAttachment(buffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil)?.uintValue ?? 0
|
||||
|
||||
let scaleTransform = CGAffineTransform(scaleX: CGFloat(1.0/scaleFactor), y: CGFloat(1.0/scaleFactor))
|
||||
let bufferData = self.jpegData(from: imageBuffer, scale: scaleTransform)
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly)
|
||||
|
||||
guard let messageData = bufferData else {
|
||||
print("corrupted image buffer")
|
||||
return nil
|
||||
}
|
||||
|
||||
let httpResponse = CFHTTPMessageCreateResponse(nil, 200, nil, kCFHTTPVersion1_1).takeRetainedValue()
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Content-Length" as CFString, String(messageData.count) as CFString)
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Width" as CFString, String(width) as CFString)
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Height" as CFString, String(height) as CFString)
|
||||
CFHTTPMessageSetHeaderFieldValue(httpResponse, "Buffer-Orientation" as CFString, String(orientation) as CFString)
|
||||
|
||||
CFHTTPMessageSetBody(httpResponse, messageData as CFData)
|
||||
|
||||
let serializedMessage = CFHTTPMessageCopySerializedMessage(httpResponse)?.takeRetainedValue() as Data?
|
||||
|
||||
return serializedMessage
|
||||
}
|
||||
|
||||
func jpegData(from buffer: CVPixelBuffer, scale scaleTransform: CGAffineTransform) -> Data? {
|
||||
var image = CIImage(cvPixelBuffer: buffer)
|
||||
image = image.transformed(by: scaleTransform)
|
||||
|
||||
guard let colorSpace = image.colorSpace else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let options: [CIImageRepresentationOption: Float] = [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption: 1.0]
|
||||
let imageData = SampleUploader.imageContext.jpegRepresentation(of: image, colorSpace: colorSpace, options: options)
|
||||
|
||||
return imageData
|
||||
}
|
||||
}
|
||||
205
ios/app/broadcast-extension/SocketConnection.swift
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class SocketConnection: NSObject {
|
||||
var didOpen: (() -> Void)?
|
||||
var didClose: ((Error?) -> Void)?
|
||||
var streamHasSpaceAvailable: (() -> Void)?
|
||||
|
||||
private let filePath: String
|
||||
private var socketHandle: Int32 = -1
|
||||
private var address: sockaddr_un?
|
||||
|
||||
private var inputStream: InputStream?
|
||||
private var outputStream: OutputStream?
|
||||
|
||||
private var networkQueue: DispatchQueue?
|
||||
private var shouldKeepRunning = false
|
||||
|
||||
init?(filePath path: String) {
|
||||
filePath = path
|
||||
socketHandle = Darwin.socket(AF_UNIX, SOCK_STREAM, 0)
|
||||
|
||||
guard socketHandle != -1 else {
|
||||
print("failure: create socket")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func open() -> Bool {
|
||||
print("open socket connection")
|
||||
|
||||
guard FileManager.default.fileExists(atPath: filePath) else {
|
||||
print("failure: socket file missing")
|
||||
return false
|
||||
}
|
||||
|
||||
guard setupAddress() == true else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard connectSocket() == true else {
|
||||
return false
|
||||
}
|
||||
|
||||
setupStreams()
|
||||
|
||||
inputStream?.open()
|
||||
outputStream?.open()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func close() {
|
||||
unscheduleStreams()
|
||||
|
||||
inputStream?.delegate = nil
|
||||
outputStream?.delegate = nil
|
||||
|
||||
inputStream?.close()
|
||||
outputStream?.close()
|
||||
|
||||
inputStream = nil
|
||||
outputStream = nil
|
||||
}
|
||||
|
||||
func writeToStream(buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int {
|
||||
return outputStream?.write(buffer, maxLength: length) ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
extension SocketConnection: StreamDelegate {
|
||||
|
||||
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||
switch eventCode {
|
||||
case .openCompleted:
|
||||
print("client stream open completed")
|
||||
if aStream == outputStream {
|
||||
didOpen?()
|
||||
}
|
||||
case .hasBytesAvailable:
|
||||
if aStream == inputStream {
|
||||
var buffer: UInt8 = 0
|
||||
let numberOfBytesRead = inputStream?.read(&buffer, maxLength: 1)
|
||||
if numberOfBytesRead == 0 && aStream.streamStatus == .atEnd {
|
||||
print("server socket closed")
|
||||
close()
|
||||
notifyDidClose(error: nil)
|
||||
}
|
||||
}
|
||||
case .hasSpaceAvailable:
|
||||
if aStream == outputStream {
|
||||
streamHasSpaceAvailable?()
|
||||
}
|
||||
case .errorOccurred:
|
||||
print("client stream error occurred: \(String(describing: aStream.streamError))")
|
||||
close()
|
||||
notifyDidClose(error: aStream.streamError)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension SocketConnection {
|
||||
|
||||
func setupAddress() -> Bool {
|
||||
var addr = sockaddr_un()
|
||||
guard filePath.count < MemoryLayout.size(ofValue: addr.sun_path) else {
|
||||
print("failure: fd path is too long")
|
||||
return false
|
||||
}
|
||||
|
||||
_ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
|
||||
filePath.withCString {
|
||||
strncpy(ptr, $0, filePath.count)
|
||||
}
|
||||
}
|
||||
|
||||
address = addr
|
||||
return true
|
||||
}
|
||||
|
||||
func connectSocket() -> Bool {
|
||||
guard var addr = address else {
|
||||
return false
|
||||
}
|
||||
|
||||
let status = withUnsafePointer(to: &addr) { ptr in
|
||||
ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||
Darwin.connect(socketHandle, $0, socklen_t(MemoryLayout<sockaddr_un>.size))
|
||||
}
|
||||
}
|
||||
|
||||
guard status == noErr else {
|
||||
print("failure: \(status)")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func setupStreams() {
|
||||
var readStream: Unmanaged<CFReadStream>?
|
||||
var writeStream: Unmanaged<CFWriteStream>?
|
||||
|
||||
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socketHandle, &readStream, &writeStream)
|
||||
|
||||
inputStream = readStream?.takeRetainedValue()
|
||||
inputStream?.delegate = self
|
||||
inputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
|
||||
|
||||
outputStream = writeStream?.takeRetainedValue()
|
||||
outputStream?.delegate = self
|
||||
outputStream?.setProperty(kCFBooleanTrue, forKey: Stream.PropertyKey(kCFStreamPropertyShouldCloseNativeSocket as String))
|
||||
|
||||
scheduleStreams()
|
||||
}
|
||||
|
||||
func scheduleStreams() {
|
||||
shouldKeepRunning = true
|
||||
|
||||
networkQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
networkQueue?.async { [weak self] in
|
||||
self?.inputStream?.schedule(in: .current, forMode: .common)
|
||||
self?.outputStream?.schedule(in: .current, forMode: .common)
|
||||
|
||||
var isRunning = false
|
||||
|
||||
repeat {
|
||||
isRunning = self?.shouldKeepRunning ?? false && RunLoop.current.run(mode: .default, before: .distantFuture)
|
||||
} while (isRunning)
|
||||
}
|
||||
}
|
||||
|
||||
func unscheduleStreams() {
|
||||
networkQueue?.sync { [weak self] in
|
||||
self?.inputStream?.remove(from: .current, forMode: .common)
|
||||
self?.outputStream?.remove(from: .current, forMode: .common)
|
||||
}
|
||||
|
||||
shouldKeepRunning = false
|
||||
}
|
||||
|
||||
func notifyDidClose(error: Error?) {
|
||||
if didClose != nil {
|
||||
didClose?(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
10
ios/app/broadcast-extension/extension.entitlements
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
78
ios/app/src/AppDelegate.swift
Normal file
@@ -0,0 +1,78 @@
|
||||
import UIKit
|
||||
import Firebase
|
||||
import JitsiMeetSDK
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
self.window = UIWindow(frame: UIScreen.main.bounds)
|
||||
|
||||
let jitsiMeet = JitsiMeet.sharedInstance()
|
||||
|
||||
// jitsiMeet.webRtcLoggingSeverity = .verbose
|
||||
|
||||
jitsiMeet.conferenceActivityType = "org.jitsi.JitsiMeet.ios.conference" // Must match the one defined in Info.plist{}
|
||||
jitsiMeet.customUrlScheme = "org.jitsi.meet"
|
||||
jitsiMeet.universalLinkDomains = ["meet.jit.si", "alpha.jitsi.net", "beta.meet.jit.si"]
|
||||
|
||||
jitsiMeet.defaultConferenceOptions = JitsiMeetConferenceOptions.fromBuilder { builder in
|
||||
// For testing configOverrides a room needs to be set
|
||||
// builder.room = "https://meet.jit.si/test0988test"
|
||||
|
||||
builder.setFeatureFlag("welcomepage.enabled", withBoolean: true)
|
||||
builder.setFeatureFlag("ios.screensharing.enabled", withBoolean: true)
|
||||
builder.setFeatureFlag("ios.recording.enabled", withBoolean: true)
|
||||
}
|
||||
|
||||
jitsiMeet.application(application, didFinishLaunchingWithOptions: launchOptions ?? [:])
|
||||
|
||||
if self.appContainsRealServiceInfoPlist() {
|
||||
print("Enabling Firebase")
|
||||
FirebaseApp.configure()
|
||||
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(!jitsiMeet.isCrashReportingDisabled())
|
||||
}
|
||||
|
||||
let vc = ViewController()
|
||||
self.window?.rootViewController = vc
|
||||
jitsiMeet.showSplashScreen()
|
||||
|
||||
self.window?.makeKeyAndVisible()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
print("Application will terminate!")
|
||||
if let rootController = self.window?.rootViewController as? ViewController {
|
||||
rootController.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Linking delegate methods
|
||||
|
||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
return JitsiMeet.sharedInstance().application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
if url.absoluteString.contains("google/link/?dismiss=1&is_weak_match=1") {
|
||||
return false
|
||||
}
|
||||
|
||||
return JitsiMeet.sharedInstance().application(app, open: url, options: options)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
|
||||
return JitsiMeet.sharedInstance().application(application, supportedInterfaceOrientationsFor: window)
|
||||
}
|
||||
}
|
||||
|
||||
// Firebase utilities
|
||||
extension AppDelegate {
|
||||
func appContainsRealServiceInfoPlist() -> Bool {
|
||||
return InfoPlistUtil.containsRealServiceInfoPlist(in: Bundle.main)
|
||||
}
|
||||
}
|
||||
42
ios/app/src/Base.lproj/LaunchScreen.storyboard
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" userInteractionEnabled="NO" contentMode="center" image="LaunchScreen" translatesAutoresizingMaskIntoConstraints="NO" id="4B8-Xf-NDE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.090196078431372548" green="0.62745098039215685" blue="0.85882352941176465" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="4B8-Xf-NDE" secondAttribute="bottom" id="aFF-BR-glX"/>
|
||||
<constraint firstItem="4B8-Xf-NDE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="glR-YN-1GF"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4B8-Xf-NDE" secondAttribute="trailing" id="tva-gl-jRX"/>
|
||||
<constraint firstItem="4B8-Xf-NDE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="yaV-1V-oEh"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="LaunchScreen" width="480" height="480"/>
|
||||
</resources>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
ios/app/src/Images.xcassets/CallKitIcon.imageset/CallKit@1x.png
vendored
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
ios/app/src/Images.xcassets/CallKitIcon.imageset/CallKit@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
ios/app/src/Images.xcassets/CallKitIcon.imageset/CallKit@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
23
ios/app/src/Images.xcassets/CallKitIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "CallKit@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "CallKit@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "CallKit@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
6
ios/app/src/Images.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
23
ios/app/src/Images.xcassets/LaunchScreen.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "LaunchScreen-480@1x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "LaunchScreen-480@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "LaunchScreen-480@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ios/app/src/Images.xcassets/LaunchScreen.imageset/LaunchScreen-480@1x.png
vendored
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
ios/app/src/Images.xcassets/LaunchScreen.imageset/LaunchScreen-480@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
ios/app/src/Images.xcassets/LaunchScreen.imageset/LaunchScreen-480@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 278 KiB |
109
ios/app/src/Info.plist
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Jitsi Meet</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>org.jitsi.meet</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>org.jitsi.meet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.googleusercontent.apps</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>com.googleusercontent.apps.your-id-here</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>FirebaseCrashlyticsCollectionEnabled</key>
|
||||
<string>false</string>
|
||||
<key>FirebaseScreenReportingEnabled</key>
|
||||
<false/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>localhost</key>
|
||||
<dict>
|
||||
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>See your scheduled meetings in the app.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Participate in meetings with video.</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Local network is used for establishing Peer-to-Peer connections.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Participate in meetings with voice.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>org.jitsi.JitsiMeet.ios.conference</string>
|
||||
</array>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
<key>RTCAppGroupIdentifier</key>
|
||||
<string>group.org.jitsi.meet.appgroup</string>
|
||||
<key>RTCScreenSharingExtension</key>
|
||||
<string>org.jitsi.meet.broadcast.extension</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
<string>fetch</string>
|
||||
<string>voip</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleLightContent</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
94
ios/app/src/ViewController.swift
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright @ 2025-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import CoreSpotlight
|
||||
import Intents
|
||||
import MobileCoreServices
|
||||
import UIKit
|
||||
|
||||
import JitsiMeetSDK
|
||||
|
||||
@objcMembers
|
||||
class ViewController: UIViewController {
|
||||
|
||||
override func loadView() {
|
||||
let jitsiView = JitsiMeetView(frame: UIScreen.main.bounds)
|
||||
self.view = jitsiView
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
guard let view = self.view as? JitsiMeetView else { return }
|
||||
view.delegate = self
|
||||
view.join(JitsiMeet.sharedInstance().getInitialConferenceOptions())
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
func terminate() {
|
||||
guard let view = self.view as? JitsiMeetView else { return }
|
||||
view.leave()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension ViewController: @preconcurrency JitsiMeetViewDelegate {
|
||||
|
||||
// MARK: - Private Helper Methods
|
||||
|
||||
private func onJitsiMeetViewDelegateEvent(_ name: String, withData data: [AnyHashable: Any]?) {
|
||||
NSLog("[%@:%d] JitsiMeetViewDelegate %@ %@", #file, #line, name, data ?? [:])
|
||||
|
||||
#if DEBUG
|
||||
assert(Thread.isMainThread, "JitsiMeetViewDelegate \(name) method invoked on a non-main thread")
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - JitsiMeetViewDelegate
|
||||
|
||||
func conferenceJoined(_ data: [AnyHashable: Any]) {
|
||||
onJitsiMeetViewDelegateEvent("CONFERENCE_JOINED", withData: data)
|
||||
|
||||
// Register a NSUserActivity for this conference so it can be invoked as a Siri shortcut.
|
||||
// Must match the one defined in Info.plist
|
||||
let userActivity = NSUserActivity(activityType: "org.jitsi.JitsiMeet.ios.conference")
|
||||
|
||||
if let urlStr = data["url"] as? String,
|
||||
let url = URL(string: urlStr),
|
||||
let conference = url.pathComponents.last {
|
||||
|
||||
userActivity.title = "Join \(conference)"
|
||||
userActivity.suggestedInvocationPhrase = "Join my Jitsi meeting"
|
||||
userActivity.userInfo = ["url": urlStr]
|
||||
userActivity.isEligibleForSearch = true
|
||||
userActivity.isEligibleForPrediction = true
|
||||
userActivity.persistentIdentifier = urlStr
|
||||
|
||||
// Subtitle
|
||||
let attributes = CSSearchableItemAttributeSet(contentType: UTType.item)
|
||||
attributes.contentDescription = urlStr
|
||||
userActivity.contentAttributeSet = attributes
|
||||
|
||||
self.userActivity = userActivity
|
||||
userActivity.becomeCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
func ready(toClose data: [AnyHashable: Any]) {
|
||||
onJitsiMeetViewDelegateEvent("READY_TO_CLOSE", withData: data)
|
||||
}
|
||||
}
|
||||
15
ios/apple-app-site-association
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"applinks": {
|
||||
"apps": [],
|
||||
"details": [
|
||||
{
|
||||
"appID": "BQNXB4G3KQ.org.jitsi.JitsiMeet.ios",
|
||||
"paths": [ "*" ]
|
||||
},
|
||||
{
|
||||
"appID": "UPXU4CQZ5P.com.atlassian.JitsiMeet.ios",
|
||||
"paths": [ "*" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
4
ios/fastlane/Appfile
Normal file
@@ -0,0 +1,4 @@
|
||||
app_identifier("com.atlassian.JitsiMeet.ios") # The bundle identifier of your app
|
||||
itc_team_id("304592") # App Store Connect Team ID
|
||||
team_id("FC967L3QRG") # Developer Portal Team ID
|
||||
|
||||
81
ios/fastlane/Fastfile
Normal file
@@ -0,0 +1,81 @@
|
||||
ENV["FASTLANE_SKIP_UPDATE_CHECK"] = "1"
|
||||
opt_out_usage
|
||||
|
||||
default_platform(:ios)
|
||||
|
||||
platform :ios do
|
||||
desc "Push a new beta build to TestFlight"
|
||||
lane :deploy do
|
||||
# Make sure we are on a clean tree
|
||||
ensure_git_status_clean
|
||||
|
||||
# Connect to Apple Store Connect
|
||||
app_store_connect_api_key(
|
||||
key_id: ENV["ASC_KEY_ID"],
|
||||
issuer_id: ENV["ASC_ISSUER_ID"],
|
||||
key_content: ENV["ASC_KEY_CONTENT"],
|
||||
duration: 1200,
|
||||
in_house: false
|
||||
)
|
||||
|
||||
# Set the app identifier
|
||||
update_app_identifier(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
plist_path: "src/Info.plist",
|
||||
app_identifier: "com.atlassian.JitsiMeet.ios"
|
||||
)
|
||||
|
||||
# Set the broadcast extension identifier
|
||||
update_app_identifier(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
plist_path: "broadcast-extension/Info.plist",
|
||||
app_identifier: "com.atlassian.JitsiMeet.ios.broadcast"
|
||||
)
|
||||
update_info_plist(
|
||||
xcodeproj: "app/app.xcodeproj",
|
||||
plist_path: "src/Info.plist",
|
||||
block: proc do |plist|
|
||||
plist["RTCScreenSharingExtension"] = "com.atlassian.JitsiMeet.ios.broadcast"
|
||||
end
|
||||
)
|
||||
|
||||
# Increment the build number by 1
|
||||
increment_build_number(
|
||||
build_number: Time.now.to_i,
|
||||
xcodeproj: "app/app.xcodeproj"
|
||||
)
|
||||
|
||||
# Actually build the app
|
||||
build_app(
|
||||
scheme: "JitsiMeet",
|
||||
include_symbols: true,
|
||||
export_xcargs: "-allowProvisioningUpdates",
|
||||
xcodebuild_formatter: ""
|
||||
)
|
||||
|
||||
# Upload the build to TestFlight
|
||||
upload_to_testflight(
|
||||
beta_app_description: ENV["JITSI_CHANGELOG"],
|
||||
beta_app_feedback_email: ENV["JITSI_REVIEW_EMAIL"],
|
||||
beta_app_review_info: {
|
||||
contact_email: ENV["JITSI_REVIEW_EMAIL"],
|
||||
contact_first_name: ENV["JITSI_REVIEW_NAME"],
|
||||
contact_last_name: ENV["JITSI_REVIEW_SURNAME"],
|
||||
contact_phone: ENV["JITSI_REVIEW_PHONE"],
|
||||
demo_account_name: ENV["JITSI_DEMO_ACCOUNT"],
|
||||
demo_account_password: ENV["JITSI_DEMO_PASSWORD"],
|
||||
},
|
||||
changelog: ENV["JITSI_CHANGELOG"],
|
||||
demo_account_required: false,
|
||||
distribute_external: true,
|
||||
groups: ENV["JITSI_BETA_TESTING_GROUPS"],
|
||||
uses_non_exempt_encryption: false
|
||||
)
|
||||
|
||||
upload_symbols_to_crashlytics
|
||||
|
||||
# Cleanup
|
||||
clean_build_artifacts
|
||||
reset_git_repo(skip_clean: true)
|
||||
end
|
||||
end
|
||||
29
ios/fastlane/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
fastlane documentation
|
||||
================
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
Install _fastlane_ using
|
||||
```
|
||||
[sudo] gem install fastlane -NV
|
||||
```
|
||||
or alternatively using `brew cask install fastlane`
|
||||
|
||||
# Available Actions
|
||||
## iOS
|
||||
### ios deploy
|
||||
```
|
||||
fastlane ios deploy
|
||||
```
|
||||
Push a new beta build to TestFlight
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-1-1.png
Normal file
|
After Width: | Height: | Size: 512 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-1.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-2.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
ios/fastlane/screenshots/Feature-Graphic-1024x500-3.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
ios/fastlane/screenshots/GroupCallIphone8Plus.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ios/fastlane/screenshots/GroupCallIphone8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
ios/fastlane/screenshots/MoreMenu8Plus.png
Normal file
|
After Width: | Height: | Size: 779 KiB |
BIN
ios/fastlane/screenshots/MoreMenu8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 888 KiB |
BIN
ios/fastlane/screenshots/WelcomePage8Plus.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
ios/fastlane/screenshots/WelcomePage8PlusDevice.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-In-Call-1.png
Normal file
|
After Width: | Height: | Size: 3.3 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-In-Call-2.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
ios/fastlane/screenshots/iPad-9.7-inch-Welcome.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
ios/fastlane/screenshots/iPadCall.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
BIN
ios/fastlane/screenshots/iPadCallDevice.png
Normal file
|
After Width: | Height: | Size: 6.4 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus Calendar.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus Group Call.png
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
BIN
ios/fastlane/screenshots/iPhone 8 Plus More.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-In-Call-2.png
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-In-Call.png
Normal file
|
After Width: | Height: | Size: 3.0 MiB |
BIN
ios/fastlane/screenshots/iPhone-5.5-inch-Welcome.png
Normal file
|
After Width: | Height: | Size: 4.4 MiB |
13
ios/jitsi-meet.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:app/app.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:sdk/sdk.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
15
ios/patches/ws-tls13.diff
Normal file
@@ -0,0 +1,15 @@
|
||||
diff --git a/SocketRocket/SRSecurityPolicy.m b/SocketRocket/SRSecurityPolicy.m
|
||||
index 3759d26e..271477e8 100644
|
||||
--- a/SocketRocket/SRSecurityPolicy.m
|
||||
+++ b/SocketRocket/SRSecurityPolicy.m
|
||||
@@ -56,8 +56,8 @@ - (instancetype)init
|
||||
|
||||
- (void)updateSecurityOptionsInStream:(NSStream *)stream
|
||||
{
|
||||
- // Enforce TLS 1.2
|
||||
- [stream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
|
||||
+ // Enforce TLS >= 1.2
|
||||
+ [stream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
|
||||
|
||||
// Validate certificate chain for this stream if enabled.
|
||||
NSDictionary<NSString *, id> *sslOptions = @{ (__bridge NSString *)kCFStreamSSLValidatesCertificateChain : @(self.certificateChainValidationEnabled) };
|
||||
36
ios/scripts/fixup-ats.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script gets executed from Xcode to disable ATS (App Transport Security)
|
||||
# on Debug builds. Doing this allows loading resources over HTTP, such as the
|
||||
# JS bundle.
|
||||
|
||||
|
||||
set -x
|
||||
|
||||
case "$CONFIGURATION" in
|
||||
Debug)
|
||||
# Speed up build times by skipping the creation of the offline package for debug
|
||||
# builds on the simulator since the packager is supposed to be running anyways.
|
||||
if [[ "$PLATFORM_NAME" == *simulator ]]; then
|
||||
echo "Skipping bundling for Simulator platform"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
DEV=true
|
||||
;;
|
||||
"")
|
||||
echo "$0 must be invoked by Xcode"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
DEV=false
|
||||
;;
|
||||
esac
|
||||
|
||||
DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
|
||||
|
||||
if [[ "$CONFIGURATION" = "Debug" && ! "$PLATFORM_NAME" == *simulator ]]; then
|
||||
PLISTBUDDY='/usr/libexec/PlistBuddy'
|
||||
PLIST=$TARGET_BUILD_DIR/$INFOPLIST_PATH
|
||||
`$PLISTBUDDY -c "Add NSAppTransportSecurity:NSAllowsArbitraryLoads bool true" "$PLIST"` || true
|
||||
fi
|
||||
67
ios/scripts/release-sdk-lite.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -u -x
|
||||
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
PROJECT_REPO=$(realpath ${THIS_DIR}/../..)
|
||||
RELEASE_REPO=$(realpath ${THIS_DIR}/../../../jitsi-meet-ios-sdk-releases)
|
||||
DEFAULT_SDK_VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" ${THIS_DIR}/../sdk/src/Lite-Info.plist)
|
||||
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
|
||||
|
||||
echo "Releasing Jitsi Meet SDK Lite ${SDK_VERSION}"
|
||||
|
||||
pushd ${RELEASE_REPO}
|
||||
|
||||
# Generate podspec file
|
||||
cat JitsiMeetSDKLite.podspec.tpl | sed -e s/VERSION/${SDK_VERSION}-lite/g > JitsiMeetSDKLite.podspec
|
||||
|
||||
# Cleanup
|
||||
rm -rf lite/Frameworks/*
|
||||
|
||||
popd
|
||||
|
||||
# Build the SDK
|
||||
pushd ${PROJECT_REPO}
|
||||
rm -rf ios/sdk/out
|
||||
xcodebuild clean \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDKLite
|
||||
xcodebuild archive \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDKLite \
|
||||
-configuration Release \
|
||||
-sdk iphonesimulator \
|
||||
-destination='generic/platform=iOS Simulator' \
|
||||
-archivePath ios/sdk/out/ios-simulator \
|
||||
SKIP_INSTALL=NO \
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
|
||||
xcodebuild archive \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDKLite \
|
||||
-configuration Release \
|
||||
-sdk iphoneos \
|
||||
-destination='generic/platform=iOS' \
|
||||
-archivePath ios/sdk/out/ios-device \
|
||||
SKIP_INSTALL=NO \
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
|
||||
xcodebuild -create-xcframework \
|
||||
-framework ios/sdk/out/ios-device.xcarchive/Products/Library/Frameworks/JitsiMeetSDK.framework \
|
||||
-framework ios/sdk/out/ios-simulator.xcarchive/Products/Library/Frameworks/JitsiMeetSDK.framework \
|
||||
-output ios/sdk/out/JitsiMeetSDK.xcframework
|
||||
popd
|
||||
|
||||
pushd ${RELEASE_REPO}
|
||||
|
||||
# Put the new files in the repo
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework lite/Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/Pods/hermes-engine/destroot/Library/Frameworks/universal/hermesvm.xcframework lite/Frameworks/
|
||||
|
||||
# Add all files to git
|
||||
git add -A .
|
||||
git commit --allow-empty -m "${SDK_VERSION} lite"
|
||||
git tag "${SDK_VERSION}-lite"
|
||||
|
||||
popd
|
||||
|
||||
echo "Finished! Don't forget to push the tags and releases repo artifacts."
|
||||
echo "The new pod can be pushed to CocoaPods by doing: pod trunk push JitsiMeetSDKLite.podspec"
|
||||
67
ios/scripts/release-sdk.sh
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -u -x
|
||||
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
PROJECT_REPO=$(realpath ${THIS_DIR}/../..)
|
||||
RELEASE_REPO=$(realpath ${THIS_DIR}/../../../jitsi-meet-ios-sdk-releases)
|
||||
DEFAULT_SDK_VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" ${THIS_DIR}/../sdk/src/Info.plist)
|
||||
SDK_VERSION=${OVERRIDE_SDK_VERSION:-${DEFAULT_SDK_VERSION}}
|
||||
|
||||
echo "Releasing Jitsi Meet SDK ${SDK_VERSION}"
|
||||
|
||||
pushd ${RELEASE_REPO}
|
||||
|
||||
# Generate podspec file
|
||||
cat JitsiMeetSDK.podspec.tpl | sed -e s/VERSION/${SDK_VERSION}/g > JitsiMeetSDK.podspec
|
||||
|
||||
# Cleanup
|
||||
rm -rf Frameworks/*
|
||||
|
||||
popd
|
||||
|
||||
# Build the SDK
|
||||
pushd ${PROJECT_REPO}
|
||||
rm -rf ios/sdk/out
|
||||
xcodebuild clean \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDK
|
||||
xcodebuild archive \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDK \
|
||||
-configuration Release \
|
||||
-sdk iphonesimulator \
|
||||
-destination='generic/platform=iOS Simulator' \
|
||||
-archivePath ios/sdk/out/ios-simulator \
|
||||
SKIP_INSTALL=NO \
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
|
||||
xcodebuild archive \
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDK \
|
||||
-configuration Release \
|
||||
-sdk iphoneos \
|
||||
-destination='generic/platform=iOS' \
|
||||
-archivePath ios/sdk/out/ios-device \
|
||||
SKIP_INSTALL=NO \
|
||||
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
|
||||
xcodebuild -create-xcframework \
|
||||
-framework ios/sdk/out/ios-device.xcarchive/Products/Library/Frameworks/JitsiMeetSDK.framework \
|
||||
-framework ios/sdk/out/ios-simulator.xcarchive/Products/Library/Frameworks/JitsiMeetSDK.framework \
|
||||
-output ios/sdk/out/JitsiMeetSDK.xcframework
|
||||
popd
|
||||
|
||||
pushd ${RELEASE_REPO}
|
||||
|
||||
# Put the new files in the repo
|
||||
cp -a ${PROJECT_REPO}/ios/sdk/out/JitsiMeetSDK.xcframework Frameworks/
|
||||
cp -a ${PROJECT_REPO}/ios/Pods/hermes-engine/destroot/Library/Frameworks/universal/hermesvm.xcframework Frameworks/
|
||||
|
||||
# Add all files to git
|
||||
git add -A .
|
||||
git commit --allow-empty -m "${SDK_VERSION}"
|
||||
git tag "${SDK_VERSION}"
|
||||
|
||||
popd
|
||||
|
||||
echo "Finished! Don't forget to push the tags and releases repo artifacts."
|
||||
echo "The new pod can be pushed to CocoaPods by doing: pod trunk push JitsiMeetSDK.podspec"
|
||||
5
ios/scripts/run-packager-helper.command
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
|
||||
exec ${THIS_DIR}/../../node_modules/react-native/scripts/packager.sh --reset-cache
|
||||
20
ios/scripts/run-packager.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is executed from Xcode to start the React packager for Debug
|
||||
# targets.
|
||||
|
||||
THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
|
||||
|
||||
export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
|
||||
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${SRCROOT}/../../node_modules/react-native/scripts/.packager.env"
|
||||
|
||||
if [[ "$CONFIGURATION" = "Debug" ]]; then
|
||||
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
|
||||
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
|
||||
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
open -g "$THIS_DIR/run-packager-helper.command" || echo "Can't start packager automatically"
|
||||
fi
|
||||
fi
|
||||
1036
ios/sdk/sdk.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0BD906E41EC0C00300C8C18E"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDK"
|
||||
ReferencedContainer = "container:sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0BD906E41EC0C00300C8C18E"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDK"
|
||||
ReferencedContainer = "container:sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "0BD906E41EC0C00300C8C18E"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDK"
|
||||
ReferencedContainer = "container:sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1340"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DE9A012D289A9A9A00E41CBB"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDKLite"
|
||||
ReferencedContainer = "container:sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DE9A012D289A9A9A00E41CBB"
|
||||
BuildableName = "JitsiMeetSDK.framework"
|
||||
BlueprintName = "JitsiMeetSDKLite"
|
||||
ReferencedContainer = "container:sdk.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
102
ios/sdk/src/AppInfo.m
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
#import "InfoPlistUtil.h"
|
||||
|
||||
@interface AppInfo : NSObject<RCTBridgeModule>
|
||||
@end
|
||||
|
||||
@implementation AppInfo
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport {
|
||||
NSDictionary<NSString *, id> *infoDictionary
|
||||
= [[NSBundle mainBundle] infoDictionary];
|
||||
|
||||
// calendarEnabled
|
||||
BOOL calendarEnabled = NO;
|
||||
#if !defined(JITSI_MEET_SDK_LITE)
|
||||
calendarEnabled = infoDictionary[@"NSCalendarsUsageDescription"] != nil;
|
||||
#endif
|
||||
|
||||
// name
|
||||
NSString *name = infoDictionary[@"CFBundleDisplayName"];
|
||||
|
||||
if (name == nil) {
|
||||
name = infoDictionary[@"CFBundleName"];
|
||||
if (name == nil) {
|
||||
name = @"";
|
||||
}
|
||||
}
|
||||
|
||||
// sdkBundlePath
|
||||
NSString *sdkBundlePath = [[NSBundle bundleForClass:self.class] bundlePath];
|
||||
|
||||
// version
|
||||
NSString *version = infoDictionary[@"CFBundleShortVersionString"];
|
||||
|
||||
if (version == nil) {
|
||||
version = infoDictionary[@"CFBundleVersion"];
|
||||
if (version == nil) {
|
||||
version = @"";
|
||||
}
|
||||
}
|
||||
|
||||
// SDK version
|
||||
NSDictionary<NSString *, id> *sdkInfoDictionary
|
||||
= [[NSBundle bundleForClass:self.class] infoDictionary];
|
||||
NSString *sdkVersion = sdkInfoDictionary[@"CFBundleShortVersionString"];
|
||||
if (sdkVersion == nil) {
|
||||
sdkVersion = @"";
|
||||
}
|
||||
|
||||
// build number
|
||||
NSString *buildNumber = infoDictionary[@"CFBundleVersion"];
|
||||
if (buildNumber == nil) {
|
||||
buildNumber = @"";
|
||||
}
|
||||
|
||||
// google services (sign in)
|
||||
BOOL isGoogleServiceEnabled = [InfoPlistUtil containsRealServiceInfoPlistInBundle:[NSBundle mainBundle]];
|
||||
|
||||
// lite SDK
|
||||
BOOL isLiteSDK = NO;
|
||||
#if defined(JITSI_MEET_SDK_LITE)
|
||||
isLiteSDK = YES;
|
||||
#endif
|
||||
|
||||
return @{
|
||||
@"calendarEnabled": [NSNumber numberWithBool:calendarEnabled],
|
||||
@"buildNumber": buildNumber,
|
||||
@"isLiteSDK": [NSNumber numberWithBool:isLiteSDK],
|
||||
@"name": name,
|
||||
@"sdkBundlePath": sdkBundlePath,
|
||||
@"sdkVersion": sdkVersion,
|
||||
@"version": version,
|
||||
@"GOOGLE_SERVICES_ENABLED": [NSNumber numberWithBool:isGoogleServiceEnabled]
|
||||
};
|
||||
};
|
||||
@end
|
||||
420
ios/sdk/src/AudioMode.m
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#import <React/RCTEventEmitter.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <WebRTC/WebRTC.h>
|
||||
|
||||
#import "JitsiAudioSession+Private.h"
|
||||
#import "callkit/JMCallKitProxy.h"
|
||||
|
||||
|
||||
// Audio mode
|
||||
typedef enum {
|
||||
kAudioModeDefault,
|
||||
kAudioModeInCall
|
||||
} JitsiMeetAudioMode;
|
||||
|
||||
// Events
|
||||
static NSString * const kDevicesChanged = @"org.jitsi.meet:features/audio-mode#devices-update";
|
||||
|
||||
// Device types (must match JS and Java)
|
||||
static NSString * const kDeviceTypeBluetooth = @"BLUETOOTH";
|
||||
static NSString * const kDeviceTypeCar = @"CAR";
|
||||
static NSString * const kDeviceTypeEarpiece = @"EARPIECE";
|
||||
static NSString * const kDeviceTypeHeadphones = @"HEADPHONES";
|
||||
static NSString * const kDeviceTypeSpeaker = @"SPEAKER";
|
||||
static NSString * const kDeviceTypeUnknown = @"UNKNOWN";
|
||||
|
||||
|
||||
@interface AudioMode : RCTEventEmitter<RTCAudioSessionDelegate>
|
||||
|
||||
@property(nonatomic, strong) dispatch_queue_t workerQueue;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AudioMode {
|
||||
JitsiMeetAudioMode activeMode;
|
||||
RTCAudioSessionConfiguration *defaultConfig;
|
||||
RTCAudioSessionConfiguration *inCallConfig;
|
||||
RTCAudioSessionConfiguration *earpieceConfig;
|
||||
BOOL audioDisabled;
|
||||
BOOL forceSpeaker;
|
||||
BOOL forceEarpiece;
|
||||
BOOL isSpeakerOn;
|
||||
BOOL isEarpieceOn;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[ kDevicesChanged ];
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport {
|
||||
return @{
|
||||
@"DEVICE_CHANGE_EVENT": kDevicesChanged,
|
||||
@"DEFAULT" : [NSNumber numberWithInt: kAudioModeDefault],
|
||||
@"IN_CALL" : [NSNumber numberWithInt: kAudioModeInCall]
|
||||
};
|
||||
};
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
dispatch_queue_attr_t attributes =
|
||||
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, -1);
|
||||
_workerQueue = dispatch_queue_create("AudioMode.queue", attributes);
|
||||
|
||||
activeMode = kAudioModeDefault;
|
||||
|
||||
defaultConfig = [[RTCAudioSessionConfiguration alloc] init];
|
||||
defaultConfig.category = AVAudioSessionCategoryAmbient;
|
||||
defaultConfig.categoryOptions = 0;
|
||||
defaultConfig.mode = AVAudioSessionModeDefault;
|
||||
|
||||
inCallConfig = [[RTCAudioSessionConfiguration alloc] init];
|
||||
inCallConfig.category = AVAudioSessionCategoryPlayAndRecord;
|
||||
inCallConfig.categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth;
|
||||
inCallConfig.mode = AVAudioSessionModeVideoChat;
|
||||
|
||||
// Manually routing audio to the earpiece doesn't quite work unless one disables BT (weird, I know).
|
||||
earpieceConfig = [[RTCAudioSessionConfiguration alloc] init];
|
||||
earpieceConfig.category = AVAudioSessionCategoryPlayAndRecord;
|
||||
earpieceConfig.categoryOptions = 0;
|
||||
earpieceConfig.mode = AVAudioSessionModeVoiceChat;
|
||||
|
||||
forceSpeaker = NO;
|
||||
forceEarpiece = NO;
|
||||
isSpeakerOn = NO;
|
||||
isEarpieceOn = NO;
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
[session addDelegate:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)methodQueue {
|
||||
// Use a dedicated queue for audio mode operations.
|
||||
return _workerQueue;
|
||||
}
|
||||
|
||||
- (BOOL)setConfigWithoutLock:(RTCAudioSessionConfiguration *)config
|
||||
error:(NSError * _Nullable *)outError {
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
|
||||
return [session setConfiguration:config error:outError];
|
||||
}
|
||||
|
||||
- (BOOL)setConfig:(RTCAudioSessionConfiguration *)config
|
||||
error:(NSError * _Nullable *)outError {
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
[session lockForConfiguration];
|
||||
BOOL success = [self setConfigWithoutLock:config error:outError];
|
||||
[session unlockForConfiguration];
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#pragma mark - Exported methods
|
||||
|
||||
RCT_EXPORT_METHOD(setDisabled:(BOOL)disabled
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled == disabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTLogInfo(@"[AudioMode] audio disabled: %d", disabled);
|
||||
|
||||
audioDisabled = disabled;
|
||||
JMCallKitProxy.enabled = !disabled;
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
if (disabled) {
|
||||
[session removeDelegate:self];
|
||||
} else {
|
||||
[session addDelegate:self];
|
||||
}
|
||||
session.useManualAudio = disabled;
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setMode:(int)mode
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RTCAudioSessionConfiguration *config = [self configForMode:mode];
|
||||
NSError *error;
|
||||
|
||||
if (config == nil) {
|
||||
reject(@"setMode", @"Invalid mode", nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset.
|
||||
if (mode == kAudioModeDefault) {
|
||||
forceSpeaker = NO;
|
||||
forceEarpiece = NO;
|
||||
}
|
||||
|
||||
activeMode = mode;
|
||||
|
||||
if ([self setConfig:config error:&error]) {
|
||||
resolve(nil);
|
||||
} else {
|
||||
reject(@"setMode", error.localizedDescription, error);
|
||||
}
|
||||
|
||||
[self notifyDevicesChanged];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(setAudioDevice:(NSString *)device
|
||||
resolve:(RCTPromiseResolveBlock)resolve
|
||||
reject:(RCTPromiseRejectBlock)reject) {
|
||||
if (audioDisabled) {
|
||||
resolve(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTLogInfo(@"[AudioMode] Selected device: %@", device);
|
||||
|
||||
RTCAudioSession *session = JitsiAudioSession.rtcAudioSession;
|
||||
[session lockForConfiguration];
|
||||
BOOL success;
|
||||
NSError *error = nil;
|
||||
|
||||
// Reset these, as we are about to compute them.
|
||||
forceSpeaker = NO;
|
||||
forceEarpiece = NO;
|
||||
|
||||
// The speaker is special, so test for it first.
|
||||
if ([device isEqualToString:kDeviceTypeSpeaker]) {
|
||||
forceSpeaker = YES;
|
||||
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
|
||||
} else {
|
||||
// Here we use AVAudioSession because RTCAudioSession doesn't expose availableInputs.
|
||||
AVAudioSession *_session = [AVAudioSession sharedInstance];
|
||||
AVAudioSessionPortDescription *port = nil;
|
||||
|
||||
// Find the matching input device.
|
||||
for (AVAudioSessionPortDescription *portDesc in _session.availableInputs) {
|
||||
if ([portDesc.UID isEqualToString:device]) {
|
||||
port = portDesc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port != nil) {
|
||||
// First remove the override if we are going to select a different device.
|
||||
if (isSpeakerOn) {
|
||||
[session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
|
||||
}
|
||||
|
||||
// Special case for the earpiece.
|
||||
if ([port.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
|
||||
forceEarpiece = YES;
|
||||
[self setConfigWithoutLock:earpieceConfig error:nil];
|
||||
} else if (isEarpieceOn) {
|
||||
// Reset the config.
|
||||
RTCAudioSessionConfiguration *config = [self configForMode:activeMode];
|
||||
[self setConfigWithoutLock:config error:nil];
|
||||
}
|
||||
|
||||
// Select our preferred input.
|
||||
success = [session setPreferredInput:port error:&error];
|
||||
} else {
|
||||
success = NO;
|
||||
error = RCTErrorWithMessage(@"Could not find audio device");
|
||||
}
|
||||
}
|
||||
|
||||
[session unlockForConfiguration];
|
||||
|
||||
if (success) {
|
||||
resolve(nil);
|
||||
} else {
|
||||
reject(@"setAudioDevice", error != nil ? error.localizedDescription : @"", error);
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(updateDeviceList) {
|
||||
if (audioDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self notifyDevicesChanged];
|
||||
}
|
||||
|
||||
#pragma mark - RTCAudioSessionDelegate
|
||||
|
||||
- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session
|
||||
reason:(AVAudioSessionRouteChangeReason)reason
|
||||
previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
|
||||
RCTLogInfo(@"[AudioMode] Route changed, reason: %lu", (unsigned long)reason);
|
||||
|
||||
// Update JS about the changes.
|
||||
[self notifyDevicesChanged];
|
||||
|
||||
dispatch_async(_workerQueue, ^{
|
||||
switch (reason) {
|
||||
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
|
||||
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
|
||||
// If the device list changed, reset our overrides.
|
||||
self->forceSpeaker = NO;
|
||||
self->forceEarpiece = NO;
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonCategoryChange:
|
||||
// The category has changed, re-apply our config.
|
||||
// NB: It's tempting to doa category check here and skip the processing,
|
||||
// but that won't work. If the config changes but the category remains
|
||||
// the same we'll still find ourselves here.
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't want to touch the category when in default mode.
|
||||
// This is to play well with other components which could be integrated
|
||||
// into the final application.
|
||||
if (self->activeMode != kAudioModeDefault) {
|
||||
RCTLogInfo(@"[AudioMode] Route changed, reapplying RTCAudioSession config");
|
||||
RTCAudioSessionConfiguration *config = [self configForMode:self->activeMode];
|
||||
[self setConfig:config error:nil];
|
||||
if (self->forceSpeaker && !self->isSpeakerOn) {
|
||||
[session lockForConfiguration];
|
||||
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
|
||||
[session unlockForConfiguration];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)audioSession:(RTCAudioSession *)audioSession didSetActive:(BOOL)active {
|
||||
RCTLogInfo(@"[AudioMode] Audio session didSetActive:%d", active);
|
||||
}
|
||||
|
||||
#pragma mark - Helper methods
|
||||
|
||||
- (RTCAudioSessionConfiguration *)configForMode:(int) mode {
|
||||
if (mode != kAudioModeDefault && forceEarpiece) {
|
||||
return earpieceConfig;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case kAudioModeDefault:
|
||||
return defaultConfig;
|
||||
case kAudioModeInCall:
|
||||
return inCallConfig;
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Here we convert input and output port types into a single type.
|
||||
- (NSString *)portTypeToString:(AVAudioSessionPort) portType {
|
||||
if ([portType isEqualToString:AVAudioSessionPortHeadphones]
|
||||
|| [portType isEqualToString:AVAudioSessionPortHeadsetMic]) {
|
||||
return kDeviceTypeHeadphones;
|
||||
} else if ([portType isEqualToString:AVAudioSessionPortBuiltInMic]
|
||||
|| [portType isEqualToString:AVAudioSessionPortBuiltInReceiver]) {
|
||||
return kDeviceTypeEarpiece;
|
||||
} else if ([portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) {
|
||||
return kDeviceTypeSpeaker;
|
||||
} else if ([portType isEqualToString:AVAudioSessionPortBluetoothHFP]
|
||||
|| [portType isEqualToString:AVAudioSessionPortBluetoothLE]
|
||||
|| [portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) {
|
||||
return kDeviceTypeBluetooth;
|
||||
} else if ([portType isEqualToString:AVAudioSessionPortCarAudio]) {
|
||||
return kDeviceTypeCar;
|
||||
} else {
|
||||
return kDeviceTypeUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyDevicesChanged {
|
||||
dispatch_async(_workerQueue, ^{
|
||||
NSMutableArray *data = [[NSMutableArray alloc] init];
|
||||
// Here we use AVAudioSession because RTCAudioSession doesn't expose availableInputs.
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
NSString *currentPort = @"";
|
||||
AVAudioSessionRouteDescription *currentRoute = session.currentRoute;
|
||||
|
||||
// Check what the current device is. Because the speaker is somewhat special, we need to
|
||||
// check for it first.
|
||||
if (currentRoute != nil) {
|
||||
AVAudioSessionPortDescription *output = currentRoute.outputs.firstObject;
|
||||
AVAudioSessionPortDescription *input = currentRoute.inputs.firstObject;
|
||||
if (output != nil && [output.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) {
|
||||
currentPort = kDeviceTypeSpeaker;
|
||||
self->isSpeakerOn = YES;
|
||||
} else if (input != nil) {
|
||||
currentPort = input.UID;
|
||||
self->isSpeakerOn = NO;
|
||||
self->isEarpieceOn = [input.portType isEqualToString:AVAudioSessionPortBuiltInMic];
|
||||
}
|
||||
}
|
||||
|
||||
BOOL headphonesAvailable = NO;
|
||||
for (AVAudioSessionPortDescription *portDesc in session.availableInputs) {
|
||||
if ([portDesc.portType isEqualToString:AVAudioSessionPortHeadsetMic] || [portDesc.portType isEqualToString:AVAudioSessionPortHeadphones]) {
|
||||
headphonesAvailable = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (AVAudioSessionPortDescription *portDesc in session.availableInputs) {
|
||||
// Skip "Phone" if headphones are present.
|
||||
if (headphonesAvailable && [portDesc.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
|
||||
continue;
|
||||
}
|
||||
id deviceData
|
||||
= @{
|
||||
@"type": [self portTypeToString:portDesc.portType],
|
||||
@"name": portDesc.portName,
|
||||
@"uid": portDesc.UID,
|
||||
@"selected": [NSNumber numberWithBool:[portDesc.UID isEqualToString:currentPort]]
|
||||
};
|
||||
[data addObject:deviceData];
|
||||
}
|
||||
|
||||
// We need to manually add the speaker because it will never show up in the
|
||||
// previous list, as it's not an input.
|
||||
[data addObject:
|
||||
@{ @"type": kDeviceTypeSpeaker,
|
||||
@"name": @"Speaker",
|
||||
@"uid": kDeviceTypeSpeaker,
|
||||
@"selected": [NSNumber numberWithBool:[kDeviceTypeSpeaker isEqualToString:currentPort]]
|
||||
}];
|
||||
|
||||
[self sendEventWithName:kDevicesChanged body:data];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
43
ios/sdk/src/ExternalAPI.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright @ 2021-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
static NSString * const sendEventNotificationName = @"org.jitsi.meet.SendEvent";
|
||||
|
||||
@interface ExternalAPI : RCTEventEmitter<RCTBridgeModule>
|
||||
|
||||
+ (ExternalAPI *)sharedInstance;
|
||||
|
||||
- (void)sendHangUp;
|
||||
- (void)sendSetAudioMuted:(BOOL)muted;
|
||||
- (void)sendEndpointTextMessage:(NSString*)message :(NSString*)to;
|
||||
- (void)toggleScreenShare:(BOOL)enabled;
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completion;
|
||||
- (void)openChat:(NSString*)to;
|
||||
- (void)closeChat;
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to;
|
||||
- (void)sendSetVideoMuted:(BOOL)muted;
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled;
|
||||
- (void)toggleCamera;
|
||||
- (void)showNotification:(NSString*)appearance :(NSString*)description :(NSString*)timeout :(NSString*)title :(NSString*)uid;
|
||||
- (void)hideNotification:(NSString*)uid;
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription;
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription;
|
||||
- (void)overwriteConfig:(NSDictionary*)config;
|
||||
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode;
|
||||
|
||||
@end
|
||||
275
ios/sdk/src/ExternalAPI.m
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "ExternalAPI.h"
|
||||
|
||||
// Events
|
||||
static NSString * const hangUpAction = @"org.jitsi.meet.HANG_UP";
|
||||
static NSString * const setAudioMutedAction = @"org.jitsi.meet.SET_AUDIO_MUTED";
|
||||
static NSString * const sendEndpointTextMessageAction = @"org.jitsi.meet.SEND_ENDPOINT_TEXT_MESSAGE";
|
||||
static NSString * const toggleScreenShareAction = @"org.jitsi.meet.TOGGLE_SCREEN_SHARE";
|
||||
static NSString * const retrieveParticipantsInfoAction = @"org.jitsi.meet.RETRIEVE_PARTICIPANTS_INFO";
|
||||
static NSString * const openChatAction = @"org.jitsi.meet.OPEN_CHAT";
|
||||
static NSString * const closeChatAction = @"org.jitsi.meet.CLOSE_CHAT";
|
||||
static NSString * const sendChatMessageAction = @"org.jitsi.meet.SEND_CHAT_MESSAGE";
|
||||
static NSString * const setVideoMutedAction = @"org.jitsi.meet.SET_VIDEO_MUTED";
|
||||
static NSString * const setClosedCaptionsEnabledAction = @"org.jitsi.meet.SET_CLOSED_CAPTIONS_ENABLED";
|
||||
static NSString * const toggleCameraAction = @"org.jitsi.meet.TOGGLE_CAMERA";
|
||||
static NSString * const showNotificationAction = @"org.jitsi.meet.SHOW_NOTIFICATION";
|
||||
static NSString * const hideNotificationAction = @"org.jitsi.meet.HIDE_NOTIFICATION";
|
||||
static NSString * const startRecordingAction = @"org.jitsi.meet.START_RECORDING";
|
||||
static NSString * const stopRecordingAction = @"org.jitsi.meet.STOP_RECORDING";
|
||||
static NSString * const overwriteConfigAction = @"org.jitsi.meet.OVERWRITE_CONFIG";
|
||||
static NSString * const sendCameraFacingModeMessageAction = @"org.jitsi.meet.SEND_CAMERA_FACING_MODE_MESSAGE";
|
||||
|
||||
@implementation ExternalAPI
|
||||
|
||||
static NSMapTable<NSString*, void (^)(NSArray* participantsInfo)> *participantInfoCompletionHandlers;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void initializeViewsMap(void) {
|
||||
participantInfoCompletionHandlers = [NSMapTable strongToStrongObjectsMapTable];
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
|
||||
static __weak ExternalAPI *_sharedExternalAPI = nil;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sharedExternalAPI = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (ExternalAPI *)sharedInstance {
|
||||
return _sharedExternalAPI;
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport {
|
||||
return @{
|
||||
@"HANG_UP": hangUpAction,
|
||||
@"SET_AUDIO_MUTED" : setAudioMutedAction,
|
||||
@"SEND_ENDPOINT_TEXT_MESSAGE": sendEndpointTextMessageAction,
|
||||
@"TOGGLE_SCREEN_SHARE": toggleScreenShareAction,
|
||||
@"RETRIEVE_PARTICIPANTS_INFO": retrieveParticipantsInfoAction,
|
||||
@"OPEN_CHAT": openChatAction,
|
||||
@"CLOSE_CHAT": closeChatAction,
|
||||
@"SEND_CHAT_MESSAGE": sendChatMessageAction,
|
||||
@"SET_VIDEO_MUTED" : setVideoMutedAction,
|
||||
@"SET_CLOSED_CAPTIONS_ENABLED": setClosedCaptionsEnabledAction,
|
||||
@"TOGGLE_CAMERA": toggleCameraAction,
|
||||
@"SHOW_NOTIFICATION": showNotificationAction,
|
||||
@"HIDE_NOTIFICATION": hideNotificationAction,
|
||||
@"START_RECORDING": startRecordingAction,
|
||||
@"STOP_RECORDING": stopRecordingAction,
|
||||
@"OVERWRITE_CONFIG": overwriteConfigAction,
|
||||
@"SEND_CAMERA_FACING_MODE_MESSAGE": sendCameraFacingModeMessageAction
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Make sure all methods in this module are invoked on the main/UI thread.
|
||||
*/
|
||||
- (dispatch_queue_t)methodQueue {
|
||||
return dispatch_get_main_queue();
|
||||
}
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[ hangUpAction,
|
||||
setAudioMutedAction,
|
||||
sendEndpointTextMessageAction,
|
||||
toggleScreenShareAction,
|
||||
retrieveParticipantsInfoAction,
|
||||
openChatAction,
|
||||
closeChatAction,
|
||||
sendChatMessageAction,
|
||||
setVideoMutedAction,
|
||||
setClosedCaptionsEnabledAction,
|
||||
toggleCameraAction,
|
||||
showNotificationAction,
|
||||
hideNotificationAction,
|
||||
startRecordingAction,
|
||||
stopRecordingAction,
|
||||
overwriteConfigAction,
|
||||
sendCameraFacingModeMessageAction
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event that occurred on JavaScript to the view's delegate.
|
||||
*
|
||||
* @param name The name of the event.
|
||||
* @param data The details/specifics of the event to send determined
|
||||
* by/associated with the specified `name`.
|
||||
* @param scope
|
||||
*/
|
||||
RCT_EXPORT_METHOD(sendEvent:(NSString *)name
|
||||
data:(NSDictionary *)data) {
|
||||
if ([name isEqual: @"PARTICIPANTS_INFO_RETRIEVED"]) {
|
||||
[self onParticipantsInfoRetrieved: data];
|
||||
return;
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:sendEventNotificationName
|
||||
object:nil
|
||||
userInfo:@{@"name": name, @"data": data}];
|
||||
}
|
||||
|
||||
- (void) onParticipantsInfoRetrieved:(NSDictionary *)data {
|
||||
NSArray *participantsInfoArray = [data objectForKey:@"participantsInfo"];
|
||||
NSString *completionHandlerId = [data objectForKey:@"requestId"];
|
||||
|
||||
void (^completionHandler)(NSArray*) = [participantInfoCompletionHandlers objectForKey:completionHandlerId];
|
||||
completionHandler(participantsInfoArray);
|
||||
[participantInfoCompletionHandlers removeObjectForKey:completionHandlerId];
|
||||
}
|
||||
|
||||
- (void)sendHangUp {
|
||||
[self sendEventWithName:hangUpAction body:nil];
|
||||
}
|
||||
|
||||
- (void)sendSetAudioMuted:(BOOL)muted {
|
||||
NSDictionary *data = @{ @"muted": [NSNumber numberWithBool:muted]};
|
||||
|
||||
[self sendEventWithName:setAudioMutedAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendEndpointTextMessage:(NSString*)message :(NSString*)to {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"to"] = to;
|
||||
data[@"message"] = message;
|
||||
|
||||
[self sendEventWithName:sendEndpointTextMessageAction body:data];
|
||||
}
|
||||
|
||||
- (void)toggleScreenShare:(BOOL)enabled {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"enabled"] = [NSNumber numberWithBool:enabled];
|
||||
|
||||
[self sendEventWithName:toggleScreenShareAction body:data];
|
||||
}
|
||||
|
||||
- (void)retrieveParticipantsInfo:(void (^)(NSArray*))completionHandler {
|
||||
NSString *completionHandlerId = [[NSUUID UUID] UUIDString];
|
||||
NSDictionary *data = @{ @"requestId": completionHandlerId};
|
||||
|
||||
[participantInfoCompletionHandlers setObject:[completionHandler copy] forKey:completionHandlerId];
|
||||
|
||||
[self sendEventWithName:retrieveParticipantsInfoAction body:data];
|
||||
}
|
||||
|
||||
- (void)openChat:(NSString*)to {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"to"] = to;
|
||||
|
||||
[self sendEventWithName:openChatAction body:data];
|
||||
}
|
||||
|
||||
- (void)closeChat {
|
||||
[self sendEventWithName:closeChatAction body:nil];
|
||||
}
|
||||
|
||||
- (void)sendChatMessage:(NSString*)message :(NSString*)to {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"to"] = to;
|
||||
data[@"message"] = message;
|
||||
|
||||
[self sendEventWithName:sendChatMessageAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendSetVideoMuted:(BOOL)muted {
|
||||
NSDictionary *data = @{ @"muted": [NSNumber numberWithBool:muted]};
|
||||
|
||||
[self sendEventWithName:setVideoMutedAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendSetClosedCaptionsEnabled:(BOOL)enabled {
|
||||
NSDictionary *data = @{ @"enabled": [NSNumber numberWithBool:enabled]};
|
||||
|
||||
[self sendEventWithName:setClosedCaptionsEnabledAction body:data];
|
||||
}
|
||||
|
||||
- (void)toggleCamera {
|
||||
[self sendEventWithName:toggleCameraAction body:nil];
|
||||
}
|
||||
|
||||
- (void)showNotification:(NSString*)appearance :(NSString*)description :(NSString*)timeout :(NSString*)title :(NSString*)uid {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"appearance"] = appearance;
|
||||
data[@"description"] = description;
|
||||
data[@"timeout"] = timeout;
|
||||
data[@"title"] = title;
|
||||
data[@"uid"] = uid;
|
||||
|
||||
[self sendEventWithName:showNotificationAction body:data];
|
||||
}
|
||||
|
||||
- (void)hideNotification:(NSString*)uid {
|
||||
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
||||
data[@"uid"] = uid;
|
||||
|
||||
[self sendEventWithName:hideNotificationAction body:data];
|
||||
}
|
||||
|
||||
- (void)startRecording:(NSString*)mode :(NSString*)dropboxToken :(BOOL)shouldShare :(NSString*)rtmpStreamKey :(NSString*)rtmpBroadcastID :(NSString*)youtubeStreamKey :(NSString*)youtubeBroadcastID :(NSDictionary*)extraMetadata :(BOOL)transcription {
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"dropboxToken": dropboxToken,
|
||||
@"shouldShare": @(shouldShare),
|
||||
@"rtmpStreamKey": rtmpStreamKey,
|
||||
@"rtmpBroadcastID": rtmpBroadcastID,
|
||||
@"youtubeStreamKey": youtubeStreamKey,
|
||||
@"youtubeBroadcastID": youtubeBroadcastID,
|
||||
@"extraMetadata": extraMetadata,
|
||||
@"transcription": @(transcription)
|
||||
};
|
||||
|
||||
[self sendEventWithName:startRecordingAction body:data];
|
||||
}
|
||||
|
||||
- (void)stopRecording:(NSString*)mode :(BOOL)transcription {
|
||||
NSDictionary *data = @{
|
||||
@"mode": mode,
|
||||
@"transcription": @(transcription)
|
||||
};
|
||||
|
||||
[self sendEventWithName:stopRecordingAction body:data];
|
||||
}
|
||||
|
||||
- (void)overwriteConfig:(NSDictionary*)config {
|
||||
NSDictionary *data = @{
|
||||
@"config": config
|
||||
};
|
||||
|
||||
[self sendEventWithName:overwriteConfigAction body:data];
|
||||
}
|
||||
|
||||
- (void)sendCameraFacingModeMessage:(NSString*)to :(NSString*)facingMode {
|
||||
NSDictionary *data = @{
|
||||
@"to": to,
|
||||
@"facingMode": facingMode
|
||||
};
|
||||
|
||||
[self sendEventWithName:sendCameraFacingModeMessageAction body:data];
|
||||
}
|
||||
@end
|
||||
28
ios/sdk/src/Info.plist
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>99.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
23
ios/sdk/src/InfoPlistUtil.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface InfoPlistUtil : NSObject
|
||||
|
||||
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle;
|
||||
|
||||
@end
|
||||
52
ios/sdk/src/InfoPlistUtil.m
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "InfoPlistUtil.h"
|
||||
|
||||
// Plist file name.
|
||||
NSString *const kGoogleServiceInfoFileName = @"GoogleService-Info";
|
||||
// Plist file type.
|
||||
NSString *const kGoogleServiceInfoFileType = @"plist";
|
||||
NSString *const kGoogleAppIDPlistKey = @"GOOGLE_APP_ID";
|
||||
|
||||
@implementation InfoPlistUtil
|
||||
|
||||
+ (BOOL)containsRealServiceInfoPlistInBundle:(NSBundle *)bundle {
|
||||
NSString *bundlePath = bundle.bundlePath;
|
||||
if (!bundlePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *plistFilePath = [bundle pathForResource:kGoogleServiceInfoFileName
|
||||
ofType:kGoogleServiceInfoFileType];
|
||||
if (!plistFilePath.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
|
||||
if (!plist) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Perform a very naive validation by checking to see if the plist has the dummy google app id
|
||||
NSString *googleAppID = plist[kGoogleAppIDPlistKey];
|
||||
if (!googleAppID.length) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
24
ios/sdk/src/JitsiAudioSession+Private.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "JitsiAudioSession.h"
|
||||
#import <WebRTC/WebRTC.h>
|
||||
|
||||
@interface JitsiAudioSession (Private)
|
||||
|
||||
+ (RTCAudioSession *)rtcAudioSession;
|
||||
|
||||
@end
|
||||
26
ios/sdk/src/JitsiAudioSession.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class AVAudioSession;
|
||||
|
||||
@interface JitsiAudioSession : NSObject
|
||||
|
||||
+ (void)activateWithAudioSession:(AVAudioSession *)session;
|
||||
+ (void)deactivateWithAudioSession:(AVAudioSession *)session;
|
||||
|
||||
@end
|
||||
34
ios/sdk/src/JitsiAudioSession.m
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "JitsiAudioSession.h"
|
||||
#import "JitsiAudioSession+Private.h"
|
||||
|
||||
@implementation JitsiAudioSession
|
||||
|
||||
+ (RTCAudioSession *)rtcAudioSession {
|
||||
return [RTCAudioSession sharedInstance];
|
||||
}
|
||||
|
||||
+ (void)activateWithAudioSession:(AVAudioSession *)session {
|
||||
[self.rtcAudioSession audioSessionDidActivate:session];
|
||||
}
|
||||
|
||||
+ (void)deactivateWithAudioSession:(AVAudioSession *)session {
|
||||
[self.rtcAudioSession audioSessionDidDeactivate:session];
|
||||
}
|
||||
|
||||
@end
|
||||
28
ios/sdk/src/JitsiMeet+Private.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <RCTReactNativeFactory.h>
|
||||
|
||||
#import "ExternalAPI.h"
|
||||
#import "JitsiMeet.h"
|
||||
|
||||
@interface JitsiMeet ()
|
||||
|
||||
- (NSDictionary *)getDefaultProps;
|
||||
- (RCTReactNativeFactory *)getReactNativeFactory;
|
||||
- (ExternalAPI *)getExternalAPI;
|
||||
|
||||
@end
|
||||
102
ios/sdk/src/JitsiMeet.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright @ 2017-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import UIKit;
|
||||
@import Foundation;
|
||||
|
||||
#import <JitsiMeetSDK/JitsiMeetConferenceOptions.h>
|
||||
|
||||
// Matches RTCLoggingSeverity from RTCLogging.h
|
||||
typedef NS_ENUM(NSInteger, WebRTCLoggingSeverity) {
|
||||
WebRTCLoggingSeverityVerbose,
|
||||
WebRTCLoggingSeverityInfo,
|
||||
WebRTCLoggingSeverityWarning,
|
||||
WebRTCLoggingSeverityError,
|
||||
WebRTCLoggingSeverityNone,
|
||||
};
|
||||
|
||||
@interface JitsiMeet : NSObject
|
||||
|
||||
/**
|
||||
* Name for the conference NSUserActivity type. This is used when integrating with
|
||||
* SiriKit or Handoff, for example.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSString *conferenceActivityType;
|
||||
|
||||
/**
|
||||
* Custom URL scheme used for deep-linking.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSString *customUrlScheme;
|
||||
|
||||
/**
|
||||
* List of domains used for universal linking.
|
||||
*/
|
||||
@property (copy, nonatomic, nullable) NSArray<NSString *> *universalLinkDomains;
|
||||
|
||||
/**
|
||||
* Default conference options used for all conferences. These options will be merged
|
||||
* with those passed to JitsiMeetView.join when joining a conference.
|
||||
*/
|
||||
@property (nonatomic, nullable) JitsiMeetConferenceOptions *defaultConferenceOptions;
|
||||
|
||||
/**
|
||||
* Custom RTCAudioDevice implementation.
|
||||
* https://github.com/jitsi/webrtc/blob/M124/sdk/objc/components/audio/RTCAudioDevice.h
|
||||
* https://github.com/mstyura/RTCAudioDevice
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) id rtcAudioDevice;
|
||||
|
||||
/**
|
||||
* Specify WebRTC logging severity.
|
||||
*/
|
||||
@property (nonatomic, assign) WebRTCLoggingSeverity webRtcLoggingSeverity;
|
||||
|
||||
#pragma mark - This class is a singleton
|
||||
|
||||
+ (instancetype _Nonnull)sharedInstance;
|
||||
|
||||
#pragma mark - Methods that the App delegate must call
|
||||
|
||||
- (BOOL)application:(UIApplication *_Nonnull)application
|
||||
didFinishLaunchingWithOptions:(NSDictionary *_Nonnull)launchOptions;
|
||||
|
||||
- (BOOL)application:(UIApplication *_Nonnull)application
|
||||
continueUserActivity:(NSUserActivity *_Nonnull)userActivity
|
||||
restorationHandler:(void (^_Nullable)(NSArray<id<UIUserActivityRestoring>> *_Nonnull))restorationHandler;
|
||||
|
||||
- (BOOL)application:(UIApplication *_Nonnull)app
|
||||
openURL:(NSURL *_Nonnull)url
|
||||
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *_Nonnull)options;
|
||||
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *_Nonnull)application
|
||||
supportedInterfaceOrientationsForWindow:(UIWindow *_Nullable)window;
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
- (void)instantiateReactNative;
|
||||
|
||||
- (void)destroyReactNative;
|
||||
|
||||
- (JitsiMeetConferenceOptions *_Nonnull)getInitialConferenceOptions;
|
||||
|
||||
- (BOOL)isCrashReportingDisabled;
|
||||
|
||||
/**
|
||||
* Shows the splash screen.
|
||||
*/
|
||||
- (void)showSplashScreen;
|
||||
|
||||
@end
|
||||
288
ios/sdk/src/JitsiMeet.m
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Intents/Intents.h>
|
||||
|
||||
#import "Orientation.h"
|
||||
|
||||
#import "JitsiMeet+Private.h"
|
||||
#import "JitsiMeetConferenceOptions+Private.h"
|
||||
#import "JitsiMeetView+Private.h"
|
||||
#import "ReactUtils.h"
|
||||
#import "ScheenshareEventEmiter.h"
|
||||
|
||||
#import <react-native-webrtc/WebRTCModuleOptions.h>
|
||||
#import <RCTReactNativeFactory.h>
|
||||
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import "JitsiReactFactoryDelegate.h"
|
||||
|
||||
#if !defined(JITSI_MEET_SDK_LITE)
|
||||
#import <RNGoogleSignin/RNGoogleSignin.h>
|
||||
#import "Dropbox.h"
|
||||
#endif
|
||||
|
||||
@implementation JitsiMeet {
|
||||
NSDictionary *_launchOptions;
|
||||
ScheenshareEventEmiter *_screenshareEventEmiter;
|
||||
RCTReactNativeFactory *_reactNativeFactory;
|
||||
JitsiReactFactoryDelegate *_reactFactoryDelegate;
|
||||
}
|
||||
|
||||
#pragma mak - This class is a singleton
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static JitsiMeet *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
|
||||
// Initialize WebRTC options.
|
||||
self.rtcAudioDevice = nil;
|
||||
self.webRtcLoggingSeverity = WebRTCLoggingSeverityNone;
|
||||
|
||||
// Initialize the listener for handling start/stop screensharing notifications.
|
||||
_screenshareEventEmiter = [[ScheenshareEventEmiter alloc] init];
|
||||
|
||||
// Register a fatal error handler for React.
|
||||
registerReactFatalErrorHandler();
|
||||
|
||||
// Register a log handler for React.
|
||||
registerReactLogHandler();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Methods that the App delegate must call
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
|
||||
_launchOptions = [launchOptions copy];
|
||||
|
||||
#if !defined(JITSI_MEET_SDK_LITE)
|
||||
[Dropbox setAppKey];
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
continueUserActivity:(NSUserActivity *)userActivity
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *))restorationHandler {
|
||||
|
||||
JitsiMeetConferenceOptions *options = [self optionsFromUserActivity:userActivity];
|
||||
if (options) {
|
||||
[JitsiMeetView updateProps:[options asProps]];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)app
|
||||
openURL:(NSURL *)url
|
||||
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
|
||||
#if !defined(JITSI_MEET_SDK_LITE)
|
||||
if ([Dropbox application:app openURL:url options:options]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ([RNGoogleSignin application:app
|
||||
openURL:url
|
||||
options:options]) {
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_customUrlScheme == nil || ![_customUrlScheme isEqualToString:url.scheme]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
JitsiMeetConferenceOptions *conferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = [url absoluteString];
|
||||
}];
|
||||
[JitsiMeetView updateProps:[conferenceOptions asProps]];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return [Orientation getOrientation];
|
||||
}
|
||||
|
||||
#pragma mark - Utility methods
|
||||
|
||||
- (void)createReactNativeFactory {
|
||||
_reactFactoryDelegate = [[JitsiReactFactoryDelegate alloc] init];
|
||||
id<RCTDependencyProvider> provider = [[RCTAppDependencyProvider alloc] init];
|
||||
_reactFactoryDelegate.dependencyProvider = provider;
|
||||
_reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:_reactFactoryDelegate];
|
||||
NSLog(@"ReactNativeFactory created: %@", _reactNativeFactory);
|
||||
|
||||
// Initialize WebRTC options.
|
||||
WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
|
||||
options.audioDevice = _rtcAudioDevice;
|
||||
options.loggingSeverity = (RTCLoggingSeverity)_webRtcLoggingSeverity;
|
||||
}
|
||||
|
||||
- (void)instantiateReactNative {
|
||||
if (_reactNativeFactory == nil) {
|
||||
[self createReactNativeFactory];
|
||||
}
|
||||
|
||||
[_reactNativeFactory.rootViewFactory initializeReactHostWithLaunchOptions:nil
|
||||
bundleConfiguration:_reactNativeFactory.bundleConfiguration
|
||||
devMenuConfiguration:_reactNativeFactory.devMenuConfiguration];
|
||||
}
|
||||
|
||||
- (void)destroyReactNative {
|
||||
_reactNativeFactory = nil;
|
||||
_reactFactoryDelegate = nil;
|
||||
}
|
||||
|
||||
- (JitsiMeetConferenceOptions *)getInitialConferenceOptions {
|
||||
if (_launchOptions[UIApplicationLaunchOptionsURLKey]) {
|
||||
NSURL *url = _launchOptions[UIApplicationLaunchOptionsURLKey];
|
||||
return [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = [url absoluteString];
|
||||
}];
|
||||
} else {
|
||||
NSDictionary *userActivityDictionary
|
||||
= _launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
|
||||
NSUserActivity *userActivity
|
||||
= [userActivityDictionary objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];
|
||||
if (userActivity != nil) {
|
||||
return [self optionsFromUserActivity:userActivity];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isCrashReportingDisabled {
|
||||
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"jitsi-default-preferences"];
|
||||
return [userDefaults stringForKey:@"isCrashReportingDisabled"];
|
||||
}
|
||||
|
||||
- (JitsiMeetConferenceOptions *)optionsFromUserActivity:(NSUserActivity *)userActivity {
|
||||
NSString *activityType = userActivity.activityType;
|
||||
|
||||
if ([activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||
// App was started by opening a URL in the browser
|
||||
NSURL *url = userActivity.webpageURL;
|
||||
if ([_universalLinkDomains containsObject:url.host]) {
|
||||
return [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = [url absoluteString];
|
||||
}];
|
||||
}
|
||||
} else if ([activityType isEqualToString:@"INStartAudioCallIntent"]
|
||||
|| [activityType isEqualToString:@"INStartVideoCallIntent"]) {
|
||||
// App was started by a CallKit Intent
|
||||
INIntent *intent = userActivity.interaction.intent;
|
||||
NSArray<INPerson *> *contacts;
|
||||
NSString *url;
|
||||
BOOL audioOnly = NO;
|
||||
|
||||
if ([intent isKindOfClass:[INStartAudioCallIntent class]]) {
|
||||
contacts = ((INStartAudioCallIntent *) intent).contacts;
|
||||
audioOnly = YES;
|
||||
} else if ([intent isKindOfClass:[INStartVideoCallIntent class]]) {
|
||||
contacts = ((INStartVideoCallIntent *) intent).contacts;
|
||||
}
|
||||
|
||||
if (contacts && (url = contacts.firstObject.personHandle.value)) {
|
||||
return [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.lowBandwidthMode = audioOnly;
|
||||
builder.room = url;
|
||||
}];
|
||||
}
|
||||
} else if (self.conferenceActivityType && [activityType isEqualToString:self.conferenceActivityType]) {
|
||||
// App was started by continuing a registered NSUserActivity (SiriKit, Handoff, ...)
|
||||
NSString *url;
|
||||
|
||||
if ((url = userActivity.userInfo[@"url"])) {
|
||||
return [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {
|
||||
builder.room = url;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)showSplashScreen {
|
||||
Class splashClass = NSClassFromString(@"SplashView");
|
||||
if (splashClass && [splashClass respondsToSelector:@selector(sharedInstance)]) {
|
||||
id splashInstance = [splashClass performSelector:@selector(sharedInstance)];
|
||||
if (splashInstance && [splashInstance respondsToSelector:@selector(showSplash)]) {
|
||||
[splashInstance performSelector:@selector(showSplash)];
|
||||
NSLog(@"Splash Screen Shown Successfully");
|
||||
}
|
||||
} else {
|
||||
NSLog(@"SplashView module not found");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Property getter / setters
|
||||
|
||||
- (NSArray<NSString *> *)universalLinkDomains {
|
||||
return _universalLinkDomains ? _universalLinkDomains : @[];
|
||||
}
|
||||
|
||||
- (void)setDefaultConferenceOptions:(JitsiMeetConferenceOptions *)defaultConferenceOptions {
|
||||
|
||||
// For testing configOverrides a room needs to be set,
|
||||
// thus the following check needs to be commented out
|
||||
if (defaultConferenceOptions != nil && defaultConferenceOptions.room != nil) {
|
||||
@throw [NSException exceptionWithName:@"RuntimeError"
|
||||
reason:@"'room' must be null in the default conference options"
|
||||
userInfo:nil];
|
||||
}
|
||||
_defaultConferenceOptions = defaultConferenceOptions;
|
||||
}
|
||||
|
||||
#pragma mark - Private API methods
|
||||
|
||||
- (NSDictionary *)getDefaultProps {
|
||||
return _defaultConferenceOptions == nil ? @{} : [_defaultConferenceOptions asProps];
|
||||
}
|
||||
|
||||
- (RCTReactNativeFactory *)getReactNativeFactory {
|
||||
if (_reactNativeFactory == nil) {
|
||||
[self createReactNativeFactory];
|
||||
}
|
||||
|
||||
return _reactNativeFactory;
|
||||
}
|
||||
|
||||
- (ExternalAPI *)getExternalAPI {
|
||||
ExternalAPI *api = [ExternalAPI sharedInstance];
|
||||
return api;
|
||||
}
|
||||
|
||||
@end
|
||||
24
ios/sdk/src/JitsiMeetBaseLogHandler+Private.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "LogUtils.h"
|
||||
#import "JitsiMeetBaseLogHandler.h"
|
||||
|
||||
@interface JitsiMeetBaseLogHandler ()
|
||||
|
||||
@property (nonatomic, retain) id<DDLogger> logger;
|
||||
|
||||
@end
|
||||
28
ios/sdk/src/JitsiMeetBaseLogHandler.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright @ 2019-present 8x8, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface JitsiMeetBaseLogHandler : NSObject
|
||||
|
||||
// These are "abstract".
|
||||
- (void)logVerbose:(NSString *)msg;
|
||||
- (void)logDebug:(NSString *)msg;
|
||||
- (void)logInfo:(NSString *)msg;
|
||||
- (void)logWarn:(NSString *)msg;
|
||||
- (void)logError:(NSString *)msg;
|
||||
|
||||
@end
|
||||