为Android组件化项目搭建Maven私服

概览

文章目录

      • 概览
      • 前言
      • 搭建 maven 私服
        • 服务器环境
        • jdk安装配置
        • nexus安装配置
        • 管理创建存储点、仓库
      • 项目中使用 maven 私服
        • 上传 module 到仓库
          • 自动发布 module
          • 手动上传单个aar包
        • 引用仓库中的 module
          • build.gradle引入远程module
      • FAQ
        • 开发阶段有些module用远程依赖,有些module用本地依赖,造成BuildConfig中DEBUG环境变量不一致?
        • 发布的组件中远程依赖引用不到了?
        • 引用的第三方aar无需根据编译环境分别打包正式/测试版,如何处理?
      • 参考链接

前言

本文根据网络上的文章以及个人实践,综合整理而成。
做这件事的目的,是为了缩短APP的编译时间。
记得接手公司项目的时候,项目已经使用了当时流行的组件化方案,当时项目刚起步,组件不多,比较轻量化,编译一次正式版用时大概五分钟左右。这几年随着项目和技术的发展,组件化方案中间重构更换了一次,项目中的组件也发展到了二十多个,现在编译一次正式版,不算加固时间,用时十七分钟左右。
开发调试阶段目前也饱受困扰。由于所有组件都依赖base_lib,只要base中改了一个字符,debug调试编译时所有组件就会重新编译一遍,及其浪费时间。

搭建 maven 私服

要正常安装使用 maven 私服,需要几个前置条件,如果你的服务器都满足的话,可以跳过这几个配置:

  • 根据nexus需求,安装合适的 java 环境
  • 安装合适的 nexus 版本
  • 打开服务器8081端口,用以支持在浏览器访问nexus管理页面
服务器环境
jdk安装配置

Download jdk 11这里我下载的是Linux x64 Compressed Archive-jdk-11.0.22这个版本
在这里插入图片描述

  1. 使用sftp上传到服务器/opt/jdk目录
    在这里插入图片描述

  2. 解压到当前目录

    cd /opt/jdk
    tar -zxvf jdk-11.0.22_linux-x64_bin.tar.gz
    

    在这里插入图片描述

  3. 使用sftp修改环境配置文件:/etc/profile

    #jdk config(在文档结尾插入)
    export JAVA_HOME=/opt/jdk/jdk-11.0.22
    export PATH=$PATH:$JAVA_HOME/bin
    export CLASSPATH=.:$JAVA_HIOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    

    在这里插入图片描述

  4. 重启 /etc/profile 使之重新生效:

    source /etc/profile
    
  5. 验证 JDK 是否安装成功

    java --version
    

    在这里插入图片描述

nexus安装配置

Download Sonatype Nexus Repository根据安装的java版本选择对应的安装包,这里我下载的是/nexus-3.68.1-02-java11-unix这个版本,对应java11
在这里插入图片描述

  1. 使用sftp上传到服务器/opt/nexus目录

  2. 解压到当前目录

    cd /opt/nexus
    tar -zxvf nexus-3.68.1-02-java11-unix.tar.gz
    

    在这里插入图片描述

  3. 使用sftp编辑配置文件/opt/nexus/nexus-3.68.1-02/bin/nexus.rc

    run_as_user="root"
    

    在这里插入图片描述

  4. 查看并开放8081端口

    # 查看防火墙某个端口是否开放
    firewall-cmd --query-port=8081/tcp
    # 开放防火墙端口 8081
    firewall-cmd --add-port=8081/tcp --permanent
    # 重新加载防火墙规则
    firewall-cmd --reload
    # 再次查看防火墙某个端口是否开放
    firewall-cmd --query-port=8081/tcp
    

    在这里插入图片描述

  5. 进入bin目录启动nexus

    cd /opt/nexus/nexus-3.68.1-02/bin
    ./nexus start
    

    在这里插入图片描述

  6. 浏览器进入管理页面,http://[服务器ip]:8081
    在这里插入图片描述

  7. 登录账号,admin 的密码在/opt/nexus/sonatype-work/nexus3/admin.password文件中
    在这里插入图片描述

管理创建存储点、仓库
  1. 创建存储点
    默认存储点是default,你也可以直接用默认的,不创建新的
    登录账号,依次进入Setting->Repository->Blob Stores
    在这里插入图片描述

  2. 创建仓库
    在创建仓库前,先介绍一下仓库的三种存储类型Release、Snapshot和Mixed,创建仓库时会使用到
    Release(正式版): 正式版,适合项目稳定后正式发布使用,特性看下面的原理简介。
    Snapshot(快照版): 快照版,适合项目在开发调试中使用,特性看下面的原理简介。
    Mixed(混合版): 可包含release和snapshot版本

    ReleaseSnapshot的原理简介:
    它们的主要区别在于本地获取这些依赖的机制不同。

    • 对于Release版本的项目: 当项目中添加了一个正式版的version为x的依赖时,构建工具在构建项目时会从远程仓库中下载这个version为x的依赖到本地仓库缓存起来,下次再构建项目时,构建工具会从本地仓库中查找是否存在这个version为x的依赖,存在就不会在去远程仓库中拉取。这种特性会导致在团队开发中,如果你发布一个正式版的项目时,仍然使用的是同一个version,就可能出现其他使用这个version项目的成员根本接收不到项目的最新变更,这是糟糕的,为了生命安全,大家尽量不要这么做。所以,在每次发布正式版项目时,必须更新version。
    • 对于Snapshot版本的项目: 当项目中添加了一个快照版的version为x的依赖时,不管本地仓库中是否存在这个version为x的依赖,构建工具都会尝试从远程仓库中查看这个version为x的依赖是否最新。这样就能保证团队开发时,所有使用这个version为x的依赖的项目都能获取到依赖最新的变更,而且不用不停的迭代依赖的version。最后一还有一点,Snapshot版项目发布时的version一定要以-SNAPSHOT结尾,英文字母必须大写。

    依次进入Setting->Repository->Repositories
    在这里插入图片描述
    在这里插入图片描述

项目中使用 maven 私服

上传 module 到仓库
自动发布 module
  1. 在module的 build.gradle 同级创建publish.gradle

    apply plugin: "maven-publish"
    
    afterEvaluate {
        def ext = rootProject.ext
        publishing {
            publications {
                release(MavenPublication) {
    
                    groupId 'com.wln100.future'
                    artifactId 'fragmentation'
                    version '1.0.0-SNAPSHOT'
    
                    if (isAndroidEnv(project)) {
                        from project.components.release
                    } else {
                        from project.components.java
                    }
    
                    pom {
                        name = 'fragmentation'
                        description = 'fragmentation'
                        url = ext.nexusMavenUrl
                    }
                }
            }
    
            repositories {
                maven {
                    allowInsecureProtocol true
                    url = ext.nexusMavenUrl
                    credentials {
                        username ext.nexusMavenUsername
                        password ext.nexusMavenPassword
                    }
                }
            }
        }
    }
    
    static def isAndroidEnv(Project project) {
        return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
    }
    
  2. 在 module 的 build.gradle 引入 publish.gradle

    apply plugin: 'com.android.library'
    
    ...
    android {
        compileSdk compileVersion
    
        defaultConfig {
            ...
        }
    
        buildTypes {
            ...
        }
        ...
    
    }
    
    dependencies {
        ...
    }
    //引入自动发布gradle
    apply from: project.file('publish.gradle')
    
  3. 同步代码,运行GradleTask
    在这里插入图片描述

  4. 之后在仓库管理页面可以看到上传成功的module
    在这里插入图片描述

手动上传单个aar包
  1. 管理页面进入Upload->android-examonline-hosted
    在这里插入图片描述

  2. 上传aar,填写必要参数
    在这里插入图片描述
    在这里插入图片描述

引用仓库中的 module

首先需要在项目级的build.gradle中添加仓库地址:

buildscript {
    ...
    repositories {
        //本地私服仓
        maven {
            allowInsecureProtocol true
            url 'http://[服务器ip]:8081/repository/[仓库名称]/'
        }
        ...
    }
    ...
}
...
allprojects {
    repositories {
        //本地私服仓
        maven {
            allowInsecureProtocol true
            url 'http://[服务器ip]:8081/repository/[仓库名称]/'
        }
        ...
    }
}
...
build.gradle引入远程module
dependencies {
    //引入组件module  
    api 'com.wln100.future:fragmentation:1.0.0-SNAPSHOT'
    //引入单个aar
    api 'me.yokeyword.fragmentation:fragmentation_core:1.0'
}

FAQ

开发阶段有些module用远程依赖,有些module用本地依赖,造成BuildConfig中DEBUG环境变量不一致?

我的解决方式为,发布module时,分别发布debug和release两包到两个仓库中;引入依赖时,根据编译命令动态切换对应的私服仓库:

  1. 发布时分别发布debug和release
    //publish.gradle
    afterEvaluate {
        publishing {
            publications {
                release(MavenPublication) {
                    ...
                    if (isAndroidEnv(project)) {
                        //打包release module
                        from project.components.release
                    } else {
                        from project.components.java
                    }
                    ...
                }
    
                debug(MavenPublication) {
                    ...
                    if (isAndroidEnv(project)) {
                    //打包debug module
                        from project.components.debug
                    } else {
                        from project.components.java
                    }
                    ...
                }
            }
    
            repositories {
                maven {
                    allowInsecureProtocol true
                    //根据编译任务动态设置发布仓库
                    if (isReleaseBuild()) {
                        url = NEXUS_URL
                    } else {
                        url = NEXUS_DEBUG_URL
                    }
                    ...
                }
            }
        }
        
    // 定义一个函数来判断是否为release版本
    def isReleaseBuild() {
        def taskNames = gradle.startParameter.taskNames
        println "isReleaseBuild>>>>taskNames:$taskNames"
        return taskNames.any { it.toLowerCase().contains("release") }
    }
    
    
    
  2. 项目根目录build.gradle动态设置仓库
    //project build.gradle
    ...
    allprojects {
        apply from: "$rootDir/gradle/maven-utils.gradle"
        repositories {
            ...
            //本地私服仓-自有组件
            maven {
                allowInsecureProtocol true
                if (isReleaseBuild()) {
                    url NEXUS_URL
                } else {
                    url NEXUS_DEBUG_URL
                }
            }
            google()
            ...
            maven { url 'https://jitpack.io' }
        }
    }
    
发布的组件中远程依赖引用不到了?

发布时配置发布参数withxml

afterEvaluate {

    publishing {
        publications {
            release(MavenPublication) {
                ...
                pom {
                    ...
                    withXml {
                        def dependenciesNode = asNode().getAt('dependencies')[0] ?:
                                asNode().appendNode('dependencies')
                        configurations.api.getDependencies().each {
                            dep -> addDependency(project, dependenciesNode, dep, "compile")
                        }
                        configurations.implementation.getDependencies().each {
                            dep -> addDependency(project, dependenciesNode, dep, "runtime")
                        }
                    }
                }
            }

            debug(MavenPublication) {
                ...
                pom {
                    ...
                    withXml {
                        def dependenciesNode = asNode().getAt('dependencies')[0] ?:
                                asNode().appendNode('dependencies')

                        configurations.api.getDependencies().each {
                            dep -> addDependency(project, dependenciesNode, dep, "compile")
                        }
                        configurations.implementation.getDependencies().each {
                            dep -> addDependency(project, dependenciesNode, dep, "runtime")
                        }
                    }
                }
            }
        }
        ...
    }
}

private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) {
    if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
        return
    }
    if (dep.version == 'unspecified') {
        return
    }

    final dependencyNode = dependenciesNode.appendNode('dependency')
    dependencyNode.appendNode('scope', scope)
    dependencyNode.appendNode('groupId', dep.group)
    dependencyNode.appendNode('artifactId', dep.name)
    dependencyNode.appendNode('version', dep.version)
    println("publish -> library <${dep.group}:${dep.name}:${dep.version}>")

    if (!dep.transitive) {
        // In case of non transitive dependency,
        // all its dependencies should be force excluded from them POM file
        final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
        exclusionNode.appendNode('groupId', '*')
        exclusionNode.appendNode('artifactId', '*')
    } else if (!dep.properties.excludeRules.empty) {
        // For transitive with exclusions, all exclude rules should be added to the POM file
        final exclusions = dependencyNode.appendNode('exclusions')
        dep.properties.excludeRules.each { ExcludeRule rule ->
            final exclusionNode = exclusions.appendNode('exclusion')
            exclusionNode.appendNode('groupId', rule.group ?: '*')
            exclusionNode.appendNode('artifactId', rule.module ?: '*')
        }
    }
}
引用的第三方aar无需根据编译环境分别打包正式/测试版,如何处理?

新建一个专门存放三方aar库的私服仓库,单独上传依赖三方aar。

