├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── build.gradle ├── classlib ├── .gitignore ├── build.gradle ├── libs │ ├── dexlib.jar │ ├── dx.jar │ └── javassist.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── baiducom │ │ └── music │ │ └── classlib │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── baidu │ │ └── music │ │ └── classlib │ │ ├── bean │ │ └── PatchItem.java │ │ ├── build │ │ └── DexClient.java │ │ ├── dex │ │ ├── PatchDex.java │ │ ├── PatchDexApplication.java │ │ ├── PatchDexExtractor.java │ │ └── ZipUtil.java │ │ ├── exception │ │ └── ReflectException.java │ │ ├── jni │ │ └── HookBridge.java │ │ ├── listener │ │ └── FileOperatorListener.java │ │ ├── manager │ │ ├── BaseManager.java │ │ ├── ContextManager.java │ │ ├── HookManager.java │ │ └── ResourceManager.java │ │ ├── resource │ │ ├── PatchContext.java │ │ └── PatchResource.java │ │ └── utils │ │ ├── ApkUtils.java │ │ ├── FileUtils.java │ │ ├── Md5Utils.java │ │ └── ReflectUtils.java │ ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── base │ │ ├── Lock.h │ │ ├── NativeException.cpp │ │ ├── NativeException.h │ │ ├── base64.cpp │ │ ├── base64.h │ │ ├── log.h │ │ ├── thread.cpp │ │ └── thread.h │ ├── hook │ │ ├── Android.mk │ │ ├── Application.mk │ │ ├── Hook.cpp │ │ ├── hookArt │ │ │ ├── HookArtMethod.cpp │ │ │ └── art.h │ │ ├── hookDalvik │ │ │ ├── DexFile.h │ │ │ ├── HookDalvikMethod.cpp │ │ │ ├── dalvik.h │ │ │ └── substrate.h │ │ ├── hookNative │ │ │ ├── ElfHook.c │ │ │ ├── ElfHook.h │ │ │ ├── HookNativeMethod.cpp │ │ │ ├── InlineHook.cpp │ │ │ ├── InlineHook.h │ │ │ ├── InlineUtils.cpp │ │ │ ├── InlineUtils.h │ │ │ ├── Linker.h │ │ │ ├── NativeElfHook.cpp │ │ │ ├── NativeElfHook.h │ │ │ ├── NativeHook.cpp │ │ │ ├── NativeHook.h │ │ │ ├── NativeInlineHook.cpp │ │ │ ├── NativeInlineHook.h │ │ │ ├── TKHooklib.h │ │ │ ├── hooktest.c │ │ │ ├── relocate.cpp │ │ │ └── relocate.h │ │ ├── libTKHooklib.so │ │ ├── libsubstrate-dvm.so │ │ └── libsubstrate.so │ └── test │ │ ├── Android.mk │ │ ├── Application.mk │ │ └── test.cpp │ └── res │ └── values │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── patch ├── DexTest.apk ├── classes │ ├── DexTest.class │ ├── MainActivity.class │ └── classes.dex └── libpatch.so ├── sample ├── .gitignore ├── build.gradle ├── keystore ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── baiducom │ │ └── music │ │ └── classpatch │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── baidu │ │ │ └── music │ │ │ └── classpatch │ │ │ ├── ClassPatchApplication.java │ │ │ ├── DexTest.java │ │ │ ├── MainActivity.java │ │ │ └── SecondActivity.java │ ├── jniLibs │ │ └── armeabi │ │ │ └── libcommonHook.so │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── content_main.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── baiducom │ └── music │ └── classpatch │ └── ExampleUnitTest.java ├── settings.gradle └── tool └── apkpatch.zip /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | ClassPatch -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.7 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ClassPatch 2 | # 第一、原理介绍 3 | 相关原理请参考:http://blog.csdn.net/xwl198937/article/details/49801975 4 | # 第二、生成patch apk 5 | 1、将改动的java文件编译生成class文件。 6 | 2、将所有的class文件放进/ClassPatch/classes/目录下面, 7 | 3、执行sample生成classes.dex文件在/ClassPatch/classes/ 8 | 4、随便找一个apk,重命名为.zip文件,将刚刚生成的clases.dex文件放进去,在重命名为.apk 9 | 5、将apk放进data/data/app-packageName/patch目录下。(具体参考sample中的复制按钮选项) 10 | 6、重启app后,patch才能生效 11 | 或者你使用tool目录下面的工具生成patch apk(这个是阿里巴巴andfix开源中的patch生成器)(这个还是有点问题)之后我会自己弄一个出来。包括资源,混淆,dex等等 12 | # 第三、说明 13 | 1、由于现在还在完善中,后期考虑加入patch实时生效的能力,还有替换布局的能力。具体参考我的另一个博客:http://blog.csdn.net/xwl198937/article/details/50134861 14 | 2、目录下面的patch是已经生成的patch apk,可以直接用,将其放进sdcard中,并重命名为ClassPatch 15 | 3、so hook 是正在研究的项目,有兴趣的可以一起讨论一下。sample中so替换功能是不能实现的。 16 | 4、现在已经基本实现dalvik系统中patch实时生效的能力。原理是在proxyDvmResolveClass增加标识,不选择从dvmDexGetResolvedClass获取class。 17 | 5、实现so hook功能,现在已经实现了 18 | 19 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.0' 9 | // classpath 'com.baidu.music.classpatch:ClassPatchGradle:1.0' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /classlib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /classlib/build.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os apply plugin: 'com.android.library' android { compileSdkVersion 22 buildToolsVersion "23.0.2" defaultConfig { minSdkVersion 9 targetSdkVersion 11 versionCode 1000 versionName "1.0.0.0" } sourceSets { main { jni.srcDirs = [] } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild, clearJar, makeJar } } def getNdkBuildFullPath() { if (hasProperty('ndk.command')) { return property('ndk.command') } if (hasProperty('ndk.path')) { def path = property('ndk.path') if (!path.endsWith(File.separator)) { path += File.separator } return path + getNdkBuildName() } return getNdkBuildName() } def getNdkBuildName() { if (Os.isFamily(Os.FAMILY_WINDOWS)) { return "ndk-build.cmd" } else { return "ndk-build" } } task clearJar(type: Delete) { delete 'build/outputs/jar/common-patch.jar' } task makeJar(type: Copy) { from('build/intermediates/bundles/release/') into('build/outputs/jar/') include('classes.jar') rename ('classes.jar', 'common-patch.jar') } task ndkBuild(type: Exec) { commandLine getNdkBuildFullPath(), 'NDK_OUT=' + temporaryDir, '-C', file('src/main/jni').absolutePath } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } -------------------------------------------------------------------------------- /classlib/libs/dexlib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarlene/ClassPatch/37c97cc4938879460189a680b0e7d8d3b3ee4bea/classlib/libs/dexlib.jar -------------------------------------------------------------------------------- /classlib/libs/dx.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarlene/ClassPatch/37c97cc4938879460189a680b0e7d8d3b3ee4bea/classlib/libs/dx.jar -------------------------------------------------------------------------------- /classlib/libs/javassist.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jarlene/ClassPatch/37c97cc4938879460189a680b0e7d8d3b3ee4bea/classlib/libs/javassist.jar -------------------------------------------------------------------------------- /classlib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\DevelopmentTools\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /classlib/src/androidTest/java/baiducom/music/classlib/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package baiducom.music.classlib; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /classlib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /classlib/src/main/java/com/baidu/music/classlib/bean/PatchItem.java: -------------------------------------------------------------------------------- 1 | package com.baidu.music.classlib.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * bean 数据源,描述一些信息。 7 | * 现在代码中没有使用到,为以后方便使用。 8 | * Created by Jarlene on 2015/11/23. 9 | */ 10 | public class PatchItem implements Serializable { 11 | 12 | public String className; 13 | 14 | public String fileHash; 15 | 16 | public String fileUrl; 17 | 18 | public String methodName; 19 | 20 | public String apkPath; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /classlib/src/main/java/com/baidu/music/classlib/build/DexClient.java: -------------------------------------------------------------------------------- 1 | package com.baidu.music.classlib.build; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.android.dx.cf.iface.ParseException; 6 | import com.android.dx.dex.DexOptions; 7 | import com.android.dx.dex.cf.CfOptions; 8 | import com.android.dx.dex.cf.CfTranslator; 9 | import com.android.dx.dex.code.PositionList; 10 | import com.android.dx.dex.file.ClassDefItem; 11 | import com.android.dx.dex.file.DexFile; 12 | 13 | import java.io.ByteArrayOutputStream; 14 | import java.io.File; 15 | import java.io.FileInputStream; 16 | import java.io.FileNotFoundException; 17 | import java.io.FileOutputStream; 18 | import java.io.IOException; 19 | import java.io.OutputStreamWriter; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import javassist.CannotCompileException; 24 | import javassist.ClassPool; 25 | import javassist.CtClass; 26 | import javassist.CtConstructor; 27 | import javassist.CtField; 28 | import javassist.CtMethod; 29 | import javassist.Modifier; 30 | import javassist.NotFoundException; 31 | 32 | 33 | /** 34 | * 生成dex文件。每一个DexClient只能使用一次。 35 | * 这里包含了自动写的代码生成class文件,再转为换dex文件逻辑 36 | * Created by Jarlene on 2015/11/23. 37 | */ 38 | public class DexClient { 39 | 40 | private static DexFile outputDex; 41 | 42 | private final CfOptions cfOptions; 43 | 44 | private final ClassPool classPool; 45 | 46 | private final DexOptions options; 47 | 48 | public DexClient() { 49 | options = new DexOptions(); 50 | outputDex = new DexFile(options); 51 | cfOptions = new CfOptions(); 52 | classPool = ClassPool.getDefault(); 53 | 54 | cfOptions.positionInfo = PositionList.LINES; 55 | cfOptions.localInfo = true; 56 | cfOptions.strictNameCheck = false; 57 | cfOptions.optimize = false; 58 | cfOptions.optimizeListFile = null; 59 | cfOptions.dontOptimizeListFile = null; 60 | cfOptions.statistics = false; 61 | } 62 | 63 | /** 64 | * 将多个class文件生成dex文件 65 | * @param srcPath 66 | * classes文件夹路径 67 | * @param savePath 68 | * dex文件路径 69 | * @return 70 | */ 71 | public File makeDex(List srcPath, String savePath) { 72 | int i = 0; 73 | String[] pathArray = new String[srcPath.size()]; 74 | for (String path : srcPath) { 75 | pathArray[i++] = path; 76 | } 77 | return makeDex(pathArray, savePath); 78 | } 79 | 80 | 81 | /** 82 | * 将多个class文件生成dex文件 83 | * @param srcPath 84 | * classes文件夹路径 85 | * @param savePath 86 | * dex文件路径 87 | * @return 88 | */ 89 | public File makeDex(String[] srcPath, String savePath) { 90 | try { 91 | if (srcPath == null || srcPath.length <= 0 || TextUtils.isEmpty(savePath)) { 92 | return null; 93 | } 94 | 95 | byte[][] content = new byte[srcPath.length][]; 96 | 97 | for (int i = 0; i < srcPath.length; i++) { 98 | content[i] = processFile(srcPath[i]); 99 | } 100 | byte[] dexByte = classesToDex(srcPath, content); 101 | return makeDex(savePath, dexByte); 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | } 105 | return null; 106 | 107 | } 108 | 109 | 110 | /** 111 | * 将一个class文件生成dex文件 112 | * @param srcPath 113 | * class文件路径 114 | * @param savePath 115 | * dex文件路径 116 | * @return 117 | */ 118 | public File makeDex(String srcPath, String savePath) { 119 | if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(savePath)) { 120 | return null; 121 | } 122 | File srcFile = new File(srcPath); 123 | if (!srcFile.exists()) { 124 | return null; 125 | } 126 | byte[] buffer = processFile(srcPath); 127 | byte[] dexByte = classToDex(savePath, buffer); 128 | return makeDex(savePath, dexByte); 129 | 130 | } 131 | 132 | /** 133 | * 将文件转化为byt[]数组 134 | * @param path 135 | * @return 136 | */ 137 | private byte[] processFile(String path) { 138 | if (TextUtils.isEmpty(path)) { 139 | return null; 140 | } 141 | File srcFile = new File(path); 142 | if (!srcFile.exists()) { 143 | return null; 144 | } 145 | FileInputStream inputStream = null; 146 | ByteArrayOutputStream byteArrayOutputStream = null; 147 | try { 148 | inputStream = new FileInputStream(srcFile); 149 | byteArrayOutputStream = new ByteArrayOutputStream(1024); 150 | byte[] b = new byte[1024]; 151 | int n; 152 | while ((n = inputStream.read(b)) != -1) { 153 | byteArrayOutputStream.write(b, 0, n); 154 | } 155 | return byteArrayOutputStream.toByteArray(); 156 | } catch (FileNotFoundException e) { 157 | e.printStackTrace(); 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | } if (inputStream != null) { 161 | try { 162 | inputStream.close(); 163 | } catch (IOException e) { 164 | e.printStackTrace(); 165 | } 166 | } 167 | 168 | if (byteArrayOutputStream != null) { 169 | try { 170 | byteArrayOutputStream.flush(); 171 | byteArrayOutputStream.close(); 172 | } catch (IOException e) { 173 | e.printStackTrace(); 174 | } 175 | } 176 | return null; 177 | } 178 | 179 | /** 180 | * 将dex字节码 转换为Dex文件 181 | * @param savePath 保存dex文件的路径 182 | * @param content dex字节 183 | * @return 184 | */ 185 | public File makeDex(String savePath, byte[] content) { 186 | if (TextUtils.isEmpty(savePath) || content == null) { 187 | return null; 188 | } 189 | File file = new File(savePath); 190 | if (file.exists()) { 191 | file.delete(); 192 | } 193 | FileOutputStream fileOutputStream = null; 194 | 195 | try { 196 | fileOutputStream = new FileOutputStream(file); 197 | fileOutputStream.write(content); 198 | } catch (FileNotFoundException e) { 199 | e.printStackTrace(); 200 | } catch (IOException e) { 201 | e.printStackTrace(); 202 | } finally { 203 | if (fileOutputStream != null) { 204 | try { 205 | fileOutputStream.flush(); 206 | fileOutputStream.close(); 207 | } catch (IOException e) { 208 | e.printStackTrace(); 209 | } 210 | } 211 | } 212 | return file; 213 | } 214 | 215 | /** 216 | * 单个class文件转为dex 217 | * @param name class文件路径 218 | * @param content class读取的内容 219 | * @return 220 | */ 221 | public byte[] classToDex(String name, byte[] content) { 222 | if (TextUtils.isEmpty(name) || content == null) { 223 | return null; 224 | } 225 | if (processClass(name, content)) { 226 | return writeDex(); 227 | } 228 | return null; 229 | } 230 | 231 | 232 | /** 233 | * 将classes文件转换为dex文件。这里面的是一堆的class文件 234 | * @param names 235 | * @param byteArrays 236 | * @return 237 | */ 238 | public byte[] classesToDex(String[] names, byte[][] byteArrays) { 239 | for (int i = 0; i < names.length; i++) { 240 | String name = names[i]; 241 | byte[] byteArray = byteArrays[i]; 242 | processClass(name, byteArray); 243 | } 244 | 245 | byte[] outputArray = writeDex(); 246 | 247 | return outputArray; 248 | } 249 | 250 | /** 251 | * Processes one classfile. 252 | * 253 | * @param name {@code non-null;} name of the file, clipped such that it 254 | * should correspond to the name of the class it contains 255 | * @param bytes {@code non-null;} contents of the file 256 | * @return whether processing was successful 257 | */ 258 | private boolean processClass(String name, byte[] bytes) { 259 | try { 260 | ClassDefItem clazz = CfTranslator.translate(name, bytes, cfOptions, options); 261 | outputDex.add(clazz); 262 | return true; 263 | } catch (ParseException ex) { 264 | ex.printStackTrace(); 265 | } 266 | return false; 267 | } 268 | 269 | /** 270 | * Converts {@link #outputDex} into a {@code byte[]}, write 271 | * it out to the proper file (if any), and also do whatever human-oriented 272 | * dumping is required. 273 | * 274 | * @return {@code null-ok;} the converted {@code byte[]} or {@code null} 275 | * if there was a problem 276 | */ 277 | private byte[] writeDex() { 278 | byte[] outArray = null; 279 | 280 | OutputStreamWriter out = new OutputStreamWriter(new ByteArrayOutputStream()); 281 | try { 282 | outArray = outputDex.toDex(out, false); 283 | } catch (Exception ex) { 284 | ex.printStackTrace(); 285 | } finally { 286 | if (out != null) { 287 | try { 288 | out.close(); 289 | } catch (IOException e) { 290 | e.printStackTrace(); 291 | } 292 | } 293 | } 294 | 295 | return outArray; 296 | } 297 | 298 | 299 | /** 300 | * 生成一个class文件。并设置器父类。 301 | * @param className 生成的类名 302 | * @param superClassName 设置父类, 可以为空 303 | * @return 304 | */ 305 | public CtClass makeClass(String className, String superClassName) { 306 | CtClass ctClass = null; 307 | try { 308 | ctClass = classPool.makeClass(className); 309 | if (!TextUtils.isEmpty(superClassName)) { 310 | classPool.importPackage(superClassName); 311 | CtClass supClass = classPool.get(superClassName); 312 | ctClass.setSuperclass(supClass); 313 | } 314 | } catch (NotFoundException e) { 315 | e.printStackTrace(); 316 | } catch (CannotCompileException e) { 317 | e.printStackTrace(); 318 | } 319 | return ctClass; 320 | } 321 | 322 | /** 323 | * 为Class添加构造函数,并设置其访问类型 324 | * @param targetClass 目标class 325 | * @param content 构造函数的内容。 326 | * @param modifier 构造函数的类型 {@link Modifier} 327 | * @param parameters 构造函数的参数 328 | * @return 329 | */ 330 | public void addConstructor(CtClass targetClass, CtClass[] parameters, String content, int modifier) { 331 | if (targetClass == null) { 332 | throw new NullPointerException("CtClass must not be null!"); 333 | } 334 | CtConstructor constructor = new CtConstructor(parameters, targetClass); 335 | constructor.setModifiers(modifier); 336 | try { 337 | constructor.setBody(content); 338 | targetClass.addConstructor(constructor); 339 | } catch (CannotCompileException e) { 340 | e.printStackTrace(); 341 | } 342 | } 343 | 344 | 345 | /** 346 | * 为类添加方法。 347 | * @param targetClass 目标class 348 | * @param returnType 返回类型 349 | * @param parameters 参数 350 | * @param content 内容 351 | * @param declaring 352 | * @param modifier 访问类型 {@link Modifier} 353 | * @return 354 | */ 355 | public void addMethod(CtClass targetClass, CtClass returnType, CtClass[] parameters, 356 | String content, CtClass declaring, int modifier) { 357 | if (targetClass == null) { 358 | throw new NullPointerException("CtClass must not be null!"); 359 | } 360 | CtMethod method = new CtMethod(returnType, content, parameters, declaring); 361 | try { 362 | method.setBody(content); 363 | method.setModifiers(modifier); 364 | targetClass.addMethod(method); 365 | } catch (CannotCompileException e) { 366 | e.printStackTrace(); 367 | } 368 | } 369 | 370 | /** 371 | * 添加成员变量 372 | * @param targetClass 目标class 373 | * @param type 类型 374 | * @param name 名字 375 | * @param declaring 376 | */ 377 | public void addField(CtClass targetClass, CtClass type, String name, CtClass declaring) { 378 | if (targetClass == null) { 379 | throw new NullPointerException("CtClass must not be null!"); 380 | } 381 | try { 382 | CtField field = new CtField(type, name, declaring); 383 | targetClass.addField(field); 384 | } catch (CannotCompileException e) { 385 | e.printStackTrace(); 386 | } 387 | } 388 | 389 | } 390 | 391 | 392 | 393 | -------------------------------------------------------------------------------- /classlib/src/main/java/com/baidu/music/classlib/dex/PatchDexApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.baidu.music.classlib.dex; 18 | 19 | import android.app.Application; 20 | import android.content.Context; 21 | 22 | import com.baidu.music.classlib.jni.HookBridge; 23 | import com.baidu.music.classlib.manager.HookManager; 24 | 25 | 26 | /** 27 | * Minimal PatchDex capable application. To use the legacy multidex library there is 3 possibility: 28 | *