如何在Android应用程序中实现Java编译器和DEX转换器?

在尝试查找Android Jasper报告的答案时,我发现还有另外两个问题需要解答,我被要求提出问题,而不是作为答案;):

我现在的问题是:“是否有任何编译器可以直接在设备上使用”和“如何在不设备设备的情况下执行此操作。如果有人可以给我一个提示,我会非常感激…


我在这种方法上看了一点时间,找到了可以直接在没有root的Android设备上创建APK的应用程序:

  • TerminalIDE – https://play.google.com/store/apps/details?id=com.spartacusrex.spartacuside&hl=de
  • JavaIDEdroid – http://code.google.com/p/java-ide-droid/
  • AIDE – https://play.google.com/store/apps/details?id=com.aide.ui&hl=en

看起来他们正在使用eclipse中的编译器和一个移植的dex转换器。 现在我想弄清楚如何做同样的事情。

当然:获取源代码并查看它。 但是,虽然我有一些奇怪的问题需要连接到服务器并试图解决它,但我请求在这里提出这个问题。 希望既能帮助别人,又能为自己找到答案;)


我从我的indigo的插件目录中获取了org.eclipse.jdt.core_3.7.3.v20120119-1537.jar并尝试了以下代码:

org.eclipse.jdt.internal.compiler.batch.Main ecjMain = new org.eclipse.jdt.internal.compiler.batch.Main(new PrintWriter(System.out), new PrintWriter(System.err), false/*noSystemExit*/, null, progress); System.err.println("compiling..."); ecjMain.compile(new String[] {"-classpath", "/system/framework", storage.getAbsolutePath()+"/Test.java"}); ecjMain.compile(new String[] {storage.getAbsolutePath()+"/Test.java"}); System.err.println("compile succeeded!!!"); 

有时会抛出exception,因为无法找到java.lang.Object,并且在使用100%的处理器加热处理器时它无法做任何事情……

在这个时候,我无法弄清楚发生了什么以及为什么。 因为我有其他工作要做这个部分必须等待一点。

我从JavaIDEdroid的源代码中获取灵感后意识到我是愚蠢的(有一段时间我试图在设备上使用带有dexified框架类的编译器 – 这本身就无法工作)。
在我成功使用sdcard上的ADTs android-jar副本编译我的Test.java后,我只需要使用DexClassLoader加载类。
在通知myselft有关如何做到这一点的同时,我在Dalvik中找到了这篇精彩的文章Custom Class Loading,这启发了我至少写了这段代码:

  File storage = getDir("all41", Context.MODE_PRIVATE); System.err.println("copying the android.jar from asssets to the internal storage to make it available to the compiler"); BufferedInputStream bis = null; OutputStream dexWriter = null; int BUF_SIZE = 8 * 1024; try { bis = new BufferedInputStream(getAssets().open("android.jar")); dexWriter = new BufferedOutputStream( new FileOutputStream(storage.getAbsolutePath() + "/android.jar")); byte[] buf = new byte[BUF_SIZE]; int len; while((len = bis.read(buf, 0, BUF_SIZE)) > 0) { dexWriter.write(buf, 0, len); } dexWriter.close(); bis.close(); } catch (Exception e) { System.err.println("Error while copying from assets: " + e.getMessage()); e.printStackTrace(); } System.err.println("instantiating the compiler and compiling the java file"); org.eclipse.jdt.internal.compiler.batch.Main ecjMain = new org.eclipse.jdt.internal.compiler.batch.Main(new PrintWriter(System.out), new PrintWriter(System.err), false/*noSystemExit*/, null); ecjMain.compile(new String[] {"-classpath", storage.getAbsolutePath()+"/android.jar", Environment.getExternalStorageDirectory().getAbsolutePath() + "/Test.java"}); System.err.println("calling DEX and dexifying the test class"); com.android.dx.command.Main.main(new String[] {"--dex", "--output=" + storage.getAbsolutePath() + "/Test.zip", Environment.getExternalStorageDirectory().getAbsolutePath() + "/./Test.class"}); System.err.println("instantiating DexClassLoader, loading class and invoking toString()"); DexClassLoader cl = new DexClassLoader(storage.getAbsolutePath() + "/Test.zip", storage.getAbsolutePath(), null, getClassLoader()); try { Class libProviderClazz = cl.loadClass("Test"); Object instance = libProviderClazz.newInstance(); System.err.println(instance.toString()); } catch (Exception e) { System.err.println("Error while instanciating object: " + e.getMessage()); e.printStackTrace(); } 

Test.java只包含一个方法:

 public String toString() { return "Hallo Welt!"; } 

要使它运行,你需要jars jdt-compiler-xxxjar(在eclipse的plugins目录中找到)和dx.jar(在Android SDK的目录platform-tools / lib中找到)


不是很难;)
现在,我将找出在JasperReports源代码中要改变的内容,以使其在我们心爱的Android设备上运行:D