最近做的android项目出现被破解问题,我从网上搜索到可以用动态加载jar的办法,将需要隐藏的代码打成资源jar,让后在使用时动态加载jar。但是在实际操作时出现问题,因为打成jar的代码需要调用工程中其他的class或是jar,这样动态加载时会报noClassFound异常。纠结了很久发现是classloader的问题,因为动态加载jar所需的DexClassLoader与项目Application的classLoader不是同一个(可参考http://www.cnblogs.com/xitang/p/3534777.html),如果可以用DexClassLoader替换掉Application的classLoader就可以了。
jar的加载:(jar放在assert中)
<pre name="code" class="java">DexClassLoader dexClassLoader= null;
ClassLoader localClassLoader = this.getClassLoader();
try {
InputStream in = getResources().getAssets().open("encode.data");
File dexInternalStoragePath = new File(getDir("pay", Context.MODE_PRIVATE), "dex.jar");
if (!dexInternalStoragePath.exists()) {
try {
dexInternalStoragePath.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
FileOutputStream out = new FileOutputStream(dexInternalStoragePath);
//CopyFile.copyFile(inputStream, fileOutputStream);
byte[] buffer = new byte[1024];
int length;
in.read();
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
in.read();
}
out.flush();
in.close();
out.close();
//String outpath = getApplicationInfo().dataDir;
final File optimizedDexOutputPath = getDir("temp",Context.MODE_PRIVATE);
String nativeDir = this.getApplicationInfo().nativeLibraryDir;
dexClassLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(), null , localClassLoader);
replaceClassLoader(dexClassLoader);
} catch (Exception e) {
e.printStackTrace();
}
替换classLoder
private void replaceClassLoader(ClassLoader classLoader)
{
try {
Field mMainThread = this.getBaseContext().getClass().getDeclaredField("mMainThread");
mMainThread.setAccessible(true);
Object mainThread = mMainThread.get(this.getBaseContext());
Class threadClass = mainThread.getClass();
Field mPackages = threadClass.getDeclaredField("mPackages");
mPackages.setAccessible(true);
WeakReference<?> ref;
Map< String , ?> map =(Map< String , ? >) mPackages.get(mainThread ) ;
ref = (WeakReference<? >) map.get(this.getPackageName());
Object apk = ref.get();
Class apkClass = apk.getClass();
Field mClassLoader = apkClass.getDeclaredField("mClassLoader");
mClassLoader.setAccessible(true);
mClassLoader.set(apk, classLoader);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
但是这个还是有问题,就是如果jar中有调用本地代码,还是会报错,即使我修改了 DexClassLoader第三个参数,依然不行,这个问题我还没有想到好的办法,若哪位知道求告知