# Miscellaneous ## Minimum requirements We officially support iOS **12.0** as iOS Deployment Target. You can try older versions but there are no guarantees it will work as expected. ## Note on Sinch.xcframework file size vs. linked size The *Sinch.xcframework* file includes a FAT-binary containing the architectures *arm64* and *x86_64*. When linking an application target against the *Sinch.xcframework* targeting an iOS device, it will add approximately 9.5 MB for *arm64*. ## Restrictions on user IDs User IDs **must not** be longer than **255** bytes, **must** only contain URL-safe characters, and are restricted to the following character set: ```text ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjiklmnopqrstuvwxyz0123456789-_= ``` If you need to use User IDs containing characters outside the allowed set above, consider base64-encoding the raw User IDs using a URL-safe base64 alphabet as described in [RFC 4648 Section 5](https://tools.ietf.org/html/rfc4648#section-5). Note that the allowed character set overlaps with the URL-safe base64 alphabet but does **not** allow characters in the non-URL-safe alphabet, such as `/` (forward slash) and `+` (plus sign). ## Local database file The Sinch SDK requires a local database file to operate properly. It is located in the application support directory (`NSApplicationSupportDirectory`) in the `sinch/db/rtc/` subfolder. The application **must not** delete this folder. ## Call details The `SinchCallDetails` class holds metadata about a call, including timestamps for various call states, the end cause, and any error information. Call details are available through the `details` property on a `SinchCall` object. ### Timestamps `SinchCallDetails` provides timestamps for each stage of the call lifecycle. All timestamps are `nil` until that stage is reached. | Property | Description | | --- | --- | | `startedTime` | When the call was initiated | | `progressedTime` | When the call started progressing | | `rungTime` | When the call reached ringing state | | `answeredTime` | When the call was answered | | `establishedTime` | When media streams were established | | `endedTime` | When the call ended | ### End cause When a call ends, `endCause` indicates the reason. Before the call ends, the value is `.none`. | Value | Description | | --- | --- | | `none` | Call has not ended yet | | `timeout` | Call timed out | | `denied` | Call was denied/rejected | | `noAnswer` | Callee did not answer | | `error` | Call ended due to an error | | `hungUp` | Call was hung up normally | | `canceled` | Call was canceled before being answered | | `otherDeviceAnswered` | Call was answered on another device | | `inactive` | Call became inactive | | `voipCallDetected` | Another VoIP call was detected | | `gsmCallDetected` | A cellular call was detected | ### Error information When `endCause` is `.error`, the `error` property contains details about what went wrong: ```swift func callDidEnd(_ call: SinchCall) { if call.details.endCause == .error { if let error = call.details.error { print("Call failed: \(error.localizedDescription)") } } } ``` ## iOS audio session During calls, the Sinch SDK manages the shared audio session ([AVAudioSession](https://developer.apple.com/documentation/avfaudio/avaudiosession)). If your app integrates CallKit or LiveCommunicationKit, the system activates/deactivates the audio session. You must forward these events to the SDK using: ```swift sinchClient?.callClient.didActivate(audioSession: audioSession) sinchClient?.callClient.didDeactivate(audioSession: audioSession) ``` ### Audio session categories At the beginning of an incoming or outgoing call, the SDK sets the category to `AVAudioSession.Category.playAndRecord` with mode `AVAudioSession.Mode.voiceChat`. At the end of each call, the SDK restores audio session category, options, and mode to their original values. ### Overriding audio session category options By default, the SDK enables `.allowBluetooth` and `.allowBluetoothA2DP` options for the `playAndRecord` category. If you need different `AVAudioSession.CategoryOptions` during calls, you can override the defaults before starting a call. The options you set will be applied for calls that start after the method is invoked. ```swift sinchClient?.audioController.setAudioSessionCategoryOptions([.allowBluetooth, .allowBluetoothA2DP, .defaultToSpeaker]) ``` Use with care Overriding category options affects route selection and mixing behavior for all SDK-managed calls. Only set options your app really needs. ## Statistics The Sinch SDK client uploads statistics to the Sinch servers at the end of a call, a call failure, or similar event. The statistics are used for monitoring of network status, call quality, and other aspects regarding the general quality of the service. Some of the information is not anonymous and may be associated with the User ID of call participants. The statistics upload is done by the client in the background. ## App extensions App Extensions is a feature introduced in iOS 8. App extensions are compiled into executables that are separate from the main application executable. The Sinch SDK uses parts of the iOS SDK APIs that are unavailable to app extensions, thus it's not supported to use the Sinch SDK in an app extension. ## Linking against the C++ standard library Since Sinch SDK version 3.4.0, it's required to link against *libc++*. If your application is also dependent on *libstdc++* (which is now considered deprecated by Apple for use on iOS), you can link against both *libc++* and *libstdc++* by passing the following linker flags: - Other Linker Flags -> `-ObjC -Xlinker -lc++ -Xlinker -lstdc++` ## SDK static and dynamic libraries The SDK is available as both a static library and a dynamic library. If you're unsure which to use, prefer the dynamic library as it's less likely to require additional configuration. If you switch from using the dynamic to the static version of the SDK, you may need to: - Change the "Embed" field for `Sinch.framework` in the target dependency from "Embed & Sign" to "Do not embed", or you may not be able to install the app on devices. - Add `-ObjC` to your app's "Other Linker Flags" (Build Settings → All → Other Linker Flags) if you experience runtime errors such as "selector not recognized". See [Apple Technical Q&A QA1490](https://developer.apple.com/library/archive/qa/qa1490/_index.html) for details. ## Encryption export regulations Please see [Encryption and Export Administration Regulations (EAR)](https://www.bis.doc.gov/index.php/policy-guidance/encryption) and ensure that, if applicable, your application is registered for encryption regulations. ## Deprecated features and APIs ### Active connection in background Since iOS 10 Apple has discontinued support for maintaining a VoIP control connection alive via `-[UIApplication setKeepAliveTimeout:handler:]`. Attempting to use this method on an iOS device running iOS 10 results in the following warning log: `Legacy VoIP background mode is deprecated and no longer supported`. The Sinch feature *Active connection in background* was using the keep alive handler API and is no longer supported on iOS. It's recommended to use [VoIP Push Notifications and CallKit](/docs/in-app-calling/ios/push-notifications) to achieve the equivalent functionality. ### Missed call push notifications The Sinch SDK primarily uses VoIP push notifications. Since iOS 13 Apple imposed stricter limitations and requirements on how each VoIP push notification that an application receives must be reported to CallKit as an incoming call. As a result, the Sinch SDK no longer supports separate "Missed Call" push notifications. We recommend using your own non-VoIP push notification mechanism to deliver "Missed Call" push notifications. See also [Apple Developer documentation on this topic](https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry). ### Bitcode Bitcode support was removed in Sinch SDK version 5.18.0. Bitcode is deprecated by Apple and is no longer enabled by default in Xcode 14. If your app previously used Bitcode, you must disable it explicitly in your Xcode project's build settings (Build Options → Enable Bitcode → No). ## Using Sinch SDK with React Native With an extra layer of [NativeModule](https://reactnative.dev/docs/legacy/native-modules-ios), you can embed the Sinch iOS library into your React Native application. Note that by doing this the SDK will only work on React Native apps running on iOS devices. To support other platforms, you must implement a NativeModule for each platform separately using the corresponding platform-specific Sinch SDKs. To add the Sinch library to a React Native application: 1. Open your native iOS React Native application in Xcode. Use the `xcworkspace` file located at `/ios`. If the file doesn't exist, run `pod install` inside the iOS folder. 2. Drag the Sinch library `.xcframework` file to the `Frameworks` Xcode group. 3. To access the Sinch SDK API from your React Native application, follow the [iOS Native Module Guide](https://reactnative.dev/docs/legacy/native-modules-ios#create-custom-native-module-files). Example `SinchModule` to create a client for a given user ID: Header file: ```objectivec #ifndef RCTSinchModule_h #define RCTSinchModule_h #import #import @interface RCTSinchModule : NSObject @property (nonatomic, strong) _Nullable id client; @end #endif /* RCTSinchModule_h */ ``` Implementation: ```objectivec #import "RCTSinchModule.h" #import #pragma mark - SINCallClientDelegate @interface RCTSinchModule (SINCallClientDelegate) @end #pragma mark - SINClientDelegate @interface RCTSinchModule (SINClientDelegate) @end @implementation RCTSinchModule RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(createClient:(NSString *)userId) { dispatch_async(dispatch_get_main_queue(), ^{ RCTLogInfo(@"Creating iOS client for userId %@", userId); NSError *error; self.client = [Sinch clientWithApplicationKey:@"" environmentHost:@"ocra.api.sinch.com" userId:userId error:&error]; self.client.delegate = self; self.client.callClient.delegate = self; [self.client start]; }); } @end @implementation RCTSinchModule (SINClientDelegate) - (void)client:(id)client requiresRegistrationCredentials:(id)registrationCallback { [registrationCallback registerWithJWT:@"user-jwt"]; } - (void)clientDidStart:(id)client { NSLog(@"Client did start"); } - (void)clientDidFail:(id)client error:(NSError *)error { NSLog(@"Client did fail"); } @end ``` After registering that module, you can call `createClient` from JavaScript: ```javascript const { SinchModule } = NativeModules; const MainScreen = ({ navigation }) => { const onPress = () => { SinchModule.createClient('myUserId'); }; return (