package com.byc.main;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
/**
*反射调用APK中类的方法
* 1.需要声明权限:
* <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
* 2.targetSdkVersion >21时需要动态申请存储权限;
* author:byc6352 create time:2019-07-19
*/
public class Apk {
private static Apk apk;
Context mContext;//主app环境;
private DexClassLoader dexClassLoader;//apk装载器;
private Class<?> clazz;//反射类;
private Method method;//反射方法;
/**
*
* @param context:主app上下文环境;
*/
private Apk(Context context){
this.mContext=context;
}
public static Apk getApk(Context context){
if (apk==null){
apk=new Apk(context);
}
return apk;
}
/**
* 装载apk文件
* 注意:必须把apk复制到app应用内存储路径才能调用里面的方法!这里是复制到CacheDir
* @param apkPath:apk的外部存储路径;
* @return:装载成功与否;
*/
public boolean loadApk(String apkPath){
String newFilePath= mContext.getCacheDir() + File.separator + "app.apk";
if (!copyFile(apkPath,newFilePath))return false;//app只能调用本app路径内的文件;
String dexOutput = mContext.getCacheDir() + File.separator + "DEX";// 优化后的dex存放路径
File file = new File(dexOutput);
if (!file.exists()) file.mkdirs();
dexClassLoader = new DexClassLoader(newFilePath, dexOutput, null, mContext.getClassLoader());
return true;
}
/**
*
* @param classFullName:类的全路径(必须包括包名)如:如:private static final String APK_HELLO_CLASS_PATH="com.byc.apkresource.HelloWorld";
* @return 装载成功与否;
*/
public boolean loadClass(String classFullName){
if (dexClassLoader==null)return false;
try {
clazz = dexClassLoader.loadClass(classFullName);// 从优化后的dex文件中加载APK_HELLO_CLASS_PATH类
return true;
} catch (ClassNotFoundException e) {
e.printstacktrace();
return false;
}
}
/**
*
* @param methodName 方法名称;
* @param parameterTypes 方法的参数类型;如:String.class,int.class
* @return 返回装载成功否;
*/
public boolean loadMethod(String methodName,Class... parameterTypes){
if (clazz==null)return false;
try {
//Object object = clazz.newInstance(); // 创建类实例
method = clazz.getmethod(methodName,parameterTypes); //
return true;
} catch (NoSuchMethodException e) {
e.printstacktrace();
return false;
} catch (SecurityException e) {
e.printstacktrace();
return false;
}
}
/**
* 反射调用方法
* @param isstatic 是否是静态方法;
* @param var2 方法参数;
* @return Object
*/
public Object invoke(boolean isstatic,Object... var2){
if (method==null)return null;
Object object=null;
if (!isstatic){
try{
object = clazz.newInstance(); // 创建类实例
}catch (illegalaccessexception e) {
e.printstacktrace();
return null;
}catch (InstantiationException e) {
e.printstacktrace();
return null;
}
}
try{
return method.invoke(object, var2); // 调用
}catch (illegalaccessexception e) {
e.printstacktrace();
return null;
}catch (IllegalArgumentException e) {
e.printstacktrace();
return null;
}catch (InvocationTargetException e) {
e.printstacktrace();
return null;
}
}
/**
* 复制单个文件
*
* @param oldpath$Name String 原文件路径+文件名 如:data/user/0/com.test/files/abc.txt
* @param newPath$Name String 复制后路径+文件名 如:data/user/0/com.test/cache/abc.txt
* @return <code>true</code> if and only if the file was copied;
* <code>false</code> otherwise
*/
public boolean copyFile(String oldpath$Name, String newPath$Name) {
try {
File oldFile = new File(oldpath$Name);
if (!oldFile.exists()) {
Log.e("--Method--", "copyFile: oldFile not exist.");
return false;
} else if (!oldFile.isFile()) {
Log.e("--Method--", "copyFile: oldFile not file.");
return false;
} else if (!oldFile.canRead()) {
Log.e("--Method--", "copyFile: oldFile cannot read.");
return false;
}
File newFile = new File(newPath$Name);
if (newFile.exists()) newFile.delete();
/* 如果不需要打log,可以使用下面的语句
if (!oldFile.exists() || !oldFile.isFile() || !oldFile.canRead()) {
return false;
}
*/
FileInputStream fileInputStream = new FileInputStream(oldpath$Name);
FileOutputStream fileOutputStream = new FileOutputStream(newPath$Name);
byte[] buffer = new byte[1024];
int byteRead;
while (-1 != (byteRead = fileInputStream.read(buffer))) {
fileOutputStream.write(buffer, 0, byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
return true;
} catch (Exception e) {
e.printstacktrace();
return false;
}
}
}
/**
使用方法:
String apkPath= Environment.getExternalStorageDirectory() + File.separator + "app.apk";
String className="com.byc.apkresource.HelloWorld";
String methodName="factorial";
Apk apk=Apk.getApk(MainActivity.this);
if(apk.loadApk(apkPath))
if(apk.loadClass(className))
if (apk.loadMethod(methodName,int.class)) {
int i= (int) apk.invoke(false,6);
tvShow.setText(String.valueOf(i)); // 将结果设置到text上
}
*/