減小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