原文 Mobile Image Optimization ADI MIZRAHI 2023/03/09
Motivation 诱因
作为移动端开发者,我们想要构建成功的应用、丰富的应用和可视化应用,这要求我们的应用拥有大量的资源(仅仅文本不行,现在已经不是90年代了)。
在理想的情况下我们希望将所有资源保留在应用上,但这没有意义。
- 这些资源会随着时间的推移而发生变化,因此我们无法将它们保留在我们的应用本地。
- 如果我们在应用上保存许多资源,它将是一个很大的文件,没有人愿意下载它。
在我们的应用中拥有许多资源,但不在本地保存的解决方案是使用网络调用从互联网远程获取这些资源。
听起来很简单,但远程提取资源可能会遇到很多问题,我将在接下来描述。
Issues 问题
- 漫游 — 由于我们谈论的是移动设备,因此无法保证用户将拥有稳定的连接,他可能正在旅行或只是在信号不好的地方,并且在连接不良的情况下远程获取资源确实具有挑战性。
- 性能问题 — 加载资源需要设备的资源,而将大型资源装入小容器将需要在设备上进行一些处理,因此请考虑同时对 10 个图像执行此操作,正如我们在屏幕截图中看到的那样可能会出现空白、漏洞或只是长时间加载直到图像最终显示。
- 响应问题 — 某些应用支持两种方向(纵向和横向),当容器在方向之间变化时,我们如何处理资源?我们会拉伸它吗?适合吗?它可能看起来很糟糕……
- 屏幕尺寸 — 屏幕尺寸有很多种,不管是iOS(那里问题不那么严重)还是Android,我们有很多屏幕尺寸,小手机和平板之间的资源大小有很大不同,我们需要吗为每个用例创建并提取资源?每种手机尺寸的 DPR(设备像素比)怎么样?如何处理这一切?问题只是从这里开始,因为很快我们就会拥有可扩展和可折叠的屏幕。
- 增加数据使用量——如果资源没有优化,它们的文件大小会更大,这意味着我们从互联网上提取更多字节,这意味着我们设备的调制解调器将工作更多,这意味着更多的电池使用。
此外,如果用户没有通过WIFI连接,可能会向他收取额外费用。 - 滥用缓存——我们当然希望使用某种缓存机制来保留本地已经获得的资源(我们不想一遍又一遍地提取相同的资源),如果资源使用大量字节,这意味着该应用变得过大,并且可能会被删除,因为它在设备上占用了太多空间。
-
内存使用 - 渲染大资源需要内存,设备只有这么多内存,如果我们尝试渲染大量大尺寸资源,我们可能会遇到内存问题,而某些设备有更多内存,可能会处理这个问题,其他人可能会因为这个问题而崩溃。
-
对服务器位置的依赖——由于我们是远程提取资源,所以我们依赖于距离服务器的距离,服务器越近,我们获取资源的速度就越快。
Does it Matter? 有关系吗?
在未经优化的情况下加载许多资源可能会导致加载页面速度延迟,可能导致性能问题,甚至崩溃。
但为什么这一切都很重要?登陆页面的加载速度真的那么重要吗?
答案是肯定的。
-
100 毫秒的延迟将导致 7% 的转化率下降(当我们说转化时,我们的意思是用户将东西放入购物车或变成付费用户或订阅用户)
将此值乘以 10,延迟 1 秒,转化率就会降低 70%
*根据 Akamai 的一项研究。
-
1 秒的延迟可能会导致流量下降 20%。
-
1 秒的延迟会使页面浏览量减少 11%。
-
1 秒的延迟可能会导致客户满意度下降 16%。
The Solution 解决方案
既然我们已经阐述了问题以及为什么优化媒体如此重要,我想向您展示如何实现这一目标。
-
提高加载速度——所以我们要做的第一件事就是提高页面加载速度,我们希望我们的页面能够快速加载并以优化的方式,这将改善我们应用的用户体验。
-
减少资源大小 - 为此,我们可以从以下方面入手:
- 减少宽度和高度(在呈现图像源或缩略图时我们不需要 4k 资源)。
- 降低图像质量,如果我们不显示完整尺寸的图像,我们可以压缩图像并降低质量,但仍然得到好看的图像。
- 我们还可以为 iOS(11+) 提供特定格式的 HEIC,为 Android 提供 AVIF(12+)/WebP(4.2.1+) 的特定格式(取决于 Android 版本)。
我刚才提到的所有事情,尺寸、格式和质量将导致更轻的资源和更优化的资源,从而使用更少的空间。
-
缓存 - 因此,我们下载图像,将其呈现给用户,然后他决定移动到另一个屏幕,或者将应用发送到后台并再次打开它,我们是否重新下载图像?当然不是,我们将使用缓存机制,因此一旦我们下载了资源,它就会保存在我们的设备上,我们可以在下次要使用它时在本地加载它,当然,我们希望资源得到优化,这样它就可以了。将在设备上使用尽可能小的空间。
-
响应式——我们希望能够获得不同尺寸的相同资源(例如不同方向或不同容器),我们希望以最优化的方式获得相同的资源。尺寸小,可实现更好的带宽使用、设备存储和设备性能。
-
CDN是一种极其重要的机制,这意味着世界各地都有一个服务器网格,一旦我们的资源第一次到达那里,我们就会将其缓存在其中。这意味着,如果第二个用户请求相同的资源,它将快速交付,因为用户和特定 CDN 服务器之间的距离比主端点短。
-
桌面与移动资源——我们中的一些人可能有一个网站,提供与我们的移动应用相同的资源,但桌面设计与应用有很大不同,资源的大小可能根据平台的不同而不同,我们需要相同的资源图像,但大小不同,为同一资源保留不同大小的多个实例是一个很好的解决方案,如果每个设备都能为其获取正确的资源,那就更好了。
Practical 实际的
现在我们已经了解了我们面临的挑战、影响以及我们如何处理这些挑战,让我们开始实际操作,看看一些代码以及如何实现更好的性能。
在本次演示中,我将使用 Cloudinary 的 Flutter SDK,请随意使用它,它需要您在 Cloudinary 的网站上注册。
Cloudinary cloudinary = Cloudinary.fromCloudName(cloudName: '<YOUR_CLOUD_NAME');
我需要做的第一件事是使用我的云名称启动我的 Cloudinary 对象。
cloudinary.image('sample').toString()
以下代码将生成图像 sample 的 URL,您可以在此处找到它。
现在我们可以创建并拉取远程资源,让我们对其进行优化。
Transformation transformation = Transformation()
..delivery(Quality(Quality.auto()))
..delivery(Format(Format.avif))
..resize(Resize.thumbnail()..width(500))
..delivery(Dpr(Dpr.auto));
我正在创建以下 Transformation 并向其中添加以下内容:
Quality.auto()— 我要求 Cloudinary 自动为我压缩图像,以获得更轻的资源,但仍然具有良好的质量。Fomrat.avif— 因为我使用的是 Android API 级别 33(Android 13)Resize.thumbnail()..width(500)- 我正在减小资源的大小,在我的例子中,我将其呈现为缩略图,并且不需要完整尺寸,因此我将宽度减小到 500,这一点很重要值得一提的是,我没有指定高度,我告诉 Cloudinary 根据我给定的宽度保持图像的长宽比。Dpr.auto— DPR — 设备像素比,我要求 Cloudinary 自动计算并为我提供适合设备的 DPR 图像。
一旦 Transformation 准备就绪,我会将其注入到我的图像创建中:
cloudinary.image('sample').transformation(transformation).toString()
这将创建以下 URL.
为了对图像进行优化,我们执行了以下操作:
- 我们减小了资源的大小(宽度和高度)。
- 我们将质量压缩设置为自动。
- 我们将 DPR 设置为自动。
- 我们为此用例设置了正确的格式
AVIF。
以下屏幕截图显示了我构建的演示应用的示例。
在左栏中,您可以看到原始图像及其大小。
在右列中,我们有变换后的图像(经过上面变换的图像)。
我们可以看到,我们成功地将每个图像的尺寸缩小了 10 倍。
这种优化将使设备更容易远程提取资源、将其渲染和解码到容器中,并为我们带来更好的整体应用性能。
Conclusion 结论
我们刚刚讨论了为什么我们还要开发移动应用。挑战是什么?为什么这件事很重要?解决办法是什么?我为您提供了实用工具,帮助您优化媒体以及应用的性能。
要记住的重要一点是,正确进行媒体优化可以提高应用的转化率、流量和客户满意度。
需要补充的是,在本文中,我们展示了一个使用 Cloudinary Flutter SDK 的示例,该 SDK 是用超过 15 种其他语言/框架编写的,例如: