Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Bug] Updating Embedded Font #11843

Closed
AlleSchonWeg opened this issue Aug 19, 2020 · 13 comments · Fixed by #13554
Closed

[Bug] Updating Embedded Font #11843

AlleSchonWeg opened this issue Aug 19, 2020 · 13 comments · Fixed by #13554

Comments

@AlleSchonWeg
Copy link
Contributor

Description

If you embed a font via
[assembly: ExportFont("fontfile.ttf", Alias = "IconFont")]
all works correctly. But if you you update the fontfile in your project, add a new glyph for example, then the new glyph is not shown. Only the rectangle placeholder.
I only tested with android, but perhaps this problem exists also in ios.

Expected Behavior

New glyph in updated fontfile should be available.

Actual Behavior

Label show only the rectangle placeholder.

Basic Information

  • Version with issue: 4.8
  • Last known good version:
  • IDE: VS 2019
  • Platform Target Frameworks:
    • iOS:
    • Android:
    • UWP:
  • Android Support Library Version:
  • Nuget Packages:
  • Affected Devices:

Screenshots

Reproduction Link

Workaround

On Android delete AppData.

@AlleSchonWeg AlleSchonWeg added s/unverified New report that has yet to be verified t/bug 🐛 labels Aug 19, 2020
@AlleSchonWeg AlleSchonWeg changed the title [Bug] Update Embedded Font [Bug] Updating Embedded Font Aug 19, 2020
@jsuarezruiz jsuarezruiz removed the s/unverified New report that has yet to be verified label Aug 27, 2020
@samhouts samhouts added this to the 5.0.0 milestone Aug 31, 2020
@AlleSchonWeg
Copy link
Contributor Author

AlleSchonWeg commented Sep 24, 2020

Somebody knows any better workaround? Because deleting appdata is no good idea if you releasing an app.

@solomonfried
Copy link

Is there any known workaround?

Your issue has been open since August. It appears in Triage with “Needs Estimate”.

Have you noticed if the issue occurs with apk bundles? I have been releasing aab. I know that the new font file is in the bundle because it gets installed if the previous version is removed first.

I was hoping there was a way to flag a resource as "always install"

Thanks

@samhouts samhouts removed this from the 5.0.0 milestone Nov 2, 2020
@AlleSchonWeg
Copy link
Contributor Author

@samhouts , @rachelkang
Is it possible to prioritise this issue? Because it blocks us from releasing our app.

@solomonfried
Copy link

solomonfried commented Nov 10, 2020

There is a solution to this issue. This worked for me,

The Shared Assembly (where the font resources are included) needs to be added to the Forms.Init call in App.xaml.cs in the UWP project.

Assuming your app is called MyApp
and you have projects something like this..

MyApp
MyApp.iOS
MyApp.Android
MyApp.UWP (Universal Windows)

Edit App.xaml.cs in MyApp.UWP

In the OnLaunched method, before Forms.Init, add the following....

protected override void OnLaunched(LaunchActivatedEventArgs e)
 {
            var assembliesToInclude = new List<Assembly>
            {
                // .. whatever assemblies you may have now for adding 3rd party controls..

                // Add the Assembly of your applications Shared App.
                 typeof(MyApp.App).GetTypeInfo().Assembly
             }

              Forms.Init(e, assembliesToInclude);
              
}

Your ExportFont should work like it does on Android and iOS

@AlleSchonWeg
Copy link
Contributor Author

Hi @solomonfried ,

