减小APK空间的方式:
一,矢量图,不会因为缩放而让图片质量下降,又可以减小apk的大小,但是有个限制,通常矢量图常应用于小图标,比如200*200以下的.
除去美工给出,还可以从Android studio中直接使用默认的一些资源.用法是,在资源上点右键 ->新建 -> Vector assert,其中有很多预制的矢量图,
标准的矢量图是<svg>为根节点的,android中矢量图仅支持<vector>为根节点的,可以通过工具做个转换,Android studio中 vector assert就可以把<svg>的转为<vector>的.
导入的矢量图会存在drawable中.
ic_ac_unit_black_24dp.xml
也有第三方库可以把svg转成vector. svg2vector.jar
矢量图应该是api21之后出现,所以会有一个跟之前版本的兼容性问题,这就导致一张ic_ac_unit_black_24dp.xml矢量图会在多个适配目录中生成对应的png文件,这反而增加了图片的占用空间,如果要仅在一个适配目录生成对应png,可以在build.gradle中配置:
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
对于矢量图,还可以直接修改矢量图的xml文件,修改图片颜色.但是更推荐通过Tint着色器去修改图片的颜色,这样可以用一个xml图片文件,显示出多个不同效果.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scr="@drawable/ic_ac_unit_black_24dp"
android:tint="@color/colorAccent"
android:backgroundTint="@color/colorPrimary"
android:foregroundTint="@color/colorPrimaryDark" />
那如果想实现选择器的效果,Tint也可以实现.
要定义背景选择器,但是这里只使用一张图片
ac_unit_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable ="@drawable/ic_ac_unit_black_24dp" android:state_pressed= "true"/>
<item android:drawable="@drawable/ic_ac_unit_black_24dp"/>
</selector>
还要定义颜色选择器
ac_unit_tint_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorPrimary" android:state_pressed="true"/>
<item android:color="@color/colorAccent"/>
</selector>
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:clickable="true"
android:tint="@color/ac_unit_tint_selector"
android:src="@drawable/ac_unit_selector"/>
二,移除无用的资源,因为需求的频繁变更,肯定会有很多文件是不在需要的.但是这些资源都会打包进apk,所以需要移除.
java代码还可以注释掉,但是xml注释很不方便,
1,通过工具 Refactor -> Remove unused resource来移除,
这种移除方式,如果代码中存在动态获取资源Id的方法,不会被检测到,相关的资源会被移除,所以不推荐
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getResources().getIdentifier("activity_main_back","layout",getPackageName());
}
2, 通过lint工具,这个工具可以在移除时让去选择那些需要保留,用这个工具的前提是你对代码熟悉,清楚那些资源是不会被需要的.
三,对与资源的国际化配置,即使是只在国内使用的apk,也是应该配置的,因为引入的第三方库会给你国际化,
如默认创建的一个app:
可以通过配置保留部分语言.
defaultConfig {
resConfigs "zh-rCN","en-rAU"
}
四,动态库的配置
so文件通常是ndk编译的动态库,因为不能跨平台,所以每个平台需要对应的so库.
这里有一个ABI的概念,ABI是(Application binary interface)应用程序二进制接口的简称,从使用的指令集,内存对齐,到可用的系统函数库,定义了二进制文件如何运行在相应的系统平台上.
在Android 系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64。
一般只需要配置armeabi-v7a就行.
defaultConfig {
ndk {
abiFilters "armeabi-v7a"
}
}
五,代码压缩,就是把
minifyEnabled true
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
压缩代码时,也混淆了代码,有时候可能会运行出错,报类找不到异常,这是需要根据错误信息,通过
proguard-rules.pro'文件keep住某些文件,不做压缩混淆处理.
六,资源压缩
shrinkResources true 这个参数需要跟代码压缩的参数同时配置才有效
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
默认是非严格模式,就是说如果代码中通过
getResources().getIdentifier("activity_main_back","layout",getPackageName());
这中格式引用资源, 非严格检查模式,就是以activity_main_back字符串开头的资源都会保留不做处理,也即是 startwith.
可以通过配置文件使用严格模式,在raw目录下创建keep.xml
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools">
tools:shrinkMode="strict"
</resources>
也可以通过tools:keep="",tools:discard=""指定保留,舍弃的文件.
七,资源的混淆,主要针对resource.arsc,及res目录,混淆时把名称变成了a,b,c,d...,更短了,并且把res下的图片做了压缩,所以减小了apk大小.
混淆的过程中res下的文件名称改成了a,b,c等,那代码中是是怎么使用的?
在代码中通过这类语句使用资源
setContentView(R.layout.activity_main);
实际是用到的R.java的定义,这里id的定义是有规则的:
资源的整型数格式为:0xpptteeee(16进制,p代表的是package,t代表的是type,e代表的是entry)。
- Package ID 包ID,系统为0x01,应用程序资源为0x7f。
- Type ID 资源的类型ID,资源的类型有animator、anim、color等等,每一种都会被赋予一个ID。
- Entry ID 资源在其所属的资源类型中所出现的次序
package com.example.tinydrawable;
public final class R {
public static final class anim {
public static final int abc_fade_in=0x7f010000;
public static final int abc_fade_out=0x7f010001;
public static final int abc_grow_fade_in_from_bottom=0x7f010002;
}
public static final class color {
public static final int abc_background_cache_hint_selector_material_dark=0x7f040000;
public static final int abc_background_cache_hint_selector_material_light=0x7f040001;
public static final int abc_btn_colored_borderless_text_material=0x7f040002;
public static final int abc_btn_colored_text_material=0x7f040003;
}
public static final class drawable {
public static final int abc_ab_share_pack_mtrl_alpha=0x7f060001;
public static final int abc_vector_test=0x7f060056;
public static final int ac_unit_selector=0x7f060057;
}
}
所以实际使用的是一个id,那么就有一个资源映射表resources.arsc,把id跟具体的资源对应起来,
实际使用是在这个映射表中根据id找到名称,找到路径,所以资源混淆后,因为修改了文件名,路径名,所以也会同步修改这个映射表中的名字,路径值.
这个功能使用腾讯的开源工具,
https://github.com/shwenzhang/AndResGuard