Migrating custom fonts from Calligraphy to Android fonts

David Miguel
3 min readJan 21, 2020

--

Photo by John-Mark Smith from Pexels
Photo by John-Mark Smith from Pexels

When we started building Peaks app three years ago the Android framework didn’t provide any straightforward way to work with custom fonts in our XML layout and style files.

The typical solution was to create a custom implementation of TextView adding a new XML attribute for specifying the font and then loading it from the app assets setting it as a Typeface. And repeat this process for any other view where you needed to use custom fonts…

Thankfully, Christopher Jenkins came up with a more elegant approach that didn’t require creating any custom view. Instead, his library Calligraphy used layout inflation injection to add the custom fonts to the views.

The fairly simple setup (almost three lines of code) convinced us to use the library instead of the custom views approach. And it worked really well during all this time.

Meanwhile, in mid-2017 Android 8 was released and in its release notes there was an exciting new feature: Fonts in XML

[…] Which lets you use fonts as resources. This means, there is no need to bundle fonts as assets. Fonts are compiled in R file and are automatically available in the system as a resource. You can then access these fonts with the help of a new resource type, font.

What’s more, the new feature was backward compatible with API versions 14 and higher thanks to the support library.

However, at that time we were pretty full of work and Calligraphy was working fine, so… the migration was lost in the backlog.

Until… some months ago, when we were trying to migrate our app to Android 10 and we were getting a nasty exception:

Calligraphy exception after targeting Android 10 (API 29)

After inspecting the logcat, we found out that Calligraphy was causing the crash. Luckily, by that time the developers of the library had already fixed the issue, but we were still using Calligraphy 2 and the fix was only available in Calligraphy 3.

As we needed to do a small migration anyway, we thought that it was a good moment to try to drop Calligraphy in favor of the native solution. After all, it always feels good to remove third-party dependencies.

The migration

The migration was easier than expected, it took us roughly 1 hour to finish it. The process was the following:

1. Move font files from assets to font folder

Move your font files (ttf or otf) from your assets folder to the font resources folder res/font.

📂/app/src/main/assets
┣ my_custom_font_regular.ttf
┣ my_custom_font_italic.ttf
┗ my_custom_font_bold.ttf
To:📂/app/src/main/res/font
┣ my_custom_font_regular.ttf
┣ my_custom_font_italic.ttf
┗ my_custom_font_bold.ttf

2. Create a custom font family

In your res/font directory, create a new file my_custom_font_family.xml. A font family is a set of font files along with its style and weight details.

Note that we use the app namespace as we are using the support library to ensure backwards compatibility. If you don’t need to support API level < 26 you can use the android namespace instead.

3. Remove Calligraphy dependency

Remove the Calligraphy dependency from your build.gradle and sync the project.

The compiler will point to all the places in your code where the library was used. For example:

error: cannot find symbol class CalligraphyTypefaceSpan
private CalligraphyTypefaceSpan typefaceSpanBold;
^
symbol: class CalligraphyTypefaceSpan

4. Remove Calligraphy code

Remove all the Calligraphy-related code.

a) Remove initialization code in the#onCreate() method of your Application class

b) Remove context wrapper in the #attachBaseContext() method of your BaseActivity class

c) Replace TypefaceUtils and CalligraphyTypefaceSpan class

Note: If you don’t need to support API level < 26, you can use resources.getFont() instead.

Tip: “Replace in Path” from Android Studio (Edit/Find/Replace in Path) may be a handy tool during the migration.

5. Update font declarations in layouts and styles

Finally, we have to update font declarations in our XML files.

a) Layouts

Note: you can specify the fontFamily attribute using the namespace:

  • android: supported from API 16.
  • app: if you need to backport this feature all the way to API 14.

b) Styles

And… migration completed! If you run the app nothing should have changed, but your mind will be more peaceful knowing that you have a third-party dependency less 🙂

References

--

--