Skip to main content

Advanced UI customization

If the basic styling tools don't satisfy your design needs, we also provide additional elements to help you get there. Nonetheless, these configurations require that your app's code feeds information into our SDK to work, mainly because they depend on files available at build time or need to be ready before the SDK can connect to our API. These features are only available to mobile apps (Android and iOS, including Flutter and React Native). If your company needs some of these features on a web app, please let us know, and we can gladly include them in our roadmap.

Custom fonts and typefaces

You can modify the fonts used by the UI elements provided by our SDK simply by providing your typefaces and letting it know how it should use them. Here's a quick guide on how to do so on Android and iOS apps:

Android

Step 1: Add your fonts

Using Android Studio, create the necessary font resources (if you don't already have them). For more details on how to do so, follow this official guide for View-based apps or this one for apps using Jetpack Compose.

Step 2: Load the fonts from code and create a configuration object

Once your fonts are accessible via "R.font", you can reference them on your code and pass them to our SDK. Now, an important note is that to minimize the memory and resource footprint of our SDK, we manage typefaces as a Font Family internally to avoid unnecessary duplication. The only downside is that you'll need to group your font configurations in a similar fashion and organize them through lists that let the SDK know which fonts are related (e.g., different weights) and can be integrated as a Family. The code example below shows two types of configurations.

You make these customizations through the UIConfig object, allowing you to link the font files to the appropriate weights and adjust font sizes (in SP units) according to your needs.

val uiConfig = UIConfig(
listOf(
// Configuration for single-weight font
// that provides only one file:
listOf(
FontConfig(
R.font.convergence_regular,
FontWeight.Normal.weight,
FontUsageBundle(
displayLarge = FontUsage(50),
displayMedium = FontUsage(55),
displaySmall = FontUsage(45),
headlineLarge = FontUsage(45),
headlineMedium = FontUsage(40),
headlineSmall = FontUsage(35),
titleLarge = FontUsage(35),
titleMedium = FontUsage(30),
titleSmall = FontUsage(25),
)
)
),

// Configuration for multi-weight font
// that provides distinct files:
listOf(
FontConfig(
R.font.dots_bold,
FontWeight.Bold.weight,
FontUsageBundle()
),
FontConfig(
R.font.dots_semibold,
FontWeight.SemiBold.weight,
FontUsageBundle(
bodyLarge = FontUsage(20),
)
),
FontConfig(
R.font.dots_medium,
FontWeight.Medium.weight,
FontUsageBundle(
bodyMedium = FontUsage(17),
)
),
FontConfig(
R.font.dots_regular,
FontWeight.Normal.weight,
FontUsageBundle(
bodySmall = FontUsage(15),
)
)
),
)
)

Step 3: Pass the configuration to the SDK

private val launchVerification: (
apiKey: String,
sessionUuid: String,
uiConfig: UIConfig
) -> Unit = {
startForResult.launch(VerificationParams(it, apiKey, uiConfig))
}

iOS

Step 1: Add your fonts

Using Xcode, create a font folder in your project (if you don't have one already) and add your fonts (as many as you need) to it using the Xcode UI (please avoid adding the files outside the IDE as it can omit them altogether). Please note that in addition to adding the files to your app's targets, you'll need to register them in your Info.plist file under the "Fonts provided by application" section. You can follow this guide from Apple for more details on how to do so.

tip

It is common to run into issues when accessing font files from code, if you do, here are some resources that might be helpful:

  • 'Common Mistakes With Adding Custom Fonts to Your iOS App'
  • Watch Xcode's terminal closely when testing your font integration, as it sometimes throws relevant warnings and errors related to your font usage. If you see an issue related to not finding the file you provided, tinker a bit with the Info.plist file values, as sometimes you need to include the full path, and sometimes you only need to provide the font name and extension (e.g., my-font.ttf)

Step 2: Load the fonts from code

In the code right before launching our SDK to start a verification, load your typefaces using variable names that are easily identifiable, for example:

let arialBold = Bundle.main.url(
forResource: "arialBold",
withExtension: "ttf"
)

// Optional: The following line is usually unnecessary,
// as our SDK registers the fonts for you. However, in some
// cases, iOS doesn't detect the files correctly, so the line
// is needed. If you use it, please ignore the warnings
// thrown by our SDK regarding this.
registerTypeface(fontUrl: arialBold! as CFURL)

Step 3: Create a configuration object

Build a UIConfig object using your fonts:

let typefaces: [TypefaceBundle] = [
TypefaceBundle(
// Please note this is the name of the typeface,
// not the file's nor your variable's.
fontName: "Arial",
fontUrl: arialBold! as CFURL,
// The size of the elements using this font.
// Consider that you can use multiple TypefaceBundle
// with the same font. This is relevant if you want
// distinct text sizes elements sharing a font.
size: 30,
usage: TypefaceUsage(
useInTitles: true,
useInBodies: false,
useInButtons: false,
useInTextFields: false
)
),
TypefaceBundle(
fontName: "Comic Sans",
fontUrl: comicSans! as CFURL,
size: 20,
usage: TypefaceUsage(
useInTitles: false,
useInBodies: true,
useInButtons: true,
useInTextFields: true
)
),
]
let type = TypographySettings(typefaces: typefaces)

let uiConfig = UIConfig(
typography: type,
forcedUIElements: nil
)

Step 4: Pass the configuration to the SDK

import VeriphOne

VeriphOneView(
sessionUuid: sessionUuid,
apiKey: apiKey,
uiConfig: uiConfig
) { result in
// Dismiss the view as needed
if let result = result {
// Verification has a result ready (could be successful or failed)
// Connect to your Result Endpoint for further instructions.
// More on this on the next section of the tutorial.
} else {
// Verification failed or was interrupted.
// Option 1: Do nothing.
// Option 2: Ask server for further instructions.
}
}

Forced modes (languages and color schemes)

By default, our SDK takes languages and color schemes (i.e., light and dark mode) directly from the user's device to keep a consistent user experience. However, if your app has a strict locale or color scheme policy, our default experience can cause issues with our app's aesthetics. For this reason, you can set directives for our SDK and force it to dynamically use the language and scheme of your choosing. This section covers how to do so:

Android

 val uiConfig = UIConfig(
null,
ForcedUIElements(
// Force a language by passing an ISO639 Alpha-2
// code referencing the language you want to use.
// - Nullable object.
// - Default: Device language.
// - Fallback: English-US
ForcedLanguage("es"),

// You can force the SDK to use Dark Mode or
// Light Mode for all UI elements by passing
// a value from the ForcedMode enum.
ForcedMode.DarkMode
)

startForResult.launch(
VerificationParams(
it,
apiKey,
uiConfig
)
)
)

iOS

import VeriphOne

let forcedElements = ForcedUIElements(
// Force a language by passing an ISO639 Alpha-2
// code referencing the language you want to use.
// - Nullable object.
// - Default: Device language.
// - Fallback: English-US
forcedLanguage: ForcedLanguage(language: "es"),

// You can force the SDK to use Dark Mode or
// Light Mode for all UI elements by passing
// a value from the ForcedMode enum.
forcedMode: .lightMode
)

let uiConfig = UIConfig(
typography: nil,
forcedUIElements: forcedElements
)

VeriphOneView(
sessionUuid: sessionUuid,
apiKey: apiKey,
uiConfig: uiConfig
) { result in
// Dismiss the view as needed
if let result = result {
// Verification has a result ready (could be successful or failed)
// Connect to your Result Endpoint for further instructions.
// More on this on the next section of the tutorial.
} else {
// Verification failed or was interrupted.
// Option 1: Do nothing.
// Option 2: Ask server for further instructions.
}
}

Specs (Android)

Package: one.veriph.sdk.data

UIConfig

data class UIConfig(
val typography: List<List<FontConfig>>?,
val forcedUIElements: ForcedUIElements?
)

FontConfig

data class FontConfig(
val resId: Int,
val weight: Int,
val usage: FontUsageBundle,
)

FontUsageBundle

data class FontUsageBundle(
val displayLarge: FontUsage? = null,
val displayMedium: FontUsage? = null,
val displaySmall: FontUsage? = null,
val headlineLarge: FontUsage? = null,
val headlineMedium: FontUsage? = null,
val headlineSmall: FontUsage? = null,
val titleLarge: FontUsage? = null,
val titleMedium: FontUsage? = null,
val titleSmall: FontUsage? = null,
val bodyLarge: FontUsage? = null,
val bodyMedium: FontUsage? = null,
val bodySmall: FontUsage? = null,
val labelLarge: FontUsage? = null,
val labelMedium: FontUsage? = null,
val labelSmall: FontUsage? = null,
)

FontUsage

data class FontUsage(
val sizeInSP: Int? = null,
)

ForcedUIElements

data class ForcedUIElements(
val forcedLanguage: ForcedLanguage?,
val forcedMode: ForcedMode?
)

ForcedMode

sealed class ForcedMode {
data object DarkMode: ForcedMode()
data object LightMode: ForcedMode()
}

ForcedLanguage

data class ForcedLanguage(val language: String)

Specs (iOS)

VeriphOne.UIConfig

public struct UIConfig {
public let typography: VeriphOne.TypographySettings?

public let forcedUIElements: VeriphOne.ForcedUIElements?

public init(typography: VeriphOne.TypographySettings?, forcedUIElements: VeriphOne.ForcedUIElements?)
}

VeriphOne.TypographySettings

public struct TypographySettings {
public let typefaces: [VeriphOne.TypefaceBundle]

public init(typefaces: [VeriphOne.TypefaceBundle])
}

VeriphOne.TypefaceBundle

public struct TypefaceBundle {
public let fontName: String

public let fontUrl: CFURL

public let size: CGFloat

public let usage: VeriphOne.TypefaceUsage

public init(fontName: String, fontUrl: CFURL, size: CGFloat, usage: VeriphOne.TypefaceUsage)
}

VeriphOne.TypefaceUsage

public struct TypefaceUsage {
public let useInTitles: Bool

public let useInBodies: Bool

public let useInButtons: Bool

public let useInTextFields: Bool

public init(useInTitles: Bool, useInBodies: Bool, useInButtons: Bool, useInTextFields: Bool)
}

VeriphOne.ForcedUIElements

public struct ForcedUIElements {
public let forcedLanguage: VeriphOne.ForcedLanguage?

public let forcedMode: VeriphOne.ForcedMode?

public init(forcedLanguage: VeriphOne.ForcedLanguage?, forcedMode: VeriphOne.ForcedMode?)
}

VeriphOne.ForcedLanguage

public struct ForcedLanguage {
public let language: String

public init(language: String)
}

VeriphOne.ForcedMode

public enum ForcedMode {
case darkMode

case lightMode
}