我们如何通过一些简单的修复将React Native应用程序的大小减少60%

I work at Mutual, a peer to peer lending Fintech in Brazil. We connect borrowers looking for fair rates to lenders looking for above-market returns. Being a very broad product with a diverse amount of users in a large country, our React Native iOS and Android apps are downloaded by all sorts of devices.

我在Mutual工作,这是巴西金融科技的点对点贷款。 我们将寻求公平汇率的借款人与寻求高于市场收益的贷方联系起来。 作为一个非常广泛的产品,在一个大国家中拥有大量用户,我们的React Native iOS和Android应用程序可以通过各种设备下载。

The majority of those users, however, are on low-end devices. We can see this using Facebook’s device-year-class library which, given a device model, shows in what year it would be considered a high-end device. For example, the most popular phone for our users is the Samsung Galaxy A10, which although was launched in March 2019, would only be considered a high-end phone in 2013. Looking at all user’s devices, 85% of those would only have been high-end in 2015 or before. Because of this, we put a premium on optimizing our app so that even with a limited device, our users can still have a great experience.

但是,这些用户中的大多数都在低端设备上。 我们可以使用Facebook的device-year-class类库来查看此信息,给定设备模型,该库显示了哪一年将被视为高端设备。 例如,最受用户欢迎的手机是三星Galaxy A10,尽管它于2019年3月推出,但在2013年将仅被视为高端手机。从所有用户设备来看,其中只有85%是高端在2015年或之前。 因此,我们非常重视优化应用程序,因此即使设备有限,我们的用户仍然可以拥有出色的体验。

Image for post
Percentage of devices considered a flagship in each year
每年被视为旗舰产品的设备百分比

On that note, we’ve more recently taken a hard look at our app size which was 26.8 MB on Android. While that size isn’t completely out of control, it is definitely above our peer’s median, which the Google Play Console reports as 16.3 MB. Size can be a deal-breaker for users who have limited data plans or little to no available disk space and have to choose which apps to keep or uninstall. This is especially important at Mutual since borrowers have to pay their monthly installments through the app. When a borrower uninstalls the app, their chances of paying on time decreases drastically, directly impacting investors’ returns in our marketplace.

关于这一点,我们最近对我们的应用程序大小进行了仔细研究,Android上的应用程序大小为26.8 MB。 尽管该大小并没有完全失控,但绝对高于我们同行的中位数,Google Play控制台报告的中位数为16.3 MB。 对于数据计划有限或几乎没有可用磁盘空间或必须选择要保留或卸载的应用程序的用户来说,大小可能是一个大问题。 这在Mutual尤其重要,因为借款人必须通过该应用程序支付每月的分期付款。 当借款人卸载该应用程序时,按时付款的机会将大大减少,直接影响投资者在我们市场上的回报。

Image for post
Mutual (26.8 MB) is much larger than peers’ apps in the same segment
互助(26.8 MB)比同一个细分市场中的同行应用程序大得多

Not only does app size affect uninstall rates, but it has a great impact on the install conversion rate also. There’s a great article by the Google Play team on the subject where they show the importance of shrinking your app.

应用程序的大小不仅会影响卸载率,而且还会对安装转换率产生很大影响。 Google Play团队有一篇很棒的文章 ,主题显示缩小应用程序的重要性。

For every 6 MB increase to an APK’s size, we see a decrease in the install conversion rate of 1%.

APK大小每增加6 MB, 安装转换率就会降低1%

They go on to reveal that in developing countries, where low-end devices are the norm, this effect is even greater:

他们继续揭示,在以低端设备为标准的发展中国家,这种影响更大:

The removal of 10 MB from an app’s APK size in emerging markets correlates with an increase in install conversion rate by ~2.5%.

在新兴市场中,从应用的APK大小中删除10 MB 可使安装转换率提高约2.5%

Image for post
Install conversion rate increase per 10MB decrease in APK size by country (Google internal data)
按国家/地区划分的APK大小每减少10MB,安装转换率就会增加(Google内部数据)

We were very motivated by the potential improvements to our install conversions and uninstall rates. So we got to work on reducing our app size as much as possible without degrading the user experience. The first step was looking through the official resources available for Android developers.

我们对安装转换和卸载率的潜在改进感到非常兴奋。 因此,我们必须在不降低用户体验的前提下,尽可能减少应用程序的大小。 第一步是浏览可用于Android开发人员的官方资源

Android应用程式套件 (Android App Bundle)

Reading through that page, we are told that the simplest way to reduce app size is to try out the new Android App Bundle (AAB) method of distribution. Up until this point, we were distributing our app by compiling a good old Android Package (APK) file that could be run in most android devices and uploading it to the Google Play Console. An AAB bundle, however, contains only your compiled code and resources. Therefore when you upload it, Google Play itself becomes responsible for generating an optimized APK for each device type, knowing its specifications and CPU architecture.

阅读该页面后,我们得知减小应用程序大小的最简单方法是尝试使用新的Android App Bundle (AAB)分发方法。 到目前为止,我们通过编译一个可以在大多数android设备上运行的旧的Android打包 (APK)文件来分发我们的应用程序,并将其上传到Google Play控制台。 但是,AAB捆绑软件仅包含您的编译代码和资源。 因此,当您上载它时,Google Play本身会负责为每种设备类型生成优化的APK,并了解其规格和CPU架构。

So with a simple change to our build pipeline, we can get a massive size reduction for no cost? Sounds too good to be true!

因此,只需对构建管道进行简单的更改,就可以免费大量减少尺寸? 听起来好得令人难以置信!

After looking through the documentation, all we did was change the React Native Gradle build script to run bundleRelease instead of the current assembleRelease . Just like that, we have our AAB file. After some further modifications to the Fastlane config’s supply action to automatically upload directly to the Play Store, we are good to go and our new reduced release shows up on the Google Play Console.

浏览完文档后,我们所做的就是更改React Native Gradle构建脚本以运行bundleRelease而不是当前的assembleRelease 。 这样,我们就有了AAB文件。 在对Fastlane配置的supply操作进行了进一步修改以直接直接上传到Play商店后,我们一切顺利,新的精简发行版显示在Google Play控制台上。

With just this change we cut 9.1 to 12.4 MB of our delivered APK size. Turns out it was really too good and true!

只需进行此更改,我们便将交付的APK大小减少了9.1至12.4 MB。 原来,这真是太好了真实!

Image for post
Old APK at 26.8MB compared to the new AAB at 14.4 to 17.7 MB
旧APK为26.8MB,而新AAB为14.4至17.7 MB

Be careful though: if you’re using React Native with Hermes, you might have to update your soloader dependency as per this issue or you risk delivering an app with a critical bug to your users. Thankfully we were able to catch this problem by testing in the alpha release track. But it could’ve easily slipped through as it doesn’t show up locally or when you build an APK.

不过要小心:如果您将React Native与Hermes一起使用 ,则可能必须根据此问题更新soloader依赖性,否则您可能会向用户交付带有严重错误的应用程序。 幸运的是,我们能够通过在Alpha版本中进行测试来解决此问题。 但是由于它在本地不显示或在构建APK时可能会轻易漏掉。

使用Android Size Analyzer优化资产 (Optimizing assets with the Android Size Analyzer)

The next suggestion on the list is the Android Size Analyzer. A command-line tool that analyzes an Android app to point out opportunities for size reduction. After running it using the command size-analyzer check-bundle [BUNDLE].aabwe receive a list of large assets and images we can optimize. We are also told to configure ProGuard.

列表上的下一个建议是Android Size Analyzer 。 一种命令行工具,可分析Android应用程序以指出减小尺寸的机会。 使用命令size-analyzer check-bundle [BUNDLE].aab运行它之后,我们会收到一个我们可以优化大型资产图像的列表 我们还被告知要配置 ProGuard

Image for post
The output of the size-analyzer command
size-analyzer命令的输出

保卫者 (Proguard)

Proguard is a tool to shrink, obfuscate, and optimize your Java bytecode. We have not yet explored this avenue, as we’ve read about possible incompatibilities with other Android libraries. As we are looking for quick and easy size reductions, we chose to leave this optimization for the future.

Proguard是缩小,混淆和优化Java字节码的工具。 由于我们已了解到与其他Android库的不兼容问题,因此我们尚未探索这一途径。 当我们寻求快速简便的尺寸减小时,我们选择将这种优化留给未来。

大资产 (Large assets)

Running the command again with a -d flag, we get a list of each asset ordered by size. As the size-analyzer tool doesn’t know our app’s user flow, it lets us decide which ones we can remove or bundle dynamically.

再次使用-d标志运行命令,我们将获得按大小排序的每种资产的列表。 由于size-analyzer工具不了解我们应用程序的用户流,因此它使我们可以决定可以动态删除或捆绑哪些应用程序。

Image for post
List of large assets ordered by size
按大小排序的大型资产清单

The first and largest item is the React Native JavaScript bundle. It is not currently possible to split and dynamically load this, but we will see how we can shrink this later on. Following further down the list of suggestions, we see many large fonts (TTF) and images (JPG and PNG) assets.

第一项也是最大的一项是React Native JavaScript捆绑包。 目前尚无法拆分和动态加载它,但是稍后我们将看到如何缩小它。 在建议列表的下方,我们看到了许多大字体(TTF)和图像(JPG和PNG)资产。

不需要的图片 (Unneeded pictures)

Our attention is immediately drawn to four huge JPG pictures being used in our internal Storybook tool. They added an extra 2 MB of trash to our production APK. What an embarrassing blunder! When things like this happen we feel pretty foolish. But in the complex world of Software Engineering, we all make mistakes. I believe in sharing them with our peers so we can all learn from them. Chances are if you don’t track the growing size of your applications you might be making some of these mistakes too.

我们的注意力立即吸引到我们内部故事书工具中使用的四张巨大JPG图片。 他们在我们的生产APK中添加了额外的2 MB垃圾。 多么令人尴尬的错误! 当这样的事情发生时,我们感到非常愚蠢。 但是在复杂的软件工程世界中,我们都会犯错。 我相信与我们的同行分享他们,以便我们都能向他们学习。 如果您不跟踪应用程序的不断增长,则很可能也会犯一些这样的错误。

字型 (Fonts)

After quickly getting rid of these large pictures, we kept looking at the rest of the list. It’s clear to see that there is an abundance of fonts that were being bundled. After talking to the design team they told us that many old components did not strictly follow the typography guidelines. So we identified which components could be removed and which could use a comparable updated font. With this, we cut down our font usage from six to four.

在Swift删除这些大图片之后,我们继续查看列表中的其余部分。 很明显,捆绑在一起的字体很多。 与设计团队交谈后,他们告诉我们许多旧组件未严格遵循印刷准则。 因此,我们确定了哪些组件可以删除,哪些组件可以使用可比的更新字体。 这样,我们将字体使用量从六种减少到四种。

Another thing we noticed is that our font asset sizes are huge! They are clocking in at almost 670 KB each. which means that our four fonts represent a whopping 2.7 MB of our uncompressed bundle size. Thankfully there is a tool called FontForge which allows us to take a deeper look and modify those font files. Opening these up, we can see that the majority of the asset size can be explained by the expansive Cyrillic script and other unneeded glyphs. We can remove all of these since our app is completely in Portuguese. With this change, we shrunk our font sizes from 670 KB to 70 KB each, a 90% reduction!

