Build Cross-Platform App with Embedded Images on Xamarin.Forms

As we all know, a picture is worth 1,000 words. More and more, we see developers utilising images as the core of their app. Images play an important role in application navigation, usability, and branding. Hence, sharing images across all platforms, i.e. iOS, Android, and Windows 10, is often a task we need to work on. Today, I will share about how we do just that with Embedded Images.

Distributing images across different platforms with Embedded Images is recommended when identical images are used on each platform, and is particularly suited to creating components, as the image is bundled with the code. In this post, I will demo how we can do that in a new Xamarin.Forms blank project.

PROJECT GITHUB REPOSITORY

The complete source code of this project can be found at https://github.com/goh-chunlin/gcl-boilterplate.csharp/tree/master/xamarin-forms/CPEI.

Setup Images Folder

Let’s say we would like to show some images in the first screen of our app for each of the platforms. We will first have a folder called Images to store all those images. Then, we need to proceed to set the Build Action of the images to be “Embedded resource”.

Right-click the selected images and then select “Properties” to modify their Build Action.

The project name is called CPEI which stands for Cross-Platform Embedded Images. I use shortform here so that the Android project will not complain about our path to the files being too long.

ACCESS Embedded ImageS on XAML

Now, let’s say if we can to show only one of the images in the first screen of our app, we can do so by editing the XAML code of MainPage.xaml. However, we need to have the following extension first to convert the image file name which is in string to ResourceImageSource, then only the image can be natively loaded by XAML.

[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
    public string Source { get; set; }

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        if (Source == null) return null;

        Assembly assembly = typeof(ImageResourceExtension).Assembly;
        var imageSource = ImageSource.FromResource(Source, assembly);

        return imageSource;
    }
}

Here we use the overload of ImageSource.FromResource that specifies the source assembly in which to search for the image so that it can work on the Release mode of UWP on Windows 10.

Now we can use this extension in the XAML, as shown below, in MainPage.xaml.

<?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:embeddedImage="clr-namespace:CPEI.Extensions;assembly=CPEI"
             x:Class="CPEI.MainPage">

    <ScrollView>
        ...

        <Image x:Name="MainImage" Source="{embeddedImage:ImageResource CPEI}" 
            WidthRequest="600" HeightRequest="400" HorizontalOptions="CenterAndExpand" />

        ...
    </ScrollView>

</ContentPage>

The highlighted sections are the parts newly added. At this point of time, we’re still not sure the name of the image. So our app now should not show any image at that part. To find out the actual image names, we can add a debugging code (which we should remove in production) in the ImageResourceExtension class as follows.

[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
    ...

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        ...

        foreach (var res in assembly.GetManifestResourceNames())
        {
            System.Diagnostics.Debug.WriteLine("found resource: " + res);
        }

        ...
    }
}

When we debug our app, the following should be shown in the Output window.

found resource: CPEI.Images.Genshin-Impact-Pic01.png
found resource: CPEI.Images.Genshin-Impact-Pic02.png
found resource: CPEI.Images.Genshin-Impact-Pic03.png
found resource: CPEI.Images.Genshin-Impact-Pic04.png
found resource: CPEI.Images.Genshin-Impact-Pic05.png
found resource: CPEI.Images.Genshin-Impact-Pic06.png

So now we know the name for each of the images. We simply update the Source in the XAML code above to correctly show the image, for example

<Image x:Name="MainImage" Source="{embeddedImage:ImageResource CPEI.Images.Genshin-Impact-Pic02.png}" WidthRequest="600" HeightRequest="400" HorizontalOptions="CenterAndExpand" /> 
Yay, the selected image is now displayed on our UWP app.

Access Embedded Images from Code Behind

Instead of XAML, we can access the embedded images from code behind too. For example, if we want to change the image above randomly through a click of button, we can have the following code in the click event of the button.

private void Button_Clicked(object sender, EventArgs e)
{
    Random rnd = new Random();
    int imageIndex = rnd.Next(1, 7);

    MainImage.Source = ImageSource.FromResource(
        $"CPEI.Images.Genshin-Impact-Pic{imageIndex:00}.png", 
        typeof(MainPage).Assembly);
}
Yay, we now can choose embedded images to be displayed in frontend from code behind.

Android and iOS

Since embedded images are shipped with those images embedded in the assembly as a resource, the images can be also displayed on Android, as demonstrated below.

Debugging our Xamarin.Forms app on Android emulator.

In order to test our app on the iOS platform, it’s easier if we choose to build our iOS app project on a Mac machine directly. Visual Studio for Mac offers the support for debugging Xamarin.iOS applications both in the iOS simulator and on iOS devices.

This is my first time building Xamarin.iOS app on my MacBook Air, so I need to download Xcode 12.5 from the Apple Developer Downloads page first. I don’t download it from the App Store because that will take a longer time and the installation may fail. Interestingly, there is a tip on how to install Xcode with xip in a faster manner but I’d still waited for like one hour to have it installed on my machine.

