Xamarin.forms: [Bug] UWP - Embedded Fonts not working in Release configuration

Created on 8 Oct 2020  路  17Comments  路  Source: xamarin/Xamarin.Forms

Description

After last XF release 4.8.0.1534 (Service release 3), in Release configuration icons on UWP not showing

Steps to Reproduce

  1. Run UWP in Release configuration

Expected Behavior

Showing icons like in Debug configuration

Actual Behavior

Not showing icons in Release configuration

Basic Information

  • Version with issue: 4.8.0.1534
  • Last known good version: None
  • Platform Target Frameworks:

    • UWP: 16299

Screenshots

Debug:
Debug

Release:
Release

Reproduction Link

Example:
EmbeddedFontsTest.zip

embedded fonts UWP bug

Most helpful comment

This is not a bug. You need to pass the assembly that has the ExportFont attributes to the Xamarin.Forms.Init() call.

All 17 comments

Hi,
could you try to delete app data and start the app again. I have a similar problem, but with android: https://github.com/xamarin/Xamarin.Forms/issues/11843.
I'm not sure if this is related.

Have the same issue, with a minor difference to the sample project provided - I'm not using an alias name for the font, I'm only using the font filename.
Builds that don't do AOT compilation work fine, but when doing a proper store build with AOT all the font symbols fail to load.

I have an issue even in debug with font awesome

So, this issue is covering the custom font issue, not just font awesome right? I'm using a font name Inkfree and in release mode, my whole page is blank. I'm sure it's another issue all together, but why does the page show blank white instead of just not showing the font?

Does anyone else just get a blank page instead of a square like others are talking about?

This is not a bug. You need to pass the assembly that has the ExportFont attributes to the Xamarin.Forms.Init() call.

This is not a bug. You need to pass the assembly that has the ExportFont attributes to the Xamarin.Forms.Init() call.

This solutions works for me. Maybe this can be added to the documentation of Fonts in Xamarin?
But in place of Xamarin.Forms.Init it is Xamarin.Forms.Forms.Init.
Thanks for the solution

Approved. Adding to assembly list solved problem

Where would I do this at? Could you please give me an example code?

I have this on the App.xaml.cs page:

[assembly: ExportFont("Inkfree.ttf", Alias = "InkFree")]

Where would I do this at? Could you please give me an example code?

I have this on the App.xaml.cs page:

[assembly: ExportFont("Inkfree.ttf", Alias = "InkFree")]

@BillyMartin1964 I think you'd include something like
Xamarin.Forms.Forms.Init(e, new[] { typeof(YourNamespace.App).Assembly });

Can someone break this down for an idiot on how to implement this because I do not follow the vague references made about assemblies. What needs to be done exactly because even in debug and release I get no icons.

John

Here is my UWP App.Xaml.cs file:

`
using GroceryList.Helpers;

using Microsoft.WindowsAzure.MobileServices;

using Syncfusion.ListView.XForms.UWP;
using Syncfusion.SfBusyIndicator.XForms.UWP;
using Syncfusion.SfChart.XForms.UWP;
using Syncfusion.SfPdfViewer.XForms.UWP;
using Syncfusion.SfPicker.XForms.UWP;
using Syncfusion.SfPullToRefresh.XForms.UWP;
using Syncfusion.SfRadialMenu.XForms.UWP;
using Syncfusion.SfRangeSlider.XForms.UWP;
using Syncfusion.XForms.UWP.BadgeView;
using Syncfusion.XForms.UWP.Border;
using Syncfusion.XForms.UWP.Buttons;
using Syncfusion.XForms.UWP.ComboBox;
using Syncfusion.XForms.UWP.Expander;
using Syncfusion.XForms.UWP.PopupLayout;
using Syncfusion.XForms.UWP.TextInputLayout;

using System;
using System.Collections.Generic;
using System.Reflection;

using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Navigation;

using Xamarin.Forms;

using Application = Windows.UI.Xaml.Application;
using Frame = Windows.UI.Xaml.Controls.Frame;
// ReSharper disable UseObjectOrCollectionInitializer

namespace GroceryList.UWP
{
///


/// Provides application-specific behavior to supplement the default Application class.
///

// ReSharper disable once RedundantExtendsListEntry
sealed partial class App : Application
{
///
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
///

public App()
{
InitializeComponent();
Suspending += OnSuspending;
}

    /// <summary>
    /// Invoked when the application is launched normally by the end user.  Other entry points
    /// will be used such as when the application is launched to open a specific file.
    /// </summary>
    /// <param name="e">Details about the launch request and process.</param>
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {

        // Do not repeat app initialization when the Window already has content,
        // just ensure that the window is active
        if (!(Window.Current.Content is Frame rootFrame))
        {
            // Create a Frame to act as the navigation context and navigate to the first page
            rootFrame = new Frame();

            rootFrame.NavigationFailed += OnNavigationFailed;

            List<Assembly> assembliesToInclude = new List<Assembly>
            {
                typeof(SfListViewRenderer).GetTypeInfo().Assembly,
                typeof(SfPickerRenderer).GetTypeInfo().Assembly,
                typeof(SfTextInputLayoutRenderer).GetTypeInfo().Assembly,
                typeof(SfBusyIndicatorRenderer).GetTypeInfo().Assembly,
                typeof(SfComboBoxRenderer).GetTypeInfo().Assembly,
                typeof(SfExpanderRenderer).GetTypeInfo().Assembly,
                typeof(SfBorderRenderer).GetTypeInfo().Assembly,
                typeof(SfPdfDocumentViewRenderer).GetTypeInfo().Assembly,
                typeof(SfRangeSliderRenderer).GetTypeInfo().Assembly,
                typeof(SfRadialMenuRenderer).GetTypeInfo().Assembly,
                typeof(SfPopupLayoutRenderer).GetTypeInfo().Assembly,
                typeof(SfButtonRenderer).GetTypeInfo().Assembly,
                typeof(SfCheckBoxRenderer).GetTypeInfo().Assembly,
                typeof(Syncfusion.XForms.UWP.Graphics.SfGradientViewRenderer).GetTypeInfo().Assembly,
                typeof(SfBadgeViewRenderer).GetTypeInfo().Assembly,
                typeof(SfChartRenderer).GetTypeInfo().Assembly,
                typeof(SfPullToRefreshRenderer).GetTypeInfo().Assembly
            };

            // Initialize Xamarin.Forms here
            Forms.Init(e, assembliesToInclude);

            if (e != null && e.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Load state from previously suspended application
            }

            // Place the frame in the current Window
            Window.Current.Content = rootFrame;
        }

        if (e != null && e.PrelaunchActivated == false)
        {
            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }
    }

    /// <summary>
    /// Invoked when Navigation to a certain page fails
    /// </summary>
    /// <param name="sender">The Frame which failed navigation</param>
    /// <param name="e">Details about the navigation failure</param>
    void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
        throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    /// <summary>
    /// Invoked when application execution is being suspended.  Application state is saved
    /// without knowing whether the application will be terminated or resumed with the contents
    /// of memory still intact.
    /// </summary>
    /// <param name="sender">The source of the suspend request.</param>
    /// <param name="e">Details about the suspend request.</param>
    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        //TODO: Save application state and stop any background activity
        deferral.Complete();
    }

    protected override void OnActivated(IActivatedEventArgs args)
    {
        base.OnActivated(args);

        if (args != null && args.Kind == ActivationKind.Protocol)
        {
            if (args is ProtocolActivatedEventArgs protocolArgs) AzureMobileServiceClientHelper.DefaultClientHelper.CurrentClient.ResumeWithURL(protocolArgs.Uri);
        }
    }
}

}
`

@norton287 , from what I've worked out, just add this to your list of assemblies to include in your UWP App.xaml.cs

           ` assembliesToInclude.Add(typeof(ExportFontAttribute).GetTypeInfo().Assembly);`

and you must have something similar to this somewhere in your core project(using your own font name, of course):

[assembly: ExportFont("Inkfree.ttf", Alias = "InkFree")]

I am still missing something, here is what I have done:

Here is core project app.xaml.cs:

[assembly: ExportFont("FontAwesome5Free-Regular.ctf", Alias = "AwesomeIcon")] [assembly: ExportFont("FontAwesome5Free-Solid.ctf", Alias = "AwesomeIconSolid")] [assembly: ExportFont("Roboto-Bold.ttf", Alias = "RobotoBold")] [assembly: ExportFont("Roboto-Regular.ttf", Alias = "RobotoRegular")]

This is what I have in app.xaml.cs in UWP project:

` List assembliesToInclude = new List
{
typeof(SfListViewRenderer).GetTypeInfo().Assembly,
typeof(SfPickerRenderer).GetTypeInfo().Assembly,
typeof(SfTextInputLayoutRenderer).GetTypeInfo().Assembly,
typeof(SfBusyIndicatorRenderer).GetTypeInfo().Assembly,
typeof(SfComboBoxRenderer).GetTypeInfo().Assembly,
typeof(SfExpanderRenderer).GetTypeInfo().Assembly,
typeof(SfBorderRenderer).GetTypeInfo().Assembly,
typeof(SfPdfDocumentViewRenderer).GetTypeInfo().Assembly,
typeof(SfRangeSliderRenderer).GetTypeInfo().Assembly,
typeof(SfRadialMenuRenderer).GetTypeInfo().Assembly,
typeof(SfPopupLayoutRenderer).GetTypeInfo().Assembly,
typeof(SfButtonRenderer).GetTypeInfo().Assembly,
typeof(SfCheckBoxRenderer).GetTypeInfo().Assembly,
typeof(Syncfusion.XForms.UWP.Graphics.SfGradientViewRenderer).GetTypeInfo().Assembly,
typeof(SfBadgeViewRenderer).GetTypeInfo().Assembly,
typeof(SfChartRenderer).GetTypeInfo().Assembly,
typeof(SfPullToRefreshRenderer).GetTypeInfo().Assembly,
typeof(ExportFontAttribute).GetTypeInfo().Assembly
};

            // Initialize Xamarin.Forms here
            Forms.Init(e, assembliesToInclude);`

This is what I have in my resource dictionary in app.xaml in core project:

<ResourceDictionary> <OnPlatform x:TypeArguments="x:String" x:Key="Pickerunselected_RobotoRegular"> <On Platform="UWP" Value="Assets/Fonts/Roboto-Regular.ttf#Roboto" /> <On Platform="Android" Value="Roboto-Regular.ttf" /> <On Platform="iOS" Value="Roboto-Regular" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="Pickerselected_RobotoBold"> <On Platform="UWP" Value="Assets/Fonts/Roboto-Bold.ttf#Roboto" /> <On Platform="Android" Value="Roboto-Bold.ttf" /> <On Platform="iOS" Value="Roboto-Bold" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="FontIcon"> <On Platform="Android" Value="Segoe_MDL2_Assets.ttf#Segoe MDL2 Assets" /> <On Platform="UWP" Value="Assets/Fonts/Segoe_MDL2_Assets.ttf#Segoe MDL2 Assets" /> <On Platform="iOS" Value="Segoe MDL2 Assets"/> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="RobotoRegular"> <On Platform="UWP" Value="Assets/Fonts/Roboto-Regular.ttf#Roboto" /> <On Platform="Android" Value="Roboto-Regular.ttf#Roboto Regular" /> <On Platform="iOS" Value="Roboto-Regular" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="RobotoBold"> <On Platform="UWP" Value="Assets/Fonts/Roboto-Bold.ttf#Roboto" /> <On Platform="Android" Value="Roboto-Bold.ttf#Roboto Bold" /> <On Platform="iOS" Value="Roboto-Bold" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="AwsomeIcon"> <On Platform="Android" Value="FontAwesome5Free-Regular.otf#Font Awesome 5 Free Regular" /> <On Platform="UWP" Value="/Assets/Fonts/FontAwesome5Free-Regular.otf#Font Awesome 5 Free" /> <On Platform="iOS" Value="FontAwesome5Free-Regular" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="AwsomeIconSolid"> <On Platform="Android" Value="FontAwesome5Free-Solid.otf#Font Awesome 5 Free Solid" /> <On Platform="UWP" Value="/Assets/Fonts/FontAwesome5Free-Solid.otf#Font Awesome 5 Free" /> <On Platform="iOS" Value="FontAwesome5Free-Solid" /> </OnPlatform> <OnPlatform x:TypeArguments="x:String" x:Key="AwsomeIconBrands"> <On Platform="Android" Value="FontAwesome5Brands-Regular.otf#Font Awesome 5 Free Brands Regular" /> <On Platform="UWP" Value="/Assets/Fonts/FontAwesome5Brands-Regular.otf#Font Awesome 5 Free Brands" /> <On Platform="iOS" Value="FontAwesome5Brands-Regular" /> </OnPlatform> <FontImageSource x:Key="Clear" FontFamily="{StaticResource FontIcon}" Glyph="&#xE894;" Size="20" Color="White" /> <FontImageSource x:Key="Refresh" Glyph="&#xE895;" Size="20" Color="White" FontFamily="{StaticResource FontIcon}" /> <FontImageSource x:Key="Delete" FontFamily="{StaticResource FontIcon}" Glyph="&#xE74D;" Size="25" Color="White" /> <FontImageSource x:Key="Print" FontFamily="{StaticResource FontIcon}" Glyph="&#xE749;" Size="20" Color="White" /> <FontImageSource x:Key="Account" FontFamily="{StaticResource FontIcon}" Glyph="&#xE77B;" Size="20" Color="White" /> <FontImageSource x:Key="Cart" FontFamily="{StaticResource FontIcon}" Glyph="&#xE7BF;" Size="20" Color="White" /> <FontImageSource x:Key="Home" FontFamily="{StaticResource FontIcon}" Glyph="&#xE80F;" Size="20" Color="White" /> <FontImageSource x:Key="Section" FontFamily="{StaticResource FontIcon}" Glyph="&#xE819;" Size="20" Color="White" /> <FontImageSource x:Key="List" FontFamily="{StaticResource FontIcon}" Glyph="&#xE8FD;" Size="20" Color="White" /> <FontImageSource x:Key="Info" FontFamily="{StaticResource FontIcon}" Glyph="&#xE946;" Size="20" Color="White" /> <FontImageSource x:Key="Help" FontFamily="{StaticResource AwsomeIcon}" Glyph="&#xf059;" Size="20" Color="White" /> <FontImageSource x:Key="Options" FontFamily="{StaticResource FontIcon}" Glyph="&#xE713;" Size="20" Color="White" /> <FontImageSource x:Key="CacheImage" FontFamily="{StaticResource FontIcon}" Glyph="&#xEB9F;" Size="20" Color="White" /> <FontImageSource x:Key="Category" FontFamily="{StaticResource FontIcon}" Glyph="&#xEC09;" Size="20" Color="White" /> <FontImageSource x:Key="ListName" FontFamily="{StaticResource FontIcon}" Glyph="&#xE71D;" Size="20" Color="White" /> <FontImageSource x:Key="Camera" FontFamily="{StaticResource FontIcon}" Glyph="&#xE722;" Size="20" Color="White" /> <FontImageSource x:Key="Share" FontFamily="{StaticResource FontIcon}" Glyph="&#xE72D;" Size="20" Color="White" /> <FontImageSource x:Key="Email" FontFamily="{StaticResource FontIcon}" Glyph="&#xE910;" Size="20" Color="White" /> <FontImageSource x:Key="Excel" FontFamily="{StaticResource AwsomeIcon}" Glyph="&#xf1c3;" Size="20" Color="White" /> <FontImageSource x:Key="Database" FontFamily="{StaticResource AwsomeIconSolid}" Glyph="&#xf1c0;" Size="20" Color="White" /> <FontImageSource x:Key="Table" FontFamily="{StaticResource AwsomeIconSolid}" Glyph="&#xf0ce;" Size="20" Color="White" /> <FontImageSource x:Key="Hamburger" FontFamily="{StaticResource AwsomeIconSolid}" Glyph="&#xf0c9;" Size="20" Color="White" /> <FontImageSource x:Key="Chart" FontFamily="{StaticResource AwsomeIconSolid}" Glyph="&#xf080;" Size="20" Color="White" />

