当前位置: 首页 > Web前端 > HTML

【手把手学习flutter】Flutter中Android包的基本配置和包体积优化攻略

时间:2023-03-29 11:46:47 HTML

Hi~豆皮粉们!最近在学什么?它有改善吗?这次请大家阅读字节跳动“saucxs”精心打造的《Flutter打包的基础配置和包体积优化策略》,增长跨端领域的知识,在你的前端“全栈”之路上迈出一小步。作者:saucxs来源:原序亲爱的读者们,你有没有愉快的开发过一个flutter项目,到了上线的时候,却对打包过程不熟悉,遇到了或大或小的问题?来看看我这样的人是怎么打包优化的吧。一、背景在本地开发中,使用flutterrun命令或Androidstudio运行或调试。Flutter构建debug版本,即本地调试右上角出现debug标志。当本地调试OK后,准备release版本,比如发布到应用商店,或者交付给用户。二、前期检查工作1、检查AndroidManifest配置检查/android/app/src/main/下的AndroidManifest.xml文件,验证这些属性是否正确,特别是:application属性,即name应用程序。uses-permission属性使flutter工具能够与应用程序进行通信。默认情况下启用。如果没有开启,直接删除该属性那一行。2.检查构建配置检查/android/app/build.gradle以验证这些属性是否正确:defaultConfig属性applicationId:制作一个始终唯一的appid。versionCode&&versionName:应用版本号和版本号字符串。minSdkVersion&&targetSdkVersion:指定应用程序设计使用的最低API级别和API级别。3.创建带有应用程序签名的密钥库。如果之前已经创建过keystore,则跳过此步骤,直接执行4.将keystore导入应用。创建密钥库并执行命令:更多详情请访问https://support.apple.com/kb/HT208050.yourMacBook-Pro:~username$keytool-genkey-v-keystore~/key.jks-keyalgRSA-keysize2048-validity10000-aliaskey生成的文件是key.jks默认文件地址:/Users/<你的电脑名>/key.jks注意:key是私有文件,不要加入git。以下是详细的执行过程最后一次登录:MonNov214:17:41onttys005默认的交互式shell现在是zsh。要更新您的帐户以使用zsh,请运行`chsh-s/bin/zsh`。有关更多信息详情请访问https://support.apple.com/kb/HT208050.yourMacBook-Pro:~username$keytool-genkey-v-keystore~/key.jks-keyalgRSA-keysize2048-validity10000-aliaskeyenter密钥保管库密码:重新输入新密码:它们不匹配。请重试输入密钥库密码:再次输入新密码:你的名字和姓氏是什么?[未知]:您的组织单位名称是什么?[Unknown]:byte你的组织名称是什么?[Unknown]:byte你所在城市或地区的名称是什么?[Unknown]:nj你所在的省/市/自治区叫什么名字?[Unknown]:nj这个单位的两个字母的国家/地区代码是什么?[未知]:cnCN=C、OU=byte、O=byte、L=nj、ST=nj、C=cn是否正确?[否]:y正在为(有效期为10,000天)生成2,048位RSA密钥对和自签名证书(SHA256withRSA):CN=C,OU=byte,O=byte,L=nj,ST=nj,C=cnenterthekeypasswordof(ifitisthesameasthekeystorepassword,pressEnter):Enternewpasswordagain:[Storing/Users/username/key.jks]Warning:JKSkeystoreusesaproprietary格式.推荐使用“keytool-importkeystore-srckeystore/Users/username/key.jks-destkeystore/Users/username/key.jks-deststoretypepkcs12”迁移到行业标准格式PKCS12。yourMacBook-Pro:~username$4.将keystore引入application在/android下新建一个key.properties文件,其中包含对keystore的引用:storePassword=<你输入的密码>keyPassword=<你输入的password>keyAlias=keystoreFile=/Users/<你的电脑名>/key.jks5.为构建配置添加签名,修改/android/app/build.gradle文件://...apply来自:“$flutterRoot/packages/flutter_tools/gradle/flutter.gradle”//新内容android{compileSdkVersion28//...//...defaultConfig{//TODO:指定您自己的唯一应用程序ID(https://developer.android.com/studio/build/application-id.html).applicationId"com.example.flutter_tester"minSdkVersion18targetSdkVersion28versionCodeflutterVersionCode.toInteger()versionNameflutterVersionName}//新内容来自signingConfigs{release{keyAliaskeystoreProperties['keyAlias']keyPasswordkeystoreProperties['keyPassword']storeFilefile(keystoreProperties['storeFile'])storePasswordkeystoreProperties['storePassword']}}//新内容buildTypes{release{//TODO:添加你自己的发布版本的签名配置。//现在使用调试密钥签名,所以`flutterrun--release`可以工作。signingConfigsigningConfigs.release}}现在应用程序的打包发布版本将被自动签名3.打包命令,然后执行打包命令,构建发布APK。如果您完成了上一节中的签名步骤,APK将被签名。使用命令行:cd是您的项目目录)。运行flutterbuildapk(flutterbuild默认包含--release选项)。打包后的发布APK位于/build/app/outputs/apk/app-release.apk。4、打包体积优化策略第3步执行完毕后,打包过程结束。不过为了追求极致,我们会发现包的尺寸有点大。接下来我们来分析一下这个APK包的组成。我们主要看不被混淆的情况。通常,静态资源文件占用大量内存。我们发现apk中的图片比例为80%+0%=80%Flutter参考资源(assets文件夹)80%Android启动页背景和applogo(res文件夹)0%main是因为图片用的比较多,并且未设置Android启动页的背景和应用程序的徽标。(一)图片和代码优化1.使用外部服务处理图片资源与其在应用程序内捆绑图片资源,不如将图片托管在外部服务如firebase上,并使用包cached_network_image在应用程序内调用这些图片.首次启动应用程序时,程序包会从提供的URL中获取图像并将其缓存,因此您可以在后续使用该应用程序时获得缓存图像,因此这些图像不会占用下载空间,因为它们没有捆绑在其中应用程序。2、压缩png和jpg如果有些图片不想从外部主机获取,必须在本地获取,而且使用的图片一定要压缩png和jpg,因为高质量的png和jpg会占空间应用。3、使用svg格式图标我们尝试使用矢量图svg而不是png,因为svg兼容不同dpi的设备,可以减少apk的体积。4.删除未使用的包pubspec.yaml文件中不需要或根本不使用的库或包。5.特殊字体使用http缓存。字体也是程序大小的一个原因。当UX需要使用特定的字体时,我们不需要在应用程序中存储字体文件,例如*.ttf或.otf文件,然后将它们映射到pubspec。yaml文件,我们可以通过http获取一次,缓存到应用程序的文件系统中。6.使用proguard优化器proguard是一个java优化器,优化器不会改变表达式的形式,以更紧凑的方式优化代码。Proguard混淆了原本名称无关紧要的类型、字段和方法名称,并将长命名字符串替换为短字符串,例如a、b、c以提高效率。但是,包名和类名可能会很长,但这不会影响效率。我们在/android/app/build.gradle中的构建类型看起来像这样:/addproguardsigningConfigsigningConfigs.release//这是发布的默认值}}在同一目录中,创建文件proguard-rules.pro并添加以下代码:##Flutterwrapper-keepclassio.flutter.app.**{*;}-keepclassio.flutter.plugin.**{*;}-保持类io.flutter.util.**{*;}-保持类io.flutter.view.**{*;}-保持io.flutter类。**{*;}-保留io.flutter.plugins类。**{*;}#-keepclasscom.google.firebase.**{*;}//如果你在项目中使用firebase,请取消注释-dontwarnio.flutter.embedding.**-ignorewarnings最后,我们在gradle.properties文件中添加:extra-gen-snapshot-options=--obfuscate7,shrinkResources删除build.gradle中无用的代码InbuildTypes{release{minifyEnabledtrue//之前添加的shrinkResourcestrue//addthisproguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'//addedpreviouslysigningConfigsigningConfigs.release//addedpreviously}}PS:使用shrinkResource和proguard优化器,优化后,体积从147.0MB减少了0.1MB到146.9MB,太小了。(2)So优化Flutter的Apk包,排名第二的是lib,28.7MB,占比19.7%。我们写的Dart代码转换成不同架构下的so库,供native调用。不同CPU架构的含义:x86_64:Intel64-bit,一般用于平板电脑或模拟器,支持x86和x86_64CPU架构设备。arm64-v8a:第8代64位,包括AArch32和AArch64两种执行状态,分别对应32位和64位,支持armeabi、armeabi-v7a和arm64-v8a。armeabi-v7a:第7代armv7,采用硬件浮点运算,具有高级扩展功能,兼容armeabi和armeabi-v7a,目前大部分手机都采用该架构。我们通过以下不同的命令分别打包构建指定CPU架构的APK包,flutterbuildapk--target-platformandroid-arm,android-arm64,android-x64--split-per-abi来解释一下:flutterbuildapk表示当前构建发布包。后来的android-arm、andriod-arm64、andriod-x64的意思就是生成指定架构的release包。最后--split-per-abi的意思是按照不同的架构分别打包,去掉的话会包含所有CPU架构的apk包。看看126.2MB的app-armeabi-v7a-release.apk包大小,酷,直接从146.9MB缩减到126.2MB。再来看看对应的apk内容:lib的占比也从原来的19.7%,28.7MB,直接降到了6.4%,8MB。(3)混淆优化Flutter还为我们提供了混淆命令:flutterbuildapk--obfuscate--split-debug-info=//简单说明:--obfuscate:开启混淆开关.--split-debug-info:混淆生成的地图符号表缓存到该位置。我们先测试一下,构建完整apk的大小。执行flutterbuildapk--obfuscate--split-debug-info=splitMapsize从146.9MB下降到145.9MB,减少了1MB。符号文件在项目根目录下生成:我们再试一次,直接针对不同的CPU生成对应的Apk并添加混淆结果。flutterbuildapk--obfuscate--split-debug-info=//--target-platformandroid-arm,android-arm64,android-x64--split-per-abi我们执行:flutterbuildapk--obfuscate--split-debug-info=splitMap--target-platformandroid-arm,android-arm64,android-x64--split-per-abi未混淆的v7a大小与启用混淆相比,126.2MB减少到125.9MB。打开混淆减少0.3MB。我认为没有太大区别。5.小结包的基本配置完成后,基本不需要改动。优化配置完成后,需要优化打包命令。我认为这是一个有用的打包命令:flutterbuildapk--obfuscate--split-debug-info=splitMap--target-platformandroid-arm,android-arm64,android-x64--split-per-abidifferentCPU的structures单独打包混淆,生成的字符串Map在splitMap文件夹下TheEnd