├── .gitignore
├── CHANGE-LOG.md
├── LICENSE
├── README.md
├── README_PUBLISH.md
├── README_module作为app独立运行.md
├── README_pin工程处理.md
├── README_代码多平台复用.md
├── README_批量发布library到maven仓库.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── galaxybruce
│ │ └── poinner
│ │ └── ExampleInstrumentedTest.java
│ ├── app1
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── galaxybruce
│ │ │ └── pionner
│ │ │ └── demo
│ │ │ └── AppActivity_1.java
│ └── res
│ │ ├── layout
│ │ └── app_layout_1.xml
│ │ └── values
│ │ └── strings.xml
│ ├── app2
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── galaxybruce
│ │ │ └── pionner
│ │ │ └── demo
│ │ │ └── AppActivity_1.java
│ └── res
│ │ ├── layout
│ │ └── app_layout_1.xml
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── galaxybruce
│ │ │ └── poinner
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── content_main.xml
│ │ ├── menu
│ │ └── menu_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── galaxybruce
│ └── poinner
│ └── ExampleUnitTest.java
├── assembleMaven
├── assets
└── btn_apache_lisence.png
├── build.gradle
├── gradle.properties
├── gradle
├── publish.gradle
├── upload_maven.gradle
├── util.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── mutilplatform.png
├── pin.png
├── run_as_app_for_component1.png
└── run_as_app_for_component2.png
├── modulemaven.json
├── pioneer-gradle-plugin
├── build.gradle
├── gradle.properties
└── src
│ └── main
│ ├── groovy
│ └── com
│ │ └── galaxybruce
│ │ └── pioneer
│ │ ├── PioneerExtension.groovy
│ │ ├── PioneerPlugin.groovy
│ │ ├── PioneerSettingsPlugin.groovy
│ │ ├── aar
│ │ └── AARDependency.groovy
│ │ ├── copy
│ │ └── ProjectCopyOutputManager.groovy
│ │ ├── flutter
│ │ └── FlutterHandler.groovy
│ │ ├── manifest
│ │ ├── PlatformSourceUtil.groovy
│ │ └── ProjectManifestMerger.groovy
│ │ ├── maven
│ │ ├── MavenInfo.groovy
│ │ ├── MavenUploadManager.groovy
│ │ └── ModuleInfo.groovy
│ │ ├── run_module
│ │ ├── ProjectModuleCache.groovy
│ │ └── ProjectModuleManager.groovy
│ │ └── utils
│ │ ├── GitUtil.groovy
│ │ ├── LogUtil.groovy
│ │ ├── Utils.groovy
│ │ └── runtime
│ │ ├── ExecuteResult.java
│ │ ├── LocalCommandExecutor.java
│ │ ├── LocalCommandExecutorImpl.java
│ │ ├── RunTimeTask.java
│ │ └── StreamGobbler.java
│ └── resources
│ └── META-INF
│ └── gradle-plugins
│ ├── galaxybruce-pioneer-settings.properties
│ └── galaxybruce-pioneer.properties
├── repo-local
└── com
│ └── galaxybruce
│ ├── android
│ └── pioneer-gradle-plugin
│ │ ├── 0.1.2
│ │ ├── pioneer-gradle-plugin-0.1.2-javadoc.jar
│ │ ├── pioneer-gradle-plugin-0.1.2-javadoc.jar.md5
│ │ ├── pioneer-gradle-plugin-0.1.2-javadoc.jar.sha1
│ │ ├── pioneer-gradle-plugin-0.1.2-javadoc.jar.sha256
│ │ ├── pioneer-gradle-plugin-0.1.2-javadoc.jar.sha512
│ │ ├── pioneer-gradle-plugin-0.1.2-sources.jar
│ │ ├── pioneer-gradle-plugin-0.1.2-sources.jar.md5
│ │ ├── pioneer-gradle-plugin-0.1.2-sources.jar.sha1
│ │ ├── pioneer-gradle-plugin-0.1.2-sources.jar.sha256
│ │ ├── pioneer-gradle-plugin-0.1.2-sources.jar.sha512
│ │ ├── pioneer-gradle-plugin-0.1.2.jar
│ │ ├── pioneer-gradle-plugin-0.1.2.jar.md5
│ │ ├── pioneer-gradle-plugin-0.1.2.jar.sha1
│ │ ├── pioneer-gradle-plugin-0.1.2.jar.sha256
│ │ ├── pioneer-gradle-plugin-0.1.2.jar.sha512
│ │ ├── pioneer-gradle-plugin-0.1.2.module
│ │ ├── pioneer-gradle-plugin-0.1.2.module.md5
│ │ ├── pioneer-gradle-plugin-0.1.2.module.sha1
│ │ ├── pioneer-gradle-plugin-0.1.2.module.sha256
│ │ ├── pioneer-gradle-plugin-0.1.2.module.sha512
│ │ ├── pioneer-gradle-plugin-0.1.2.pom
│ │ ├── pioneer-gradle-plugin-0.1.2.pom.md5
│ │ ├── pioneer-gradle-plugin-0.1.2.pom.sha1
│ │ ├── pioneer-gradle-plugin-0.1.2.pom.sha256
│ │ └── pioneer-gradle-plugin-0.1.2.pom.sha512
│ │ ├── maven-metadata.xml
│ │ ├── maven-metadata.xml.md5
│ │ ├── maven-metadata.xml.sha1
│ │ ├── maven-metadata.xml.sha256
│ │ └── maven-metadata.xml.sha512
│ └── testlibrary-app2
│ ├── 1.0.1-SNAPSHOT
│ ├── maven-metadata.xml
│ ├── maven-metadata.xml.md5
│ ├── maven-metadata.xml.sha1
│ ├── maven-metadata.xml.sha256
│ ├── maven-metadata.xml.sha512
│ ├── testlibrary-app2-1.0.1-20221026.044255-1-sources.jar
│ ├── testlibrary-app2-1.0.1-20221026.044255-1-sources.jar.md5
│ ├── testlibrary-app2-1.0.1-20221026.044255-1-sources.jar.sha1
│ ├── testlibrary-app2-1.0.1-20221026.044255-1-sources.jar.sha256
│ ├── testlibrary-app2-1.0.1-20221026.044255-1-sources.jar.sha512
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.aar
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.aar.md5
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.aar.sha1
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.aar.sha256
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.aar.sha512
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.module
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.module.md5
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.module.sha1
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.module.sha256
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.module.sha512
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.pom
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.pom.md5
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.pom.sha1
│ ├── testlibrary-app2-1.0.1-20221026.044255-1.pom.sha256
│ └── testlibrary-app2-1.0.1-20221026.044255-1.pom.sha512
│ ├── maven-metadata.xml
│ ├── maven-metadata.xml.md5
│ ├── maven-metadata.xml.sha1
│ ├── maven-metadata.xml.sha256
│ └── maven-metadata.xml.sha512
├── settings.gradle
└── testlibrary
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
├── AndroidManifest.xml
├── androidTest
└── java
│ └── com
│ └── galaxybruce
│ └── testlibrary
│ └── ExampleInstrumentedTest.java
├── debug-test
├── AndroidManifest.xml
├── build.gradle
├── java
│ └── debug
│ │ ├── MyApp.java
│ │ └── activity
│ │ └── MainActivity.java
└── res
│ ├── layout
│ └── main_layout.xml
│ ├── mipmap-xhdpi
│ └── demo_b_ic_launcher.png
│ └── strings.xml
├── p_lib1
├── app1
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── galaxybruce
│ │ │ └── testlibrary
│ │ │ └── Lib1Activity_2.java
│ └── res
│ │ ├── layout
│ │ └── lib1_layout_2.xml
│ │ └── values
│ │ └── strings.xml
├── app2
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── galaxybruce
│ │ │ └── testlibrary
│ │ │ ├── GFileProvider.java
│ │ │ └── Lib1Activity_2.java
│ └── res
│ │ ├── layout
│ │ └── lib1_layout_2.xml
│ │ ├── values
│ │ └── strings.xml
│ │ └── xml
│ │ └── galaxybruce_provider_paths.xml
├── build.gradle
├── libs
│ └── Msc.jar
└── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── galaxybruce
│ │ └── testlibrary
│ │ └── Lib1Activity_1.java
│ └── res
│ ├── layout
│ └── lib1_layout.xml
│ └── values
│ └── strings.xml
├── p_lib2
└── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── galaxybruce
│ │ └── testlibrary
│ │ └── LibActivity2.java
│ └── res
│ ├── layout
│ └── lib2_layout.xml
│ └── values
│ └── strings.xml
└── test
└── java
└── com
└── galaxybruce
└── testlibrary
└── ExampleUnitTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea/
4 | /local.properties
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .MWebMetaData/
16 |
--------------------------------------------------------------------------------
/CHANGE-LOG.md:
--------------------------------------------------------------------------------
1 | ## 更新日志
2 |
3 | * 0.1.0 `2022/08/14`
4 | * [1] 增加新feature: module作为app独立运行
5 |
6 | * 0.0.1 `2019/03/29`
7 | * [1] 增加feature: pin工程处理
8 | * [2] 增加feature: 代码多平台复用
9 | * [3] 增加feature: 批量发布library到maven仓库
10 |
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2018 bruce.zhang
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | AndroidPioneer是一个汇集Android工程编译相关的gradle插件。
3 |
4 | ## bintray-release [](https://bintray.com/galaxybruce/maven/pioneer-gradle-plugin/_latestVersion) [](LICENSE)
5 |
6 | ### 目前有以下功能:
7 | * [module作为app独立运行](https://github.com/galaxybruce/AndroidPionner/blob/master/README_module%E4%BD%9C%E4%B8%BAapp%E7%8B%AC%E7%AB%8B%E8%BF%90%E8%A1%8C.md)
8 | * [pin工程处理](https://github.com/galaxybruce/AndroidPionner/blob/master/README_pin%E5%B7%A5%E7%A8%8B%E5%A4%84%E7%90%86.md)
9 | * [代码多平台复用](https://github.com/galaxybruce/AndroidPionner/blob/master/README_%E4%BB%A3%E7%A0%81%E5%A4%9A%E5%B9%B3%E5%8F%B0%E5%A4%8D%E7%94%A8.md)
10 | * [批量发布library到maven仓库](https://github.com/galaxybruce/AndroidPionner/blob/master/README_%E6%89%B9%E9%87%8F%E5%8F%91%E5%B8%83library%E5%88%B0maven%E4%BB%93%E5%BA%93.md)
11 |
12 |
--------------------------------------------------------------------------------
/README_PUBLISH.md:
--------------------------------------------------------------------------------
1 | ### 发布
2 | * 发布到local maven(.m2目录): ./gradlew :pioneer-gradle-plugin:publishToMavenLocal
3 | * 发布到remote maven或者指定目录: ./gradlew :pioneer-gradle-plugin:publish
4 | * 参考文章:https://juejin.cn/post/6844904185754812423
5 |
6 | ### 发布到jcenter,在项目根目录依次输入下面两个命令
7 | * ./gradlew install
8 | * ./gradlew bintrayUpload
9 |
10 | ### 发布到jcenter参考文章
11 | https://blog.csdn.net/linglongxin24/article/details/53415932
12 |
13 | 还有一篇宣传极简文章:https://juejin.im/post/59cef9baf265da066a105f92
14 |
15 | 也可以像arouter那样把install和bintray拆封成两个文件install.gradle和bintray.gradle
16 |
17 | butterknife中对android和java包做了区分,值得参考 https://github.com/JakeWharton/butterknife/blob/master/gradle/gradle-mvn-push.gradle
18 |
--------------------------------------------------------------------------------
/README_module作为app独立运行.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | `module作为app独立运行`是组件化开发中最基本的一个环节,适合团队规模不大,module在一个工程中的情况(团队非常大的情况,建议采用插件化的方式,每个业务独立为一个工程开发)。
3 |
4 | ### 效果图
5 | 
6 |
7 | ### 使用方式
8 |
9 | #### 1. 该功能默认是关闭的,如需开启,在 local.properties 中增加
10 | ```
11 | RUN_AS_APP_FOR_COMPONENT=true
12 | ```
13 |
14 | #### 2. 每个module的build.gradle最顶部添加
15 | ```
16 | apply plugin: 'galaxybruce-pioneer'
17 | ```
18 |
19 | #### 3. 每个module的src目录下增加 debug-test 目录
20 | 目录结构如下,参考 `testlibrary` module
21 |
22 | 
23 |
24 | 每个文件作用:
25 | * MyApp - 运行该module需要的最简初始化代码
26 | * MainActivity - 简单的入口(一般有两个按钮,一个登录,一个进入该模块功能)
27 | * AndroidManifest.xml - 配置MyApp以及MainActivity
28 | * build.gradle - 增加module独立运行时需要的额外依赖
29 |
30 | #### 4. 暴露给外面的属性
31 | * androidPluginApplied
32 | androidPluginApplied属性表示插件内部已经apply application或者library插件,外层可以根据该属性做些处理,如:
33 | ```
34 | if (!(project.ext.has('androidPluginApplied') && project.ext.androidPluginApplied)) {
35 | apply plugin: "com.android.library"
36 | }
37 | ```
38 |
39 | * runAsApp
40 | runAsApp属性表示该module是否已经apply application,外层可以根据这个属性做些处理,比如添加额外依赖
41 | ```
42 | if (!(project.ext.has('runAsApp') && project.ext.runAsApp)) {
43 |
44 | }
45 | ```
46 |
47 | * assembleThisModule
48 | assembleThisModule表示该module正在独立运行
49 |
--------------------------------------------------------------------------------
/README_pin工程处理.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | `pin工程处理`是在一个module中把业务进一步细化成更小的工程结构。具有以下优势:
3 | * 业务模块中进一步隔离代码和资源
4 | * 方便实验性代码的隔离和删除
5 | * 把相似业务作为pin工程放在一个module中,相比较作为一个module来说,编译速度更快
6 |
7 | ps: pin工程概念建议参考这篇文章[微信Android模块化架构重构实践](https://www.jianshu.com/p/3990724aa7e4)
8 |
9 | ### 使用方式
10 | #### 1. 插件默认开启pin工程支持,无需做任何配置
11 | #### 2. 在module的build.gradle中添加
12 | ```
13 | apply plugin: 'galaxybruce-pioneer'
14 | ```
15 | #### 3. pin工程目录约定都已p_开头,否则无法识别
16 | * 3.1 pin工程的目录结构与普通的module结构一模一样
17 | * 3.2 pin工程下可以设置独立的build.gradle,但是该build.gradle中不允许apply plugin: 'com.android.library'
18 | 
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README_代码多平台复用.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | `代码多平台复用`是指同一份代码支持差异化打包,配置不同的平台标识,运行差异化代码。
3 |
4 | ps: 多平台复用是可以和pin工程结合使用的
5 |
6 | ### 多平台项目结构介绍
7 | 
8 |
9 | * app1目录中只存放在app1上运行有差异化的代码
10 | * app2目录中只存放在app2上运行有差异化的代码
11 | * main目录中就是共用部分的代码
12 |
13 | ### 使用方式
14 | #### 1. 插件默认支持多平台复用,无需额外配置
15 |
16 | #### 2. 在module的build.gradle中添加
17 | ```
18 | apply plugin: 'galaxybruce-pioneer'
19 | ```
20 |
21 | #### 3. 根目录下的build.gradle中设置插件属性时指定当前平台标识
22 | ```
23 | apply plugin: 'galaxybruce-pioneer'
24 |
25 | galaxybrucepioneer {
26 | // 该标识用来匹配代码目录
27 | platformSourceDir = 'app2'
28 | ...
29 | }
30 | ```
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/README_批量发布library到maven仓库.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | `批量发布library到maven仓库`支持根据配置把工程中多个module发布到maven仓库。
3 |
4 | ### 使用方式
5 |
6 | #### 1. 根目录下的build.gradle中添加如下代码
7 | ```
8 | apply plugin: 'galaxybruce-pioneer'
9 |
10 | galaxybrucepioneer {
11 | // 配置需要发布到maven仓库的module信息
12 | moduleDataPath = "${project.rootDir.path}/modulemaven.json"
13 |
14 | // =================start==================
15 | // 公司maven私服
16 | mavenUrl = 'http://test.xxx.com/nexus/content/repositories/releases'
17 | // 公司maven私服SnapShot
18 | mavenUrlSnapShot = 'http://test.xxx.com/nexus/content/repositories/snapshots'
19 | // maven账号
20 | mavenAccount = 'deployment'
21 | // maven密码
22 | mavenPwd = '666666'
23 | // true: maven生成到指定目录:url = project.uri(project.rootProject.projectDir.absolutePath + '/repo-local')
24 | localMaven = false
25 | // =================end==================
26 | }
27 |
28 | buildscript {
29 | dependencies {
30 | classpath 'com.galaxybruce.android:pioneer-gradle-plugin:xxx'
31 | }
32 | }
33 | ```
34 |
35 | #### 2. 配置发布到module信息
36 | modulemaven.json:
37 | ```
38 | {
39 | "group": "com.galaxybruce",
40 | "version": "1.0.1",
41 | "modules": [
42 | {"name": "testlibrary", "artifactId": "testlibrary", "version": ""}
43 | ]
44 | }
45 | ```
46 | 每个library支持配置三个字段:
47 | * name: 必填项,必须是module名称
48 | * artifactId: 可选项,优先级: artifactId > project.name
49 | * version: 可选项,优先级: 这里的version > 上一层的version > android.defaultConfig.versionName
50 |
51 |
52 | #### 3. 上传maven命令:
53 | ```
54 | ./gradlew uploadMaven
55 | ```
56 |
57 | #### 4. 如果一个module上传为不同的平台发布,配置如下
58 | modulemaven.json内容:
59 | ```
60 | {
61 | "group": "com.galaxybruce",
62 | "version": "1.0.1",
63 | "platform_modules": {
64 | "app1": [
65 | {"name": "testlibrary"}
66 | ],
67 | "app2": [
68 | {"name": "testlibrary"}
69 | ]
70 | }
71 | }
72 | ```
73 |
74 | #### 5. 上传maven命令:
75 | ```
76 | ./gradlew uploadMaven -PplatformSourceDir=app1
77 | ./gradlew uploadMaven -PplatformSourceDir=app2
78 | ```
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'galaxybruce-pioneer'
3 |
4 | android {
5 | compileOptions {
6 | sourceCompatibility JavaVersion.VERSION_1_8
7 | targetCompatibility JavaVersion.VERSION_1_8
8 | }
9 |
10 | buildFeatures {
11 | dataBinding true
12 | }
13 |
14 | compileSdk 31
15 | defaultConfig {
16 | applicationId "com.galaxybruce.poinner"
17 | minSdkVersion 21
18 | targetSdkVersion 31
19 | versionCode 1
20 | versionName "1.0"
21 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation fileTree(dir: 'libs', include: ['*.jar'])
33 | implementation 'androidx.appcompat:appcompat:1.0.0'
34 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta7'
35 | implementation 'com.google.android.material:material:1.0.0'
36 | testImplementation 'junit:junit:4.12'
37 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
38 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
39 |
40 | implementation project(':testlibrary')
41 | }
42 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/galaxybruce/poinner/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.poinner;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.galaxybruce.poinner", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/app1/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
21 | * modification history:
22 | */
23 | class PioneerPlugin implements Plugin
12 | * modification history:
13 | *
14 | * @deprecated 该类已废弃,flutter依赖的插件module通过dart写的脚本依赖mvn命令批量上传
15 | */
16 | @Deprecated
17 | class FlutterHandler {
18 |
19 |
20 | static def handleRootProject(Project rootProject) {
21 | def plugins = new Properties()
22 | def pluginsFile = new File(rootProject.rootDir.parent, '.flutter-plugins')
23 | if (pluginsFile.exists()) {
24 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
25 | }
26 |
27 | // 在project.afterEvaluate中读取group version等参数并apply上传maven脚本
28 | rootProject.subprojects {
29 | project.afterEvaluate {
30 | project.plugins.withId('com.android.library') {
31 | if(plugins.containsKey(project.name) || 'flutter' == project.name) {
32 | // 读取shell脚本中运行./gradlew xxx命令时传递的参数
33 | def artGroupId = project.rootProject.hasProperty('gArtGroupId') ? project.rootProject.ext.gArtGroupId : null
34 | def artVersion = project.rootProject.hasProperty('gArtVersion') ? project.rootProject.ext.gArtVersion : null
35 |
36 | if(artGroupId && artVersion) {
37 | project.group = artGroupId
38 | project.version = artVersion
39 | // 第三方的包在group里加上.thirdparty
40 | if(project.projectDir.absolutePath.indexOf("pub-cache/hosted/pub.flutter-io.cn") >= 0
41 | || project.projectDir.absolutePath.indexOf("pub-cache\\hosted\\") >= 0) {
42 | project.group += ".thirdparty"
43 | }
44 |
45 | LogUtil.log(project, "PioneerPlugin", "==group: $project.group:$project.name:$project.version")
46 |
47 |
48 | // 给每个module添加上传maven脚本
49 | // def mavenScriptPath = project.rootProject.file('../android_flutter_maven.gradle')
50 | // project.apply from: mavenScriptPath
51 | applyMaven(project)
52 | }
53 | }
54 | }
55 | }
56 | }
57 |
58 | // 很重要,用来覆盖各个自依赖中的group和version
59 | // ./gradlew clean assembleRelease -PfGroupId=${fGroupId} -PfArtifactId=${fArtifactId} -PfVersion=${fVersion}
60 | // 执行了这个命令,根目录的build.gradle就会执行,这时候把参数设置到project.rootProject.ext,后面各个subProject就可以拿到
61 | final def artGroupId = rootProject.hasProperty('fGroupId') && rootProject.fGroupId ? rootProject.fGroupId : null
62 | final def artVersion = rootProject.hasProperty('fVersion') && rootProject.fVersion ? rootProject.fVersion : null
63 | if(artGroupId && artVersion) {
64 | rootProject.ext {
65 | gArtGroupId = artGroupId
66 | gArtVersion = artVersion
67 | }
68 | }
69 | }
70 |
71 | static def applyMaven(Project project) {
72 | project.apply plugin: 'maven'
73 |
74 | // 这里不需要artifacts,uploadArchives命令会自动生成并上传./build/outputs/flutter-release.aar,不然出现下面错误
75 | // A POM cannot have multiple artifacts with the same type and classifier
76 | //artifacts {
77 | // archives file('./build/outputs/flutter-release.aar')
78 | //}
79 |
80 | final def artGroupId = project.group
81 | final def artVersion = project.version
82 | final def artifactId = project.hasProperty('fArtifactId') && project.fArtifactId ? project.fArtifactId : null
83 | final def isFlutterModule = project.hasProperty('fModule') && project.fModule ? project.fModule : false
84 |
85 |
86 | if(artifactId == null || artVersion == null) {
87 | return
88 | }
89 |
90 | // 因为只要执行./gradlew xxx等命令,rootProject和subProject的build.gradle都要执行一次,
91 | // 所以这里要判断当前module和是否和正在处理的module一样,不是相同module就不处理,
92 | // 但是因为不同业务的flutter module名称都是flutter并且artifactId和module名称又不相同,所以要通过isFlutterModule参数区分
93 | if(!project.name.equals(artifactId) && (!project.name.equals("flutter") || !isFlutterModule)) {
94 | return
95 | }
96 |
97 | //project.group = artGroupId
98 | //project.version = artVersion
99 |
100 | //true: 发布到本地maven仓库, false: 发布到maven私服
101 | def localMaven = project.rootProject.galaxybrucepioneer.localMaven
102 | def mavenUrl = project.rootProject.galaxybrucepioneer.mavenUrl
103 | def mavenUrlSnapShot = project.rootProject.galaxybrucepioneer.mavenUrlSnapShot
104 | def mavenAccount = project.rootProject.galaxybrucepioneer.mavenAccount
105 | def mavenPwd = project.rootProject.galaxybrucepioneer.mavenPwd
106 |
107 | LogUtil.log(project, "PioneerPlugin", "${localMaven} : ${mavenUrl} : ${mavenUrlSnapShot} : ${mavenAccount} : ${mavenPwd}")
108 |
109 | project.uploadArchives {
110 | repositories {
111 | mavenDeployer {
112 | LogUtil.log(project, "PioneerPlugin", "==maven url: ${artGroupId}:${artifactId}:${artVersion}")
113 |
114 | if(localMaven && localMaven == true) {
115 | repository(url: project.uri(project.rootProject.projectDir.absolutePath + '/repo-local'))
116 | } else {
117 | repository(url: mavenUrl) {
118 | authentication(userName: mavenAccount, password: mavenPwd)
119 | }
120 |
121 | snapshotRepository(url: mavenUrlSnapShot) {
122 | authentication(userName: mavenAccount, password: mavenPwd)
123 | }
124 | }
125 |
126 | pom.groupId = artGroupId
127 | pom.artifactId = artifactId
128 | pom.version = artVersion
129 |
130 | pom.project {
131 | licenses {
132 | license {
133 | name 'The Apache Software License, artVersion 2.0'
134 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
135 | }
136 | }
137 | }
138 | }
139 | }
140 | }
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/manifest/PlatformSourceUtil.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.manifest
2 |
3 |
4 | import org.gradle.api.Project
5 |
6 | /**
7 | * @author bruce.zhang
8 | * @date 2020/11/11 17:06
9 | * @description
10 | *
11 | * modification history:
12 | */
13 | class PlatformSourceUtil {
14 |
15 | static String getPlatformFlag(Project project) {
16 | Project rootProject = project.rootProject
17 | // 优先通过通过./gradlew uploadMaven -PplatformSourceDir=xxx获取参数
18 | String platformSourceDir = rootProject.getProperties()?.get("platformSourceDir")
19 | if(platformSourceDir == null || platformSourceDir.isEmpty()) {
20 | platformSourceDir = rootProject.galaxybrucepioneer.platformSourceDir
21 | }
22 |
23 | if(platformSourceDir == null) {
24 | platformSourceDir = ''
25 | }
26 | return platformSourceDir
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/manifest/ProjectManifestMerger.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.manifest
2 |
3 |
4 | import com.android.manifmerger.ManifestMerger2
5 | import com.android.manifmerger.MergingReport
6 | import com.android.manifmerger.XmlDocument
7 | import com.android.utils.ILogger
8 | import com.android.utils.Pair
9 | import com.galaxybruce.pioneer.run_module.ProjectModuleManager
10 | import com.galaxybruce.pioneer.utils.LogUtil
11 | import com.google.common.collect.ImmutableList
12 | import org.gradle.api.Project
13 |
14 | import java.lang.reflect.Field
15 |
16 | /**
17 | * 合并pin工程中的AndroidManifest.xml
18 | */
19 | class ProjectManifestMerger {
20 |
21 | static boolean mergeManifest(Project project) {
22 | project.buildscript.repositories {
23 | google()
24 | jcenter()
25 | }
26 | //history version: 25.3.0
27 | project.buildscript.dependencies.add("classpath", "com.android.tools.build:manifest-merger:30.0.3")
28 |
29 | mergeManifest(project, true)
30 | }
31 |
32 | static void mergeManifest(Project project, boolean needMerge) {
33 | def manifestSrcFiles = []
34 |
35 | File moduleDir = new File("$project.projectDir/src")
36 | File[] pModuleDirs = moduleDir.listFiles()
37 | if (pModuleDirs == null || pModuleDirs.length == 0) {
38 | return
39 | }
40 |
41 | def platformDir = PlatformSourceUtil.getPlatformFlag(project)
42 | LogUtil.log(project, "ProjectManifestMerger", "app platform source Dir: ${platformDir}")
43 | project.android.sourceSets.main.jniLibs.srcDir("libs")
44 |
45 | pModuleDirs.each {
46 | if (it.isDirectory() && it.name.startsWith("p_")) {
47 | // pin工程下可以设置独立的build.gradle,但是该build.gradle中不允许apply plugin: 'com.android.library'
48 | if(new File("$project.projectDir/src/$it.name/build.gradle").exists()) {
49 | project.apply from: "src/$it.name/build.gradle"
50 | }
51 | // // 添加pin工程下的libs依赖,pin/build.gradle中无需再添加 implementation fileTree(dir: 'src/p_lib1/libs', include: ['*.jar'])
52 | // project.dependencies.add("api",
53 | // project.fileTree(dir: "src/$it.name/libs", include: ['*.jar']))
54 |
55 | def dirs = platformDir != null && platformDir.trim().length() > 0 ? ["main", "${platformDir}"] : ["main"]
56 | // 遍历main和对应平台的目录
57 | dirs.each { dir ->
58 | if(dir != null && !dir.isEmpty()) {
59 | if(project.file("${it.absolutePath}/$dir").exists()) {
60 | LogUtil.log(project, "ProjectManifestMerger", "valid pin project resource dir: ${it.absolutePath}/$dir")
61 | // manifest
62 | def manifestPath = it.absolutePath + "/$dir/AndroidManifest.xml"
63 | def manifestSrcFile = new File(manifestPath)
64 | if (manifestSrcFile.exists() && !manifestSrcFiles.contains(manifestPath)) {
65 | manifestSrcFiles << manifestPath
66 | }
67 |
68 | // 其他资源
69 | project.android.sourceSets.main.java.srcDir("src/$it.name/$dir/java")
70 | project.android.sourceSets.main.resources.srcDir("src/$it.name/$dir/resources")
71 | project.android.sourceSets.main.res.srcDir("src/$it.name/$dir/res")
72 | project.android.sourceSets.main.assets.srcDir("src/$it.name/$dir/assets")
73 | project.android.sourceSets.main.jniLibs.srcDir("src/$it.name/$dir/libs")
74 | // project.dependencies.add("api",
75 | // project.fileTree(dir: "src/$it.name/$dir/libs", include: ['*.jar']))
76 | }
77 | }
78 | }
79 | } else if (it.isDirectory() &&
80 | (it.name == "main" ||
81 | it.name == "${platformDir}" ||
82 | // debug-test目录在module当做独立模块运行时生效
83 | (it.name == ProjectModuleManager.DEBUG_DIR && project.ext.has('runAsApp') && project.ext.runAsApp))) {
84 |
85 | if(it.name == ProjectModuleManager.DEBUG_DIR && project.ext.has('runAsApp') && project.ext.runAsApp){
86 | // debug-test目录下可以设置独立的build.gradle,但是该build.gradle中不允许apply plugin: 'com.android.library'
87 | if (new File("$project.projectDir/src/$it.name/build.gradle").exists()) {
88 | project.apply from: "src/$it.name/build.gradle"
89 | }
90 | }
91 |
92 | LogUtil.log(project, "ProjectManifestMerger", "valid resource dir: ${it.absolutePath}")
93 | // pin工程以外的的情况,只处理main和platformDir两个目录
94 | // manifest
95 | def manifestPath = it.absolutePath + "/AndroidManifest.xml"
96 | def manifestSrcFile = new File(manifestPath)
97 | if (manifestSrcFile.exists() && !manifestSrcFiles.contains(manifestPath)) {
98 | manifestSrcFiles << manifestPath
99 | }
100 |
101 | // 其他资源
102 | project.android.sourceSets.main.java.srcDir("src/$it.name/java")
103 | project.android.sourceSets.main.resources.srcDir("src/$it.name/resources")
104 | project.android.sourceSets.main.res.srcDir("src/$it.name/res")
105 | project.android.sourceSets.main.assets.srcDir("src/$it.name/assets")
106 | project.android.sourceSets.main.jniLibs.srcDir("src/$it.name/libs")
107 | // project.dependencies.add("api",
108 | // project.fileTree(dir: "src/$it.name/libs", include: ['*.jar']))
109 | }
110 | }
111 |
112 | // src目录下的manifest
113 | def manifestPath = "$project.projectDir/src/AndroidManifest.xml"
114 | def manifestSrcFile = new File(manifestPath)
115 | if (manifestSrcFile.exists() && !manifestSrcFiles.contains(manifestPath)) {
116 | manifestSrcFiles << manifestPath
117 | LogUtil.log(project, "ProjectManifestMerger", "valid root manifest: ${manifestPath}")
118 | }
119 |
120 | if (manifestSrcFiles == null || manifestSrcFiles.isEmpty()) {
121 | return
122 | }
123 |
124 | int size = manifestSrcFiles.size()
125 | LogUtil.log(project, "ProjectManifestMerger", "manifestSrcFiles.size: ${size}")
126 | if(size == 1) {
127 | project.android.sourceSets.main.manifest.srcFile "${manifestSrcFiles[0]}"
128 | } else {
129 | def intermediateManifestFile = new File("$project.buildDir/AndroidManifest.xml")
130 | if(intermediateManifestFile.exists() && !needMerge) {
131 | project.android.sourceSets.main.manifest.srcFile intermediateManifestFile.absolutePath
132 | LogUtil.log(project, "ProjectManifestMerger", "merged manifest exists!!!: ${intermediateManifestFile.absolutePath}")
133 | return
134 | }
135 |
136 | File mainManifestFile = new File(manifestSrcFiles[size - 1])
137 | ManifestMerger2.MergeType mergeType = ManifestMerger2.MergeType.LIBRARY
138 | ManifestMerger2.Invoker invoker = ManifestMerger2.newMerger(mainManifestFile, logger, mergeType)
139 | invoker.asType(XmlDocument.Type.LIBRARY)
140 |
141 | try {
142 | Class c = invoker.getClass()
143 | Field f = c.getDeclaredField("mLibraryFilesBuilder")
144 | f.setAccessible(true)
145 |
146 | ImmutableList.Builder
12 | * modification history:
13 | */
14 | class MavenInfo {
15 |
16 | String group
17 | String version
18 |
19 | List
24 | * modification history:
25 | */
26 | class MavenUploadManager {
27 |
28 | /**
29 | * library module设置上传maven task
30 | * @param rootProject
31 | */
32 | static void setModuleUploadMaven(Project rootProject) {
33 | rootProject.afterEvaluate {
34 | LogUtil.log(rootProject, "PioneerPlugin", "moduleDataPath: ${rootProject.galaxybrucepioneer.moduleDataPath}")
35 | // 读取module maven配置
36 | if (rootProject.galaxybrucepioneer.moduleDataPath) {
37 | File file = new File(rootProject.galaxybrucepioneer.moduleDataPath)
38 | if (file.exists()) {
39 | String fileContents = file.getText('UTF-8')
40 | LogUtil.log(rootProject, "PioneerPlugin", "moduleData: \n" + fileContents)
41 | try {
42 | var mavenInfo = JSONObject.parseObject(fileContents, MavenInfo.class)
43 | mavenInfo?.initModuleInfo(PlatformSourceUtil.getPlatformFlag(rootProject))
44 | rootProject.ext.mavenInfo = mavenInfo
45 | } catch (Exception e) {
46 | e.printStackTrace()
47 | }
48 |
49 | // todo 如果mavenInfo是空,可以考虑把所有的module都上传到maven
50 | }
51 | }
52 | }
53 |
54 | rootProject.afterEvaluate {
55 | // 创建批量上传maven task
56 | rootProject.tasks.create(name: "uploadMaven") {
57 | doLast {
58 | LogUtil.log(rootProject, "PioneerPlugin", "start upload library to maven...")
59 |
60 | final MavenInfo mavenInfo = Utils.getExtValue(rootProject, "mavenInfo")
61 | final List
8 | * modification history:
9 | */
10 | class ModuleInfo {
11 |
12 | // module name
13 | String name
14 |
15 | // 默认是module.name,如果不一致,这里需要设置
16 | String artifactId
17 |
18 | // 版本号
19 | String version
20 |
21 | /**
22 | * 是否支持多平台,这个字段已经废弃,如果是多品台打包,用{@link MavenInfo#platform_modules}节点配置
23 | */
24 | boolean platform
25 | }
26 |
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/run_module/ProjectModuleCache.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.run_module
2 |
3 | import com.android.builder.model.AndroidProject
4 | import com.galaxybruce.pioneer.PioneerPlugin
5 | import org.gradle.api.Project
6 |
7 | /**
8 | * 文件操作辅助类
9 | *
10 | */
11 | class ProjectModuleCache {
12 | final static def CACHE_INFO_DIR = PioneerPlugin.PLUGIN_NAME
13 |
14 | private static File getCacheFile(Project project, String fileName) {
15 | String baseDir = getCacheFileDir(project)
16 | if (mkdirs(baseDir)) {
17 | return new File(baseDir + fileName)
18 | } else {
19 | throw new FileNotFoundException("Not found path:" + baseDir)
20 | }
21 | }
22 |
23 | static boolean isSameAsLastBuildType(Project project, boolean isApp) {
24 | File cacheFile = getCacheFile(project, "build-type.json")
25 | if (cacheFile.exists()) {
26 | return (cacheFile.text == 'true') == isApp
27 | }
28 | return false
29 | }
30 |
31 | static void cacheBuildType(Project project, boolean isApp) {
32 | File cacheFile = getCacheFile(project, "build-type.json")
33 | cacheFile.getParentFile().mkdirs()
34 | if (!cacheFile.exists())
35 | cacheFile.createNewFile()
36 | cacheFile.write(isApp.toString())
37 | }
38 |
39 | private static String getCacheFileDir(Project project) {
40 | return project.getBuildDir().absolutePath + File.separator +
41 | AndroidProject.FD_INTERMEDIATES + File.separator +
42 | CACHE_INFO_DIR + File.separator
43 | }
44 |
45 | /**
46 | * 创建文件夹
47 | * @param dirPath
48 | * @return boolean
49 | */
50 | static boolean mkdirs(String dirPath) {
51 | def baseDirFile = new File(dirPath)
52 | def isSuccess = true
53 | if (!baseDirFile.isDirectory()) {
54 | isSuccess = baseDirFile.mkdirs()
55 | }
56 | return isSuccess
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/run_module/ProjectModuleManager.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.run_module
2 |
3 | import com.galaxybruce.pioneer.PioneerPlugin
4 | import com.galaxybruce.pioneer.utils.LogUtil
5 | import org.gradle.api.Project
6 |
7 | import java.util.regex.Pattern
8 |
9 | /**
10 | * 工程中的组件module管理工具
11 | * 1. 用于管理组件module以application或library方式进行编译
12 | * 2. 用于管理组件依赖(只在给当前module进行集成打包时才添加对组件的依赖,以便于进行代码隔离)
13 | *
14 | * 注意:该功能默认关闭,如需开启,在local.properties中增加 RUN_AS_APP_FOR_COMPONENT=true
15 | *
16 | * PS:这个类中的功能来自开源项目 [https://github.com/luckybilly/CC],之所以没有直接用CC,
17 | * 而是copy过来,是因为cc-register中部分功能与galaxybruce-pioneer中部分功能重叠。
18 | */
19 | class ProjectModuleManager {
20 | static final String TAG = 'ProjectModuleManager'
21 | static final String PLUGIN_NAME = PioneerPlugin.PLUGIN_NAME
22 |
23 | // module作为app运行功能默认关闭,如需开启,在local.properties中增加 RUN_AS_APP_FOR_COMPONENT=true
24 | static final String RUN_AS_APP_FOR_COMPONENT = "RUN_AS_APP_FOR_COMPONENT"
25 |
26 | //为区别于组件单独以app方式运行的task,将组件module打包成aar时,比如上传maven仓库,
27 | //在local.properties文件中添加 ASSEMBLE_AAR_FOR_COMPONENT=true
28 | static final String ASSEMBLE_AAR_FOR_COMPONENT = "ASSEMBLE_AAR_FOR_COMPONENT"
29 | /**
30 | * 手动在gradle命令中指定当前是为哪一个module打apk
31 | * 主要用途:
32 | * 1. 插件化打包 (由于gradle命令不在正则表达式 {@link #TASK_TYPES}范围内,但需要集成打包)
33 | * ./gradlew :demo_component_b:assembleDebug -PccMain=demo_component_b
34 | * 2. 打aar包,相反的用途,指定ccMain为一个不存在的module名称即可,可替代assemble_aar_for_component的作用
35 | * ./gradlew :demo_component_b:assembleRelease -PccMain=nobody
36 | * 注意:此用法对于ext.mainApp=true的module无效,对于ext.alwaysLib=true的module来说无意义
37 | */
38 | static final String ASSEMBLE_APK_FOR_COMPONENT = "ccMain"
39 | //组件单独以app方式运行时使用的测试代码所在目录(manifest/java/assets/res等),这个目录下的文件不会打包进主app
40 | static final String DEBUG_DIR = "debug-test"
41 | //主app,一直以application方式编译
42 | static final String MODULE_MAIN_APP = "mainApp"
43 | //apply了galaxybruce-pioneer-runmodule的module,但不是组件,而是一直作为library被其它组件依赖
44 | static final String MODULE_ALWAYS_LIBRARY = "alwaysLib"
45 |
46 | /**
47 | * 以app模式运行的module name,主module除外
48 | */
49 | static String mainModuleName
50 | /**
51 | * 当前是否是打包命令
52 | */
53 | static boolean taskIsAssemble
54 |
55 | static boolean manageModule(Project project) {
56 | taskIsAssemble = false
57 | mainModuleName = null
58 |
59 | if (!project.rootProject.ext.has('runAsAppForComponent')) {
60 | Properties localProperties = new Properties()
61 | try {
62 | def localFile = project.rootProject.file('local.properties')
63 | if (localFile != null && localFile.exists()) {
64 | localProperties.load(localFile.newDataInputStream())
65 | }
66 | project.rootProject.ext.runAsAppForComponent = 'true' == localProperties.getProperty(RUN_AS_APP_FOR_COMPONENT)
67 | project.rootProject.ext.assembleAarForComponent = 'true' == localProperties.getProperty(ASSEMBLE_AAR_FOR_COMPONENT)
68 | } catch (Exception ignored) {
69 | LogUtil.log(project, TAG, "local.properties not found")
70 | }
71 | }
72 |
73 | boolean runAsApp = false
74 | if(project.rootProject.ext.runAsAppForComponent) {
75 | if(new File(project.projectDir.getAbsolutePath() + "/src/${DEBUG_DIR}/AndroidManifest.xml").exists()) {
76 | initByTask(project)
77 |
78 | def mainApp = isMainApp(project)
79 | def assembleFor = isAssembleFor(project)
80 | def buildingAar = isBuildingAar(project)
81 | def alwaysLib = isAlwaysLib(project)
82 |
83 | if (mainApp) {
84 | runAsApp = true
85 | } else if (alwaysLib || buildingAar) {
86 | runAsApp = false
87 | } else if (assembleFor) {
88 | // 这是真正的判断是否独立运行module的变量
89 | runAsApp = true
90 | project.ext.assembleThisModule = true
91 | } else if (!taskIsAssemble) {
92 | // 点击"sync now"时,给apply plugin: 'com.android.application',可以时module显示在运行列表中
93 | runAsApp = true
94 | }
95 | LogUtil.log(project, TAG,
96 | "mainModuleName=${mainModuleName}, project=${project.name}, runAsApp=${runAsApp} . taskIsAssemble:${taskIsAssemble}. " +
97 | "settings(mainApp:${mainApp}, alwaysLib:${alwaysLib}, assembleThisModule:${assembleFor}, buildingAar:${buildingAar})")
98 | }
99 | } else {
100 | LogUtil.log(project, TAG, "[runAsAppForComponent] feature not open.")
101 | }
102 | project.ext.runAsApp = runAsApp
103 | // 这个属性给外面判断,避免重复apply application或者library
104 | project.ext.androidPluginApplied = true
105 | if (runAsApp) {
106 | project.apply plugin: 'com.android.application'
107 | } else {
108 | project.apply plugin: 'com.android.library'
109 | }
110 |
111 | performBuildTypeCache(project, runAsApp)
112 | return runAsApp
113 | }
114 |
115 | //需要集成打包相关的task
116 | //./gradlew :demo_component_b:clean :demo_component_b:assembleDebug
117 | static final String TASK_TYPES = ".*((((ASSEMBLE)|(BUILD)|(INSTALL)|((BUILD)?TINKER)|(RESGUARD)).*)|(ASR)|(ASD))"
118 | static void initByTask(Project project) {
119 | //先检查是否手动在当前gradle命令的参数中设置了mainModule的名称
120 | //设置方式如:
121 | // ./gradlew :demo:xxxBuildPatch -PccMain=demo //用某插件化框架脚本为demo打补丁包
122 | // ./gradlew :demo_component_b:assembleRelease -PccMain=anyothermodules //为demo_b打aar包
123 | def projectProps = project.gradle.startParameter.projectProperties
124 | if (projectProps && projectProps.containsKey(ASSEMBLE_APK_FOR_COMPONENT)) {
125 | mainModuleName = projectProps.get(ASSEMBLE_APK_FOR_COMPONENT)
126 | taskIsAssemble = true
127 | return
128 | }
129 | def taskNames = project.gradle.startParameter.taskNames
130 | def allModuleBuildApkPattern = Pattern.compile(TASK_TYPES)
131 | for (String task : taskNames) {
132 | if (allModuleBuildApkPattern.matcher(task.toUpperCase()).matches()) {
133 | taskIsAssemble = true
134 | if (task.contains(":")) {
135 | def arr = task.split(":")
136 | mainModuleName = arr[arr.length - 2].trim()
137 | }
138 | break
139 | }
140 | }
141 | }
142 |
143 | /**
144 | * 当前是否正在给指定的module集成打包
145 | */
146 | static boolean isAssembleFor(Project project) {
147 | return project.name == mainModuleName
148 | }
149 |
150 | static boolean isMainApp(Project project) {
151 | return project.ext.has(MODULE_MAIN_APP) && project.ext.mainApp
152 | }
153 |
154 | static boolean isAlwaysLib(Project project) {
155 | return project.ext.has(MODULE_ALWAYS_LIBRARY) && project.ext.alwaysLib
156 | }
157 |
158 | //判断当前设置的环境是否为组件打aar包(比如将组件打包上传maven库)
159 | static boolean isBuildingAar(Project project) {
160 | return project.rootProject.ext.assembleAarForComponent
161 | }
162 |
163 | private static void performBuildTypeCache(Project project, boolean isApp) {
164 | // if (!ProjectModuleCache.isSameAsLastBuildType(project, isApp)) {
165 | // ProjectModuleCache.cacheBuildType(project, isApp)
166 | // //兼容gradle3.0以上组件独立运行时出现的问题:https://github.com/luckybilly/CC/issues/62
167 | // //切换app/lib编译时,将transform目录清除
168 | // def cachedJniFile = project.file("build/intermediates/transforms/")
169 | // if (cachedJniFile && cachedJniFile.exists() && cachedJniFile.isDirectory()) {
170 | // FileUtils.deleteDirectory(cachedJniFile)
171 | // }
172 | // }
173 | }
174 | }
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/utils/GitUtil.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.utils
2 |
3 | /**
4 | * git 命令
5 | */
6 | class GitUtil {
7 |
8 | static void init(File dir) {
9 | def process = ("git init").execute(null, dir)
10 | def result = process.waitFor()
11 | if (result != 0) {
12 | throw new RuntimeException("[repo] - git fail to execute [git init] under ${dir.absolutePath}\nmessage: ${process.err.text}")
13 | }
14 | }
15 |
16 | static void addRemote(File dir, String url) {
17 | def process = ("git remote add origin $url").execute(null, dir)
18 | def result = process.waitFor()
19 | if (result != 0) {
20 | throw new RuntimeException("[repo] - git fail to execute [git remote add origin $url] under ${dir.absolutePath}\nmessage: ${process.err.text}")
21 | }
22 | }
23 |
24 | static void addFiles(File dir, String files) {
25 | def process = ("git add $files").execute(null, dir)
26 | def result = process.waitFor()
27 | if (result != 0) {
28 | throw new RuntimeException("[repo] - git fail to execute [git add $files] under ${dir.absolutePath}\nmessage: ${process.err.text}")
29 | }
30 | }
31 |
32 | static void removeFiles(File dir, String files) {
33 | def process = ("git rm --cached -r $files").execute(null, dir)
34 | process.waitFor()
35 | }
36 |
37 | static void clone(File dir, String url, String branchName) {
38 | def process = ("git clone -b " + branchName + " " + url + " -l " + dir.name).execute(null, dir.parentFile)
39 | def result = process.waitFor()
40 | if (result != 0) {
41 | throw new RuntimeException("[repo] - git fail to execute [git clone -b $branchName $url \".\"] under ${dir.absolutePath}\n message: ${process.err.text}")
42 | }
43 | }
44 |
45 | static void commit(File dir, String message) {
46 | def process = ("git commit -m \"" + message + "\"").execute(null, dir)
47 | def result = process.waitFor()
48 | if (result != 0) {
49 | throw new RuntimeException("[repo] - git fail to execute [git commit -m \"" + message + "\"] under ${dir.absolutePath}\n message: ${process.err.text}")
50 | }
51 | }
52 |
53 | static boolean isGitDir(File dir) {
54 | return new File(dir, ".git").exists()
55 | }
56 |
57 | static String getRemoteUrl(File dir) {
58 | def process = ("git remote get-url origin").execute(null, dir)
59 | def result = process.waitFor()
60 | if (result != 0) {
61 | throw new RuntimeException("[repo] - git fail to execute [git remote get-url origin] under ${dir.absolutePath}\n message: ${process.err.text}")
62 | }
63 | return process.text.trim()
64 | }
65 |
66 | static String getBranchName(File dir) {
67 | def process = ("git symbolic-ref --short -q HEAD").execute(null, dir)
68 | def result = process.waitFor()
69 | if (result != 0) {
70 | throw new RuntimeException("[repo] - git fail to execute [git symbolic-ref --short -q HEAD] under ${dir.absolutePath}\n message: ${process.err.text}")
71 | }
72 | return process.text.trim()
73 | }
74 |
75 | static boolean isBranchChanged(File dir, String branch) {
76 | def currentBranchName = getBranchName(dir)
77 | return currentBranchName != branch
78 | }
79 |
80 | static boolean isClean(File dir) {
81 | def process = ("git status -s").execute(null, dir)
82 | def result = process.waitFor()
83 | if (result != 0) {
84 | throw new RuntimeException("[repo] - git fail to execute [git status -s] under ${dir.absolutePath}\n message: ${process.err.text}")
85 | }
86 | return process.text.trim() == ""
87 | }
88 |
89 | static boolean isLocalBranch(File dir, String branchName) {
90 | return new File(dir, ".git/refs/heads/$branchName").exists()
91 | }
92 |
93 | static boolean isRemoteBranch(File dir, String branchName) {
94 | def process = ("git fetch").execute(null, dir)
95 | def result = process.waitFor()
96 | if (result != 0) {
97 | throw new RuntimeException("[repo] - git fail to execute [git fetch] under ${dir.absolutePath}\n message: ${process.err.text}")
98 | }
99 | if(branchName == "master") {
100 | branchName = "HEAD"
101 | }
102 | return new File(dir, ".git/refs/remotes/origin/$branchName").exists()
103 | }
104 |
105 | static void checkoutBranch(File dir, String branchName) {
106 | def process = ("git checkout " + branchName).execute(null, dir)
107 | def result = process.waitFor()
108 | if (result != 0) {
109 | throw new RuntimeException("[repo] - git fail to execute [git checkout $branchName] under ${dir.absolutePath}\n message: ${process.err.text}")
110 | }
111 | }
112 |
113 | static void checkoutRemoteBranch(File dir, String branchName) {
114 | def process = ("git checkout -b $branchName origin/$branchName").execute(null, dir)
115 | def result = process.waitFor()
116 | if (result != 0) {
117 | throw new RuntimeException("[repo] - git fail to execute [git checkout -b $branchName origin/$branchName] under ${dir.absolutePath}\n message: ${process.err.text}")
118 | }
119 | }
120 |
121 | static void checkoutNewBranch(File dir, String branchName) {
122 | def process = ("git checkout -b " + branchName).execute(null, dir)
123 | def result = process.waitFor()
124 | if (result != 0) {
125 | throw new RuntimeException("[repo] - git fail to execute [git checkout -b $branchName] under ${dir.absolutePath}\n message: ${process.err.text}")
126 | }
127 | }
128 |
129 | static void commitRepoFile(File dir) {
130 | def process = ("git add repo.xml").execute(null, dir)
131 | def result = process.waitFor()
132 | if (result != 0) {
133 | throw new RuntimeException("[repo] - git fail to execute [git add repo.xml] under ${dir.absolutePath}\n message: ${process.err.text}")
134 | }
135 |
136 | commit(dir, "keep repo.xml")
137 | }
138 |
139 | static void revertRepoFile(File dir) {
140 | def process = ("git checkout repo.xml").execute(null, dir)
141 | def result = process.waitFor()
142 | if (result != 0) {
143 | throw new RuntimeException("[repo] - git fail to execute [git checkout repo.xml] under ${dir.absolutePath}\n message: ${process.err.text}")
144 | }
145 | }
146 |
147 | }
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/utils/LogUtil.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.utils
2 |
3 |
4 | import org.gradle.api.Project
5 |
6 | public class LogUtil {
7 |
8 | public static void log(Project project, String tag, def msg) {
9 | println ">>> Android Pioneer <<< [${tag}]: \n${msg}\n"
10 | }
11 |
12 | public static void log(String tag, def msg) {
13 | log(null, tag, msg)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/pioneer-gradle-plugin/src/main/groovy/com/galaxybruce/pioneer/utils/Utils.groovy:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.pioneer.utils
2 |
3 | import com.android.utils.FileUtils
4 | import com.galaxybruce.pioneer.PioneerExtension
5 | import com.galaxybruce.pioneer.PioneerPlugin
6 | import org.gradle.api.Project
7 |
8 | import java.util.function.Consumer
9 | import java.util.regex.Pattern
10 |
11 | public class Utils {
12 |
13 | /**
14 | * 也可以这样获取属性 project.galaxybrucepioneer.xxx
15 | * 注意:
16 | * 1. 使用属性之间必须先创建属性 project.extensions.create(EXT_NAME, PioneerExtension)
17 | * 2. 因为build.gradle中给属性赋值是在apply plugin之后,所以直接在Plugin.apply方法中获取的属性是空的
18 | * 3. 为了解决2中的为问题,一般是在project.afterEvaluate中获取属性,或者在subproject中可以直接使用
19 | * rootProject中的属性: project.rootProject.galaxybrucepioneer.xxx
20 | * @param project
21 | * @return
22 | */
23 | public static PioneerExtension getPioneerExtension(Project project) {
24 | return project.rootProject.extensions.findByName(PioneerPlugin.EXT_NAME) as PioneerExtension
25 | }
26 |
27 | /**
28 | * 也可以这样获取属性 project.rootProject.galaxybrucepioneer.xxx
29 | * @param project
30 | * @return
31 | */
32 | public static PioneerExtension getRootProjectPioneerExtension(Project project) {
33 | return project.rootProject.extensions.findByName(PioneerPlugin.EXT_NAME) as PioneerExtension
34 | }
35 |
36 | /**
37 | * 任何项目都可以使用该方法
38 | * @param pathKey 环境变量中的key
39 | * @param jenkinsPath 打包机器上的库路径
40 | * @return
41 | */
42 | public static String getLibraryPathWithKey(Object project, final String pathKey, final String jenkinsPath) {
43 | if(pathKey == null || '' == pathKey.trim()) {
44 | throw new IllegalStateException('pathKey must not be empty')
45 | }
46 |
47 | def libraryPath = getLocalValue(project, pathKey)
48 | if (!libraryPath) {
49 | libraryPath = System.getenv(pathKey)
50 | if (!libraryPath && jenkinsPath) {
51 | libraryPath = jenkinsPath
52 | }
53 | if(libraryPath) {
54 | def props = new Properties()
55 | def propFile = new File(project.rootDir, 'local.properties')
56 | props.put(pathKey, libraryPath)
57 | props.store(propFile.newWriter(), null)
58 | }
59 | }
60 |
61 | return libraryPath
62 | }
63 |
64 | /**
65 | * 读取properties中的值
66 | * @param project
67 | * @param key
68 | * @return
69 | */
70 | static String getPropertiesValue(def project, String key) {
71 | return project.hasProperty(key) ? project."$key" : null
72 | // project.hasProperty("MAVEN_MODULE_NAME") && MAVEN_MODULE_NAME ? MAVEN_MODULE_NAME : null
73 | // project.hasProperty("MAVEN_MODULE_NAME") && MAVEN_MODULE_NAME ? project.getProperties().get(key) : null
74 | }
75 |
76 | // 读取project.ext中的值
77 | static Object getExtValue(def project, String key) {
78 | return project.ext.has(key) ? project.ext."$key" : null
79 | }
80 |
81 | static Properties LOCAL_PROPERTIES
82 |
83 | /**
84 | * 初始化local.properties,避免后面每次都读取
85 | * @param project
86 | */
87 | static void initLocalProperties(Object project) {
88 | Properties localProperties = new Properties()
89 | def localPropertiesFile = new File(project.rootDir, 'local.properties')
90 | if (localPropertiesFile.exists()) {
91 | localPropertiesFile.withReader('UTF-8') { reader ->
92 | localProperties.load(reader)
93 | LOCAL_PROPERTIES = localProperties
94 | }
95 | LogUtil.log("PioneerPlugin",
96 | "read local.properties in [$project] :\n ${LOCAL_PROPERTIES.toMapString()}")
97 | } else {
98 | LogUtil.log("PioneerPlugin", "local.properties doesn't exist !!!")
99 | }
100 | }
101 |
102 | /**
103 | * 第一个参数可能是settings和project
104 | * @param project
105 | * @param key
106 | * @return
107 | */
108 | static String getLocalValue(Object project, String key) {
109 | if(key == null || '' == key.trim()) {
110 | throw new IllegalStateException('key must not be empty')
111 | }
112 | if(LOCAL_PROPERTIES == null) {
113 | initLocalProperties(project)
114 | }
115 | if(LOCAL_PROPERTIES != null) {
116 | return LOCAL_PROPERTIES.getProperty(key)
117 | }
118 | return null
119 | }
120 |
121 | static boolean equalLocalValue(Object project, String key, String value) {
122 | return value == getLocalValue(project, key)
123 | }
124 |
125 |
126 | /**
127 | * 获取参数,参数可能在local.proerties、gradle.properties、系统环境变量中
128 | * @param project
129 | * @param key
130 | * @return
131 | */
132 | static String getParameterAnyWhere(Object project, String key) {
133 | def value = getLocalValue(project, key)
134 | if(!value) {
135 | value = System.getenv(key)
136 | }
137 | if(!value) {
138 | value = System.properties[key]
139 | }
140 | if(!value) {
141 | value = project.getProperties().get(key)
142 | }
143 | return value
144 | }
145 |
146 | public static void deleteCheckSumFile(Project project) {
147 | def localMaven = project.rootProject.galaxybrucepioneer.localMaven
148 | if(localMaven != true) {
149 | return
150 | }
151 | def repoLocal = project.rootProject.projectDir.absolutePath + '/repo-local'
152 | File repoLocalDir = new File(repoLocal)
153 | if(repoLocalDir.isDirectory() && repoLocalDir.exists()) {
154 | List
17 | * modification history:
18 | */
19 | public class MainActivity extends AppCompatActivity {
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.main_layout);
25 |
26 | findViewById(R.id.btn_lib1).setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | startActivity(new Intent(MainActivity.this, Lib1Activity_1.class));
30 | }
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/testlibrary/src/debug-test/res/layout/main_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 | * modification history:
12 | */
13 | public class GFileProvider extends FileProvider {
14 |
15 | @Override
16 | public boolean onCreate() {
17 | // 可以在这里做些启动初始化工作
18 | // Utils.init(getContext());
19 | return true;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/testlibrary/src/p_lib1/app2/java/com/galaxybruce/testlibrary/Lib1Activity_2.java:
--------------------------------------------------------------------------------
1 | package com.galaxybruce.testlibrary;
2 |
3 | import android.content.Intent;
4 | import androidx.appcompat.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | public class Lib1Activity_2 extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.lib1_layout_2);
14 |
15 | findViewById(R.id.btn_lib1).setOnClickListener(new View.OnClickListener() {
16 | @Override
17 | public void onClick(View v) {
18 | startActivity(new Intent(Lib1Activity_2.this, LibActivity2.class));
19 | }
20 | });
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/testlibrary/src/p_lib1/app2/res/layout/lib1_layout_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 | * modification history:
14 | */
15 | public class Lib1Activity_1 extends AppCompatActivity {
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.lib1_layout);
21 |
22 | findViewById(R.id.btn_lib1).setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | startActivity(new Intent(Lib1Activity_1.this, Lib1Activity_2.class));
26 | }
27 | });
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/testlibrary/src/p_lib1/main/res/layout/lib1_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |