# Get started with Avalonia

> Build a small Avalonia app that enrols your face and verifies it offline, on your own phone.

Source: https://docs.faceping.ai/start/avalonia/

What you'll build

### A face check that works in airplane mode

An app that enrols your face, verifies it live with a head-turn liveness check, and still matches with no network.

About 10 minutes
Android or iPhone
Free sandbox key

## Get a sandbox key

Sign up at [app.faceping.ai/signup](https://app.faceping.ai/signup) with your email, then open [**Developers → Sandbox keys → Create sandbox key**](https://app.faceping.ai/developers). It starts with `fp_test_`.

The sandbox is free and instant: up to 25 faces per device, each deleted 24 hours after it was enrolled. No card, no approval.

## Create the project

You need the [.NET 10 SDK](https://dotnet.microsoft.com/download) with the Android and iOS workloads, and an Android phone (Android 7 or later, 64-bit) or an iPhone with a cable. The Avalonia template makes a shared project for your screens, plus one project per platform.

```bash
dotnet workload install android ios
dotnet new install Avalonia.Templates
dotnet new avalonia.xplat -n FaceCheck
cd FaceCheck
```

First mobile .NET app on this machine?

The 10 minutes assume your machine already builds .NET apps for phones. If it doesn't, set it up first (the workloads and Android tools take a while to download):

- **Android:** the Android SDK and a JDK. Install them with [Android Studio](https://developer.android.com/studio), or let .NET fetch them with `dotnet build -t:InstallAndroidDependencies` (Microsoft's [Android set-up guide](https://learn.microsoft.com/dotnet/android/getting-started/installation/dependencies) has the full command). Turn on **USB debugging** on the phone.
- **iPhone:** a Mac with [Xcode](https://developer.apple.com/xcode/) 26 or later, signed in with your Apple ID (**Xcode → Settings → Apple Accounts**).
- **Avalonia:** see Avalonia's [mobile set-up](https://docs.avaloniaui.net/docs/guides/platforms/android/setting-up-your-developer-environment-for-android).

FacePing runs on Android and iOS, so you can delete the `FaceCheck.Desktop` and `FaceCheck.Browser` projects (they'd still build, but face checks there report that FacePing runs on Android and iOS devices).

## Add FacePing

One package, in the shared project and in both platform projects. It brings the face models, liveness checks and a camera control with it.

```bash
dotnet add FaceCheck package FacePing.Sdk.Avalonia --prerelease
dotnet add FaceCheck.Android package FacePing.Sdk.Avalonia --prerelease
dotnet add FaceCheck.iOS package FacePing.Sdk.Avalonia --prerelease
```

FacePing for Avalonia is in preview: `--prerelease` gets the latest preview from [NuGet](https://www.nuget.org/packages/FacePing.Sdk.Avalonia). It needs Avalonia 12.

Then set the platforms FacePing runs on: 64-bit Android 7 (API 24) or later, and iOS 15 or later. The template's minimums are lower, and the build stops with a message until you change them. Give each app your own reverse-DNS id too (iOS signs the app with it):

```xml title="FaceCheck.Android.csproj"
<SupportedOSPlatformVersion>24</SupportedOSPlatformVersion>
<RuntimeIdentifiers>android-arm64;android-x64</RuntimeIdentifiers>
<ApplicationId>com.yourcompany.facecheck</ApplicationId>
```

```xml title="FaceCheck.iOS.csproj"
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
<ApplicationId>com.yourcompany.facecheck</ApplicationId>
```

## Allow the camera

The package adds Android's camera permission for you. iOS asks the person with your own words: add them to the iOS project's Info.plist.

```xml title="FaceCheck.iOS/Info.plist"
<!-- inside <dict> -->
<key>NSCameraUsageDescription</key>
<string>FaceCheck uses the camera to verify your face.</string>
```

## Turn FacePing on

Each platform project starts the app in `CustomizeAppBuilder`. Add FacePing there, with your sandbox key, in both.

```csharp title="FaceCheck.Android/Application.cs"
using FacePing.Sdk.Avalonia;

protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) =>
    base.CustomizeAppBuilder(builder)
        .WithInterFont()
        .UseFacePing(o => o.SandboxKey = "fp_test_…");
```

```csharp title="FaceCheck.iOS/AppDelegate.cs"
using FacePing.Sdk.Avalonia;

protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) =>
    base.CustomizeAppBuilder(builder)
        .WithInterFont()
        .UseFacePing(o => o.SandboxKey = "fp_test_…");
```

## Add the screen

A camera control and two buttons: one enrols your face on the phone, the other verifies it. `FaceCameraView` is drawn by Avalonia, so it sits in your layout like any other control.

```xml title="Views/MainView.axaml"
<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:fp="using:FacePing.Sdk.Avalonia"
             x:Class="FaceCheck.Views.MainView">
  <StackPanel Margin="24,48,24,24" Spacing="16">
    <fp:FaceCameraView x:Name="Camera" Height="420" />
    <Button Content="Enrol my face" Click="OnEnroll" HorizontalAlignment="Stretch" />
    <Button Content="Verify" Click="OnVerify" HorizontalAlignment="Stretch" />
    <TextBlock x:Name="Status" FontSize="18" HorizontalAlignment="Center" />
  </StackPanel>
</UserControl>
```

```csharp title="Views/MainView.axaml.cs"
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using FacePing.Sdk;
using FacePing.Sdk.Avalonia;

namespace FaceCheck.Views;

public partial class MainView : UserControl
{
    readonly IFacePing faceping = IFacePing.Current;

    public MainView() => InitializeComponent();

    async void OnEnroll(object? sender, RoutedEventArgs e)
    {
        try
        {
            var photo = await Camera.CaptureAsync();
            var result = await faceping.EnrollAsync("me", photo);
            Status.Text = result.Outcome == EnrollOutcome.Enrolled
                ? "Enrolled. Now tap Verify."
                : $"Try again: {result.Outcome}";
        }
        catch (Exception ex) when (ex is FacePingSetupException or FacePingModelException or InvalidOperationException)
        {
            // For example a mistyped key, no connection on the very first run (the sandbox key is
            // activated once), or no camera. The message says which.
            Status.Text = ex.Message;
        }
    }

    async void OnVerify(object? sender, RoutedEventArgs e)
    {
        try
        {
            // A live check: matches your face, then asks you to turn your head (liveness).
            var result = await faceping.VerifyLiveAsync("me", Camera);
            Status.Text = $"{result.Outcome} · {result.Elapsed.TotalSeconds:0.00} s";
        }
        catch (Exception ex) when (ex is FacePingSetupException or FacePingModelException or InvalidOperationException)
        {
            Status.Text = ex.Message;
        }
    }
}
```

The template's `MainView` sets a view model as its `DataContext` in `App.axaml.cs`; it does no harm, or remove it.

## Run it on your phone

Plug your phone in and run a Release build. The first run needs a connection, to activate your sandbox key. Tap **Enrol my face**, then **Verify**: you should see `Match`.

```bash title="Android"
dotnet build FaceCheck.Android -t:Run -c Release
```

```bash title="iOS"
# Simulators have no front camera: use a connected iPhone. The easiest way is Run in Rider or
# Visual Studio. From the command line, build, then install with Xcode's tools (use your ApplicationId):
dotnet build FaceCheck.iOS -c Release -p:RuntimeIdentifier=ios-arm64
xcrun devicectl list devices
xcrun devicectl device install app --device <device id> FaceCheck.iOS/bin/Release/net10.0-ios/ios-arm64/FaceCheck.iOS.app
xcrun devicectl device process launch --device <device id> com.yourcompany.facecheck
```

**First time on an iPhone?** `dotnet build` signs the app with a provisioning profile it finds on your Mac, but it can't create one. If the build says there's no profile for your ApplicationId, make one once in Xcode: create a new iOS App project with the same bundle identifier, pick your **Team** under **Signing & Capabilities**, and run it on the phone. Then build again. On the phone, turn on **Developer Mode** (**Settings → Privacy & Security → Developer Mode**) and, if iOS says the developer isn't trusted, trust it under **Settings → General → VPN & Device Management**.

The Android build includes the phone (`arm64`) and emulator (`x86_64`) versions of the face engine. For a smaller app, set `<RuntimeIdentifiers>android-arm64</RuntimeIdentifiers>` (phones only), or publish an Android App Bundle so each phone downloads only its own.

**Now switch on airplane mode and tap Verify again.** Still a match: the check ran entirely on your phone.

## You've built a face check that works offline

Next, make it real: verify the people in your app (members, staff or people with tickets), and apply to go live when you're ready.

- [Clone the finished app](https://github.com/faceping/avalonia-starter): github.com/faceping/avalonia-starter
- [How the SDK works](https://docs.faceping.ai/sdk/): Liveness, storage, sandbox limits
- [Avalonia reference](https://docs.faceping.ai/sdk/avalonia/): Every type and method
- [Go to production](https://docs.faceping.ai/going-live/): Apply and sync faces to devices
