How to Build Camera Barcode Scanner App in Xamarin.Forms
Tags: xamarinforms, xamarin, barcode, camera
Published: 2021-04-09 08:53:31

Xamarin is a cross-platform framework for building Android and iOS apps using .NET programming. The code structure of Xamarin Android and Xamarin iOS is different. For developers who want to construct UI for Android and iOS from a single codebase, Xamarin.Forms is the only solution. This article shares how to implement camera barcode scanner apps for both Android and iOS platforms using Xamarin.Forms. Since camera logic is platform-dependent, a bunch of platform-specific code is required.

![camera barcode scanner in Xamarin.Forms](https://www.dynamsoft.com/codepool/img/2021/xamarin-forms-camera-barcode-scanner.jpg)



## Getting Started with Xamarin.Forms

### Setting Up Environment on Windows 10
1. Run **Visual Studio Installer** and select **Mobile development with .NET**
    
    ![visual studio installer](https://www.dynamsoft.com/codepool/img/2021/visual-studio-installer.png)

2. In **Visual Studio 2019**, click **Tools > Options > Xamarin > iOS Settings > Pair to Mac**. Add a Mac IP for remotely building and debugging iOS project.

    ![xamarin mac pair](https://www.dynamsoft.com/codepool/img/2021/xamarin-pair-mac.png)

3. Click the Android icon to install Android SDKs and tools:

    ![xamarin android installation](https://www.dynamsoft.com/codepool/img/2021/xamarin-androdi-tool.png)

### The Hello World Program

We create a new project with the mobile app template:

![Xamarin.Forms mobile app](https://www.dynamsoft.com/codepool/img/2021/xamarin.forms.png)

To simplify the project, we select **Blank**.

![Xamarin.Forms template](https://www.dynamsoft.com/codepool/img/2021/xamarin-forms-template.png)

Build and test the project for iOS:

![Xamarin.Forms iOS app](https://www.dynamsoft.com/codepool/img/2021/xamarin-mac.png)

If there is nothing wrong, we can take a further step to add code for camera preview.

## Peeking Xamarin Camera-relevant APIs
To avoid re-inventing the wheel, we'd better search for Xamarin camera APIs beforehand. Unfortunately, there is only [Media Picker](https://docs.microsoft.com/en-us/xamarin/essentials/media-picker?context=xamarin%2Fxamarin-forms&tabs=android) available in Xamarin.Essentials. The MediaPicker class lets a user pick or take a photo or video on the device. But what we want is a custom camera view that allows us to do barcode scanning by processing video frames.

Although there is no Xamarin Camera API existed, Xamarin Github repository contains two useful sample code demonstrating how to implement custom content page and view:
- [https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/ContentPage](https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/ContentPage)
- [https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/View](https://github.com/xamarin/xamarin-forms-samples/tree/master/CustomRenderers/View)

It is not as convenient as React Native and Flutter camera plugin, though, it is better than nothing.

The two samples implement camera logic differently. The content page sample uses the deprecated Android Camera APIs, whereas the view sample uses the Android Camera2 APIs. The compatibility of Android Camera2 APIs is so far not good for many devices. If you are not going to dig too many camera functionalities, Android Camera APIs are still the best choice.

## Implementing Barcode Scanning using Xamarin.Forms
Now, let's implement our own barcode scanner app.

First, we install [Dynamsoft Xamarin Barcode Reader SDK](https://www.dynamsoft.com/barcode-reader/sdk-mobile/) respectively for Android and iOS projects via NuGet.

![Xamarin Barcode SDK](https://www.dynamsoft.com/codepool/img/2021/dynamsoft-xamarin-barcode-sdk.png)

### Xamarin Shared Code Project
In the shared code project, we define some camera control interfaces in `Interfaces/ICaptureUI.cs`:

```csharp
public interface ICaptureUI: IDisposable
{
    /// <summary>
    /// Starts the Capture Session.
    /// </summary>
    void StartSession();

    /// <summary>
    /// Stops the Capture Session.
    /// </summary>
    void StopSession();

    /// <summary>
    /// Determines if the Capture Session is active.
    /// </summary>
    bool GetSessionActive();

    /// <summary>
    /// res.
    /// </summary>
    string GetResults();

    /// <summary>
    /// Turn on or off the flash.
    /// </summary>
    void onClickFlash();
}
```

We create `Controls/CaptureUI.cs` which extends `ContentView` and is bound to platform-specific camera view:

```csharp
public class CaptureUI : ContentView
{

}
```

A capture view model `ViewModels/CaptureViewModel.cs` is implemented for receiving the barcode scanning results:

```csharp
class CaptureViewModel : ViewModelBase
{
    public CaptureViewModel() 
    {

    }
    /// <summary>
    /// Begins a Capture Sequence, preparing the UI and the Timer.
    /// </summary>
    public void StartCaptureSequence()
    {
        CaptureHandler = App.CurrentCaptureUI;
        Timer t = new Timer(500);
        t.Elapsed += new ElapsedEventHandler(Timer_Tick);
        t.AutoReset = true;
        t.Enabled = true;
    }
    public void Timer_Tick(object source, ElapsedEventArgs e)
    {
        Instruction = CaptureHandler.GetResults();
    }

    /// <summary>
    /// The current Instruction to the User.
    /// </summary>
    public string Instruction
    {
        get { return _Instruction; }
        set
        {
            _Instruction = value;
            UpdateProperty();
        }
    }
    /// <summary>
    /// Backing Field for <see cref="Instruction"/>.
    /// </summary>
    private string _Instruction;

    private ICaptureUI CaptureHandler { get; set; }
}
```

Finally, we open `MainPage.xaml` file to design the UI, adding the custom view and binding the barcode scanning results to a label:

```xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:DBRXFSample.Controls"
             x:Class="DBRXFSample.MainPage">
    
    <Grid
        HorizontalOptions="FillAndExpand"
        VerticalOptions="FillAndExpand">
        <controls:CaptureUI x:Name="Capture"
            HorizontalOptions="FillAndExpand"
            VerticalOptions="FillAndExpand" />
        <Image Source="scannerbox" HorizontalOptions="Center" VerticalOptions="Center"/>
        <Label Text="DBR Is Scanning Continuously" TextColor="#FF4646" FontSize="18" HorizontalOptions="Center" Margin="0,100,0,0" />
        <StackLayout
            HorizontalOptions="Center"
            VerticalOptions="Center"
            Margin="0,480,0,0">
                <Button x:Name="flash" ImageSource="flashon" HorizontalOptions="Center" WidthRequest="50" HeightRequest="50" Clicked="flash_Clicked" />
                <Label x:Name="label" Text="{Binding Instruction}" TextColor="#000000" BackgroundColor="#7F999999"/>
        </StackLayout>
    </Grid>
</ContentPage>
```

![Xamarin barcode scanner design](https://www.dynamsoft.com/codepool/img/2021/xamarin-barcode-scanner-design.png)

### Xamarin Android and iOS Project
The diagram shows the relationship between Xamarin.Forms view and platform-specific view.

![](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view-images/view-classes.png)

According to [Microsoft's online tutorial](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view), we can quickly implement the corresponding camera views.

Afterward, we can use the following code to decode barcodes from video frames:

```java
// Android
private static BarcodeReader barcodeReader = new BarcodeReader("LICENSE-KEY");

try
{
    YuvImage image = (YuvImage)msg.Obj;
    if (image != null)
    {
        int[] stridelist = image.GetStrides();
        TextResult[] text = barcodeReader.DecodeBuffer(image.GetYuvData(), previewWidth, previewHeight, stridelist[0], EnumImagePixelFormat.IpfNv21, "");
        if (text != null && text.Length > 0)
        {
            for (int i = 0; i < text.Length; i++)
            {
                if (i == 0)
                    msg1.Obj = "Code[1]: " + text[0].BarcodeText;
                else
                    msg1.Obj = msg1.Obj + "\n\n" + "Code[" + (i + 1) + "]: " + text[i].BarcodeText;
            }
        }
    }
}
catch (BarcodeReaderException e)
{
    msg1.Obj = "";
    e.PrintStackTrace();
}
```

```swift
// iOS
DynamsoftBarcodeReader reader = new DynamsoftBarcodeReader("LICENSE-KEY");

results = reader.DecodeBuffer(buffer, width, height, bpr, EnumImagePixelFormat.Argb8888, "", out errorr);
if (results != null && results.Length > 0)
{
    for (int i = 0; i < results.Length; i++)
    {
        if (i == 0)
            result = "Code[1]: " + results[0].BarcodeText;
        else
            result = result + "\n\n" + "Code[" + (i + 1) + "]: " + results[i].BarcodeText;
    }
}
```

Get the [30-day FREE Trial license](https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr).

## Source Code
[https://github.com/Dynamsoft/xamarin/tree/master/examples/XamarinForms](https://github.com/Dynamsoft/xamarin/tree/master/examples/XamarinForms)