Gradle實戰:發布aar包到maven倉庫

查看原文:http://blog.csdn.net/u0108184...

Gradle實戰系列文章:

《Gradle基本知識點與常用配置》
《Gradle實戰:Android多渠道打包方案匯總》
《Gradle實戰:不同編譯類型的包同設備共存》
《Gradle實戰:執行sql操作hive數據庫》


aar簡介

aar文件是Google為Android開發所設計的一種library格式,全名為Android Archive Library,與Java Jar Library不同的是,aar除了java code之外還包含資源文件,即xml文件、圖片、文字等。
本文著重介紹發布過程和遇到的一些坑及其解決方案,文中的maven倉庫是指公司搭建的maven倉庫,如果要發布到jCenter或maven central,可以參考文章最后的“深入學習“。

1. 準備工作

  • 開發工具:Android Studio;

  • 復習《Gradle基本知識點與常用配置》,本文會用到gradle中全局屬性設置、文件讀取、shell指令執行等相關知識點;

  • 工程必須是lib工程,即該工程對應的build.gradle文件中要引用:

    apply plugin: 'com.android.library'

  • 在根目錄的build.gradle文件中添加

    allprojects {

    apply plugin: 'idea'
    apply plugin: 'maven'configurations {deployerJars
    }

    }

    configurations.all {

    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'//不使用緩存,使用倉庫中最新的包

    }

    subprojects { //表示除主工程外所有子模塊

    dependencies {deployerJars "org.apache.maven.wagon:wagon-http:2.2"
    }

    }

    ext { //倉庫選擇標記

    repoType = "remote" //發布到遠程倉庫(下文中會用到)

    // repoType = "local" //發布到本地倉庫,方便調試,避免調試期間頻繁上傳到maven倉庫(下文中會用到)
    }

  • 在gradle.properties文件中添加:

    releaseRepositoryUrl=xxx //正式包倉庫地址(下文中會用到)
    snapshotRepositoryUrl=xxx //測試包倉庫地址(下文中會用到)
    repositoryGroup=com.company.appname // 定義要上傳的aar所在倉庫的Group,可自定義,但后續引用處要與此一致

  • 在工程根目錄下新建一個名為“mavenAccount.properties”文件,并將該文件加入到ignore 中,該文件用于存放訪問maven倉庫的賬戶和密碼以及本地倉庫地址,只有該模塊的開發者才有權發布該aar包。

    repositoryUserName=xxx
    repositoryPassword=xxx
    localRepositoryUrl=file:///Users/admin/Documents/Android/repo/

2. 編寫上傳腳本

  • 生成aar包

    > 在工程根目錄下新建一個名為“release-as-aar.gradle”的文件,其中腳本如下:
    

    uploadArchives() {

    repositories {mavenDeployer {configuration = configurations.deployerJarsprintln 'repoType : ' + rootProject.ext.repoTypeif ((rootProject.ext.repoType).equals("remote")) { //發布到遠程倉庫snapshotRepository(url: snapshotRepositoryUrl) { // 測試包//從本地文件讀取倉庫賬號和密碼def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上傳到遠程倉庫'} else {println '沒有發布權限'}} else {println '沒有發布權限'}}repository(url: releaseRepositoryUrl) { // 正式包def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上傳到遠程倉庫'} else {println '沒有發布權限'}} else {println '沒有發布權限'}}} else { // 發布到本地倉庫def localRepositoryUrldef File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('localRepositoryUrl')) {localRepositoryUrl = props['localRepositoryUrl']snapshotRepository(url: localRepositoryUrl)repository(url: localRepositoryUrl)println '上傳到本地倉庫'} else {println '沒有發布權限'}} else {println '沒有發布權限'}}}
    }

    }

  • 生成jar包

    > 在工程根目錄下新建一個名為“release-as-jar.gradle”的文件,其中腳本如下:
    

    task androidJavadocs(type: Javadoc) {

    failOnError = false
    source = android.sourceSets.main.java.srcDirs
    ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
    classpath += files(ext.androidJar)

    }

    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {

    classifier = 'javadoc'
    from androidJavadocs.destinationDir

    }

    task androidSourcesJar(type: Jar) {

    classifier = 'sources'
    from android.sourceSets.main.java.srcDirs

    }

    uploadArchives {

    repositories {mavenDeployer {configuration = configurations.deployerJarsprintln 'repoType : ' + rootProject.ext.repoTypeif ((rootProject.ext.repoType).equals("remote")) { //發布到遠程倉庫snapshotRepository(url: snapshotRepositoryUrl) {def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上傳到遠程倉庫'} else {println 'sorry,你沒有上傳aar包的權限'}} else {println 'sorry,你沒有上傳aar包的權限'}}repository(url: releaseRepositoryUrl) {def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上傳到遠程倉庫'} else {println 'sorry,你沒有上傳aar包的權限'}} else {println 'sorry,你沒有上傳aar包的權限'}}} else {//發布到本地倉庫def localRepositoryUrldef File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('localRepositoryUrl')) {localRepositoryUrl = props['localRepositoryUrl']snapshotRepository(url: localRepositoryUrl)repository(url: localRepositoryUrl)println '上傳到本地倉庫'} else {println 'sorry,本地倉庫路徑不存在'}} else {println 'sorry,本地倉庫路徑不存在'}}}
    }

    }

    artifacts {

    archives androidSourcesJar
    archives androidJavadocsJar

    }

3. 子模塊中相關配置

  • 在子模塊的build.gradle文件中添加:

    group repositoryGroup
    //version '0.0.1'
    version '0.0.1-SNAPSHOT' //表示測試版,正式發版時去掉“-SNAPSHOT”

    //打成aar格式
    apply from: '../release-as-aar.gradle' //引用上傳插件

    //打成jar格式
    //apply from: '../release-as-jar.gradle'

4. 打包上傳

  • 編譯通過后,打開android studio自帶的終端,進入相應的module目錄下,輸入:gradle uploadArchives

5. 使用aar

  • 在需要引用aar包的工程中,根目錄的build.gradle文件中進行如下配置:

    allprojects {

    repositories {

    // jcenter(); //注釋jcenter,表示不直接從jcenter倉庫獲取,而是通過公司私服倉庫去獲取

        maven {name 'xxx' //key與value之間有空格url 'xxx' //key與value之間有空格}mavenLocal();
    }

    }

  • 在子模塊的build.gradle文件中進行如下引用:

    dependencies {

    compile group: repositoryGroup, name: 'xxx', version: '0.0.1', ext: 'aar', changing: true

    }

6. 踩到的坑

  • 問題一:上傳時找不到服務器

上傳時需關閉android studio的翻墻代理設置,且注釋settings.gradle中自動生成的代理服務器相關配置,否則上傳時會報找不到倉庫服務器的錯誤。

  • 問題二:aar包無法更新

有時上傳了最新的snapshot包,引用的地方也sync、clean了,但引用的還是舊的包,此時需要刪除“~/.gradle”中的相關記錄。為方便執行,我們可以在應用工程根目錄的build.gradle文件中,采用shell命令刪除,該命令會在你執行clean操作時先執行:

    task deleteDescriptors(type: Exec) { //執行shell命令executable "sh"args "-c", "rm -rf ~/.gradle/caches/modules-2/metadata-2.16/descriptors/com.company.appname" //此處的“com.company.appname“就是之前定義的“repositoryGroup“。}task clean(type: Delete, dependsOn: deleteDescriptors) { //clean工程時順帶執行上述任務delete rootProject.buildDir}

此時,再clean一下,引用的就是最新的aar包了。

  • 問題三:無法設置debug編譯類型

在lib工程中無論怎么設置編譯類型,最后生成的aar包中始終都是release版本,該問題見google反饋。既然不可設置編譯類型,我們可以在aar包代碼中通過反射來獲取應用的編譯類型:

    private Object getBuildConfigValue(Context context, String fieldName) {try {Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");Field field = clazz.getField(fieldName);return field.get(null);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}//使用String buildType = getBuildConfigValue(ctx,"BUILD_TYPE").toString();if (!TextUtils.isEmpty(buildType) && buildType.equals("debug")) { // debug...} else { // release...}

但是,這里面還有一個坑,系統版本在4.4以下的設備中,該方法無法獲得包名,會拋空指針錯誤。以下我們給出完整的解決方案:

     public class BuildConfigProvider {private static Context sContext;private static String packageName;public static String getBuildType() {String buildType = (String) getBuildConfigValue("BUILD_TYPE");if ("debug".equals(buildType)) {buildType = "debug";}if ("release".equals(buildType)) {buildType = "release";}return buildType;}public static final boolean isDebug() {return BuildConfig.DEBUG;}/*** 通過反射獲取ApplicationContext** @return*/private static Context getContext() {if (sContext == null) {try {final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");final Method currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread");final Object activityThread = currentActivityThread.invoke(null);final Method getApplication = activityThreadClass.getDeclaredMethod("getApplication");final Application application = (Application) getApplication.invoke(activityThread);sContext = application.getApplicationContext();} catch (Exception e) {e.printStackTrace();}}return sContext;}/*** 通過反射獲取包名** @return*/private static String getPackageName() {if (packageName == null) {try {final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");final Method currentPackageName = activityThreadClass.getDeclaredMethod("currentPackageName");packageName = (String) currentPackageName.invoke(null);} catch (Exception e) {packageName = getContext().getPackageName();}}return packageName;}public static Object getBuildConfigValue(String fieldName) {try {Class<?> clazz = Class.forName(packageName + ".BuildConfig");Field field = clazz.getField(fieldName);return field.get(null);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IndexOutOfBoundsException e) {e.printStackTrace();}return "";}}

當然,有人可能會說,既然可以通過反射得到ApplicationContext,就沒必要再去反射獲得包名了,這里只是提供不同的解決方案以作參考。

  • 問題四:多包共存模式下獲得編譯類型為空

在上一篇博客《 Gradle實際應用(二):同名包共存》中,我們可以在一個設備中安裝同一個應用不同編譯類型的包。但是,非release包中我們獲得的包名是帶有編譯類型后綴的(如“com.company.appname.debug“),而編譯類型我們是通過反射獲取,“BuildConfig“所在的包名還是原始的、不加后綴的包名(如“com.company.appname“),此時我們拿到的編譯類型為空,那么我們可以在獲取包名后做一個檢查:

    private static String checkPackageName(String packageName) {String[] temp = packageName.split("\\.");String sub = temp[temp.length - 1];//如果多包共存模式,剔除包名中的后綴if (sub.equals("debug")) {StringBuilder sb = new StringBuilder();for (int i = 0; i < temp.length - 1; i++) {sb.append(temp[i]);if (i != temp.length - 2) {sb.append(".");}}packageName = sb.toString();}return packageName;}

深入學習

  • 同步aar到jCenter與maven central

  • Android Studio使用Gradle上傳AAR至Maven

  • aar無法設置debug問題解決參考

查看原文:http://blog.csdn.net/u0108184...

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283725.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283725.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283725.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

synchronized與Lock的區別

類別synchronizedLock存在層次Java的關鍵字&#xff0c;在jvm層面上是一個類鎖的釋放1、以獲取鎖的線程執行完同步代碼&#xff0c;釋放鎖 2、線程執行發生異常&#xff0c;jvm會讓線程釋放鎖在finally中必須釋放鎖&#xff0c;不然容易造成線程死鎖鎖的獲取假設A線程獲得鎖&am…

even兼容

var eventarguments.callee.caller.arguments[0]||window.event;//消除瀏覽器差異 var ewindow.event||event; //消除瀏覽器差異 轉載于:https://www.cnblogs.com/webqiand/articles/11250768.html

普通中年人的真實出路

閱讀本文大概需要6分鐘。互聯網人甚至中國整體的用工市場的確有中年淘汰的問題&#xff0c;我們可以當它不存在&#xff0c;甚至當有人給出解法的時候&#xff0c;我們也可以認為他們在傳播焦慮&#xff0c;但事實就是事實&#xff0c;它的存在不隨個人意愿而轉移。最近抖音上有…

項目管理常見的問題

綜合管理 缺乏企業級的項目管理平臺;項目目標不清楚;項目經理不了解項目管理流程和工具;項目模板不統一;計劃意識薄弱&#xff0c;缺乏規范的分解。難以過程監控&#xff0c;實時地了解項目進度,靠手工統計和匯報項目進度&#xff0c;難以真實反映進度。項目控制不力&#xff0…

常用小提示

阿里云Linux安裝軟件鏡像源 第一步&#xff1a;備份你的原鏡像文件&#xff0c;以免出錯后可以恢復。 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup第二步&#xff1a;下載新的CentOS-Base.repo 到/etc/yum.repos.d/ CentOS 5 wget -O /etc…

抽象工廠模式(Absraact Factory)介紹與實現

創建一個IProduct,后面模擬業務時要用到 package com.xiawei.factory; public class IProduct { private String productNo "";} package com.xiawei.factory;/** * 規范工廠接口 </p> *///創建一個所有工廠的規范接口,后面所有的工廠類都要來實現這個接口,并…

【溫故知新】C# Linq中 Select SelectMany 使用技巧

微信公眾號&#xff1a;趣編程ACE關注可了解更多的.NET日常實戰開發技巧&#xff0c;如需源碼 后臺回復 源碼 即可;如果覺得對你有幫助&#xff0c;歡迎關注C# Linq中 Select && SelectMany 使用技巧Select 和 SelectMany 是我們開發中對集合常用的兩個擴展方法&#x…

bzoj4870

http://www.lydsy.com/JudgeOnline/problem.php?id4870 矩陣快速冪。。。 人話題意&#xff1a;從nk個物品里選模k余r個物品&#xff0c;問方案數模P 那么我們有方程 f[i][j]f[i-1][j]f[i-1][j-1] 跟組合數一個樣子 j∈(0,k) 這個物品選還是不選加起來 構造矩陣&#xff1a;x.…

15000 字的 SQL 語句大全,值得收藏!

基礎 1、說明&#xff1a;創建數據庫 CREATE DATABASE database-name 2、說明&#xff1a;刪除數據庫 drop database dbname 3、說明&#xff1a;備份sql server --- 創建 備份數據的 device USE master EXEC sp_addumpdevice disk, testBack, c:\mssql7backup\MyNwind_1.dat -…

Codeforces Round #410 (Div. 2) D. Mike and distribution 思維+數學

鏈接&#xff1a; http://codeforces.com/contest/798/problem/D 題意&#xff1a; 給你兩個長度為n的數列a和b&#xff0c;讓你選n/21個下標&#xff0c;使得2*∑ai>suma,2*∑bi>sumb 題解1&#xff1a; 用一個叫random_shuffle的東西&#xff0c;每次都亂選&#xff0c…

PerfView專題 (第三篇):如何尋找 C# 中的 VirtualAlloc 內存泄漏

一&#xff1a;背景 上一篇我們聊到了如何用 PerfView 去偵察 NTHeap 的內存泄漏&#xff0c;這種內存泄漏往往是用 C 的 malloc 或者 C 的 new 分配而不釋放所造成的&#xff0c;這一篇我們來聊一下由 VirtualAlloc 方法造成的泄漏如何去甄別&#xff1f;了解 VirtualAlloc 的…

[APP]- 找回Xcode7的代碼折疊功能

為什么80%的碼農都做不了架構師&#xff1f;>>> 原 找回Xcode7的代碼折疊功能 升級到Xcode7后&#xff0c;會發現代碼折疊功能不見了&#xff0c;這是怎么回事&#xff1f; 其實這個功能還在的&#xff0c;只是蘋果默認把這個功能禁掉了&#xff1a;在Xcode菜單里選…

有哪些值得推薦的.NET ORM框架?

前言&#xff1a; 最近有很多同學問我.NET方面有哪些好用的ORM框架&#xff0c;我覺得這方面的介紹網上應該會介紹的比較全面文章&#xff0c;于是我想搜一篇全面的介紹文章發給他們結果我發現網上說來說去基本上就是那幾個&#xff0c;于是就有了這篇文章。 什么是ORM? ORM 是…

從S3中導入數據到Dynamodb

本節如果你已經從Dynamodb中導出過數據&#xff0c;而且導出的文件以及被存入S3。文件內部結構會在Verify Data Export File 中描寫敘述。我們稱之前導出數據的原始表為source table&#xff0c;數據將要被導入的表為destination table。你能夠將S3中的導出文件導入到dynamodb的…

HTML5程序開發范例寶典 完整版 (韓旭等著) 中文pdf掃描版

HTML5程序開發范例寶典緊密圍繞編程者在編程中遇到的實際問題和開發中應該掌握的技術&#xff0c;全面介紹了利用HTML進行程序開發的各方面技術和技巧。全書共16章&#xff0c;內容包括HTML網頁布局、HTML基本元素、HTML高級元素、表單的使用、列表的使用、超鏈接、表格應用、圖…

ASP.NET Core 6框架揭秘實例演示[11]:診斷跟蹤的幾種基本編程方式

在整個軟件開發維護生命周期內&#xff0c;最難的不是如何將軟件系統開發出來&#xff0c;而是在系統上線之后及時解決遇到的問題。一個好的程序員能夠在系統出現問題之后馬上定位錯誤的根源并找到正確的解決方案&#xff0c;一個更好的程序員能夠根據當前的運行狀態預知未來可…

Autofac詳解

Autofac詳解 零、文章目錄 一、Autofac詳解 1、概述 Autofac是第三方IOC容器&#xff0c;是當前最流行的IOC容器。功能強大&#xff0c;比asp.netcore內置容器強大得多&#xff0c;支持屬性注入和方法注入&#xff0c;支持AOP。官網地址&#xff1a;http://autofac.org/源碼下載…

與ObjectDataSource共舞

4&#xff0c;ORM組件XCode&#xff08;與ObjectDataSource共舞&#xff09; XCode為了能更方便的解決大部分問題&#xff0c;不得不“屈身”于ObjectDataSource。 先上一個經典例子&#xff08;ObjectDataSourceGridView&#xff09;&#xff08;ObjectDataSource&#xff0…

ASP.NET Core 3.1中使用JWT身份認證

文章目錄 0、引言1、關于Authentication與Authorization2、整個認證流程是怎樣的&#xff1f;3、開始JWT身份認證 3.1 安裝JwtBearer包3.2 安裝Swashbuckle.AspNetCore包3.3 添加身份認證相關服務到容器中3.4 添加Swagger服務到容器中3.5 將身份認證加入到管道中3.6 將swagger加…

簡單泛型

一般的類和方法&#xff0c;只能使用具體的類型&#xff1a;要么是基本類型&#xff0c;要么是自定義的類。如果要編寫可以應用于多種類型的代碼&#xff0c;這種刻板的限制對代碼的束縛就會很大。----《java Generics FAQ》 多態算是一種泛化機制。例如&#xff0c;將方法的參…