Camera Preview Control for WinUI, UWP and Uno (iOS & Android) Applications

The Windows Community Toolkit provides a limited feature camera preview control for both UWP and WinUI but this doesn’t help if you want to build a cross platform application with the Uno Platform. In this post I wanted to share the very, very, very early version of a CameraPreview control for Uno. Initial support will include iOS, Android, UWP and WinUI3 (desktop) applications. I’ll walk through getting started with this control.

Firstly, the control is available via the BuildIt.Media.Uno.WinUI nuget package. This seems like a bit of a mouthful but this is to make it clear that this package targets Uno applications that are based on WinUI (rather than UWP). Note however, that the package does include UWP as a target, so can be used in any UWP application (that doesn’t necessarily need to use Uno).

Let’s go through building a simple application that shows a camera preview. To create the solution I’m going to use the unoapp-winui dotnet new template (part of the Uno dotnet templates). This template generates a solution that uses the WinUI build of Uno (meaning that the namespaces etc align with those from WinUI3, rather than UWP).

Upgrading Project Reunion to 0.8.1

At the point of writing this post, the template generates a WinUI project that references Project Reunion 0.5.6. The first thing you should do is to upgrade this to target 0.8.1 of the WindowsAppSdk (package name is still Microsoft.ProjectReunion). Here’s a list of the main changes that are required

  • Add “<UseWinUI>true</UseWinUI>” to the PropertyGroup in the csproj for the desktop project
  • Update the PackageReference for Microsoft.ProjectReunion to version 0.8.1
  • Remove the FrameworkReference elements for Microsoft.Windows.SDK.NET.Ref as these are no longer required
  • Update the PackageReference in the wapproj for the packaging project to version 0.8.1 for the Microsoft.ProjectReunion package
  • Remove the PropertyGroup immediately prior to the ItemGroup with the PackageReference to Microsoft.ProjectReunion – this block is no longer required
  • Restart Visual Studio and Rebuild the WinUI desktop project to ensure the latest nuget packages are restored

These updates won’t be required once the Uno template has been updated to target the latest WindowsAppSdk version.

Camera Preview

Adding the camera preview control requires three steps:

  1. Add NuGet package reference
  2. Add CameraPreview control to XAML page
  3. Add camera/webcam permission

Let’s go through these steps in more detail. Firstly, we need to add the BuildIt.Media.Uno.WinUI package. This should be added to the iOS, Android and WinUI projects. If you have a UWP project, you can add it to that too.

One thing you’ll notice is that this package does not contain a prebuilt library (eg a .dll). Instead it includes source code which is essentially added to each project. You’ll see this clearly in the WinUI project where the added files appear as linked files in the project in Solution Explorer.

Note that you won’t see the linked files in the iOS or Android folder as they’re still using the old style project system but the files are still correctly imported into the projects.

Next, we need to add the CameraPreview control to the page. I’ve also added a Button which we’ll use to start the camera preview.

<Page x:Class="UnoAppWinUI.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:UnoAppWinUI"
      xmlns:media="using:BuildIt.Media.Uno.WinUI"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <media:CameraPreview x:Name="Preview"
                                 Height="500"
                                 Width="500" />
            <Button Content="Start"
                    Click="StartPreviewClick" />
        </StackPanel>
    </Grid>
</Page>

The code for the StartPreviewClick event handler starts the preview.

private async void StartPreviewClick(object sender, RoutedEventArgs e)
{
    await Preview.StartPreview();
}

Now the only thing left is to make sure that each platform requests permission to use the camera when installing the app. This is done as follows:

Windows – package.appxmanifest

To add permissions to the Windows application, expand the packaging project and double-click the package.appxmanifest to open the property designer. Switch to the Capabilities tab and check the Webcam item in the list.

This adds the Webcam capability to the package.appxmanifest

<?xml version="1.0" encoding="utf-8"?>
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
 xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap rescap">
  ....
  <Capabilities>
    <rescap:Capability Name="runFullTrust" />
    <DeviceCapability Name="webcam"/>
  </Capabilities>
</Package>

Android – AndroidManifest.xml

Double-click the Properties node in the Android project in Solution Explorer to open the project properties designer. Switch to the Android Manifest tab and type camera in the search box under the Required permissions heading. Check the CAMERA option.

This adds the android.permission.CAMERA user permission to the AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="UnoAppWinUI.UnoAppWinUI" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="29" />
	<uses-permission android:name="android.permission.CAMERA" />
	<application android:label="UnoAppWinUI"></application>
</manifest>

iOS – info.plist

In the iOS project in Solution Explorer, right-click the info.plist file and select View Code (you can’t enable the camera via the plist designer). Add a key-string pair with the key being NSCameraUsageDescription and the string being a description of how the camera is used by the app.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
        .......
	<key>NSCameraUsageDescription</key>
	<string>This app is using the camera</string>
  </dict>
</plist>

Note that if you want to enable iOS debugging directly to a device on Windows, you can add a reference to the Xamarin.Forms NuGet package and then add the following logic to the Main.cs file of your application.

#if DEBUG
    public class HotRestartDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions)
        {
            Microsoft.UI.Xaml.Application.Start(_ => new App());
            return base.FinishedLaunching(uiApplication, launchOptions);
        }
    }
#endif

You’ll need to rebuild the iOS project and perhaps toggle which project is the startup project. You also need to follow the instructions on how to enable Xamarin Hot Restart.

Running the Camera Preview

Now that you’ve added the camera preview control, all you have to do is run the application (pick the platform you want to run on) and then click the Start button to display the camera preview. Here’s the same app running on both Windows and Android.

The Windows app is showing a real camera feed, whilst the Android app is running on the emulator, so is showing a fake camera feed that’s useful for testing apps.

There is currently a red background that is marking the background of the CameraPreview control. This can be hidden in the current build by setting the Stretch property on the CameraPreview to UniformToFill. In future builds the background red will be removed.

Currently the CameraPreview control is very limited but over the coming weeks I expect to tidy up the code and provide more options for controlling the camera, capturing photos and perhaps even down the line video.

If anyone feels like assisting with implementing either the MacOS or WASM platforms, I’d love some assistance with getting these platforms to work. Leave a comment, or ping me on Twitter.