this did not work for my with android (I don't use UWP). I used this:

  protected override void OnCreate(Bundle savedInstanceState)
     {
 		....
 		global::Xamarin.Forms.Forms.Init(this, savedInstanceState, typeof(xxx.App).GetTypeInfo().Assembly);
 		LoadApplication(new App());
 	}

and a colleague created a new PR with an additional icon in our custom font. The new icon is not shown. Only reinstalling the app works. Then the icon appears.

@solomonfried
Copy link

solomonfried commented Nov 11, 2020

Hi @solomonfried ,

this did not work for my with android (I don't use UWP). I used this:

  protected override void OnCreate(Bundle savedInstanceState)
     {
 		....
 		global::Xamarin.Forms.Forms.Init(this, savedInstanceState, typeof(xxx.App).GetTypeInfo().Assembly);
 		LoadApplication(new App());
 	}

and a colleague created a new PR with an additional icon in our custom font. The new icon is not shown. Only reinstalling the app works. Then the icon appears.

My apologies. I confused 2 separate ExportFont issues that I was following.

For the issue of having to remove and reinstall the app in order to show glyph changes, have you tried renaming the FontFile? (e.g. add a number to the end) Then change the [ExportFont] attribute to reflect the change. I would assume that that would have to create a new Embedded Resource which should resolve the issue.

This is not a long term solution, but might get you through releasing your app now.

@AlleSchonWeg
Copy link
Contributor Author

Hi @solomonfried ,
this did not work for my with android (I don't use UWP). I used this:

  protected override void OnCreate(Bundle savedInstanceState)
     {
 		....
 		global::Xamarin.Forms.Forms.Init(this, savedInstanceState, typeof(xxx.App).GetTypeInfo().Assembly);
 		LoadApplication(new App());
 	}

and a colleague created a new PR with an additional icon in our custom font. The new icon is not shown. Only reinstalling the app works. Then the icon appears.

My apologies. I confused 2 separate ExportFont issues that I was following.

For the issue of having to remove and reinstall the app in order to show glyph changes, have you tried renaming the FontFile? (e.g. add a number to the end) Then change the [ExportFont] attribute to reflect the change. I would assume that that would have to create a new Embedded Resource which should resolve the issue.

This is not a long term solution, but might get you through releasing your app now.

Thanks. Renaming the updated fontfile works. I changed the name to fontfile_1.ttf and the attribute to [assembly: ExportFont("fontfile_1.ttf", Alias = "IconFont")]. No need to change the alias.

@tringert
Copy link

Thank you @solomonfried you saved my day! Renaming was the solution!

@ChristopherStephan
Copy link

Another workaround is to include the font files in the platform projects and mark them as AndroidAsset/BundleResource.

@juwens
Copy link

juwens commented Mar 30, 2021

I developed this:

public static void DeleteFontCacheIfFontChanged()
{
    var assembly = typeof(App).Assembly;
    var exportFontAttribute = assembly.GetCustomAttributes(typeof(ExportFontAttribute), true).FirstOrDefault() as ExportFontAttribute;
    
    if (exportFontAttribute == null) return;
    
    string? fontFilePath = null;
    if (Device.RuntimePlatform == Device.Android)
    {
        fontFilePath = Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, exportFontAttribute.FontFileName);
    }
    else if (Device.RuntimePlatform == Device.UWP)
    {
        fontFilePath = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, "fonts", exportFontAttribute.FontFileName);
    }
    else if (Device.RuntimePlatform == Device.iOS)
    {
        // TODO
    }
    
    if (fontFilePath == null || !File.Exists(fontFilePath)) return;
    
    var deleteFile = false;
    
    var asmName = assembly.GetName().Name;
    using (var embeddedStream = assembly.GetManifestResourceStream(asmName + ".Resources.Fonts." + exportFontAttribute.FontFileName))
    using (var fileStream = File.OpenRead(fontFilePath))
    {
        var embeddedFontHash = GetHash(embeddedStream);
        var cachedFontHash = GetHash(fileStream);
    
        deleteFile = !embeddedFontHash.SequenceEqual(cachedFontHash);
    }
    
    if (deleteFile)
    {
        Debug.WriteLine($"deleting '{fontFilePath}'");
        File.Delete(fontFilePath);
    }
    
    static byte[] GetHash(Stream stream)
    {
        using (SHA256 hashAlgorithm = SHA256.Create())
        {
            byte[] data = hashAlgorithm.ComputeHash(stream);
            return data;
        }
    }
}

@juwens
Copy link

juwens commented Mar 30, 2021

Any idea how I can add iOS to my code?
I didn't find the file on the disk

@Seuleuzeuh
Copy link

Thanks @juwens for the workaround, it work greats (for an Android App).

I've adapted it to work with multiple EmbeddedFont.

@zain442
Copy link

zain442 commented Nov 30, 2021

juwens where did you add that code?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants