Using custom fonts in Android applications have always been a bit of a pain. Instead of being able to set fonts by XML, it was necessary to write code to set the desired font in a widget.

To circumvent this problem, I had been using the Calligraphy library for the past couple of years, as well as embedding those fonts inside the application.

At last, Android 8 (API level 26) introduced a native solution to this problem. This feature is also supported on devices till Android 4.1 by using Support Library 26 or more.

Reference embedded fonts

It was surprisingly not easy to find some proper steps to achieve this in Xamarin hence the writing of this blog post.

The natural way to use a custom font is to include it inside the application bundle. Android Studio comes with a wizard to do this, but unfortunately we do not have this luxury in Visual Studio. It is not a big issue though as doing it manually is pretty straightforward.

Emmbbed the font in the application bundle

  • Get your font file ready or download one from Google Fonts for example the Modak
  • Create a folder named font under the Resources folder.
  • Put the font file inside it and ensure that there are no space in the file name like : modak_regular.ttf.
  • Ensure that the file’s build action is set to AndroidResource.

Create a font family file

A font family file is necessary to reference the font. It consists of a collection of font elements which defines the font style or font weight.

  • Still inside the font folder create a new xml file and give it a name like : modak.xml.
  • Ensure that the file’s build action is set to AndroidResource.
  • Edit the newly created xml by taking inspiration on the file below.
    <?xml version="1.0" encoding="utf-8"?>
    <font-family xmlns:android="http://schemas.android.com/apk/res/android"
                 xmlns:app="http://schemas.android.com/apk/res-auto">
        <font android:font="@font/modak_regular"
              android:fontStyle="normal"
              android:fontWeight="400"
              app:font="@font/modak_regular"
              app:fontStyle="normal"
              app:fontWeight="400" />
    </font-family>
    

Use the font

Finally use the font in any widget by referencing the font family created above.

<TextView
  android:text="My text content"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:fontFamily="@font/modak" />

Of course embedding a font makes the application bigger and if lots of applications on the user’s device uses the same font he gets them several times for nothing. That is why Google introduced downloadables fonts.

Reference downloadable fonts

The implementation of downloadable fonts in Android is pretty simple and can be summed up like this : A font provider like Google Fonts has the font we want to use. In order to use it, we need to tell Android which font it is and from which font provider to get it.

Define the font

  • Inside the font folder, create a new xml file for exemple : modak.xml.
  • Ensure that the file’s build action is set to AndroidResource.
  • Copy the following xml inside the newly created file.
    <?xml version="1.0" encoding="utf-8"?>
    <font-family xmlns:app="http://schemas.android.com/apk/res-auto"
            app:fontProviderAuthority="com.google.android.gms.fonts"
            app:fontProviderPackage="com.google.android.gms"
            app:fontProviderQuery="Modak"
            app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
    </font-family>
    

The font provider in this case is Google Fonts. If you need to use another font provider, you will need to update the values above accordingly.

Define the font provider certificates

If you are using the support libraries, it is necessary to declare the certificates of the font providers.

The exemple below is for Google Fonts. If you have other providers you will need to add or update values in accordingly.

  • Under the Resouces/values folder, create a new font_certs.xml file.
  • Ensure that the file’s build action is set to AndroidResource.
  • Copy the following xml inside the newly created file.
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <array name="com_google_android_gms_fonts_certs">
            <item>@array/com_google_android_gms_fonts_certs_dev</item>
            <item>@array/com_google_android_gms_fonts_certs_prod</item>
        </array>
        <string-array name="com_google_android_gms_fonts_certs_dev">
            <item>
                MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
            </item>
        </string-array>
        <string-array name="com_google_android_gms_fonts_certs_prod">
            <item>
                MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
            </item>
        </string-array>
    </resources>
    

How did I got this values ? From a newly Android native project using custom fonts. The certificate are always the same so no worries in copy pasting.

Declare the downloadable fonts

Up until now, we have defined a downloadable font and the necessary certificates. But Android still does not know how to automatically download the font. To achieve this a little more work is necessary.

  • Under the Resouces/values folder, create a new preloaded_fonts.xml file.
  • Copy the following xml inside the newly created file
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <array name="preloaded_fonts" translatable="false">
            <item>@font/modak</item>
        </array>
    </resources>
    
  • Edit the Android manifest by adding the following metadata inside the application element
    <meta-data
        android:name="preloaded_fonts"
        android:resource="@array/preloaded_fonts" />
    

Do not forget to add your other downloadable fonts inside preloaded_fonts.xml if any !

Conclusion

Using custom fonts in XML requires a bit of initial work. But once done, it is easier than ever. Beside removing the need of writing code, it allows defining fonts inside styles. You can then inherit from those take and enjoy having the fonts defined only once in the application.

Downloadable fonts removes the need to include each and every fonts you need to use. By sharing fonts with all the others applications on the users device, as well as excluding fonts from each application updates, downloadable fonts saves your users bandwidth and storage. So be a good developer and use them if you can !

As always, please feel free to read my previous posts and to comment below, I will be more than happy to answer.

Comments