提交 5b5d45c8 编写于 作者: B Blankj

see 07/15 log

上级 c80b6a10
* `19/07/10` [upd] Bus plugin for use BusUtils. Publish bus plugin v2.0.
* `19/07/10` [add] Api plugin for use ApiUtils. Publish api plugin v1.0.
* `19/07/15` [upd] Bus plugin for use BusUtils. Publish bus plugin v2.0.
* `19/07/15` [add] Api plugin for use ApiUtils. Publish api plugin v1.0.
* `19/07/09` [upd] The frame of project.
* `19/07/06` [upd] BusUtils which behave same as EventBus.
* `19/07/03` [add] ApiUtils which decoupling modules.
......@@ -95,7 +95,7 @@
* `18/06/13` 新增 CacheMemoryUtils 和 CacheDoubleUtils
* `18/06/12` 完善 FragmentUtils#add 和 replace 新增 tag
* `18/05/30` 完善 DeviceUtils#getMacAddress,发布 1.16.4 版本
* `18/05/30` 修复 ToastUtils 在 targetSdkVersion 为 27 在 result 25 机器快速 show 两次崩溃的异常,发布 1.16.3 版本
* `18/05/30` 修复 ToastUtils 在 targetSdkVersion 为 27 在 api 25 机器快速 show 两次崩溃的异常,发布 1.16.3 版本
* `18/05/29` 完善 TimeUtils 的 timeSpan 带符号位,ToastUtils 去除弱引用,发布 1.16.2 版本
* `18/05/25` 新增 AppUtils#registerAppStatusChangedListener 和 AppUtils#unregisterAppStatusChangedListener,发布 1.16.1 版本
* `18/05/22` 新增 ThreadUtils,发布 1.16.0 版本
......
......@@ -68,8 +68,8 @@ dependencies {
}
def getSuffix() {
if (project.path == ":app:launcher:app") return ""
return project.path.replace(":", "_").substring(4, project.path.length() - 4)
if (project.path == ":feature:launcher:app") return ""
return project.path.replace(":", "_").substring(":feature".length(), project.path.length() - ":app".length())
}
def configSigning() {
......
......@@ -14,8 +14,8 @@ class Config {
static compileSdkVersion = 27
static minSdkVersion = 14
static targetSdkVersion = 27
static versionCode = 1_024_007
static versionName = '1.24.7'// E.g. 1.9.72 => 1,009,072
static versionCode = 1_025_000
static versionName = '1.25.0'// E.g. 1.9.72 => 1,009,072
// lib version
static kotlin_version = '1.3.10'
......@@ -25,7 +25,7 @@ class Config {
// appConfig 配置的是可以跑 app 的模块,git 提交务必只包含 launcher
static appConfig = ['launcher']
// pkgConfig 配置的是要依赖的功能包,为空则依赖全部,git 提交务必为空
static pkgConfig = ['main', 'utilcode']
static pkgConfig = []
static depConfig = [
plugin : [
......@@ -38,12 +38,12 @@ class Config {
// 本地第一次上传插件新的版本需设置 useLocal = true, isApply = false
// 本地上传成功之后 isApply = true 即可应用插件来调试,后续版本更新无需设置 isApply = false
// 发布版本的话把 useLocal = false, isApply = false,发布成功后 isApply = true 即可使用远程库版本
api : new DepConfig(true/*是否本地调试*/, "com.blankj:api-gradle-plugin:1.0", true/*是否使用插件*/),
bus : new DepConfig(true/*是否本地调试*/, "com.blankj:bus-gradle-plugin:2.0", true/*是否使用插件*/),
api : new DepConfig(false/*是否本地调试*/, "com.blankj:api-gradle-plugin:1.0", true/*是否使用插件*/),
bus : new DepConfig(false/*是否本地调试*/, "com.blankj:bus-gradle-plugin:2.0", true/*是否使用插件*/),
],
api_gradle_plugin: new DepConfig(":plugin:api-gradle-plugin", true),
bus_gradle_plugin: new DepConfig(":plugin:bus-gradle-plugin", true),
api_gradle_plugin: new DepConfig(":plugin:api-gradle-plugin", false),
bus_gradle_plugin: new DepConfig(":plugin:bus-gradle-plugin", false),
feature : [
mock : new DepConfig(":feature:mock"),
......@@ -107,4 +107,4 @@ class Config {
],
]
}
//./gradlew clean :utilcode:lib:bintrayUpload
\ No newline at end of file
//./gradlew clean :lib:utilcode:bintrayUpload
\ No newline at end of file
......@@ -32,7 +32,7 @@ class DepConfig {
}
DepConfig(boolean useLocal, String path, boolean isApply) { // 自定义插件的构造函数
this(useLocal, "", path, true)
this(useLocal, "", path, isApply)
}
DepConfig(boolean useLocal, String localPath, String remotePath) {
......
......@@ -77,23 +77,23 @@ getSurnameFirstLetter: 根据名字获取姓氏的首字母
[appStore.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
[appStore.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
[appStore.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
[appStore.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
[coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
[coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
[coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
[coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
[country.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/CountryUtils.java
[country.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
[country.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CountryUtils.java
[country.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
[dangerous.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/DangerousUtils.java
[dangerous.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
[dangerous.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java
[dangerous.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
[location.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java
[location.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
[location.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/LocationUtils.java
[location.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
[pinyin.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java
[pinyin.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
[pinyin.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/PinyinUtils.java
[pinyin.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
......@@ -77,23 +77,23 @@ getSurnameFirstLetter
[appStore.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
[appStore.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
[appStore.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/AppStoreUtils.java
[appStore.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/appStore/AppStoreActivity.kt
[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
[clipboard.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/ClipboardUtils.java
[clipboard.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/ClipboardUtilsTest.java
[coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
[coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
[coordinate.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CoordinateUtils.java
[coordinate.test]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/test/java/com/blankj/subutil/util/CoordinateUtilsTest.java
[country.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/CountryUtils.java
[country.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
[country.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/CountryUtils.java
[country.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/country/CountryActivity.kt
[dangerous.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/DangerousUtils.java
[dangerous.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
[dangerous.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/DangerousUtils.java
[dangerous.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/dangerous/DangerousActivity.kt
[location.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/LocationUtils.java
[location.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
[location.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/LocationUtils.java
[location.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/location/LocationActivity.kt
[pinyin.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/lib/src/main/java/com/blankj/subutil/util/PinyinUtils.java
[pinyin.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
[pinyin.java]: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/subutil/src/main/java/com/blankj/subutil/util/PinyinUtils.java
[pinyin.demo]: https://github.com/Blankj/AndroidUtilCode/blob/master/feature/subutil/pkg/src/main/java/com/blankj/subutil/pkg/feature/pinyin/PinyinActivity.kt
![logo][logo]
# ApiUtils
## 关于
组件化开发会涉及到模块与模块之间相互调用,而各模块之间又是解偶的,所以就产生了很多路由方案,或者是把接口下沉到 `base` 组件中,但在 **[StaticBus][bus]** 看来,它们都略显复杂,**[StaticBus][bus]** 只需调用一个静态函数便可自由穿梭于各个模块,就像一辆巴士,由于是基于静态函数来实现,所以称她为 **[StaticBus][bus]**,如今已支持 Kotlin。
组件化开发会涉及到模块与模块之的相互调用,而各模块之间又是解偶的,所以就产生了很多路由方案,或者是把接口下沉到 `base` 组件中,在 AucFrame 架构中,我们可以通过 ApiUtils 来自由调用各模块的 APIs,各业务通过对外提供 export 模块来供其他业务方使用,自身实现 export 中的接口即可。AucFrame 结构如下图所示:
![AucFrame](https://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/auc_frame.png)
ApiUtils 扮演的角色如下所示:
![ApiUtilsPlayer](https://raw.githubusercontent.com/Blankj/AndroidUtilCode/master/art/communication.png)
当然,在正常项目中你也可以使用 ApiUtils,下面来介绍其使用方式。
## 基本使用
在项目根目录的 `build.gradle` 中添加 `bus` 插件:
在项目根目录的 `build.gradle` 中添加 `api` 插件:
```groovy
buildscript {
dependencies {
...
classpath 'com.blankj:bus-gradle-plugin:2.0'
classpath 'com.blankj:api-gradle-plugin:1.0'
}
}
```
......@@ -21,52 +29,26 @@ buildscript {
然后在 application 模块中使用该插件:
```groovy
apply plugin: "com.blankj.bus"
apply plugin: "com.blankj.api"
```
给 base 模块添加 [AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) 依赖:
```groovy
result "com.blankj:utilcode:1.25.0"
api "com.blankj:utilcode:1.25.0"
```
比如 module0 中存在的 `Module0Activity.java`,我们通常都是在它内部写一个 `start` 函数来启动它,现在我们给它添加 `@BusUtils.Subscribe` 注解,并给注解的 `name` 赋唯一值,要注意,函数务必要 `public static`
比如 feature0 中存在的 `Feature0Activity.java`,我们通常都是在它内部写一个 `start` 函数来启动它,现在我们通过 ApiUtils 来启动它,建立一个抽象类 `Feature0Api` 如下所示
```java
// java
public class Module0Activity extends Activity {
@BusUtils.Subscribe(name = "startModule0")
public static boolean start(Context context, String name, int age) {
Intent starter = new Intent(context, Module0Activity.class);
starter.putExtra("name", name);
starter.putExtra("age", age);
context.startActivity(starter);
return true;
}
}
// kotlin
class Module0Activity : Activity() {
companion object {
@BusUtils.Subscribe(name = "startModule0")
fun start(context: Context, name: String, age: Int): Boolean {
val starter = Intent(context, Module0Activity::class.java)
starter.putExtra("name", name)
starter.putExtra("age", age)
context.startActivity(starter)
return true
}
}
}
```
在其他模块通过 `BusUtils.post("startModule0", Context, String, int)` 即可访问到它,一定要注意 `name` 之后的参数顺序和个数一定要和前面声明的函数相一致,其返回值也就是前面函数的返回值:
```java
// java
boolean result = BusUtils.post("startModule0", context, "blankj", 18);
boolean api = BusUtils.post("startModule0", context, "blankj", 18);
// kotlin
val result = BusUtils.post("startModule0", context, "blankj", 18)
......
此差异已折叠。
此差异已折叠。
......@@ -57,8 +57,12 @@ public final class UriUtils {
String path = uri.getPath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& path != null && path.startsWith("/external/")) {
return new File(Environment.getExternalStorageDirectory().getAbsolutePath()
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ path.replace("/external", ""));
if (file.exists()) {
Log.d("UriUtils", uri.toString() + " -> /external");
return file;
}
}
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
if (path != null) return new File(path);
......
......@@ -24,18 +24,20 @@ public class ApiClassVisitor extends ClassVisitor {
private String superClassName;
private boolean hasAnnotation;
private boolean isMock;
private String mApiUtilsClass;
public ApiClassVisitor(ClassVisitor classVisitor, Map<String, ApiInfo> apiImplMap, List<String> apiClasses) {
public ApiClassVisitor(ClassVisitor classVisitor, Map<String, ApiInfo> apiImplMap, List<String> apiClasses, String apiUtilsClass) {
super(Opcodes.ASM5, classVisitor);
mApiImplMap = apiImplMap;
mApiClasses = apiClasses;
mApiUtilsClass = apiUtilsClass.replace(".", "/");
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name;
superClassName = superName;
if ("com/blankj/utilcode/util/ApiUtils$BaseApi".equals(superName)) {
if ((mApiUtilsClass + "$BaseApi").equals(superName)) {
mApiClasses.add(name);
}
super.visit(version, access, name, signature, superName, interfaces);
......@@ -43,7 +45,7 @@ public class ApiClassVisitor extends ClassVisitor {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if ("Lcom/blankj/utilcode/util/ApiUtils$Api;".equals(desc)) {
if (("L" + mApiUtilsClass + "$Api;").equals(desc)) {
hasAnnotation = true;
return new AnnotationVisitor(Opcodes.ASM5, super.visitAnnotation(desc, visible)) {
@Override
......
package com.blankj.api
class ApiExtension {
boolean abortOnError = true
String apiUtilsClass = "com.blankj.utilcode.util.ApiUtils";
@Override
String toString() {
return "BusExtension { " +
"abortOnError: " + abortOnError +
", apiUtilsClass: " + apiUtilsClass +
" }";
}
}
......@@ -5,27 +5,41 @@ import org.apache.commons.io.FileUtils
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
class ApiInject {
static void start(Map<String, String> apiImplMap, File apiJar) {
String jarPath = apiJar.getAbsolutePath()
String decompressedJarPath = jarPath.substring(0, jarPath.length() - 4);
File decompressedJar = new File(decompressedJarPath)
ZipUtils.unzipFile(apiJar, decompressedJar)
static void start(Map<String, String> apiImplMap, File apiUtilsTransformFile, String busUtilsClass) {
if (apiUtilsTransformFile.getPath().endsWith(".jar")) {
String jarPath = apiUtilsTransformFile.getAbsolutePath()
String decompressedJarPath = jarPath.substring(0, jarPath.length() - 4);
File decompressedJar = new File(decompressedJarPath)
ZipUtils.unzipFile(apiUtilsTransformFile, decompressedJar)
File apiUtilsFile = new File(decompressedJarPath + Config.FILE_SEP + Config.API_UTILS_CLASS)
File apiUtilsFile = new File(
decompressedJarPath + Config.FILE_SEP +
busUtilsClass.replace('.', Config.FILE_SEP) + '.class'
)
inject2ApiUtils(apiUtilsFile, apiImplMap, busUtilsClass)
FileUtils.forceDelete(apiUtilsTransformFile)
ZipUtils.zipFiles(Arrays.asList(decompressedJar.listFiles()), apiUtilsTransformFile)
FileUtils.forceDelete(decompressedJar)
} else {
File apiUtilsFile = new File(
apiUtilsTransformFile.getAbsolutePath() + Config.FILE_SEP +
busUtilsClass.replace('.', Config.FILE_SEP) + '.class'
)
inject2ApiUtils(apiUtilsFile, apiImplMap, busUtilsClass)
}
}
private static void inject2ApiUtils(File apiUtilsFile, Map<String, String> apiImplMap, String apiUtilsClass) {
ClassReader cr = new ClassReader(apiUtilsFile.bytes);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ApiUtilsClassVisitor(cw, apiImplMap);
ClassVisitor cv = new ApiUtilsClassVisitor(cw, apiImplMap, apiUtilsClass);
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(apiUtilsFile, cw.toByteArray())
FileUtils.forceDelete(apiJar)
ZipUtils.zipFiles(Arrays.asList(decompressedJar.listFiles()), apiJar)
FileUtils.forceDelete(decompressedJar)
}
}
\ No newline at end of file
......@@ -17,9 +17,6 @@ class ApiPlugin implements Plugin<Project> {
project.extensions.create(Config.EXT_NAME, ApiExtension)
def android = project.extensions.getByType(AppExtension)
android.registerTransform(new ApiTransform(project))
project.afterEvaluate {
def ext = project[Config.EXT_NAME] as ApiExtension
}
}
}
}
\ No newline at end of file
package com.blankj.api
import com.blankj.api.util.LogUtils
import com.blankj.api.util.ZipUtils
import groovy.io.FileType
import org.apache.commons.io.FileUtils
......@@ -11,19 +12,34 @@ class ApiScan {
Map<String, ApiInfo> apiImplMap = [:]
List<String> apiClasses = []
File utilcodeJar
File apiUtilsTransformFile
String apiUtilsClass
ApiScan(String apiUtilsClass) {
this.apiUtilsClass = apiUtilsClass
}
void scanJar(File jar) {
File tmp = new File(jar.getParent(), "temp_" + jar.getName())
List<File> unzipFile = ZipUtils.unzipFile(jar, tmp)
if (unzipFile != null && unzipFile.size() > 0) {
scanDir(tmp)
scanDir(tmp, jar)
FileUtils.forceDelete(tmp)
}
}
void scanDir(File root) {
scanDir(root, root)
}
void scanDir(File root, File source) {
if (!root.isDirectory()) return
String rootPath = root.getAbsolutePath()
if (!rootPath.endsWith(Config.FILE_SEP)) {
rootPath += Config.FILE_SEP
}
root.eachFileRecurse(FileType.FILES) { File file ->
def fileName = file.name
if (!fileName.endsWith('.class')
......@@ -33,9 +49,19 @@ class ApiScan {
return
}
def filePath = file.absolutePath
def packagePath = filePath.replace(rootPath, '')
def className = packagePath.replace(Config.FILE_SEP, ".")
// delete .class
className = className.substring(0, className.length() - 6)
if (apiUtilsClass == className) {
apiUtilsTransformFile = source
LogUtils.l("<ApiUtils transform file>: $source")
}
ClassReader cr = new ClassReader(file.bytes);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ApiClassVisitor(cw, apiImplMap, apiClasses);
ClassVisitor cv = new ApiClassVisitor(cw, apiImplMap, apiClasses, apiUtilsClass);
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(file, cw.toByteArray());
......
......@@ -40,11 +40,17 @@ class ApiTransform extends Transform {
throws TransformException, InterruptedException, IOException {
super.transform(transformInvocation)
LogUtils.l(getName() + " started")
long stTime = System.currentTimeMillis()
def ext = mProject[Config.EXT_NAME] as ApiExtension
LogUtils.l("apiExtension: $ext")
if (ext.apiUtilsClass.trim().equals("")) {
throw new Exception("ApiExtension's apiUtilsClass is empty.")
}
File jsonFile = new File(mProject.projectDir.getAbsolutePath(), "__api__.json")
FileUtils.write(jsonFile, "{}")
long stTime = System.currentTimeMillis()
def inputs = transformInvocation.getInputs()
def referencedInputs = transformInvocation.getReferencedInputs()
def outputProvider = transformInvocation.getOutputProvider()
......@@ -52,7 +58,7 @@ class ApiTransform extends Transform {
outputProvider.deleteAll()
ApiScan apiScan = new ApiScan()
ApiScan apiScan = new ApiScan(ext.apiUtilsClass)
inputs.each { TransformInput input ->
input.directoryInputs.each { DirectoryInput dirInput ->// 遍历文件夹
......@@ -66,9 +72,9 @@ class ApiTransform extends Transform {
)
FileUtils.copyDirectory(dir, dest)
LogUtils.l("scan dir: $dir [$dest]")
LogUtils.l("scan dir: ${dirInput.file} -> $dest")
apiScan.scanDir(dir)
apiScan.scanDir(dest)
}
input.jarInputs.each { JarInput jarInput ->// 遍历 jar 文件
File jar = jarInput.file
......@@ -82,25 +88,18 @@ class ApiTransform extends Transform {
)
FileUtils.copyFile(jar, dest)
if (jarName.startsWith("com.blankj:utilcode:")
|| jarName.startsWith("com.blankj:utilcodex:")
|| jarName.equals(":lib:utilcode")) {
apiScan.utilcodeJar = dest
LogUtils.l("utilcode jar: $jarName [$dest]")
return
}
if (jumpScan(jarName)) {
LogUtils.l("jump jar: $jarName [$dest]")
LogUtils.l("jump jar: $jarName -> $dest")
return
}
LogUtils.l("scan jar: $jarName [$dest]")
apiScan.scanJar(jar)
LogUtils.l("scan jar: $jarName -> $dest")
apiScan.scanJar(dest)
}
}
if (apiScan.utilcodeJar != null) {
if (apiScan.apiUtilsTransformFile != null) {
if (apiScan.apiClasses.isEmpty()) {
LogUtils.l("no api.")
} else {
......@@ -115,6 +114,7 @@ class ApiTransform extends Transform {
}
}
Map apiDetails = [:]
apiDetails.put("ApiUtilsClass", ext.apiUtilsClass)
apiDetails.put("implApis", implApis)
apiDetails.put("noImplApis", noImplApis)
String apiJson = JsonUtils.getFormatJson(apiDetails)
......@@ -122,16 +122,15 @@ class ApiTransform extends Transform {
FileUtils.write(jsonFile, apiJson)
if (noImplApis.size() > 0) {
def ext = mProject[Config.EXT_NAME] as ApiExtension
if (ext.abortOnError) {
throw new Exception("u should impl these apis: " + noImplApis +
"\n u can check it in file: " + jsonFile.toString())
}
}
ApiInject.start(apiScan.apiImplMap, apiScan.utilcodeJar)
ApiInject.start(apiScan.apiImplMap, apiScan.apiUtilsTransformFile, ext.apiUtilsClass)
}
} else {
LogUtils.l('u should <implementation "com.blankj:utilcode(x):1.25.+">')
throw new Exception("No ApiUtils of ${ext.apiUtilsClass} in $mProject.")
}
LogUtils.l(getName() + " finished: " + (System.currentTimeMillis() - stTime) + "ms")
......
......@@ -21,10 +21,12 @@ import java.util.Map;
public class ApiUtilsClassVisitor extends ClassVisitor {
private Map<String, ApiInfo> mApiImplMap;
private String mApiUtilsClass;
public ApiUtilsClassVisitor(ClassVisitor classVisitor, Map<String, ApiInfo> apiImplMap) {
public ApiUtilsClassVisitor(ClassVisitor classVisitor, Map<String, ApiInfo> apiImplMap, String apiUtilsClass) {
super(Opcodes.ASM5, classVisitor);
mApiImplMap = apiImplMap;
mApiUtilsClass = apiUtilsClass.replace(".", "/");
}
@Override
......@@ -53,7 +55,7 @@ public class ApiUtilsClassVisitor extends ClassVisitor {
for (Map.Entry<String, ApiInfo> apiImplEntry : mApiImplMap.entrySet()) {
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitLdcInsn(Type.getType("L" + apiImplEntry.getValue().implApiClass + ";"));
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "com/blankj/utilcode/util/ApiUtils", "registerImpl", "(Ljava/lang/Class;)V", false);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, mApiUtilsClass, "registerImpl", "(Ljava/lang/Class;)V", false);
}
}
};
......
......@@ -14,6 +14,4 @@ class Config {
]
public static final String FILE_SEP = System.getProperty("file.separator")
public static final String API_UTILS_CLASS = 'com.blankj.utilcode.util.ApiUtils'.replace('.', FILE_SEP) + '.class'
}
package com.blankj.api;
import com.blankj.utilcode.util.ApiUtils;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
......@@ -36,7 +34,7 @@ public class ApiTest {
ClassReader cr = new ClassReader(TestApiImpl.class.getName());
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ApiClassVisitor(cw, apiImplMap, apiClasses);
ClassVisitor cv = new ApiClassVisitor(cw, apiImplMap, apiClasses, ApiUtils.class.getCanonicalName());
cr.accept(cv, ClassReader.SKIP_FRAMES);
System.out.println("apiImplMap = " + apiImplMap);
......@@ -47,7 +45,7 @@ public class ApiTest {
private static void inject2ApiUtils(Map<String, ApiInfo> apiImpls) throws IOException {
ClassReader cr = new ClassReader(ApiUtils.class.getName());
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new ApiUtilsClassVisitor(cw, apiImpls);
ClassVisitor cv = new ApiUtilsClassVisitor(cw, apiImpls, ApiUtils.class.getCanonicalName());
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(new File("ApiUtils2333.class"), cw.toByteArray());
......
#project
project.name=ApiPlugin
project.name=BusPlugin
project.groupId=com.blankj
project.artifactId=api-gradle-plugin
project.artifactId=bus-gradle-plugin
project.packaging=aar
project.siteUrl=https://github.com/Blankj/AndroidUtilCode
project.gitUrl=https://github.com/Blankj/AndroidUtilCode.git
#javadoc
javadoc.name=ApiPlugin
\ No newline at end of file
javadoc.name=BusPlugin
\ No newline at end of file
package com.blankj.bus
import com.blankj.bus.util.LogUtils
import com.blankj.bus.util.ZipUtils
import org.apache.commons.io.FileUtils
import org.objectweb.asm.ClassReader
......@@ -10,19 +9,18 @@ import org.objectweb.asm.ClassWriter
class BusInject {
static void start(Map<String, BusInfo> busMap, File busUtilsTransformFile, String busUtilsClass) {
LogUtils.l("===>" + busUtilsTransformFile)
if (busUtilsTransformFile.getPath().endsWith(".jar")) {
String jarPath = busUtilsTransformFile.getAbsolutePath()
String decompressedJarPath = jarPath.substring(0, jarPath.length() - 4);
File decompressedJar = new File(decompressedJarPath)
ZipUtils.unzipFile(busUtilsTransformFile, decompressedJar)
File apiUtilsFile = new File(
File busUtilsFile = new File(
decompressedJarPath + Config.FILE_SEP +
busUtilsClass.replace('.', Config.FILE_SEP) + '.class'
)
inject2BusUtils(apiUtilsFile, busMap, busUtilsClass)
inject2BusUtils(busUtilsFile, busMap, busUtilsClass)
FileUtils.forceDelete(busUtilsTransformFile)
ZipUtils.zipFiles(Arrays.asList(decompressedJar.listFiles()), busUtilsTransformFile)
......@@ -44,5 +42,4 @@ class BusInject {
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(apiUtilsFile, cw.toByteArray())
}
}
\ No newline at end of file
......@@ -54,7 +54,7 @@ class BusScan {
className = className.substring(0, className.length() - 6)
if (busUtilsClass == className) {
busUtilsTransformFile = source
LogUtils.l("BusUtils transform file: $source")
LogUtils.l("<BusUtils transform file>: $source")
}
ClassReader cr = new ClassReader(file.bytes);
......
......@@ -43,9 +43,9 @@ class BusTransform extends Transform {
long stTime = System.currentTimeMillis()
def ext = mProject[Config.EXT_NAME] as BusExtension
LogUtils.l(ext)
LogUtils.l("busExtension: $ext")
if (ext.busUtilsClass.trim().equals("")) {
throw new Exception("BusExtension is empty.")
throw new Exception("BusExtension's busUtilsClass is empty.")
}
File jsonFile = new File(mProject.projectDir.getAbsolutePath(), "__bus__.json")
FileUtils.write(jsonFile, "{}")
......
......@@ -20,7 +20,7 @@ import java.util.Map;
public class BusUtilsClassVisitor extends ClassVisitor {
private Map<String, List<BusInfo>> mBusMap;
private String mBusUtilsClass;
private String mBusUtilsClass;
public BusUtilsClassVisitor(ClassVisitor classVisitor, Map<String, List<BusInfo>> busMap, String busUtilsClass) {
super(Opcodes.ASM5, classVisitor);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册