Are the fonts for UWP to go into the core project now? Or am I still doing something wrong?

I appreciate the help very much!

John

@norton287 , from what I've worked out, just add this to your list of assemblies to include in your UWP App.xaml.cs

           ` assembliesToInclude.Add(typeof(ExportFontAttribute).GetTypeInfo().Assembly);`

and you must have something similar to this somewhere in your core project(using your own font name, of course):

[assembly: ExportFont("Inkfree.ttf", Alias = "InkFree")]

Including the assembly for the ExportFontAttribute isn't going to do very much. You need to include the assembly where the actual fonts are embedded into.

An easy way to do this is to declare an empty class after the ExportFont lines:

[assembly: ExportFont("Inkfree.ttf", Alias = "InkFree")]

public class _FontAssemby {}

Then in your UWP project:

assembliesToInclude.Add(typeof(_FontAssembly).GetTypeInfo().Assembly);

It doesn't seem to work with Font Awesome .otf fonts, they show up with the broken image. My .ttf fonts work fine.

Any ideas?

John

Thanks for all the help!

We've tried the suggestion of adding typeof(App).Assembly to Xamarin.Forms.Forms.Init(..), however this significantly increases the startup time from <5s to well over 1 minute (the only code change was adding this assembly loading line).

When the app finally loads, the fonts are there, but this solution won't work for us.

Is there something I'm doing wrong (i.e. I shouldn't be loading our main app assembly?), or is there a reason why the startup time is so slow with this addition - and is there a fix for this @MarMarIV ?

@kevcrooks You could put your fonts in a separate assembly

Thanks @activa I tried this and it seems to have a similar problem (it's difficult to do repeated testing because I only see this in release mode, which takes time to build!).

The startup time might reduce slightly, but at best is > 30s which is too slow for us to use.

If there's not a good fix for this, we'll have to revert to doing fonts on a per-platform basis again, but I'd thought there must be a good way of doing for all platforms at once with Xamarin Forms.

Was this page helpful?
0 / 5 - 0 ratings