前段時間公司項目需要開發一個 SDK,最后需要打包給其他用戶,然而我之前從來沒搞過……網上看了一些文章,但總覺得有些七零八落,自己做的過程也是磕磕絆絆,這兩天問題總算搞定了,因此在這里做個小結。
整體步驟實現如下:
1 創建 Module
首先在項目中創建一個 Android Library
,如圖所示:
選擇 Android Library:
創建后的項目結構如下:
此時 mylibrary
目錄下的內容是空的。我們要做的就是將需要打包的內容復制到相應目錄下。如圖所示:
注:關于打包,有兩種格式:
*.jar
和*.aar
,
有關二者的區別:簡單點理解,前者只包含代碼文件;而后者包含(圖片、布局等)資源文件。
本例是包含資源文件的,因此最后需要的是
*.aar
格式的包;若打包代碼不含資源文件則只復制代碼即可。
2 配置文件
PS: 這些配置是為了打包 *.jar
包配置的,若只要導出 *.aar
包,則無需這些配置。
在 mylibrary
目錄下的 build.gradle
中添加如下代碼:
task makeJar(type: proguard.gradle.ProGuardTask, dependsOn: "build") {
injars 'build/intermediates/bundles/default/classes.jar' // 未混淆的jar路徑
outjars 'build/outputs/mylibrary-1.0.0.jar' // 混淆后的jar輸出路徑
configuration 'proguard-rules.pro' // 混淆協議
}
或者下面這種格式:
task clearJar(type: Delete) {
//這行表示如果你已經打過一次包了,再進行打包則把原來的包刪掉
delete 'build/libs/mylibrary-1.0.0.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/default/') //這行表示要打包的文件的路徑,根據下面的內容,其實是該路徑下的classes.jar
into('build/libs/') //這行表示打包完畢后包的生成路徑,也就是生成的包存在哪
include('classes.jar') //看到這行,如果你對分包有了解的話,你就可以看出來這行它只是將一些類打包了
rename ('classes.jar', 'mylibrary-1.0.0.jar')
}
makeJar.dependsOn(clearJar, build)
本人暫未搞明白二者的區別在哪,只是看起來語法有些不同,但實現效果相同。
注意:
task clearJar
的路徑推薦選擇.../bundles/release
,若無該路徑,可選擇.../bundles/default
。
此外,build.gradle
中的 minifyEnabled
一般配置為 true
(默認為 false
),如下所示:
android {
...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
至于作用,實測后發現設置 true
對導出的包進行了壓縮。不管 true
或 false
,混淆的效果都是有的。 proguardFiles
就是指定的混淆協議。
3 配置混淆協議
我們給其他人提供的包是不希望別人看到源碼的,因此需要將源碼進行混淆。
打開 mylibrary
目錄下的 proguard-rules.pro
文件,配置混淆協議,如下:
3.1 Androdi Studio 自帶的配置文檔
# 表示混淆時不使用大小寫混合類名
-dontusemixedcaseclassnames
# 表示不跳過library中的非public的類
-dontskipnonpubliclibraryclasses
# 打印混淆的詳細信息
-verbose
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
# 表示不進行校驗,這個校驗作用 在java平臺上的
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontwarn android.support.**
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
3.2 自定義配置
# 引入依賴包rt.jar(jdk路徑)
-libraryjars /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/rt.jar
# 引入依賴包android.jar(android SDK路徑)
#-libraryjars ~/Library/Android/sdk/platforms/android-25/android.jar
# 如果用到Appcompat包,需要引入
#-libraryjars /xxx/xxx/xx/xxx/MyApplication/library-banner/build/intermediates/exploded-aar/com.android.support/appcompat-v7/24.1.1/jars/classes.jar
#-libraryjars /xx/xx/xx/xx/MyApplication/library-banner/build/intermediates/exploded-aar/com.android.support/support-v4/24.1.1/jars/classes.jar
#忽略警告
-ignorewarnings
#保證是獨立的jar,沒有任何項目引用,如果不寫就會認為我們所有的代碼是無用的,從而把所有的代碼壓縮掉,導出一個空的jar
-dontshrink
#保護泛型
-keepattributes Signature
3.3 類和方法相關配置
# 下面兩個僅供參考,具體根據實際需求配置
# 不混淆某個類(使用者可以看到類名)
-keep class com.example.mylibrary.MyRelativeLayout
# 不混淆某個類中以 public 開始的方法(使用者可以看到該方法)
-keepclassmembers class com.example.mylibrary.MyRelativeLayout {
public *;
}
4 混淆打包
在命令行指向下面命令:
// Mac 系統
./gradlew makeJar
// Windows 系統
gradlew makeJar
出現 BUILD SUCCESSFUL
表示成功了(其實就是執行上面配置的 task makeJar
)。
或者,點開 Android Studio 右上部分的 Gradle
目錄,選擇 :mylibrary -> Tasks -> other
,如圖所示:
下滑找到并執行其中的 makeJar
也可以。
執行成功后,打開相應的目錄(這里用的 outputs
目錄,可改變),即可看到已經生成了 *.jar
包(還有 *.aar
包),如圖所示:
若要導出包含資源文件的包,使用 mylibrary-release.aar
即可。
PS: 若只需要
*.aar
包,則只需無需配置task makeJar
,只要在項目選擇Build -> Rebuild Project
,之后即可找到release.aar
包。
5 導入包
得到 *.jar
或 *.aar
后,若要在其他項目中引入該包,則需先復制該包(這里以 *.aar
包為例)到 app/libs
目錄下(若無則創建一個),然后在 app
的 build.gradle
中進行下述配置:
// 這是需要添加的
allprojects {
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
...
// 添加這一行
compile(name: 'mylibrary-1.0.0', ext: 'aar')
}
之后就能在項目中引用包里面的相關類和資源了:
此外,在 External Library
中也能看到我們引入的包,如圖所示:
PS: 有點納悶的是為什么跟其他的包格式不太一樣,后面有個小橫線……
點擊進入包內,可以看到包里面相關的類和方法已經進行了混淆,如圖所示:
Demo 鏈接:
打包:https://github.com/JiaoXR/Android-Demo/tree/master/RelativeLayoutTest
導入包:https://github.com/JiaoXR/Android-Demo/tree/master/LibraryTest
到此就算大體完成了。
參考鏈接:
- http://blog.csdn.net/lsyz0021/article/details/53107595
- https://stackoverflow.com/questions/21712714/how-to-make-a-jar-out-from-an-android-studio-project
- http://www.lxweimin.com/p/0a3ce6e9ab85
- http://blog.csdn.net/guolin_blog/article/details/50451259
推薦閱讀: