You’ve probably finished developing the React Native app and are ready to release it. So what else do you need to prepare for your app launch? I don’t mean answers like “Make sure the test passes” or “Do the smoke test several times.” Obviously you need to do “push to AppStore and Android AppStore”, but is that all there is to it?
At Infinite Red, we release React Native apps all the time, so we’re well aware of the pitfalls. So let’s share our experience with you! Hopefully this experience will help you launch your app more smoothly.
-
Remove the console logs
-
The compressed image
-
Remove Android’s default permission Settings
-
Consider using ProGuard and Hermes
-
QA inspection
-
Check startup speed
-
Protect your App from cracking
-
Restart the ATS.
1. Remove the console. Logs
As you probably know, including console logs slows React Native apps down, and you should remove them before publishing. You can of course erase logs with find and replace, but some logs can provide useful debugging information and may need to be kept in the code, we just need to remove them from the production version. That’s what we’re going to do.
Commonly used method
The React Native documentation recommends using Babel:
npm i babel-plugin-transform-remove-console --save-dev
Copy the code
You can then set.babelrc to remove all logs from your code or only work with the production version (as in the example below).
The other way
Dev mode sets the __DEV__ variable to true. You just put the following code into index.js and you can use it to turn off logging. You can do the same with.error and other console output.
Q: Will if (__DEV__) be removed by Metro in the release? A: I’ve tried, but I can’t. This check is also used in many other places to check for releases.
One advantage of this approach is that you can replace the original log code with something else you might need. For example, if you need to report error or warning for background analysis, you can replace error and warning with event reporting code.
Either way, make sure you don’t keep console.logs as they slow down your app!
2. Compress the image
You may have done automatic optimization of app resource files, but we want to be able to optimize images to minimize package size. I usually use squoosh.app and drag each image up for verification and visual inspection. This allowed me to test multiple compression methods and confirm that the image quality was not compromised. This also helps me find out if any images have been zoomed in or deleted incorrectly.
Left manuscript – right optimization result: no obvious difference!
Most of my images are optimized, but one is not optimized at all! All images were optimized to reduce the file size by 49%.
Images are easy app resources to work with, but if your app uses other resource files (e.g. PDFS, AI models, pre-loaded data), be sure to optimize them as well.
Reducing the size of your app speeds up your UI launch!
3. Remove the default permissions on Android
You may not have added Android permissions when you built your app. React Native projects don’t typically start with zero permissions. By default, the Android portion of an RN project has the following permissions:
-
Internet – You usually need this
-
System Alert – Debug mode is required
-
Read phone State — Don’t understand why this is also the default
-
Read and Write External Storage – You usually need this as well
-
Check License – If no, +1
You can delete some of them. Since it is not explicitly listed, it can be tricky to deal with, and official documentation can help.
4. Consider ProGuard and Hermes
Both Hermes and ProGuard can improve app performance, but require extensive testing.
ProGuard
If you haven’t turned ProGuard on yet, you may be missing out on opportunities to optimize, obfuscate, and slim down versions of Android. RN does not turn ProGuard on by default. Once ProGuard is turned on you need to run all the tests to see if there are any problems. Some problems (like this one) are due to ProGuard not being configured properly. Keep in mind that by default, opening ProGuard can only be tested in a release version of Android. This can cause problems for your tests.
As a reminder, connect to your Android device and then run yarn/NPX react-native run-Android –variant = release to make sure everything is correct
React Native opens the ProGuard document
When you open ProGuard, you can also try opening “shrinkResources,” which means shrinking any external libraries. ⚠_ This configuration is tested in the release _! Opening “shrinkResources” can completely mess up your app image, so don’t do it blindly.
Hermes
Facebook announced Hermes in Chain React 2019 and added iOS Hermes support in version 0.64. Once Hermes is enabled, RN will compile the JS bundle into bytecode and then package it into the App. The bytecode loading speed will greatly improve the app startup speed! Anyone who has used a Flutter should know this. It’s easy to open Hermes, but you can’t guarantee that it will work with your app. Some Native Modules are bundled with JSC, but Hermes is well worth a try if possible.
How to open Hermes
Note: Hermes may be easy to open on different versions, but it may not work at all. Note that Proxy support was not provided in earlier versions of Hermes, so using MobX 5 (but MobX 4 is also available), Immer and even Amplify’s app will not be able to use Hermes. Check that the React Native version you are using corresponds to the Release Notes of Hermes.
5. QA
It has become increasingly important for any development to conduct in-depth quality checks prior to release. No matter how much you test on the development build, there are always new issues with the production build. As long as you force yourself to go through everything before Posting and see what’s missing, you’ll get better and better at catching them.
I can crop features to get the app released, but I can’t skip pre-release QA. At the very least, you need to walk through the App from every Angle to see possible problems and highlights.
Especially if you have ProGuard on, permissions adjusted, or Hermes enabled, it’s important to fully test every screen. Automated tests can catch crashes, but we need to take a deeper look.
As you complete each check, don’t forget to open Perf Monitor from the development menu. We need to find where the JS FPS drops below 24 frames and make sure there is no slow leakage of RAM (i.e., increasing RAM consumption).
If a problem is found on Perf Monitor or in any check, and you can reproduce the problem, that means you have found a good problem to try profiling.
When checking your app, do not test in a staging environment, but in a production environment. If you can only use a staging or test environment, make sure you switch to production before releasing your app.
Small screen and big screen
Test on devices that support the smallest screen sizes, and keep the display area smaller. For iOS, open the “In-Call Status Bar” (on an emulator without bangs). This limits the available space of your application.
When checking small-screen devices, test the input form and test all KeyboardAvoidingView locations. You can decide not to support the device, but you shouldn’t make that decision after you see the problem.
Then there are the big screen devices. At this point, you need to pay attention to whether the finger can reach the controls at the edge of the App. Also watch out for image quality and layout distortion.
Network condition
The test network is “almost unavailable” and “completely unavailable.” The “network is completely unavailable” condition is a mandatory test. Your app may need to deal with occasional disconnections. Try to create this when you test.
On a Mac, Network Link is used to control the Network.
Accessibility (A11y)
Make sure your app has accessibility tags and reminders in place. You may not be familiar with this area. So that you can take time to read the React Native the org.eclipse.swt.accessibility] (reactnative. Dev/docs/access…
On iOS, set the system text to a larger size and see if the app’s key text displays are scrambled. Adding fonts will definitely cause some text in your app to fail to display properly, but it’s good to know what’s going on with your app’s text display.
If you see this problem in your app, you can try to fix it, or set allowFontScaling={false} to Text.
Finally, check it on the real phone, lower the screen brightness, and start the app. This will help you identify any lack of contrast that someone with poor vision may be experiencing. I should mention that I have an app on my iPhone called “Unfollow” that has too poor contrast in Dark mode to work in any Dark place at all.
6. Check the startup speed
As of this writing, unless Hermes is enabled, the entire JavaScript package must be loaded before the app can be launched. If your app has a time-consuming Component, the entire app will wait for it to load. If your app has a lot of screens, the app will wait until all the screens have loaded before the first screen is displayed.
These problems are not so difficult to solve if they are considered from the outset. But if you wait until the last minute to think about these issues before launch, you could be in trouble.
Checking Bundle size
Generating JavaScript bundles from the command line makes it easy to quickly check file sizes. These two commands should work:
# Generate your Android production bundle (just code no assets)$ yarn react-native bundle --platform android --dev false --entry-file index.js --bundle-output ./index.android.bundle# Generate your iOS production bundle (just code no assets)$ yarn react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ./index.ios.bundleCopy the code
If less than 10MB, your app is great! If you reach 50MB, you should consider using RAM Bundles. RAM Bundles are particularly useful for screens that are not in a hurry to load or may never load. This can greatly reduce the load time of your app.
Use the Inline the Require
Import causes the Module to load immediately, and require helps delay module loading. If your app has a component that is very time-consuming but does not need to start the app, consider loading the component with inline require, which will speed up the app launch. Inline require is supported since version 0.59 of RN.
FaceBook is currently experimenting with a new Metro configuration that automatically changes all imports to inline require.
Open metro.config.js to make sure inlineRequires is enabled. Apps with complex structures should see good improvements.
Split the ABI to reduce the APK size
You can compare the size with other apps’ APK packages. The average Google Play APK is 11.5MB, but there are plenty of apps larger than 30MB. You can reduce the size of APK through ABI splitting.
APK supports a wide range of mobile hardware architectures, and ABI splitting lets you build multiple APKs, each for a specific hardware architecture, as well as more detailed APKs based on screen resolution.
React Native comes directly with some ABI options, which can save about 4MB directly from the app. Build a option enableSeparateBuildPerCPUArchitecture gradle, by default it is set to false. If enabled, you get two APKs, one for ARM and one for x86 devices. Upload them all to Google Play, and different phones will get the right package.
7. Protect the App
At this point, you’ve tested your app for problems, and you’re almost ready to launch. But you can’t just release it, there’s a crucial step.
You probably already use something like App Center or Firebase Crashlytics. This will report all application crashes to you. We should talk a little bit more about crashes.
Exit gracefully is an often overlooked but crucial requirement. Most apps are great when they work, but when something goes wrong they flip the table and leave.
By default, a crash in the React Native app shuts down the app directly, leaving users staring at the home screen. WTF? Many users repeatedly tap the app icon to make sure their fingers are working correctly and that they are not confused.
We need to let the app handle this to avoid creating a non-traumatic user experience.
Gotta Catch ’em All
Now you need to search your code for any toDos left behind in comments to make sure you haven’t left anything important behind.
More importantly, search your code for things that might go wrong and handle errors you don’t want your users to see. In all JS Promises there should be a “catch”, wrapped in a “try” when invoking third party services. It is acceptable for one function to fail, but it is not acceptable for the entire app to shut down and lose data.
I know anomalies don’t come up very often, but they do. You need to catch the exception and keep your app running. Users are not QA, and they don’t want to experience app crashes.
Make sure to provide crash information to users
When a fatal JavaScript or Native bug occurs in a production version, not only do you need to collect crash site and analytics data, but you also need to let users know that something is wrong with your app.
I usually use the React Native Exception Handler. The library provides the location of the offending code, and you can even display a nice apology message to the user if the error is in the JavaScript layer rather than the Native layer.
If you use global exception handling hooks, you should set the third parameter to true. This way, when errors come from the Native layer, you can still run some JavaScript code, but it won’t show up on the UI.
8. Restore the ATS
In iOS 9, Apple enabled Application Transfer Security (ATS), a feature that requires any communication to be secured using HTTPS. The ATS prevents connections that do not conform to security specifications. By default, React Native projects add an ATS exception to make it easier to load bundles locally.
Now that your app is ready for release, you may need to remove the exception. This will make it easier for you to pass the App Store review.
The trouble is, the next time you start development, you have to add that back in. Usually, I turn this feature off and release an iOS version, then roll back the changes.
Localhost exception in info.plist, as shown below:
If this seems annoying, honestly, it is! However, you can do this automatically and save yourself a headache. Of course you can use Fastlane to modify info.plist
Voila! Your app is finally ready to launch! 🚢
Ready to release React Native?