App
App copied to clipboard
[$1000] Standardize on single fontFamily names across platforms
Problem
Coming from this discussion, react-native-asset let's us easily link and manage assets, including fonts. However, it fails to provide a cross platform way to use font typeface modifiers such as fontWeight and fontStyle in combination with a custom fontFamily name, in both iOS and Android, which in turn results in keeping multiple font-families such as, ExpensifyNewKansas-Medium, ExpensifyNewKansas-MediumItalic instead of a single ExpensifyNewKansas font-family.
iOS seems to work out of the box as long as we use the postScript name for the font. However, android uses the font filename which results in the different fontFamilies above.
Why is this important
Ease of importing new fonts and keeping/maintinaing a single font type-face.
Solution
Update react-native-asset to support XML fonts in android and auto-group font families into XML fontFamilies.
cc @roryabraham
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~0165fabbe62a87ed20
- Upwork Job ID: 1641731454588358656
- Last Price Increase: 2023-03-31
cc @Luke9389 for visibility
nice!
Love it! Thanks y'all
No update yet
Sorry for the delay here. I'm going to make this a weekly, but my plan here is to:
- Create a couple simple demo React Native projects to show the difference between the "old" way of bundling fonts that we use today vs the "new" way (i.e: Android xml fonts)
- Then create an issue in https://github.com/unimonkiez/react-native-asset to show the "before" and "after" that explains what we would expect react-native-asset to do, given font assets in the top-level assets directory.
- Once that is done, we can re-group, but it's likely I would want to pass this off to an expert contractor (or even better, hire the react-native-asset maintainer directly) to do the actual implementation. I think I could implement it, but I just don't know when I'll have enough time.
I think that sounds great @roryabraham. Thanks for the update
No update this week :(
No update again
Sorry, still no update here.
No update, won't prioritize until after ECX at the earliest. If we could very clearly state our goal here we could pass this off to an agency, which has been my intention since the start
I've held onto this for too long and I've been struggling to make time for this. Given that I have several other higher-priority initiatives, I'm going to drop this for now.
Should we make this external? Other contributors can propose a fix to react-native-asset
Asked callstack here
Hi, I'm Fábio from Callstack and I would like to work on this issue.
Update: Regarding to this issue, I will start investigation today and will keep you updated here once I have a proposal.
Thanks for the update @fabioh8010!
Update: Did some investigation and tests to validate the idea, I expect to provide a proposal on Monday.
Update: Proposal being reviewed internally, also exploring one alternative solution.
Proposal
Please re-state the problem that we are trying to solve in this issue.
iOS and Android have different ways of handling custom fonts on RN. While iOS has a more robust way to "query" the fonts available to use, in Android we have to rely on the font's file name to be able to use that custom font. In this way, it's difficult to have a cross-platform configuration that satisfies both platforms.
What is the root cause of that problem?
As stated in this issue, Android has a different logic to manage fonts related to iOS, requiring the developer to rely on the font file's name to be able to use the font properly in the application.
In Android, we have the ReactFontManager.java file that manages font typeface's cache and registry, and there is a logic to find the correct font file based on the fontFamily provided, an extension and the file extension itselt (.ttf or .otf). In fact, there is indeed a logic to determine if the font is bold or italic based on its name. For example, if you set fontFamily to Lato and fontWeight to bold and you have a font file called Lato_bold.ttf, the logic will correctly choose this file to use for the bold font you specified.
The problem is that this logic is flawed as it only works if the font file name have a specific and uncommon format, and it don't cover other font weights.
What changes do you think we should make in order to solve the problem?
We propose to go with the CLI improvement, making it execute the steps described here in an automatic way. We are going to do this in the following steps:
- When the CLI is run, search for the font files that were placed in the project.
- For each font file:
- Run
fontnamenpm package or similar tool to get the font’s information. - Get the font's information like font style and weight, by either:
- Reading the file metadata and extracting this info (if possible).
- Guessing the font style and weight by the font's file name.
- Run
- When all fonts are scanned, build a map with all different font families found.
- For each font family:
- Rename the corresponding font files and copy to android’s folder.
- Create a XML file with all variants for this font family (we can use
fast-xml-parsernpm package). - Use regular expressions in the
MainApplication.javafile to find and insert the import and theaddCustomFont()method to register that font family.
- Make a PR to react-native-asset library.
- When merged, use this tool in Expensify's project and make a PR with the changes.
What alternative solutions did you explore? (Optional)
We thought about making an improvement directly in the RN repo, improving ReactFontManager's logic to detect the fonts in a better way than the current one (using common suffixes for these fonts), but we ended up sticking with the CLI solution as we think it will provide a safer approach to use the fonts in a cross-platform way.
@fabioh8010 That sounds great to me 👍🏼
I've contributed to react-native-asset before so can help review.
Agreed! The steps above sound good! Let's get it started!
Great! I'll start development tomorrow and will keep you updated here.
Job added to Upwork: https://www.upwork.com/jobs/~0165fabbe62a87ed20
Triggered auto assignment to @sakluger (External), see https://stackoverflow.com/c/expensify/questions/8582 for more details.
Triggered auto assignment to Contributor-plus team member for initial proposal review - @mollfpr (External)
Current assignees @roryabraham and @luacmartins are eligible for the External assigner, not assigning anyone new.
In order to achieve cross-platform compatibility for custom fontFamily names with fontWeight and fontStyle modifiers, we can follow the steps below:
Rename the font files to match the desired fontFamily name, for example, "ExpensifyNewKansas-Regular" for the regular weight.
In the react-native.config.js file, add the following code snippet:
module.exports = { assets: ['./src/assets/fonts/'], ios: {}, android: { sourceDir: './android', fontFamily: 'ExpensifyNewKansas', fontWeight: { Regular: '400', Medium: '500', Bold: '700', }, fontStyle: { Italic: 'italic', }, }, };
Here, we have added "fontFamily", "fontWeight", and "fontStyle" properties to the Android configuration.
Modify the styles as follows: const styles = StyleSheet.create({ textRegular: { fontFamily: Platform.OS === 'android' ? 'ExpensifyNewKansas-Regular' : 'ExpensifyNewKansas', fontWeight: Platform.OS === 'android' ? '400' : 'normal', fontStyle: 'normal', }, textMedium: { fontFamily: Platform.OS === 'android' ? 'ExpensifyNewKansas-Medium' : 'ExpensifyNewKansas', fontWeight: Platform.OS === 'android' ? '500' : 'bold', fontStyle: 'normal', }, textBoldItalic: { fontFamily: Platform.OS === 'android' ? 'ExpensifyNewKansas-Bold' : 'ExpensifyNewKansas-BoldItalic', fontWeight: Platform.OS === 'android' ? '700' : 'bold', fontStyle: 'italic', }, });
In the above code, we use the Platform module to differentiate between iOS and Android and set the appropriate font family, fontWeight, and fontStyle properties. This allows us to use a single fontFamily for all weight and style variations, including custom names with modifiers.
By following these steps, we can achieve cross-platform compatibility with custom fontFamily names in combination with fontWeight and fontStyle modifiers. I wish hope you are doing well [email protected]
📣 @luckchain007! 📣
Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork. Please follow these steps:
- Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
- Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
- Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details.

Format:
Contributor details
Your Expensify account email: <REPLACE EMAIL HERE>
Upwork Profile Link: <REPLACE LINK HERE>
Or, While react-native-asset provides a convenient way to manage assets, including fonts, it does not offer a cross-platform solution for using font typeface modifiers with custom fontFamily names. This can result in having to create multiple font families, each with a different name, in order to use different font weights and styles.
In iOS, using the postScript name for the font works out of the box and allows you to use font typeface modifiers with a custom fontFamily name. However, in Android, the font filename is used instead of the postScript name, which can lead to the creation of multiple font families.
To achieve a consistent font family name across both iOS and Android, you can modify the font files to include the necessary information in their filenames. For example, you can add "-Regular", "-Medium", "-Bold", or "-Italic" to the font filename to indicate the font weight or style. This will ensure that the correct font is used on both platforms, without the need to create multiple font families.
Alternatively, you can use a third-party library, such as react-native-vector-icons, which offers cross-platform support for font typeface modifiers with custom fontFamily names. This library provides a wide range of icons, as well as support for custom fonts, and allows you to easily use font typeface modifiers with a custom fontFamily name on both iOS and Android.