# 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 SinchRTC.xcframework file size vs. linked size

The *SinchRTC.xcframework* file includes a FAT-binary containing the architectures *arm64* and *x86_64*. When linking an application target against the *SinchRTC.xcframework* targeting an iOS device, it will add approximately 9 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 `SinchRTC.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.


## Swift runtime support for Objective-C projects

Migration required from v.5.39
If you are using the Objective-C framework (`Sinch.xcframework`), you need to migrate to the Swift framework (`SinchRTC.xcframework`) starting from **v.5.39**.

Starting from recent SDK versions (**v.5.39**), the Sinch SDK is only distributed as Swift framework. Support for the Objective-C distribution has been removed. When a pure Objective-C project links against a library containing Swift code, the Swift runtime must be explicitly enabled. Without this, your application will fail to build or crash at runtime.

### Why is this required?

Static Swift libraries don't embed the Swift runtime — they only reference it. By including a Swift source file in your Objective-C project, you tell Xcode that your target uses Swift, which causes the linker to:

1. Link the Swift standard library
2. Link Swift compatibility libraries (swiftCompatibility50, etc.)
3. Set up the Swift runtime environment


### How to enable Swift runtime support

1. In Xcode, select **File** → **New** → **File from Template...**
2. Choose **Swift File** and name it `SwiftRuntimeLoader.swift` (or any name you prefer)
3. When Xcode prompts **"Would you like to configure an Objective-C bridging header?"**, click **"Create Bridging Header"**
4. You can leave the Swift file empty or add a comment explaining its purpose


**The bridging header prompt doesn't appear**

If Xcode doesn't prompt you to create a bridging header:

1. Manually create a file named `YourProjectName-Bridging-Header.h` in your project
2. In your target's Build Settings, search for "Objective-C Bridging Header"
3. Set the path to `$(PROJECT_NAME)/YourProjectName-Bridging-Header.h`


## 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.

From v.5.39
From **v.5.39** only the Swift SDK (`SinchRTC.xcframework`) is available. Use the SinchRTC module and `SinchClient` (Swift) or the SinchRTC Objective-C interface. The example below uses the Objective-C SDK pattern, adapt it to SinchRTC (e.g. `#import <SinchRTC/SinchRTC.h>` and the current API).

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 `<YourReactNativeApp>/ios`. If the file doesn't exist, run `pod install` inside the iOS folder.
2. Drag the `SinchRTC.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 <React/RCTBridgeModule.h>
#import <Sinch/Sinch.h>

@interface RCTSinchModule : NSObject <RCTBridgeModule>

@property (nonatomic, strong) _Nullable id<SINClient> client;

@end

#endif /* RCTSinchModule_h */
```

Implementation:


```objectivec
#import "RCTSinchModule.h"
#import <React/RCTLog.h>

#pragma mark - SINCallClientDelegate
@interface RCTSinchModule (SINCallClientDelegate) <SINCallClientDelegate>
@end

#pragma mark - SINClientDelegate
@interface RCTSinchModule (SINClientDelegate) <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:@"<your-app-key>"
                                  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<SINClient>)client requiresRegistrationCredentials:(id<SINClientRegistration>)registrationCallback {
  [registrationCallback registerWithJWT:@"user-jwt"];
}

- (void)clientDidStart:(id<SINClient>)client {
  NSLog(@"Client did start");
}

- (void)clientDidFail:(id<SINClient>)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 (
    <Button
      title="LOGIN"
      onPress={onPress}
    />
  );
};
```

Note
1. Because you're editing native iOS files, each time you change the code you'll need to rerun `npx react-native run-ios` to test your changes.
2. This snippet is only an entry point to show how to interact with the Sinch SDK from a React Native app. For more complete use cases that handle errors and various callbacks, see the `samples` folder of the Sinch SDK archive. The snippet does not handle validations like ensuring the Sinch client is not already initialized or started.