1 需求
你是否用過(guò)友盟、微信、微博、支付寶的sdk?
有沒(méi)有想研究一下對(duì)方的代碼,卻發(fā)現(xiàn)已經(jīng)混淆了?
你有沒(méi)有想過(guò)有一天,你也會(huì)進(jìn)入一家牛逼的企業(yè),需要發(fā)布自己SDK?
又或者僅僅是滿足自己的虛榮心,發(fā)布一個(gè)自己得意的工具?
這篇文章正是為實(shí)現(xiàn)這一目的
2 開(kāi)發(fā)環(huán)境及工具
- MAC(Windows也無(wú)所謂,路徑不同而已)
- Android Studio 2.3.1
- JDK 1.8
- Github
- Maven
3 實(shí)現(xiàn)步驟
3.1 新建工程
新建一個(gè)工程TestModule,選擇empty activity,讓Android studio生成一個(gè)最簡(jiǎn)單的activity,這個(gè)工程我們用來(lái)做什么的呢?
大家知道,你交付的代碼是需要有質(zhì)量保證的,因此需要對(duì)他有過(guò)詳盡的測(cè)試,這個(gè)工程就是我們的測(cè)試工程,簡(jiǎn)單來(lái)說(shuō)就模擬用戶的開(kāi)發(fā)環(huán)境
3.2 新建module
新版本的Android Studio已經(jīng)支持模塊開(kāi)發(fā),我們選擇File-->New-->New Module,此時(shí)會(huì)有一個(gè)彈框,我們選擇Android Library,并起名為MySDK

新建成功后,你會(huì)發(fā)現(xiàn)左側(cè)工程導(dǎo)航欄里,多出了一個(gè)模塊工程,這個(gè)工程有著獨(dú)立的一套目錄結(jié)構(gòu),跟app一樣。他有自己獨(dú)立的gradle配置

3.2 建立功能類
在mysdk這個(gè)模塊下的操作跟普通的Android工程沒(méi)有任何區(qū)別,所以我們按平常一樣,建立一個(gè)新的activity,起名叫mySDKTest,并自動(dòng)建好layout。這篇文章的重點(diǎn)不在功能,所以我們?cè)谶@個(gè)layout中隨便建一個(gè)什么view,我們就建一個(gè)button吧,實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的功能,點(diǎn)擊這個(gè)button,就打印出一句“You clicked module button”。
假設(shè),這個(gè)就是我們最終要封裝的功能。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button"
android:text="Button"/>
</LinearLayout>
public class mySDKTest extends AppCompatActivity {
private static final String TAG = "mySDKTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_sdktest);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i(TAG, "You clicked module button!!");
}
});
}
}
3.3測(cè)試功能
此時(shí),你會(huì)發(fā)現(xiàn)你根本run不起來(lái)這個(gè)工程,根本沒(méi)有選項(xiàng)去跑這個(gè)功能,可選的只有app,沒(méi)有mysdk。

這就是我們?cè)?.1新建工程時(shí)說(shuō)這個(gè)工程是測(cè)試工程的原因,因?yàn)镸odule根本跑不起來(lái)的啊
3.4配置依賴
因此我們要用到app來(lái)測(cè)試SDK,所以我們要在app中配置依賴mysdk。
方法是在app的build.gradle里加入依賴語(yǔ)句
compile project(':mysdk')
此時(shí),再去app的MainActivity里,你就可以import我們剛剛建立的mySDKTest了。
同樣,我們實(shí)現(xiàn)一個(gè)button,點(diǎn)擊跳轉(zhuǎn)到mysdk的activity。
Button button = (Button)findViewById(com.flame.mysdk.R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, mySDKTest.class);
startActivity(intent);
}
});
這樣就能跑起來(lái)測(cè)試了
跑起來(lái)后,點(diǎn)擊跳轉(zhuǎn)按鈕,會(huì)發(fā)現(xiàn)進(jìn)入了sdk的頁(yè)面,再點(diǎn)擊按鈕,會(huì)打出那句log。
之后你可以根據(jù)自己的需求,繼續(xù)開(kāi)發(fā),并測(cè)試。

3.5 管理依賴
3.5.1簡(jiǎn)單方式
我們假設(shè),你已經(jīng)完成了功能開(kāi)發(fā)和測(cè)試,現(xiàn)在需要發(fā)布出去或者提交給用戶,如何給到用戶呢?
我們打開(kāi)mysdk的目錄,在build-->outputs-->aar下面是有生成的AAR文件,你把這個(gè)文件拷貝一份給用戶其實(shí),也是可以的,大家搜一下導(dǎo)入AAR文件即可。

3.5.2 Maven + Github
Apache Maven是Apache開(kāi)發(fā)的一個(gè)工具,提供了用于貢獻(xiàn)library的文件服務(wù)器。
通過(guò)Maven + Github的方式,我們可以更簡(jiǎn)單的發(fā)布,更便捷的做版本管理;用戶可以更簡(jiǎn)單的導(dǎo)入。
也是我們重點(diǎn)要講的內(nèi)容
3.5.2.1配置打包gradle
在mysdk的目錄下,新建一個(gè)名為maven-release-aar.gradle的文件,并在build.gradle中添加如下字段:
apply from: 'maven-release-kline-aar.gradle'

3.5.2.2配置maven-release-aar.gradle
可以這么理解,maven-release-aar.gradle就是我們用來(lái)設(shè)置打包的腳本,在文件中添加如下代碼:
注意看注釋!!
// 1.maven-插件
apply plugin: 'maven'
// 2.maven-信息
ext {// ext is a gradle closure allowing the declaration of global properties
PUBLISH_GROUP_ID = 'com.flame'
PUBLISH_ARTIFACT_ID = 'mySDK'
PUBLISH_VERSION = android.defaultConfig.versionName
}
// 3.maven-輸出路徑
uploadArchives {
repositories.mavenDeployer {
//這里就是最后輸出地址,在自己電腦上新建個(gè)文件夾,把文件夾路徑粘貼在此
//注意”file://“ + 路徑,有三個(gè)斜杠,別漏了
repository(url: "file:///Users/flame/Documents/sourceTree/mysdk")
pom.project {
groupId project.PUBLISH_GROUP_ID
artifactId project.PUBLISH_ARTIFACT_ID
version project.PUBLISH_VERSION
}
}
}
//以下代碼會(huì)生成jar包源文件,如果是不開(kāi)源碼,請(qǐng)不要輸入這段
//aar包內(nèi)包含注釋
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles
}
artifacts {
archives androidSourcesJar
}
3.5.2.3生成AAR文件
- 接下來(lái)就是生成最終的AAR文件了,在Android studio右側(cè)有個(gè)gradle側(cè)邊欄,點(diǎn)擊會(huì)有如下畫(huà)面,選擇mysdk,點(diǎn)擊uploadArchives

- 最后build成功

- 再去上面配置好的maven輸出路徑下看,會(huì)發(fā)現(xiàn)已經(jīng)有生成文件了。
- 注意看,version是1.0,而且有jar包,解壓jar包就會(huì)得到全部源文件
- 如果在上一步不開(kāi)源,注釋掉生成jar包的代碼,這里就不會(huì)有jar包

3.5.2.4上傳至github
- 將整個(gè)文件夾上傳至Github,注意,要上傳的是完整的路徑
- 在github中新建organization,create new-new organization.
- 此處需要注意,create new有兩個(gè)選項(xiàng),new repository和new organization,此處務(wù)必要選擇organization,雖然區(qū)別不大,但是假如選擇repository的話不能夠作為私有倉(cāng)庫(kù)導(dǎo)入到新項(xiàng)目(報(bào)Failed to resolve錯(cuò)誤)
3.5.2.5 管理版本
剛剛提到之所以用maven的一個(gè)原因就是版本控制,這里我們就演示一下,所謂的版本控制
- 打開(kāi)mysdk的build.gradle,修改defaultConfig下的versionName 為"1.1"

再來(lái)一次#3.5.2.3 - uploadArchives,build成功后再看目錄,已經(jīng)生成了新的版本1.1
再上傳至Github
這樣我們就有了清晰的版本控制

3.6 如何引用
在之前的章節(jié)中,我們已經(jīng)生成了對(duì)應(yīng)代碼,那么如何引用呢?
首先我們先要在app的build.gradle里面移除之前的依賴方法
//注釋掉這段,不需要了
//compile project(':mysdk')
3.6.1 本地模式
代碼就在我們本地,我們當(dāng)然可以就近引用咯
我們?cè)赼pp的build.gradle中加入如下代碼,這里已經(jīng)省略了無(wú)關(guān)代碼
repositories {
jcenter()
//略
//指定絕對(duì)路徑
maven { url "file:///Users/flame/Documents/sourceTree/mysdk" }
}
dependencies {
//略
//mysdk,這里可以指定版本,我們有1.0,1.1兩個(gè)版本可選
compile('com.flame:mySDK:1.1')
}
3.6.2 網(wǎng)絡(luò)模式
上面提到的方法,當(dāng)然是少數(shù),畢竟我們大多數(shù)都是在網(wǎng)絡(luò)導(dǎo)入依賴庫(kù),這里就是需要用到之前上傳至Github的代碼了。
只需把路徑指向Github即可
repositories {
jcenter()
//略
//指定Github路徑
maven { url "https://github.com/flameandroid/mysdk/raw/master" }
}
dependencies {
//略
?
//mysdk,這里可以指定版本,我們有1.0,1.1兩個(gè)版本可選
compile('com.flame:mySDK:1.1')
}
3.7 混淆
我們打開(kāi)External Libraries,會(huì)發(fā)現(xiàn)mySDK已經(jīng)導(dǎo)入工程,而且還是完全開(kāi)源的。
而很多時(shí)候我們是不需要開(kāi)源的,那么如何做到呢?其實(shí)和普通的Android打包混淆一模一樣
把混淆過(guò)的代碼上傳至Github,這樣我們就完成了SDK的制作和發(fā)布
release {
// 不顯示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
//Zipalign優(yōu)化
zipAlignEnabled true
// 移除無(wú)用的resource文件
shrinkResources true
//前一部分代表系統(tǒng)默認(rèn)的android程序的混淆文件,該文件已經(jīng)包含了基本的混淆聲明,后一個(gè)文件是自己的定義混淆文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
4 注意事項(xiàng)
- 注意路徑一定要寫(xiě)對(duì),特別是大小寫(xiě),路徑的大小寫(xiě)不對(duì)是找不到文件的,這雖然是低級(jí)錯(cuò)誤,但其實(shí)挺常見(jiàn)的
- 注意Github路徑不是常見(jiàn)的https://github.com/flameandroid/mysdk.git,
而是https://github.com/flameandroid/mysdk/raw/master - 注意如果選擇了混淆,切勿在打包那步生成了jar,還上傳到Github了,否則白混淆了