我们注意到的另一件事是我们的字体资源很大! 它们每个时钟几乎为670 KB。 这意味着我们的四种字体代表了未压缩捆绑包大小的2.7 MB。 值得庆幸的是,有一个名为FontForge的工具,它使我们可以更深入地了解并修改这些字体文件。 打开这些图,我们可以看到,资产的大部分可以由扩展的西里尔字母和其他不需要的字形来解释。 由于我们的应用程序完全使用葡萄牙语,因此我们可以删除所有这些内容。 通过此更改,我们将字体大小从670 KB缩小到70 KB,减少了90%!

Image for post
Example of some glyphs being included in our fonts
我们的字体中包含一些字形的示例

Removing unneeded fonts and optimizing the remaining ones totaled a 3.8 MB decrease, which translates into a cool 2 MB reduction to the final APK size.

删除不需要的字体并优化其余字体,总共减少了3.8 MB,这相当于最终APK大小减少了2 MB。

Image for post
Image for post
Before and after removing two fonts and optimizing the rest
删除两种字体前后并优化其余字体

优化图像 (Optimizing images)

Taking a look at the remaining images some of them are quite large. We ran a couple of them through an image optimizer tool (tinyjpg) and saw large reductions in size. After that, we decided to optimize all 41 JPG and PNG assets used within our app.

看一下其余的图像,其中有些图像很大。 我们通过图像优化器工具( tinyjpg )运行了其中的几个,并看到尺寸大大减小了。 之后,我们决定优化应用程序中使用的所有41种JPG和PNG资产。

Image for post
Before and after of one of the images we optimized
我们对其中一张图片进行了前后优化

That brought us down from a total of 2.5 MB in image assets to 756 KB, a 70% reduction. However, because the images were not optimized, they were already being compressed in the process of generating the final APK. So, in practice, we only cut 500 KB to the end-user.

这使我们从2.5 MB的图像资源减少到756 KB,减少了70%。 但是,由于未对图像进行优化,因此在生成最终APK的过程中已经对其进行了压缩。 因此,实际上,我们仅削减了500 KB给最终用户。

After this, we realized that we’ve already depleted all of the easy low hanging fruit optimizations. All further asset optimizations would either take a lot more effort or result in only marginal improvements.

此后,我们意识到我们已经耗尽了所有简单的低挂水果优化方法。 所有进一步的资产优化都将花费更多的精力,或者只会带来很小的改善。

优化我们的React Native JavaScript包 (Optimizing our React Native JavaScript bundle)

Now that we are done looking at the native assets, it is time to analyze our JavaScript bundle. This is an especially good thing to optimize for three reasons. Firstly, it reduces the bundle size of our finished APK. Secondly, it also results in a faster app startup as the JS virtual machine needs to parse less code. Finally, and most importantly, it speeds up over the air (OTA) updates that we ship out multiple times a week through CodePush.

现在我们已经完成了对本机资产的查看,现在该分析我们JavaScript包了。 由于三个原因,这是优化的特别好事情。 首先,它减小了我们完成的APK的捆绑包大小。 其次,由于JS虚拟机需要解析更少的代码,因此还可以加快应用程序的启动速度。 最后,最重要的是,它加快了我们通过CodePush每周多次发布的空中(OTA)更新的速度

捆绑分析仪 (Bundle analyzer)

To decide how we will reduce the size of our bundle, first, we need to be able to see what is taking up the most space. For this we will count on another great open-source tool: react-native-bundle-visualizer. Running it against our project, we get a visualization of every folder and dependency of our application and their respective sizes.

要决定如何减少捆绑包的大小,首先,我们需要能够看到占用最大空间的东西。 为此,我们将依靠另一个出色的开源工具: react-native-bundle-visualizer 。 在我们的项目上运行它,我们可以看到每个文件夹以及应用程序的依赖关系以及它们各自的大小。

Image for post
Snapshot of the libraries and folders of Mutual’s front end code base with their respective sizes
Mutual前端代码库的库和文件夹及其各自大小的快照

We can see that the app bundle totals 5.49 MB, with 57.8% of that being from node_modules dependencies, 27.5% from the application code, and the rest the tool wasn’t able to map. The bundling process already removes unused code paths, so what we see here is the code that is actually used by our app. Even so, there is always still room for improvement.

我们可以看到该应用程序包总计5.49 MB,其中57.8%来自node_modules依赖关系,27.5%来自应用程序代码,而其余工具则无法映射。 捆绑过程已经删除了未使用的代码路径,因此我们在这里看到的是我们的应用程序实际使用的代码。 即使这样,仍然仍然有改进的空间。

The biggest dependency that we have is math.js which as the name implies implements many mathematical operations. We shouldn’t need this dependency since we execute all sensitive calculations in the server and only send the results to the app. Taking a closer look at the front end code, the library was being used for some simple operations. Most likely it was used out of habit by a developer who had also worked on the back end code. We quickly extracted these methods from the library and took it into our codebase, removing the dependency entirely. This brought down the bundle size to 4.64 MB. We got a 15.5% reduction from removing one lib!

我们最大的依赖项是math.js,顾名思义,它实现了许多数学运算。 我们不需要这种依赖关系,因为我们在服务器中执行了所有敏感的计算,仅将结果发送到应用程序。 仔细查看前端代码,该库已用于一些简单的操作。 最有可能是出于开发习惯,也曾经从事后端代码的开发人员使用它。 我们从库中快速提取了这些方法,并将其带入我们的代码库,从而完全消除了依赖性。 这使捆绑包大小减小到4.64 MB。 删除一个库,我们减少了15.5%!

As mentioned before, we use Storybook for developing and testing components independently. However, it should only be available in the local and staging environments. No end-user should be able to see it. Because of this, we use an ENVIRONMENT variable to control whether we enable this part of the app. While this works for restricting access, the bundler has no way of knowing the value of this variable. Because of this limitation, all of the Storybook code ends up going to our production bundle.

如前所述,我们使用Storybook来独立开发和测试组件。 但是,它仅应在本地和暂存环境中可用。 任何最终用户都不能看到它。 因此,我们使用一个ENVIRONMENT变量来控制是否启用应用程序的这一部分。 虽然这可以限制访问,但捆绑程序无法知道此变量的值。 由于此限制,所有Storybook代码最终都进入了我们的产品包。

To remedy this, we isolated the import of this section to a single file. Then we created two versions of the file: one that includes Storybook and another one for production that just has a dummy component. To toggle between those when targeting production, we wrote a script that runs before the bundling step that swaps the two files. Through this method we were able to completely remove the Storybook code path from production, eliminating the node_modules dependency as well as all internal code configuring each story.

为了解决这个问题,我们将本节的导入隔离到一个文件中。 然后,我们创建了文件的两个版本:一个包含Storybook,另一个用于生产,仅包含一个虚拟组件。 为了在定位生产时在这些文件之间切换,我们编写了一个脚本,该脚本在交换两个文件的捆绑步骤之前运行。 通过这种方法,我们能够从生产中完全删除Storybook代码路径,从而消除了node_modules依赖性以及配置每个故事的所有内部代码。

Image for post
The updated storybook folder with two versions of the index file
更新的故事书文件夹,其中包含两个版本的索引文件

With both these changes, we were able to bring our bundle size from 5.49 MB to 4.2 MB. Meaning our users will have faster app startup speeds and update downloads.

通过这两个更改,我们能够将包大小从5.49 MB增大到4.2 MB。 这意味着我们的用户将具有更快的应用启动速度和更新下载。

Image for post
Final bundle totaling 4.2 MB in size
最终捆绑包大小总计4.2 MB

After all these improvements, we uploaded our app to the Play Store again. It was now reporting that our final APK size would be between 10.5 to 13.7 MB. An incredible ~60% reduction from our original 26.8 MB! This means we could potentially increase our install conversion rates by 3.75%, as indicated by the Google Play team’s article.

经过所有这些改进之后,我们再次将我们的应用上传到了Play商店。 现在据报道,我们最终的APK大小在10.5至13.7 MB之间。 与我们原来的26.8 MB相比,减少了惊人的60%! 这意味着我们有可能如Google Play团队文章所述将安装转换率提高3.75%。

Image for post
Comparison between our initial APK and the final AAB version with all improvements
我们的初始APK与最终AAB版本之间的比较,并进行了所有改进

总结思想 (Closing thoughts)

As business-oriented Software Engineers, we know that sometimes the best decision for the company is to accumulate technical debt to evolve the product faster. This is especially true in early-stage startups like Mutual that are trying to find their product-market fit. But without monitoring this debt, you could make some big blunders, like bundling 2 MB of testing pictures and using a huge library unnecessarily. Don’t let technical debt get out of control and blow up in your face!

作为面向业务的软件工程师,我们知道有时候对公司而言,最好的决定是累积技术债务以更快地开发产品。 在像Mutual这样的早期初创公司中,尤其是在试图找到适合自己产品市场的公司中,尤其如此。 但是,如果不监控这些债务,您可能会犯一些大错误,例如将2 MB的测试图片捆绑在一起,并不必要地使用庞大的库。 不要让技术债务失控而炸毁你的脸!

It is also common to tunnel vision and let pass by quick and easy opportunities to optimize what you already have. So a good idea is to periodically take a step back. Ascertain that you’re not missing out on quick improvements to the size, speed, or any aspect of your application. It took us only two days to analyze, plan out, and execute all of the above improvements which brought the size of our app down by up to 60%. It’s hard to think of anything that would bring so many tangible results for so little effort.

挖掘视力并绕过快速便捷的机会来优化现有资源也很常见。 因此,一个好主意是定期退后一步。 确保您没有错过应用程序的大小,速度或任何方面的快速改进。 我们仅花了两天时间就进行了分析,计划和执行上述所有改进,这使我们的应用程序大小减少了60%。 很难想到任何事半功倍就能带来如此多切实成果的事情。

A special thank you to my colleagues at Mutual for proofreading and creating an all-around great environment for all of us to grow and improve every day.

特别感谢Mutual的同事们进行校对并为我们所有人每天成长和改善创造一个全方位的良好环境。

翻译自: https://medium.com/swlh/how-we-reduced-our-react-native-app-size-by-60-with-a-few-simple-fixes-3d59adc2ed3d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Node.js程序转换为React Native应用,并在安卓上运行,你可以按照以下步骤进行操作: 1. 确保你已经安装了Node.js和React Native的开发环境。你可以参考React Native的官方文档(https://reactnative.dev/docs/environment-setup)进行设置。 2. 在你的React Native项目目录中,打开终端并执行以下命令安装必要的依赖: ``` npm install ``` 3. 创建一个新的React Native组件,该组件将作为你的应用程序的入口点。你可以使用`react-native init`命令创建一个新的React Native项目,或者直接在现有的项目中创建一个新的组件。 4. 在新创建的组件中,使用React Native提供的组件和API来实现你的应用程序逻辑。你需要根据你的Node.js程序逻辑进行相应的改写和调整。 5. 如果你的Node.js程序有依赖其他Node模块,你需要使用React Native的兼容模块或者寻找适当的替代方案来满足相同的需求。 6. 当你完成了React Native应用程序的开发,你可以使用以下命令将其构建为安卓应用: ``` npx react-native run-android ``` 确保你已经连接了安卓设备或者配置了模拟器,以便能够在设备上运行应用程序。 这些步骤将帮助你将Node.js程序转换为React Native应用,并在安卓上运行。请注意,由于Node.js和React Native之间的差异,你可能需要进行一些额外的调整和改进来适应React Native的开发模式和环境。 希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值