我想知道Parallel Space应用程序如何复制和执行其他应用程序而无需复制其APK或在Playstore上的其他应用程序下运行它们(例如:"com.whatever.name-of-duplicated-app").
在研究了他们的AndroidManifest.xml,在/ data/data /上创建的文件夹以及设备上的日志之后,我得到的唯一结论是,Parallel Space能够以某种方式执行来自其他APK的代码,但它会映射数据目录这些应用程序进入自己的数据目录.
证据:
最初,我认为它与DexClassLoader/PathClassLoader API有关,但我无法继续进行调查.我也看到了一些这样的问题,一个,但它似乎并不如此.
似乎Android应用程序类加载器允许反射性地获取对public static包私有类的字段的引用,甚至来自不同的包(比上面定义的类中的那个),而Sun JDK类加载器例如没有.
更具体地说,给定以下类定义:
package org.example.a
class PackagePrivateClass {
public static final Parcelable.Creator<PackagePrivateClass> CREATOR = generateCreator();
}
Run Code Online (Sandbox Code Playgroud)
以下代码在一个单独的包中:
package org.example.b
public class TestClass {
public void testMethod() {
final Class classRef = Class.forName("org.example.a.PackagePrivateClass");
final Field creatorFieldRef = classRef.getField("CREATOR");
creatorFieldRef.get(null); // throws here (unless on Android)
}
}
Run Code Online (Sandbox Code Playgroud)
在Sun JVM上执行时,它会抛出IllegalAccessException最后一行:
java.lang.IllegalAccessException: Class org.example.b.TestClass can not access a member of class org.example.a.PackagePrivateClass with modifiers "public static final"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
...
Run Code Online (Sandbox Code Playgroud)
但是,当在Android设备(5.1 Lollipop FWIW)上运行时,它会在不抛出的情况下执行,并creatorFieldRef.get(null)实际返回对该CREATOR字段的有效引用.
我的问题是:为什么会这样?它是Android类加载器的错误还是功能?(或者,如果适用的话,我的例子中出了什么问题?)
升级到64位armeabi库,打包打包发布到googleplay后,在googleplay崩溃报告页面遇到如下问题:
java.lang.RuntimeException:
at android.app.ActivityThread.handleReceiver (ActivityThread.java:3982)
at android.app.ActivityThread.access$2300 (ActivityThread.java:273)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2050)
at android.os.Handler.dispatchMessage (Handler.java:112)
at android.os.Looper.loop (Looper.java:216)
at android.app.ActivityThread.main (ActivityThread.java:7625)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:987)
Caused by: java.lang.ClassNotFoundException:
at dalvik.system.BaseDexClassLoader.findClass (BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass (ClassLoader.java:379)
at java.lang.ClassLoader.loadClass (ClassLoader.java:312)
at android.app.AppComponentFactory.instantiateReceiver (AppComponentFactory.java:84)
at android.support.v4.app.CoreComponentFactory.instantiateReceiver (CoreComponentFactory.java:56)
at android.app.ActivityThread.handleReceiver (ActivityThread.java:3975)
at android.app.ActivityThread.access$2300 (ActivityThread.java:273)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2050)
at android.os.Handler.dispatchMessage (Handler.java:112)
at android.os.Looper.loop (Looper.java:216)
at android.app.ActivityThread.main (ActivityThread.java:7625)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:524)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:987)
Run Code Online (Sandbox Code Playgroud)
它仅出现在 Android 9 设备上
我在我最小的发布版本应用程序中关闭了 R8。但它看起来和以前一样。问题仍然发生 …
对于一个长期的学生项目,我正在尝试使用插件开发模块化应用程序.具体来说,我们会:
我们可以搜索,更新,删除和运行插件的主应用程序.此主应用程序还将存储插件中的一些数据.
从带有代码和GUI组件的HTTP服务器下载的几个插件.
现在,我有一个主应用程序,它能够从HTTP下载.apk文件,并从此.apk文件中定义的类创建一个新实例.我使用这里描述的方式:http://android-developers.blogspot.fr/2011/07/custom-class-loading-in-dalvik.html使用DexClassLoader()方法.
但是我无法看到如何在插件.apk文件中显示存储为资源的布局(或任何其他GUI组件).例如,我试图通过使用插件类名从主应用程序创建一个Intent,但没有成功:
DexClassLoader cl = new DexClassLoader(...);
Class<?> libClass = cl.loadClass("plugin_classname");
Intent intent = new Intent(this.getApplicationContext(), libClass);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为Intent未在主应用程序的AndroidManifest.xml中声明.这也在这个其他线程中描述:Android-使用DexClassLoader加载apk文件
这是否意味着绝对没有办法建立这样的"动态"用户界面?更一般地说,这种类型的插件系统可以在Android上完成吗?我应该尝试其他方法吗?
我们有一个大型的应用程序,总是遇到恐惧方法计数限制.我被要求想方设法让它做得更多,包括支持插件.寻找方法来卸载代码,我跑过JNI提示其说
只有在与ClassLoader关联的所有类都可以进行垃圾回收时,才会卸载类,这种情况很少见,但在Android中并非不可能.
这似乎意味着如果你说,你可以卸载一个插件
DexClassLoader为每个.jar文件使用new ,所以,我创建了一个测试用例:
ReferenceQueue<ClassLoader>使用该队列创建了一个并创建了对我的两个加载器的弱引用; 我创建/启动了一个无限循环,执行队列.remove()和报告的线程.ReferenceQueue<Class<?>>并getClass()使用队列创建了对每个插件的弱引用; 我创建/启动了另一个监视类引用队列的线程.我的监控线程似乎工作 - loader2当我loader1以前错误地加载两个插件时,我看到得到gc-ed ;-) - 但是否则我的线程保持沉默,即使在4.3.我可能在这个测试用例中遗漏了一些明显的东西,或者仍然是这样的情况
Dalvik VM目前没有卸载类
正如Google员工fadden在Android中所说的那样:什么时候系统会卸载类?
我已成功通过以下方式从dex文件动态加载类
enter code here
File file = getDir("dex", 0);
DexClassLoader dexClassLoader = new DexClassLoader("/data/data/com.example.callerapp/files/test.dex", file.getAbsolutePath(), null, getClassLoader());
try {
Class<Object> _class = (Class<Object>)
dexClassLoader.loadClass("com.example.calledapp.test");
Object object = _class.newInstance();
Method method = _class.getMethod("function");
method.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
但是我想做的是从aar文件动态加载类,如android dev页面所示(DexClassLoader:一个类加载器,它从包含classes.dex条目的.jar和.apk文件中加载类。可以使用执行未作为应用程序一部分安装的代码。)
我在Android Studio中创建了一个库模块(“ testlibrary”),在该库模块中创建了Test.java(我想在调用方应用中动态加载的内容),并通过Gradle Project-> Excute Gradle Task创建了一个aar文件
如何通过dexclassloader在以这种一般方式创建的aar文件中动态加载类?我已通过提供商将aar文件从CalledApp移到CallerApp
还是创建aar文件的过程错误?在运行期间,出现错误消息
02-10 09:43:48.744 16487-16487/com.example.callerapp W/System.err: java.lang.ClassNotFoundException: Didn't find class "com.example.calledlibrary.Test" on path: DexPathList[[zip file "/data/data/com.example.callerapp/files/testlibrary.aar"],nativeLibraryDirectories=[/system/lib64, /vendor/lib64]]
02-10 09:43:48.744 16487-16487/com.example.callerapp W/System.err: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
02-10 09:43:48.744 16487-16487/com.example.callerapp W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
02-10 09:43:48.744 …Run Code Online (Sandbox Code Playgroud) 我正在使用 DexClassLoader 进行一些测试,看看是否可以使用新功能“更新”我的应用程序。目前我已经有了这个测试方法,它与 testClass 一起使用并运行 test() 方法。我想知道的是,我如何“替换”或“更新”和已经存在的类..?欢迎任何想法或其他建议。
方法:
public static void loadExtLib(String pathDexFile, Context ctx) {
String temp = ctx.getDir("temp", 0).toString();
DexClassLoader classLoader = new DexClassLoader(pathDexFile,
temp, null, ctx.getClass().getClassLoader());
String testClass = "com.mystudio.myapp.TestClass";
Class<?> libProviderClass = null;
try {
libProviderClass = classLoader.loadClass(testClass);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
try {
Method m = libProviderClass.getDeclaredMethod("test", null);
try {
m.invoke(libProviderClass, null);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} …Run Code Online (Sandbox Code Playgroud) 我想使用ApplicationWrapepr方法在我的应用程序中使用multidex,如此处所述https://plus.google.com/104023661970539138053/posts/YTMf8ADTcFg
我使用了--minimal-main-dex选项以及这样的keep文件:
android/support/multidex/ZipUtil.class
android/support/multidex/ZipUtil$CentralDirectory.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDexExtractor.class
com/<mypackage>/common/MyApplication.class
com/<mypackage>/common/MyApplicationWrapper.class
com/<mypackage>/common/ui/DashboardActivity.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDex.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/MultiDex$V4.class
Run Code Online (Sandbox Code Playgroud)
这导致我的主dex文件中列出的类是可以的.我使用一个使用以下代码的库来列出dexfile中的所有类,但只获取主"clesses.dex"的条目,而不是所有其他加载的dex文件的条目,因为新的DexFile只检查"classes.dex" :
private static List<String> getPaths(final String[] sourcePaths) {
List<String> result = new ArrayList<String>();
for (String s : sourcePaths) {
try {
DexFile dexfile = new DexFile(s);
Enumeration<String> entries = dexfile.entries();
while (entries.hasMoreElements()) {
result.add(entries.nextElement());
}
} catch (IOException ioe) {
Log.w(TAG, "cannot open file=" + s + ";Exception=" + ioe.getMessage());
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
现在的单一路径通过以下方式确定:
application.getApplicationContext().getApplicationInfo().sourceDir;
Run Code Online (Sandbox Code Playgroud)
结果像/data/../myapplicationname.apk
还有另一种可能性来列出dex文件中的所有类吗?或者目前在ClassLoaders中的所有课程?该库对项目至关重要,并使用此方法稍后通过反射查找组件实现.
EDIT1: 如果发现classes2.dex文件位于:/data/data/com./code_cache/secondary-dexes/com.-1.apk.classes2.dex
但是当使用带有此路径的新DexFile()时,将抛出IOEsxception,并显示消息"无法打开dexfile".