//project build.gradle
...
allprojects {
    apply from: "$rootDir/gradle/maven-utils.gradle"
    repositories {

        //本地私服仓-三方lib
        maven{
            allowInsecureProtocol true
            url 'http://x.x.x.x:8081/repository/android-third-lib-hosted/'
        }
        ...
        google()
        ...
    }
}

参考链接

Centos开放端口以及查看端口和防火墙配置命令
centos7下搭建nexus
CentOS 7 安装 JDK11(注意版本号要与自己的版本一致)
centos7安装Nexus(Maven私服)与配置使用教程
【github】Blankj/AndroidUtilCode-publish.gradle

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/676947.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

构建大型语言模型(LLM)产品的实战指南

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

#13前端后花园周刊-10个现代 Node.js 运行时新特性、Nextjs15、Astro4.9、CSS压缩

⚡️行业动态 JavaScript 的创建者 Brendan Eich 在 Twitter/X 上出现&#xff0c;反驳了 JS 是“最邋遢的”的说法&#xff0c;称其只有 50% 。 &#x1f4c6;发布 Next.js 15 RC 流行的 React 元框架已经准备好迎接一个主要的新版本&#xff0c;它有一个 RC&#xff0c;让…

YOLOv9改进策略 | 添加注意力篇 | 利用YOLOv10提出的PSA注意力机制助力YOLOv9有效涨点(附代码 + 详细修改教程)

一、本文介绍 本文给大家带来的改进机制是YOLOv10提出的PSA注意力机制&#xff0c;自注意力在各种视觉任务中得到了广泛应用&#xff0c;因为它具有显著的全局建模能力。然而&#xff0c;自注意力机制表现出较高的计算复杂度和内存占用。为了解决这个问题&#xff0c;鉴于注意…

群体优化算法---蝙蝠优化算法分类Iris数据集

介绍 蝙蝠算法&#xff08;Bat Algorithm, BA&#xff09;是一种基于蝙蝠回声定位行为的优化算法。要将蝙蝠算法应用于分类问题&#xff0c;可以通过将蝙蝠算法用于优化分类器的参数&#xff0c;图像分割等 本文示例 我们使用一个经典的分类数据集&#xff0c;如Iris数据集&…

基于深度学习的CT影像肺癌检测识别

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 肺癌是全球范围内导致癌症死亡的主要原因之一&#xff0c;早期检测和诊断对于提高患者生存率至关重要。随着深度学习技术的迅猛发展&#xff0c;基于CT影像的肺癌检测识别成为了研究热点。本文介绍…

Spire.PDF for .NET【文档操作】演示:在 C# 中向 PDF 文件添加图层

Spire.PDF 完美支持将多页 PDF 拆分为单页。但是&#xff0c;更常见的情况是&#xff0c;您可能希望提取选定的页面范围并保存为新的 PDF 文档。在本文中&#xff0c;您将学习如何通过 Spire.PDF 在 C#、VB.NET 中根据页面范围拆分 PDF 文件。 Spire.PDF for .NET 是一款独立 …

wireshark 二次开发

一、 Windows 准备 1、源代码下载 Git&#xff1a;https://github.com/wireshark/wireshark 2、 准备Visual C 要编译wireshark&#xff0c;开发电脑上应该安装了Visual Studio并包括了Visual C&#xff0c;请至少安装Visual Studio 2010以减少不必要的麻烦。 visual studio …

英码科技推出鸿蒙边缘计算盒子:提升国产化水平,增强AI应用效能,保障数据安全

当前&#xff0c;随着国产化替代趋势的加强&#xff0c;鸿蒙系统Harmony OS也日趋成熟和完善&#xff0c;各行各业都在积极拥抱鸿蒙&#xff1b;那么&#xff0c;边缘计算要加快实现全面国产化&#xff0c;基于鸿蒙系统开发AI应用势在必行。 关于鸿蒙系统及其优势 鸿蒙系统是华…

友顺科技(UTC)分立器件与集成IC产品选型和应用

友顺科技股份有限公司成立于1990年&#xff0c;是全球领先的集成电路与功率半导体厂商 ,集团总部位于台北&#xff0c;生产基地位于福州、厦门。 友顺科技具有完整模拟组件产品线&#xff0c;其中类比IC涵盖各种稳压器、PWM控制IC, 放大器、比较器、逻辑IC、Voltage Translato…

Pulsar 社区周报 | No.2024-05-30 | BIGO 百页小册《Apache Pulsar 调优指南》

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;每周发布。 ” BIGO 百页小册《Apache Pulsar 调优指南》 Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问…

VB.net实战(VSTO):Excel插件设计Ribbon界面

1. 新建Ribbon 1.1 开发环境 Visual Studio 2022 1.2 解决方案资源管理器中右击My Project 1.3 添加》新建项 1.4 office/SharePoint》功能区(可视化设计器)&#xff0c;双击 2.调出工具箱 Visual Studio 2022》视图》工具箱 3.设计界面 3.1 添加功能区选项卡 3.2拖动Group…

OZON的选品工具,OZON选品工具推荐

在电商领域&#xff0c;选品一直是决定卖家成功与否的关键因素之一。随着OZON平台的崛起&#xff0c;越来越多的卖家开始关注并寻求有效的选品工具&#xff0c;以帮助他们在这个竞争激烈的市场中脱颖而出。本文将详细介绍OZON的选品工具&#xff0c;并推荐几款实用的辅助工具&a…

【嵌入式DIY实例】-OLED显示网络时钟和天气数据

OLED显示网络时钟和天气数据 文章目录 OLED显示网络时钟和天气数据1、硬件准备与接线2、代码实现在前面的的文章中,我们制作了一个互联网气象站,其中天气数据(温度、湿度、压力、风速和风度)被串行发送到笔记本电脑并显示在SSD1306 OLED屏幕(12864像素)上。 在该项目中,…

麦肯锡:ChatGPT等生成式AI应用激增,大中华区增长最快

全球顶级咨询公司麦肯锡&#xff08;McKinsey & Company&#xff09;在官网发布了《he state of AI in early 2024:Gen AI adoption spikes and starts to generate value》&#xff0c;一份关于生成式AI应用的调查报告。 麦肯锡对多个国家/地区的1,363位管理者进行了调查…

6个PPT素材模板网站,免费!

免费PPT素材模板下载&#xff0c;就上这6个网站&#xff0c;建议收藏&#xff01; 1、菜鸟图库 ppt模板免费下载|ppt背景图片 - 菜鸟图库 菜鸟图库是一个设计、办公、媒体等素材非常齐全的网站&#xff0c;站内有几百万的素材&#xff0c;其中PPT模板就有几十万个&#xff0c;…

vulnhub靶机Hack_Me_Please

下载地址&#xff1a;https://download.vulnhub.com/hackmeplease/Hack_Me_Please.rar 主机发现 目标192.168.21.160 端口扫描 nmap --min-rate 10000 -p- 192.168.21.160 服务扫描 nmap -sV -sT -O -p80,3306,33060 192.168.21.160 漏洞扫描 nmap --scriptvuln -p80,3306,…

论文Compiler Technologies in Deep Learning Co-Design: A Survey分享

目录 标题摘要引言背景深度学习软件和硬件的发展不同时期的协同设计深度学习协同设计系统神经网络架构设计和优化协同设计技术 用于协同设计的深度学习系统中的编译技术深度学习编译器TVM 生态系统和MLIR生态系统IR转换和优化代码生成运行时和执行模式 Buddy-Compiler: 一个针对…

(软工) 功能性和非功能性需求是什么?

文章目录 前言&#x1f31f;功能性需求⭐⭐⭐系统应该做什么&#xff1f;或者应该提供什么功能&#xff1f;⭐⭐⭐&#x1faf0;举例 &#x1f31f;非功能性需求⭐⭐⭐系统应该在哪些条件下能执行这些功能&#xff0c;且执行的很好。⭐⭐⭐❤️‍&#x1f525;质量属性(Quality…

(2024|ICML,Mamba2,SSD,SSM,SMA,矩阵变换,张量收缩,张量并行)Transformer 是 SSM

Transformers are SSMs: Generalized Models and Efficient Algorithms Through Structured State Space Duality 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 引言 2. …

SQL实验 数据的插入、修改和删除操作

一、实验目的 1&#xff0e;掌握Management Studio的使用。 2&#xff0e;掌握SQL中INSERT、UPDATE、DELETE命令的使用。 二、实验内容及要求 用SQL语句完成下列功能。使用数据库为SCHOOL数据库。 1、新开设一门课程&#xff0c;名叫网络安全与防火墙&#xff0c;学时40&#x…