xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

[Bug] UWP - Embedded Fonts not working in Release configuration #12404

Closed MarMarIV closed 4 years ago

MarMarIV commented 4 years ago

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

Screenshots

Debug: Debug

Release: Release

Reproduction Link

Example: EmbeddedFontsTest.zip

AlleSchonWeg commented 4 years ago

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.

MitchBomcanhao commented 4 years ago

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.

VladislavAntonyuk commented 4 years ago

I have an issue even in debug with font awesome

BillyMartin1964 commented 4 years ago

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?

activa commented 4 years ago

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

MichielDG commented 4 years ago

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

MarMarIV commented 4 years ago

Approved. Adding to assembly list solved problem

BillyMartin1964 commented 4 years ago

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")]

MitchBomcanhao commented 4 years ago

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 });

norton287 commented 4 years ago

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);
        }
    }
}

} `

BillyMartin1964 commented 4 years ago

@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")]

norton287 commented 4 years ago

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:

`

        <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

activa commented 4 years ago

@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);
norton287 commented 4 years ago

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!

kevcrooks commented 4 years ago

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 ?

activa commented 4 years ago

@kevcrooks You could put your fonts in a separate assembly

kevcrooks commented 4 years ago

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.

bruzkovsky commented 3 years ago

I had this problem too, and the assembly thing solved it for me. Summing it up for anyone getting here, because this thread is a bit confusing:

Solution 1: The ExportFont attribute is in your main XF assembly

If you just slapped the attribute on let's say the MyApp.Core/App.xaml.cs like this:

...
[assembly: ExportFont("materialdesignicons-webfont.ttf", Alias = "MaterialFontFamily")]
namespace MyApp.Core
{
    public partial class App
    {
...

It should be enough to add the MyApp assembly to your Xamarin.Forms.Forms.Init() call in your MyApp.UWP/App.xaml.cs:

...
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
...
var assemblies = new List<Assembly>();
assemblies.Add(typeof(App).GetTypInfo().Assembly);
Xamarin.Forms.Forms.Init(e, assemblies);
...

Solution 2: The ExportFont attribute is in a separate assembly

If solution 1 increases your startup time or crashes the app at startup (which happened to me), you have to put the embedded resource and the ExportFont attribute into a separate project and pass this assembly to the Xamarin.Forms.Forms.Init call. To do this, I just created a new netstandard project, moved the font from the core XF project as embedded resource and added this single file:

using Xamarin.Forms;

[assembly: ExportFont("materialdesignicons-webfont.ttf", Alias = "MaterialFontFamily")]
namespace MyApp.Fonts
{
    public class Fonts
    {
        // empty on purpose
    }
}

Then in the OnLaunched of your MyApp.UWP/App.xaml.cs use the same code as above, but change the typeof(App) to typeof(Fonts.Fonts) and there are your icons!

norton287 commented 3 years ago

@bruzkovsky

Will this work with FontAwesome OTF font files? That's what I am mainly using for my font images now.

Thanks for the feedback

John

bruzkovsky commented 3 years ago

@norton287 sorry that I can't tell you, I'm not using an OTF file. I don't see why it should not work, though, just try it out?

norton287 commented 3 years ago

@bruzkovsky Does not work with OTFs at all I'm afraid to say.

bruzkovsky commented 3 years ago

@norton287 I suggest you file a separate ticket for OTF files with a small repro project, so that the XF team or some other good soul can fix it.

activa commented 3 years ago

@bruzkovsky

Will this work with FontAwesome OTF font files? That's what I am mainly using for my font images now.

Thanks for the feedback

John

You could simply use the FontAwesome TTF files. That's what I do and it works great on all platforms.

shugaoye commented 3 years ago

I have the same issue when I use this GitHub project. It can work in UWP release build now using this workaround. Xamarin.Forms.FontAwesome