After getting both XCode 12.5 and VS 2019 for Mac installed, I proceed to checkout the Xamarin.iOS app from the source control and update the Deployment Target accordingly in order to have our app running on the simulators, as shown in the following screenshot.

Running our Xamarin.iOS app on iPhone 12 simulator.

As demonstrated below, our app can be run on iPad as well with all the embedded images loaded successfully.

This shows our Xamarin.iOS app running on iPad Air (4th Generation) simulator.

References

The code of this project described in this article can be found in my GitHub repository: https://github.com/goh-chunlin/gcl-boilterplate.csharp/tree/master/xamarin-forms/CPEI.

Build Xamarin.CommunityToolkit Sample App on Windows 10 in March 2021

In January 2021, a new stable version of Xamarin.Forms, the version 5.0, is released. Actually I had been playing with it when its preview version was released in the previous year. Together with the release of Xamarin.Forms 5, Microsoft also announced Xamarin Community Toolkit which provides a collection of common elements for mobile development with Xamarin.Forms.

Xamarin Community Toolkit is available on GitHub as an open-source .NET Foundation project. There is a sample solution offered as well in the repository. So, we can simply clone the GitHub project and build it on our Windows 10 machine to find out how behaviors, converters, effects, MVVM utilities, and new controls can be implemented.

UWP version of the Xamarin Community Toolkit sample.

However, to successfully build the sample project, it’s not that straightforward, at least at the point of time I write this article in March 2021. So I will guide you through building and running the Xamarin Community Toolkit sample on Windows 10 machine.

Tools

In this article, I’m using the following tools.

  • Windows 10 Home version 20H2;
  • Visual Studio 2019 Professional Preview (16.10.0 Preview 10);
  • .NET 5 (5.0.200-preview.21077.7);
  • NuGet Packages:
    • Xamarin.Essentials 1.6.1;
    • Xamarin.Forms 5 (5.0.0.2012);
    • Microsoft.NETCore.UniversalWindowsPlatform 6.2.12;
    • Xamarin.CommunityToolkit 1.0.3.

Setup the Project

Firstly, we can directly clone the Xamarin Community Toolkit sample from its GitHub repository.

There are many platforms supported in the sample application. However, here I will only talk about UWP and a bit of Android. So I am going to unload the projects for iOS, GTK, Tizen, and WPF. After that, I will set the UWP project as the Startup Project, as shown in the screenshot below.

UWP project is set as the Startup Project.

Now, we can proceed to run it. However, some of us may encounter a few issues. I will share what I have encountered so far and how I proceed to fix them.

Issue 01: UWP Build Errors

The build errors that I encountered all originated from the Xamarin.CommunityToolkit project which targets at Windows 10 SDK 10.0.17763 and .NET Standard 1.0, as shown in the following screenshot.

Build errors in Xamarin.CommunityToolkit targetting at Windows 10

There are a few solutions to this problem. Firstly is head to Visual Studio Installer to install the Windows 10 SDK 10.0.17763.0, which took additional 2.8 GB in space.

Installing Windows 10 SDK 10.0.17763.0.

Second solution to this issue is that we can re-target the Xamarin.CommunityToolkit to the latest Windows 10 SDK that you have. For my case, it is 10.0.19041.0. So I simply need to update the UAP version in the .csproj of the project, as shown in the screenshot below.

Re-targeting Xamarin.CommunityToolkit dependency on UWP framework.

Once we have done either of the above, the build errors should be gone.

Of course, if you don’t want to touch the Xamarin.Community.Toolkit project which is referenced by the sample application, we can unload the project. After that, in each of the platform project, we change to use the NuGet package of the Xamarin.Community.Toolkit which is stable and we don’t have to re-build it ourselves.

Issue 02: File Path Too Long

If you happen to put the sample project in a directory having a long path length, then there will be some files not being generated, for example the Java file as shown in the screenshot below. This is because on Windows, there is a limitation of the file path length.

The path length is too long!

So, once we move the entire solution to another directory with shorter path length, we shall be able to see the sample project being shown successfully.

Xamarin Community Toolkit sample on Android.

Issue 03: Blank UWP Page

The sample application will look similar on the UWP as well. However, besides the first screen, most of the subsequent screen has a blank content. However, as shown in the video clip below, the pages will actually back to normal once we resize the app window.

After few hours of investigation, I found that as long as we comment out or remove the CollectionView.Footer used in those pages, we realise that the problem above will be fixed.

The CollectionView.Footer in App.xaml is shared by those blank UWP pages.

Currently, I have filed an issue on the Xamarin Community Toolkit GitHub about this issue and workaround. So, let’s wait and see if this will be fixed in the future releases. Other than all these issues, the Xamarin Community Toolkit is still a very good tool for the developers.

Learn More about Xamarin Community Toolkit

There is a Xamarin Community Toolkit YouTube video with Gerald Versluis shared by my senior Riza Marhaban. I find it to be very useful and I hope you enjoy learning more about Xamarin too. Have fun!