前段时间公司项目需要开发一个 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.jianshu.com/p/0a3ce6e9ab85
- http://blog.csdn.net/guolin_blog/article/details/50451259
推荐阅读: