针对安卓APP开发,打包的安卓apk之后发布应用。但在实现原有功能的前提下,怎么样保证apk体量尽可能的小又安全是我们需要追求的极致。
使用svg转vector
可缩放矢量图形,SVG不会像位图一样因为缩放而让图片质量下降。节约空间与内存,常用于简单小图标。
1.在Android Studio中使用:
将svg图片转换为VectorDrawable。
2.使用注意兼容性:
在app/build.gradle中添加:
// 使用support-v7兼容
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
implementation 'com.android.support:appcompat-v7:28.0.0'
在布局中引用:
app:srcCompat="@drawable/icon"
3.静态VectorDrawable在XML中的定义
官方例子:
//视图的宽度,下面的pathData中的内容便会在600宽高的画布内操作
//旋转角度,顺时针
//路径的数据
效果:
解析一下数据:M300,70 l 0,-70 70,70 0,0 -70,70z
相关的指令:
M = moveto 相当于 android Path 里的moveTo(),用于移动起始点
L = lineto 相当于 android Path 里的lineTo(),用于画线
H = horizontal lineto 用于画水平线
V = vertical lineto 用于画竖直线
C = curveto 相当于cubicTo(),三次贝塞尔曲线
S = smooth curveto 同样三次贝塞尔曲线,更平滑
Q = quadratic Belzier curve quadTo(),二次贝塞尔曲线
T = smooth quadratic Belzier curveto 同样二次贝塞尔曲线,更平滑
A = elliptical Arc 相当于arcTo(),用于画弧
Z = closepath 相当于closeTo(),关闭path
坐标轴为以(0,0)为中心,X轴水平向右,Y轴水平向下;
所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系;
指令和数据间的空格可以省略;同一指令出现多次可以只用一个。
(还有很多高级动画操作,请自行百度)
使用着色器Tint
实现目的:
1.适配所有颜色:
Drawable drawable = ContextCompat.getDrawable(this, R.mipmap.icon);
// 保留原来的图片
Drawable.ConstantState state = drawable.getConstantState();
/**
* DrawableCompat类:是Drawable的向下兼容类,我们为了在6.0一下兼容tint属性而使用
* wrap方法:使用tint就必须调用该方法对Drawable进行一次包装
* 调用mutate后会对ConstantState进行一次拷贝
*/
Drawable drawable1 = DrawableCompat.wrap(state == null ? drawable : state.newDrawable()).mutate();
drawable1.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
//设置Tint属性
DrawableCompat.setTint(drawable, ContextCompat.getColor(this, R.color.colorAccent));
my_image.setImageDrawable(drawable);// 改变后的图片
my_image1.setImageDrawable(drawable1);// 原来的图片
2.实现selector
Drawable drawable = ContextCompat.getDrawable(this, R.mipmap.icon);
int[] colors = new int[]{ContextCompat.getColor(this, R.color.colorPrimary), ContextCompat.getColor(this, R.color.colorAccent)};
int[][] states = new int[2][];
// 注意顺序
states[0] = new int[]{android.R.attr.state_pressed};
states[1] = new int[]{};
ColorStateList colorList = new ColorStateList(states, colors);
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(states[0], drawable);
stateListDrawable.addState(states[1], drawable);
Drawable.ConstantState state = stateListDrawable.getConstantState();
drawable = DrawableCompat.wrap(state == null ? stateListDrawable : state.newDrawable()).mutate();
// 设置各个状态下的颜色
my_image.setImageDrawable(drawable);
资源打包配置
当应用不需要支持几十种语言时,通过配置 resConfigs 去除无用的语言资源。可以减少apk体积100k左右。
defaultConfig {
applicationId "com.zachary.util"
minSdkVersion 18
targetSdkVersion 26
versionCode 101
versionName "1.0.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//只保留默认的资源和指定的资源:中文、英文
resConfigs "zh-rCN", "en-rUS"
}
动态库的打包配置(定制化设备除外)
当引入so库的时候,modle的build.gradle:
//将so库打包到apk内
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
在modle的build.gradle中defaultConfig配置so库架构,减小apk体积
//配置so库架构(真机:arm 模拟器:x86)
ndk {
abiFilters('armeabi', 'armeabi-v7a')
}
buildTypes {
release {
// 移除无用的resource文件
shrinkResources true
}
}
注:打包时会删除没有用到的资源。若是动态获取资源id,在打包时也会将其删除。
通过Android Studio中:Refactor-->Remove Unused Resources...快速删除(慎用)
通过Android Studio中:Analyze-->Run Inspection by Name-->unused resources
根据自己的实际需求进行选择,直接删除不需要的资源文件即可。
开启代码混淆
在modle的build.gradle中buildTypes配置
buildTypes {
release {
// 开启混淆(反编译)
minifyEnabled true
// 移除无用的resource文件
shrinkResources false
debuggable false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
可以查看文章:Android之傻瓜混淆
注:将所需要的混淆都加进去,发现哪个class混淆有问题就将其keep,重复的删掉:
为保持第三方库中的类而不乱,-dontwarn和-keep 结合使用,意思是保持com.xx.bbb.**这个包里面的所有类和所有方法而不混淆,接着还叫ProGuard不要警告找不到com.xx.bbb.**这个包里面的类的相关引用。
-dontwarn com.xx.bbb.**
-keep class com.xx.bbb.** { *;}
启用资源缩减
在第五步中有介绍,在modle的build.gradle中buildTypes配置,移除无用资源:
buildTypes {
release {
// 移除无用的resource文件
shrinkResources true
}
}
使我们保留了代码文件,只是不打包进入apk,如果没有动态获取资源id,打包没有问题的话,请开启。因为总是会因为各种需求的变化,我们的项目中留有暂时没有用到的资源。
注:混淆文件proguard-rules.pro
里,添加以下命令,启用资源缩减无效。
-dontshrink
将png格式大图转webp格式
WebP是一种同时提供了有损压缩与无损压缩的图片文件格式,这种图片格式相比png或者jpg格式的图片损失的质量几乎可以忽略不计,但是压缩后的体积却比png和jpg要小很多。
在Android Studio中进行转换:右键png图片,选择Convert to WebP
针对大图压缩还是很明显的。
进行批量转换:
介绍一下工具iSparta,可以将png批量转换成webp格式、生成APNG、图片无损压缩、png有损压缩。
官网地址:iSparta,我尝试过最新版本下载,下载过程很痛苦,下载之后也不能正常使用,具体原因不知。
因此我在百度云提供:win64、win32、mac的iSparta工具下载:
微信开源的AndResGuard进行资源混淆:AndResGuard
1.在项目根目录下build.gradle中,添加插件的依赖:
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// 资源混淆
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.15'
}
2.在app目录下,创建and_res_guard.gradle文件(可以直接将内容写入build.gradle文件):
apply plugin: 'AndResGuard'
andResGuard {
// mappingFile = file("./resource_mapping.txt")
mappingFile = null
use7zip = true
useSign = true
// 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
keepRoot = false
// 白名单
whiteList = [
// for your icon
"R.drawable.logo",
// for fabric
"R.string.com.crashlytics.*",
// for google-services
"R.string.google_app_id",
"R.string.gcm_defaultSenderId",
"R.string.default_web_client_id",
"R.string.ga_trackingId",
"R.string.firebase_database_url",
"R.string.google_api_key",
"R.string.google_crash_reporting_api_key",
// 例如:友盟、融云在sdk里面写死了资源名,但是被我们混淆之后找不到指定资源,则会报崩溃
// umeng share for sina
"R.drawable.sina*",
// for umeng update
"R.string.umeng*",
"R.string.UM*",
"R.string.tb_*",
"R.string.rc_*",
"R.layout.umeng*",
"R.layout.tb_*",
"R.layout.rc_*",
"R.drawable.umeng*",
"R.drawable.tb_*",
"R.drawable.rc_*",
"R.drawable.u1*",
"R.drawable.u2*",
"R.anim.umeng*",
"R.color.umeng*",
"R.color.tb_*",
"R.color.rc_*",
"R.style.*UM*",
"R.style.umeng*",
"R.style.rc_*",
"R.id.umeng*",
"R.id.rc_*",
// 项目中遇到第三方使用getIdentifier访问的资源的问题,只好全部id都放入白名单
"R.id.*"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.15'
//path = "/usr/local/bin/7za"
}
/**
* 可选: 如果不设置则会默认覆盖assemble输出的apk
**/
// finalApkBackupPath = "${project.rootDir}/final.apk"
/**
* 可选: 指定v1签名时生成jar文件的摘要算法
* 默认值为“SHA-1”
**/
// digestalg = "SHA-256"
}
3.在build.gradle文件中引用and_res_guard.gradle。
apply from: 'and_res_guard.gradle'
集成完AndResGuard完毕,在app的gradle的tasks中执行指令。
双击执行resguardRelease指令,执行完毕后,可以在app目录下的/build/output/apk/release/AndResGuard_{apk_name}/ 文件夹中找到混淆后的Apk。
注:
1.出现异常(Execution failed for task ':app:resguardRelease'. > can't the get signConfig for release build)
解决:配置相应签名即可
// 定义APK的签名信息.
signingConfigs {
debug {
}
release {
keyAlias '***'
keyPassword '***'
storeFile file('D:/**签名/**.jks')
storePassword '***'
}
}
buildTypes {
release {
signingConfig signingConfigs.release //增加签名
}
debug {
}
}
2.若写死了资源名,则需要白名单使用正则表达式指定资源文件不被混淆。
资源混淆后的效果: