This iOS/macOS Framework provides an easy way to obtain a video selfie to be used with Unissey's SaaS solution on an iOS or macOS application. This SDK has been developed with SwiftUI, allowing for an easy integration on both SwiftUI apps and traditional UIKit apps.
The version of your app must be at least iOS 14.0 and macOS 11.0 in order to use this SDK.
If you already have Xcode configured with a GitHub personal access token with the proper permissions, you can skip directly to the third step of the installation.
First, you need to generate an access token by following the instructions
provided here
by GitHub. Make sure to include at least the repo
and read:packages
permissions.
Then, to gain access to Unissey's SDK, you need to contact the Unissey team and provide your GitHub account name.
Open Xcode, open the Settings
window (CMD + ,
) and go to the second tab Accounts
. Add a new
account by clicking on the +
button on the bottom left corner, select GitHub
and add your GitHub
account's email and the personal access token you generated previously.
Finally, you can download our framework using the Swift Package Manager. To do so, in Xcode, go to
File -> Add Packages... and enter the following URL in the search
bar: https://github.com/unissey/sdk-ios
. There Xcode will let you define the dependency rule. You
can choose a specific version of your choice or use the latest version available that should be on
the master
branch.
Unissey's SDK offers three screens, one of which is optional:
The sample apps are here to provide a basic implementation of this library that you can use as a
base for your integration inside your own application. Whether you're using SwiftUI
or a traditional approach with UIKit, you will have to create a UnisseyViewModel
and
a UnisseyScreen
to interact with this SDK. The UnisseyViewModel
is the developer interface with
which you can interact in your application's code, it's also the class that you can configure to
suit your needs. The UnisseyScreen
on the other hand holds the user interface and it's what your
user will see and interact with.
The UnisseyViewModel
class offers a constructor that should be used to create an instance of it.
Only an AcquisitionPreset
object and an OnRecordEndedListener
are necessary to use the SDK. Note
that the OnRecordEndedListener
is optional during the initialization of the UnisseyViewModel
since, most of the time, you're going to want to reference self
inside your callback to handle the
result, and there are situations where you will not be able to reference self
when initializing
the object. This field is still mandatory for the SDK to hand back a response, if you fail to
provide an OnRecordEndedListener
, the user will get stuck at the end of the video acquisition.
In addition to those parameters, the SDK can be further customized with an OnStateChangedListener
and a SessionConfig
. All of these parameters are detailed in the Reference
section.
See the following code for simple usages where the default values are suitable for your use case:
let unisseyViewModel = UnisseyViewModel(acquisitionPreset: .selfieFast, onRecordEndedListener: { result in
do {
// `result` is a Result<Success, Failure> containing the response or an error
let response = try result.get()
print("Video record ended with file path: '\(response.videoFilePath)'")
} catch {
print("An error occurred while recording the video: \(error)")
}
})
Once you have an instance of UnisseyViewModel
, you can create the UnisseyScreen
with the
ViewModel as a parameter.
In SwiftUI, you can use the UnisseyScreen
as you would use any other View in your application:
struct ContentView: View {
var body: some View {
let unisseyViewModel = ...
UnisseyView(unisseyViewModel: unisseyViewModel)
}
}
If your application is built with the older Storyboard and UIKit system, you can rely on
a UIHostingController to
host the SwiftUI UnisseyView
. If you're not familiar with this class, it's a view controller that
encapsulates and manages a SwiftUI hierarchy. You just need to provide a SwiftUI view as
the rootView
parameter when initializing your hosting controller:
import Foundation
import SwiftUI
import UnisseySdk
class UnisseyHostingController: UIHostingController<UnisseyView> {
var videoUri: URL?
let unisseyViewModel: UnisseyViewModel
required init?(coder: NSCoder) {
// Set up the UnisseyViewModel and UnisseyView
unisseyViewModel = UnisseyViewModel(acquisitionPreset: .selfieFast)
let unisseyView = UnisseyView(unisseyViewModel: unisseyViewModel)
super.init(coder: coder, rootView: unisseyView)
}
override func viewDidLoad() {
// Register the callback
unisseyViewModel.onRecordEndedListener = { result in
do {
// `result` is a Result<SessionResponse, Error> containing the response or an error
let response = try result.get()
print("Video record ended with file path: '\(response.videoFilePath)'")
self.videoUri = response.videoFilePath
DispatchQueue.main.async {
// Navigate to the next screen
}
} catch {
print("An error occurred while recording the video: \(error)")
}
}
}
}
You can use this UIHostingController
as you would use any standard UIViewController
in your
storyboard:
The present SDK provides presets defining how the video is recorded. Even if you decide to override
its values, you must select a preset when creating an instance of UnisseyViewModel
.
Here are the 2 current possible values of AcquisitionPreset
:
Preset name | Recording duration | Video quality | Description |
---|---|---|---|
selfieFast | 1 second | 480p resolution if possible, or 720p | The preset that most use cases rely on. It provides the minimal configuration needed for Unissey's AI models to work at their best |
selfieSubstantial | 3 seconds | 720p resolution if possible, or 1080p | The preset fit for use cases aiming for a PVID substantial compliance |
This is the callback that triggers when the user is done recording a video.
This is a type alias for (Result<SessionResponse, Error>) -> Void
.
The SessionResponse
:
Parameter name | Type | Description |
---|---|---|
videoFilePath | URL | The path to the video file saved in the cache directory of your app |
metadata | String | A String containing technical metadata useful to Unissey to be added to the request to Unissey's API |
This is a callback that triggers everytime there's a significant change of state while the user is interacting with the SDK. This callback offers a possibility for your application to react to SDK and user events while the SDK is being used. This allows for more advanced usages that you could have, some of which are described in the Advanced usages section.
This is a type alias for (UnisseyEvent) -> Void
.
A UnisseyEvent
represents an event happening inside the SDK, often initiated by the user. Here's
an exhaustive list of possible events:
Event | Description |
---|---|
instructionsShown | When the Instructions screen is displayed to the user |
cameraPermissionShown | When the Camera Permission screen is displayed to the user. This screen provides a simple explanation as to why this permission is necessary |
cameraPermissionRequested | When the camera permission has been requested, meaning when the system alert is being displayed to the user |
cameraPermissionAccepted | When the user has accepted the permission |
cameraPermissionDenied | When the user has declined the permission |
cameraPreviewShown | When the Video Capture screen is displayed, showing a live preview of the camera |
cameraReady | There is an initialization delay before the camera is fully set up and available. This event fires when the camera is actually ready to record a video. |
videoCaptureStarted | When the video capture has started. The term "video capture" refers to the process that begins when the user hits the "Start" button. The recording doesn't start right away, there's a first stage where a face detection is happening to help the user position their face in the oval |
videoRecordStarted | When the recording has started |
videoRecordProgress | This event is the only one to feature a parameter. It fires multiple times during the recording and provides a progress parameter indicating the recording progress with a value contained between 0 and 1 (1 being 100%) |
videoRecordEnded | When the recording is over. This event triggers along with the OnRecordEndedListener callback |
If the default state of the SDK doesn't suit your needs, the UnisseyViewModel
can take
a SessionConfig
parameter with ways to customize the behavior of the library.
Here's what a SessionConfig
is composed of:
Parameter name | Type | Description |
---|---|---|
recordingConfig | RecordingConfig | A nested configuration object meant for technical configuration |
uiConfig | UiConfig | A nested configuration object meant for graphic configuration |
The RecordingConfig
:
Parameter name | Type | Default value | Description |
---|---|---|---|
recordingDurationMs | Float? | nil | The duration of the recording, overrides the value from the AcquisitionPreset |
qualities | [VideoQuality] | nil | An array of VideoQuality to override the qualities set in the AcquisitionPreset . The qualities are to be set in order of preference |
The VideoQuality
is an enum representing available qualities that the video can be recorded in:
Quality | Resolution |
---|---|
lowest | 144p |
sd | 480p |
hd | 720p |
fhd | 1080p |
uhd | 2160p |
highest | The highest resolution possible on the user device |
⚠️ NOTE: When providing custom qualities to override the preset, you should make sure to provide
plausible fallback values to support as many devices as possible. If no provided quality is
available on the user's device, an error will be thrown on the OnRecordEndedListener
callback.
The UiConfig
:
Parameter name | Type | Default value | Description |
---|---|---|---|
showInstructions | Bool | true | Specify whether to show the first instructions screen or not |
showVideoCaptureButton | Bool | true | Specify whether to show the "Start" button on the video capture screen or not. This is mainly useful if you choose to enable auto-starting of the video capture, as explained in the Auto-starting the video capture section |
showWideWindowPreviewInputsToTheRight | Bool | true | Specify whether the preview inputs should be displayed to the right of the camera preview or to the left in wide window mode (typically on phones in landscape mode) |
A few variables and functions in the UnisseyViewModel
are accessible in read or write mode from
the client's application. Here's the exhaustive list:
Name | Type | Description |
---|---|---|
currentPage | UnisseyPage (read only) | Indicates which screen is being displayed to the user. It's an enum with values comprised in instructions , cameraPermission and videoCapture |
navigateUp | Function | Tells the UnisseyViewModel to navigate one screen up |
startVideoCapture | Function | Tells the UnisseyViewModel to start the video capture process. Useful when you want the video capture to autostart when the screen appears for example |
Here's an exhaustive list of the String resources used in the SDK and that can be overridden (see the Customizing the texts and translations section to know how to override them):
Key | English value | French value |
---|---|---|
unissey_instructions_title | Record a short video selfie | Enregistrez un selfie vidéo |
unissey_instructions_subtitle | Let's make sure no one is impersonating you. | Cette étape permet de vérifier que personne n'usurpe votre identité |
unissey_instruction_maintain_stable_position | Look straight at the camera, and keep your face clearly visible | Maintenez votre visage droit et entièrement visible |
unissey_instruction_plain_expression | Have a plain expression | Conservez une expression neutre |
unissey_instruction_well_lit_environment | Stand in a well-lit environment | Assurez-vous d’être suffisamment éclairé |
unissey_continue_label | Continue | Continuer |
unissey_camera_permission_explanation | The camera permission is required for this feature to be available. Please grant the permission. | L'utilisation de la caméra est nécessaire à cette fonctionnalité. Merci d'autoriser l'usage de la caméra. |
unissey_camera_permission_button | Request permission | Donner la permission |
unissey_video_capture_title | The acquisition will last %d second(s). | L'acquisition durera %d seconde(s). |
unissey_start_label | Start | Commencer |
unissey_instruction_position_face_oval | Position your face in the oval | Placez-vous dans l'ovale |
unissey_instruction_multiple_faces_detected | Multiple faces detected | Plusieurs visages détectés |
unissey_instruction_no_face_detected | No face detected | Aucun visage détecté |
unissey_instruction_get_closer | Get closer | Rapprochez-vous |
unissey_instruction_get_further_away | Get further away | Reculez-vous |
unissey_instruction_move_right | Move your face to the right | Plus vers la droite |
unissey_instruction_move_left | Move your face to the left | Plus vers la gauche |
unissey_instruction_move_up | Move your face up | Plus vers le haut |
unissey_instruction_move_down | Move your face down | Plus vers le bas |
unissey_instruction_do_not_move | Perfect, don't move | Parfait, ne bougez plus |
This SDK offers a few Color assets to theme its UI elements that can be overridden (see Customizing the assets (colors and images) section to know how to override them).
Here's the exhaustive list of colors used in the SDK along with their default values corresponding to the Unissey color theme:
Key | Default light mode value | Default dark mode value |
---|---|---|
UnisseyCardBackground | #F6F6F6 |
#48454F |
UnisseyOverlayBackground | #FFFFFF - 80% opacity |
#000000 - 80% opacity |
UnisseyPrimary | #09165C |
#3C58E8 |
UnisseySecondary | #3C58E8 |
#3C58E8 |
This SDK contains three customizable images (see Customizing the assets (colors and images) section to know how to override them). Those images illustrate the three instructions on the first optional screen.
Here's the exhaustive list of images:
Key | Description |
---|---|
UnisseyFacePositionPicto | The first illustration showing how to position the user's face |
UnisseyFaceExpressionPicto | The second illustration indicating to have a neutral expression |
UnisseyFaceLightPicto | The third illustration that displays that a good lighting is necessary |
The SDK provides customizable fonts used throughout the three screens ( see Customizing the types section to know how to override them). Those are SwiftUI fonts that follow default text styles, allowing them to scale automatically with the user's accessibility settings.
Here's the exhaustive list of types along with their default values:
Parameter name | Default family | Default weight | Default Text Style |
---|---|---|---|
unisseyHeadline | System Default | Bold | Font.title |
unisseyTitle | System Default | Bold | Font.title3 |
unisseyBody | System Default | Normal | Font.body |
unisseyLabel | System Default | Medium | Font.body |
To give you an idea of how you can customize the SDK to fit your needs using the SessionConfig
,
here's an example use case. Say you're happy with the SDK but you'd rather have your own
instructions page, to make sure it fits your UI Design. And you want the video recording to last 2
seconds instead of the default 1 second of the SelfieFast
preset, for whatever reason.
You could leverage the SessionConfig
to achieve this:
let recordingConfig = RecordingConfig(recordingDurationMs: 2000)
let uiConfig = UiConfig(showInstructions: false)
let sessionConfig = SessionConfig(recordingConfig: recordingConfig, uiConfig: uiConfig)
let unisseyViewModel = UnisseyViewModel(acquisitionPreset: .selfieFast,
sessionConfig: sessionConfig) { result in
...
}
The Unissey SDK provides various default English texts as well as a French translation that you can
choose to leave as they are. However you're free to override any or all of them through
the Localizable.strings
and Localizable.stringsdict
resource file if they're not fit for your
needs.
To do this, you just need to add a line in your Localizable.strings
for each text you want to
override. An exhaustive list of the texts you can redefine is available in
the String resources section. You can redefine any language and even define
your own that isn't English or French.
All of our strings' keys are prefixed with "unissey" to prevent any conflict with the naming of your
own string resources.
There is a special case for the unissey_video_capture_title
string. Because the string can be
pluralized according to the duration of the video, it's defined in a separate file of
type .stringsdict
that allows this pluralization out of the box.
Here's our definition of this string, were you to override it:
<dict>
<key>unissey_video_capture_title</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@recording_duration_seconds@</string>
<key>recording_duration_seconds</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>lld</string>
<key>zero</key>
<string>The acquisition will last %lld seconds.</string>
<key>one</key>
<string>The acquisition will last %lld second.</string>
<key>other</key>
<string>The acquisition will last %lld seconds.</string>
</dict>
</dict>
</dict>
And here's the view from Xcode:
Example: Overriding the Instructions screen's title
"unissey_instructions_title" = "My custom title inside Unissey's SDK";
This SDK exposes some colors and images in its Assets.xcassets
directory. They can be freely
overridden by just providing your own colors and images using the same keys as the ones defined in
the Framework and detailed in the Colors and Images sections.
This SDK is using the default system fonts. It exposes a number of variables that can be overridden by the client's application, which are all listed in the Typography section. To override a type, you just need to redefine the corresponding value anywhere in your application before you create the UnisseyScreen. You can have a look at the official documentation to see how to define and import custom fonts in your application.
Example: Let's say you want to change the font family to "Futura" which should be present on iOS
devices by default. You just need to write this function and call it somewhere
before UnisseyScreen
is instantiated, it could be in your app's initializer for example:
import SwiftUI
import UnisseySdk
@main
struct MyAwesomeSwiftUiApp: App {
init() {
customizeUnisseyTypography()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
func customizeUnisseyTypography() {
unisseyHeadline = Font.custom("Futura", size: 24, relativeTo: .title).weight(.bold)
unisseyTitle = Font.custom("Futura", size: 18, relativeTo: .title3).weight(.bold)
unisseyBody = Font.custom("Futura", size: 16, relativeTo: .body)
unisseyLabel = Font.custom("Futura", size: 16, relativeTo: .body).weight(.medium)
}
⚠️ NOTE: Do not forget to import UnisseySdk
to gain access to the typography variables. Note
that the example makes use of the SwiftUI Font.custom()
function to apply a font supporting
dynamic sizing to match the user's accessibility settings in terms of font size, as explained in
the official documentation.
This SDK provides an OnStateChangedListener that you can leverage to
achieve more advanced behavior. One good example of advanced usage would be to use this listener,
along with the public function startVideoCapture()
, to auto-start the video capture when the
camera is ready, so that the user doesn't have to click on the "Start" button.
First of all, you're going to hide the "Start" button which doesn't make any sense if we want the
video to be captured right away. Then, you need to implement an OnStateChangedListener
and
trigger the startVideoCapture()
function when the SDK's state becomes cameraReady
.
Here's how you could do that in SwiftUI:
struct ContentView: View {
var body: some View {
let unisseyViewModel = createUnisseyViewModel()
UnisseyView(unisseyViewModel: unisseyViewModel)
}
func createUnisseyViewModel() -> UnisseyViewModel {
let sessionConfig = SessionConfig(uiConfig: UiConfig(showVideoCaptureButton: false))
let unisseyViewModel = UnisseyViewModel(acquisitionPreset: .selfieFast, sessionConfig: sessionConfig) { result in
...
}
unisseyViewModel.onStateChangedListener = { state in
if case .cameraReady = state {
unisseyViewModel.startVideoCapture()
}
}
return unisseyViewModel
}
}
We're creating the UnisseyViewModel
in a dedicated function to avoid
the Type '()' cannot conform to 'View'
error in SwiftUI when trying to assign
an OnStateChangedListener
on our UnisseyViewModel
.
Note that doing it in UIKit is pretty much exactly the same as in SwiftUI.
To use this SDK on macOS, you need to provide an entitlement file specifying that your application can interact with the built-in and external cameras, as per the official documentation.
On iOS, you must provide a value for the
key NSCameraUsageDescription.
Note that this is the text that will be displayed in the system alert once the user clicks on
the Request permission
button, if the camera permission hasn't been granted before the use of the
SDK. If you fail to provide this information, the application will crash when the use tries to grant
the camera access.
link |
Stars: 0 |
Last commit: 6 weeks ago |
This version is a full refactor of Unissey's iOS Framework. It features, as the previous one, an instructions page, a camera permission request page as well as a page dedicated to capture a video selfie.
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics