Gradle实战:发布aar包到maven仓库

查看原文:http://blog.csdn.net/u010818425/article/details/52441711

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.deployerJars
    
                println ‘repoType : ‘ + rootProject.ext.repoType
    
                if ((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 localRepositoryUrl
                    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(‘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.deployerJars
    
                println ‘repoType : ‘ + rootProject.ext.repoType
    
                if ((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 localRepositoryUrl
                    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(‘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的FQ代理设置,且注释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;
    }
    

深入学习

查看原文:http://blog.csdn.net/u010818425/article/details/52441711

时间: 2024-11-10 08:15:58

Gradle实战:发布aar包到maven仓库的相关文章

maven添加本地jar包到maven仓库

maven添加本地jar包到maven仓库mvn install:install-file -DgroupId=io.netty -DartifactId=netty-all -Dversion=5.0.0.Alpha1 -Dpackaging=jar -Dfile=G:/java/jar包/netty-all-5.0.0.Alpha1.jar 我下载的这个 jar 包是放到了 D:\mvn 目录下(D:\mvn\spring-context-support-3.1.0.RELEASE.jar)

手动添加jar包到maven仓库

引言: 虽然配置了maven以后可以通过索引的方式自动下载jar包到本地maven仓库,从而使项目中直接使用本地仓库里面的架包, 但是这一招并不是每一次都灵应,也有遇到了失败的时候,当遇到失败的时候,我们可以通过使用命令的形式将架包导入 本地的maven仓库,然后项目中就可以直接使用了.eg: 我在使用druid时无法从阿里的仓库中直接获取到druid-1.0.27-sources.jar. druid-1.0.27-javadoc.jar,只能从国际仓库中获取了以后在导入到本地仓库. 1. m

安装jar包到maven仓库

1)将所要安装的jar包放在自定义目录下. 2)(maven环境变量配置无误的情况下)windows环境下,打开命令提示符,输入如下命令: mvn install:install-file -Dfile=jar包的位置 -DgroupId=上面的groupId -DartifactId=上面的artifactId -Dversion=上面的version -Dpackaging=jar 3)这时,可以打开Maven仓库,根据groupId查找刚才安装的jar包位置. 4)打开.pom文件,复制j

发布jar包至maven本地库及私服

pom文件见附件,如不打至私服,不需要 <distributionManagement> 标签 中的内容 C:\Users\chao.gao>E: E:\>cd E:\old_passform\jfinal_demo_for_jsp\WebRoot\WEB-INF\lib E:\old_passform\jfinal_demo_for_jsp\WebRoot\WEB-INF\lib>mvn install:install-file  -DgroupId=com.cloopen

如何上传jar包到maven仓库

拷贝jar包到非本地仓库目录 进入控制台,输入下面命令即可: mvn deploy:deploy-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar -Dfile=ojdbc6-11.2.0.3.jar -Durl=http://ip:port/nexus/content/repositories/releases/ -DrepositoryId=Releases 其中Durl.Drep

Tomcat发布War包或者Maven项目

在tomcat的conf目录下面的server.xml中修改如下: Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> <Context path="/ibs-auth

windows下将jar包打入maven仓库

mvn install:install-file -DgroupId=org.csource -DartifactId=fastdfs-client-java -Dversion=1.27 -Dpackaging=jar -Dfile=D://fastdfs-client-java-1.27-SNAPSHOT.jar DgroupId:项目的包名 DartifactId:项目模块名 Dversion:版本号 Dfile:jar包的本地地址 原文地址:https://www.cnblogs.com

如何将自己打的jar包放到maven仓库中

1,导入 mvn install:install-file -DgroupId=com.qsfs  -DartifactId=qsfs  -Dversion=1.0 -Dfile=文件的绝对路径   -Dpackaging=jar 2,引入 pom文件引入的时候为 ?<dependency> <groupId>com.qsfs </groupId> <artifactId>qsfs</artifactId> <version>1.0&

Gradle实战:Android多渠道打包方案汇总

查看原文:http://blog.csdn.net/u010818425/article/details/52319382 Gradle实战系列文章: <Gradle基本知识点与常用配置> <Gradle实战:不同编译类型的包同设备共存> <Gradle实战:发布aar包到maven仓库> <Gradle实战:执行sql操作hive数据库> 本文将延续之前几篇博客的风格,先从基本概念入手,这有助于我们对后文的理解: 在后续的代码中如果忘了某个概念的具体意义,