zulip / zulip-mobile

Zulip mobile apps for Android and iOS.
https://zulip.com/apps/
Apache License 2.0
1.3k stars 654 forks source link

Solution found: Newer Unicode emojis don't render on older Android devices #3885

Open chrisbobbe opened 4 years ago

chrisbobbe commented 4 years ago

Older Android devices are missing newer Unicode emoji; they just show up as empty squares. I'm mostly sure this is the same issue as https://github.com/zulip/zulip-mobile/issues/3181, but that one is mostly screenshots, and I'd like to start fresh with some (hopefully clear) steps to a solution at the top.

To use the Android EmojiCompat library would be the best solution if React Native supported it. Without support, we'd be left to do a lot of imperative string processing to get it to work, and probably make our own wrapper of Android's native TextView component, and we'd get in the way of the React Native layer by doing this. See the React Native feature request here.

So, without that, we can ask the app to use an emoji font of our choosing for all of its Unicode emoji. We considered using it as a fallback font, just to fill in what's missing, but the inconsistency in style between the system font and the new font would be jarring, so it's preferable to use the new font for all Unicode emojis. We'd like to try using the Noto Color Emoji font, as mentioned by @raphlinus (thanks Raph!) in the RC realm (link accessible only to users in that realm). Since it's a large font (around 9 MB), we'd like to load it dynamically instead of shipping it with the app.

We've found a way to do that, which should work with compatibility back to Android API version 14, inclusive, using Downloadable Fonts.

We don't see documentation in React Native about its support for Downloadable Fonts, so I'll refer directly to the commit (https://github.com/facebook/react-native/commit/fd6386a07eb75a8ec16b1384a3e5827dea520b64 on PR https://github.com/facebook/react-native/pull/24595) that introduced it, included in React Native versions 0.60.0 and above. (This is a second attempt; the history shows a first attempt in https://github.com/facebook/react-native/commit/f01c4e2a14c194c7a02bc5afe1900573af02b0c7 on PR https://github.com/facebook/react-native/pull/23865, but that was reverted in https://github.com/facebook/react-native/commit/eb40b09bfd0e617912663fb056d0bdea85ce0c2f.)

So, let's try:

  1. Await the upgrade to React Native 0.60.0; this is already in progress. 🙂
  2. As directed in a comment at https://github.com/facebook/react-native/pull/24595/commits/fe3dd73ee196e06c84c035fd524cace3dffca802#diff-d4141c42bc6789637b6fdc7754ec1dd9R86-R92, we need to put some XML in the res/font folder to identify the Noto Color Emoji font. An Android developer guide describes what to put there. 2.a. It shows that we need the Android Support Library 26; we don't have to do anything here because we're using 28. 2.b. We can optionally pre-declare the font in the manifest to mitigate delays in the initial load of the font.
  3. Then, I believe (again, from https://github.com/facebook/react-native/pull/24595/commits/fe3dd73ee196e06c84c035fd524cace3dffca802#diff-d4141c42bc6789637b6fdc7754ec1dd9R86-R92, and also from a tester app modified at https://github.com/facebook/react-native/pull/24595/commits/fe3dd73ee196e06c84c035fd524cace3dffca802#diff-fa16d6c913409ad4467bc9a55506815fR50 in that same commit), we can do ReactFontManager.getInstance().addCustomFont(this, "NotoColorEmoji", R.font.NotoColorEmoji); in public void onCreate in /android/app/src/main/java/com/zulipmobile/MainApplication.java.
  4. We can then change the CSS in the MessageList WebView to use the font. Since it's an emoji font, we expect that it only has glyphs for emojis themselves, and that regular text will still be rendered with the system font. (@WesleyAC)
  5. And we can style the React Native components that use emoji (the emoji picker and reactions list, possibly others) to also use the font.

Then: 🪀🧱🦙🦞🪗!

gnprice commented 4 years ago

The RN upgrade is complete! So it should now be possible for us to try this solution.