虽然这个问题很老,但我会回答,因为我为自己的同一个问题找到了一个明确的答案。首先,我想强调您问题中的一个明确要求是从设备上尚未安装的 .apk 加载一个类。因此,使用 getPackageManager() 调用包管理器并为其提供包路径显然会导致 NameNotFoundException,因为设备上未安装包含该包的 .apk。
因此,从设备上未安装的 .apk 文件加载类的方法(即,您只有 .apk 存储在 SDCARD 上的目录中)是使用DexClassLoader如下:
1- 确保您的 SDCARD 目录中有 .apk 文件。我的 Offloadme.apk 在我的 SDCARD 的下载文件夹中。
2- 在您的 AndroidManifest.xml 中添加读取权限,以允许您的应用从清单中读取。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3- 使用以下定义来定义 .apk 的路径、apk 中的类名以及您要调用的该类中的方法名:
final String apkFile =Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Offloadme.apk";
String className = "com.khaledalanezi.offloadme.SimpleCalculator";
String methodToInvoke = "add";
4- 使用DexClassLoader加载.apk并使用反射调用SimpleCalculator类中的add方法,如下:
final File optimizedDexOutputPath = getDir("outdex", 0);
DexClassLoader dLoader = new DexClassLoader(apkFile,optimizedDexOutputPath.getAbsolutePath(),
null,ClassLoader.getSystemClassLoader().getParent());
try {
Class<?> loadedClass = dLoader.loadClass(className);
Object obj = (Object)loadedClass.newInstance();
int x =5;
int y=6;
Method m = loadedClass.getMethod(methodToInvoke, int.class, int.class);
int z = (Integer) m.invoke(obj, y, x);
System.out.println("The sum of "+x+" and "+"y="+z);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
请注意,在我的简单示例中,我使用从 Offloadme.apk 加载的 SimpleCalculator 类中提供的 add 方法添加了两个数字文件存储在我的 SDCARD 中,我能够打印出正确的答案,即 11。