-
Notifications
You must be signed in to change notification settings - Fork 1.6k
重定向修改jar #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
重定向修改jar #301
Changes from 1 commit
cce6904
58e5a0d
82142dd
e27e49d
c03c6aa
a4c067f
d4853cb
c2ca290
0ca937c
a49598f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
|
|
||
| package com.qihoo360.replugin.gradle.plugin.inner | ||
|
|
||
| import com.qihoo360.replugin.gradle.plugin.AppConstant | ||
|
|
||
| /** | ||
| * @author 247321453 | ||
| */ | ||
| public class InjectorVersion { | ||
|
|
||
| def String jarPath | ||
|
|
||
| def String jarMd5 | ||
|
|
||
| def String pluginVersion | ||
|
|
||
| InjectorVersion(){ | ||
|
|
||
| } | ||
|
|
||
| InjectorVersion(String jarPath, String jarMd5, String pluginVersion) { | ||
| this.jarPath = jarPath | ||
| this.jarMd5 = jarMd5 | ||
| this.pluginVersion = pluginVersion | ||
| } | ||
|
|
||
| InjectorVersion(File jar){ | ||
| this.jarPath = jar.getAbsolutePath() | ||
| this.jarMd5 = Util.md5File(jar) | ||
| this.pluginVersion = AppConstant.VER | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,10 @@ import com.android.build.api.transform.JarInput | |
| import com.android.build.api.transform.TransformInput | ||
| import com.android.build.gradle.internal.scope.GlobalScope | ||
| import com.android.sdklib.IAndroidTarget | ||
| import com.google.common.reflect.TypeToken | ||
| import com.google.gson.Gson | ||
| import com.google.gson.GsonBuilder | ||
| import com.google.gson.stream.JsonReader | ||
| import com.qihoo360.replugin.gradle.plugin.AppConstant | ||
| import org.apache.commons.codec.digest.DigestUtils | ||
| import org.apache.commons.io.FileUtils | ||
|
|
@@ -32,7 +36,6 @@ import org.gradle.api.Project | |
| import java.lang.reflect.Field | ||
| import java.nio.file.Files | ||
| import java.nio.file.Paths | ||
| import java.util.zip.ZipEntry | ||
| import java.util.zip.ZipFile | ||
|
|
||
| import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES; | ||
|
|
@@ -69,7 +72,8 @@ public class Util { | |
| def projectDir = project.getRootDir().absolutePath | ||
|
|
||
| println ">>> Unzip Jar ..." | ||
|
|
||
| Map<String, InjectorVersion> injectorMap = readJarInjectorHistory(project) | ||
| boolean needSave = false | ||
| inputs.each { TransformInput input -> | ||
|
|
||
| input.directoryInputs.each { DirectoryInput dirInput -> | ||
|
|
@@ -100,123 +104,144 @@ public class Util { | |
|
|
||
| } else { | ||
| //重定向jar | ||
| File reJar = new File(project.getBuildDir().path + | ||
| File.separator + FD_INTERMEDIATES + File.separator + "replugin-jar" | ||
| + File.separator + md5File(jar) + ".jar"); | ||
| String reJarPath = reJar.getAbsolutePath() | ||
| boolean needInject = false | ||
| if (reJar.exists()) { | ||
| //检查修改插件版本 | ||
| needInject = checkJarInjectorVersion(reJarPath) | ||
| if (jarPath.contains(File.separator + FD_INTERMEDIATES + File.separator + "replugin-jar")) { | ||
| // | ||
| } else { | ||
| FileUtils.copyFile(jar, reJar) | ||
| needInject = true; | ||
| } | ||
| //设置重定向jar | ||
| setJarInput(jarInput, reJar) | ||
| if(needInject){ | ||
| includeJars << reJarPath | ||
| map.put(reJarPath, reJarPath) | ||
|
|
||
| /* 将 jar 包解压,并将解压后的目录加入 classpath */ | ||
| // println ">>> 解压Jar${jarPath}" | ||
| String jarZipDir = reJar.getParent() + File.separatorChar + reJar.getName().replace('.jar', '') | ||
| if (unzip(jarPath, jarZipDir)) { | ||
| classPath << jarZipDir | ||
| //保存修改的插件版本号 | ||
| saveJarInjectorVersion(jarZipDir) | ||
| visitor.setBaseDir(jarZipDir) | ||
| Files.walkFileTree(Paths.get(jarZipDir), visitor) | ||
| String md5 = md5File(jar); | ||
| File reJar = new File(project.getBuildDir().path + | ||
| File.separator + FD_INTERMEDIATES + File.separator + "replugin-jar" | ||
| + File.separator + md5 + ".jar"); | ||
| String reJarPath = reJar.getAbsolutePath() | ||
|
|
||
| boolean needInject = false | ||
| if (reJar.exists()) { | ||
| //检查修改插件版本 | ||
| InjectorVersion injectorVersion = injectorMap.get(jar.getAbsolutePath()); | ||
| if (injectorVersion != null) { | ||
| if (!AppConstant.VER.equals(injectorVersion.pluginVersion)) { | ||
| //版本变化了 | ||
| needInject = true | ||
| } else { | ||
| if (!md5.equals(injectorVersion.jarMd5)) { | ||
| //原始jar内容变化 | ||
| needInject = true | ||
| } | ||
| } | ||
| } else { | ||
| //无记录 | ||
| needInject = true | ||
| } | ||
| } else { | ||
| FileUtils.copyFile(jar, reJar) | ||
|
||
| needInject = true; | ||
| } | ||
| //设置重定向jar | ||
| setJarInput(jarInput, reJar) | ||
|
||
| if (needInject) { | ||
|
||
| includeJars << reJarPath | ||
| map.put(reJarPath, reJarPath) | ||
|
||
|
|
||
| /* 将 jar 包解压,并将解压后的目录加入 classpath */ | ||
| // println ">>> 解压Jar${jarPath}" | ||
| String jarZipDir = reJar.getParent() + File.separatorChar + reJar.getName().replace('.jar', '') | ||
| if (unzip(jarPath, jarZipDir)) { | ||
|
||
| classPath << jarZipDir | ||
| //保存修改的插件版本号 | ||
| needSave = true | ||
| injectorMap.put(jar.getAbsolutePath(), new InjectorVersion(jar)) | ||
|
|
||
| visitor.setBaseDir(jarZipDir) | ||
| Files.walkFileTree(Paths.get(jarZipDir), visitor) | ||
| } | ||
| // 删除 jar | ||
| FileUtils.forceDelete(reJar) | ||
| } else { | ||
| map.remove(reJarPath) | ||
| includeJars.remove(reJarPath) | ||
| } | ||
| // 删除 jar | ||
| FileUtils.forceDelete(reJar) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (needSave) { | ||
| saveJarInjectorHistory(project, injectorMap) | ||
| } | ||
| return classPath | ||
| } | ||
|
|
||
| def static md5File(File jar){ | ||
| /** | ||
| * 计算jar的md5 | ||
| */ | ||
| def static md5File(File jar) { | ||
| FileInputStream fileInputStream = new FileInputStream(jar); | ||
| String md5 = DigestUtils.md5Hex(fileInputStream); | ||
| fileInputStream.close() | ||
| return md5 | ||
| } | ||
|
|
||
| def static setJarInput(JarInput jarInput, File rejar) { | ||
| Field fileField = null; | ||
| Class<?> clazz = jarInput.getClass(); | ||
| while(fileField == null && clazz != Object.class){ | ||
| try { | ||
| fileField = clazz.getDeclaredField("file"); | ||
| } catch (Exception e) { | ||
| //ignore | ||
| clazz = clazz.getSuperclass(); | ||
| } | ||
| /** | ||
| * 读取修改jar的记录 | ||
| */ | ||
| def static readJarInjectorHistory(Project project) { | ||
| File file = new File(project.getBuildDir(), FD_INTERMEDIATES | ||
| + File.separator + "replugin-jar" + File.separator + "version.json"); | ||
| if (!file.exists()) { | ||
| return new HashMap<String, InjectorVersion>(); | ||
| } | ||
| if(fileField != null){ | ||
| fileField.setAccessible(true); | ||
| fileField.set(jarInput, rejar); | ||
| Gson gson = new GsonBuilder() | ||
| .create(); | ||
| FileReader fileReader = new FileReader(file) | ||
| JsonReader jsonReader = new JsonReader(fileReader); | ||
| Map<String, InjectorVersion> injectorMap = gson.fromJson(jsonReader, new TypeToken<Map<String, InjectorVersion>>() { | ||
| }.getType()); | ||
| jsonReader.close() | ||
| if (injectorMap == null) { | ||
| injectorMap = new HashMap<String, InjectorVersion>(); | ||
| } | ||
| return injectorMap; | ||
| } | ||
|
|
||
| /** | ||
| * 通过META-INF/replugin_version.txt判断是否需要修改 | ||
| * 保存修改jar的记录 | ||
| */ | ||
| def static checkJarInjectorVersion(String jar) { | ||
| boolean needInjector = true; | ||
| ZipFile zf = null; | ||
| ZipEntry ze = null; | ||
| InputStream inputStream = null; | ||
| try{ | ||
| zf = new ZipFile(jar); | ||
| ze = zf.getEntry("META-INF/replugin_version.txt"); | ||
| if(ze != null){ | ||
| byte[] data = new byte[jar.length()]; | ||
| inputStream = zf.getInputStream(ze); | ||
| int len = inputStream.read(data, 0, data.length); | ||
| String ver = new String(data, "utf-8").trim(); | ||
| needInjector = !AppConstant.VER.equals(ver); | ||
| } | ||
| }catch (Throwable e){ | ||
| // | ||
| }finally{ | ||
| if(inputStream != null){ | ||
| inputStream.close(); | ||
| } | ||
| if(zf != null){ | ||
| zf.close(); | ||
| def static saveJarInjectorHistory(Project project, Map<String, InjectorVersion> injectorMap) { | ||
| Gson gson = new GsonBuilder() | ||
| .setPrettyPrinting() | ||
| .create(); | ||
| File file = new File(project.getBuildDir(), FD_INTERMEDIATES | ||
| + File.separator + "replugin-jar" + File.separator + "version.json"); | ||
| if (file.exists()) { | ||
| file.delete() | ||
| } else { | ||
| File dir = file.getParentFile(); | ||
| if (!dir.exists()) { | ||
| dir.mkdirs() | ||
| } | ||
| } | ||
| return needInjector; | ||
| file.createNewFile() | ||
| FileWriter fileWriter = new FileWriter(file); | ||
| String json = gson.toJson(injectorMap); | ||
| fileWriter.write(json) | ||
| fileWriter.close() | ||
| } | ||
|
|
||
| /** | ||
| * 记录版本号到META-INF/replugin_version.txt | ||
| * 反射,修改引用的jar路径 | ||
| */ | ||
| def static saveJarInjectorVersion(String jarZipDir) { | ||
| File verFile = new File(jarZipDir, "META-INF/replugin_version.txt"); | ||
| if(verFile.exists()){ | ||
| verFile.delete(); | ||
| }else{ | ||
| File dir = verFile.getParentFile(); | ||
| if(!dir.exists()){ | ||
| dir.mkdirs(); | ||
| def static setJarInput(JarInput jarInput, File rejar) { | ||
| Field fileField = null; | ||
| Class<?> clazz = jarInput.getClass(); | ||
| while (fileField == null && clazz != Object.class) { | ||
| try { | ||
| fileField = clazz.getDeclaredField("file"); | ||
| } catch (Exception e) { | ||
| //ignore | ||
| clazz = clazz.getSuperclass(); | ||
| } | ||
| } | ||
| verFile.createNewFile(); | ||
| FileOutputStream fileOutputStream = null; | ||
| try{ | ||
| fileOutputStream = new FileOutputStream(verFile); | ||
| fileOutputStream.write(AppConstant.VER.getBytes("utf-8")); | ||
| fileOutputStream.flush(); | ||
| }catch (Throwable e){ | ||
| // | ||
| }finally{ | ||
| if(fileOutputStream!=null){ | ||
| fileOutputStream.close(); | ||
| } | ||
| if (fileField != null) { | ||
| fileField.setAccessible(true); | ||
| fileField.set(jarInput, rejar); | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里方法和变量的命名,还是建议更精准一些,比如InjectorVersion ,里面包含了插件版本信息,和jar的md5信息,类名建议叫JarInfo(或者有更确切的名字也可以),包括injectorMap也建议修改为jarInfoMap,这部分相关的代码和类名尽量不带‘injector’字样,毕竟‘injector’的本意是注入器,这只应该injector模块及相关部分中使用。
另:json文件也建议与此保持一致,这样代码整体一致性更强些。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
或者类名叫BuildCacheInfo,更确切些,供参考