I am working on an Android application (under Android studio) that allows an user to run at run time a "Java android" code.
My first research help me to create a library from a "MyClass.java", understandable by the Android application.
- Use the command "Javac" to create the "MyClass.class" from "MyClass.java"
C:\Program Files\Android\Android Studio\jre\bin\javac -source 1.8 -target 1.8 -d "./" -classpath "C:\Users\user_account\AppData\Local\Android\Sdk\platforms\android-27\android.jar" -bootclasspath "C:\Program Files\Android\Android Studio\jre\jre\lib\rt.jar" "MyClass.java"
- Transform this "MyClass.class" into a Jar library with "Jar" command
C:\Program Files\Android\Android Studio\jre\bin\jar cvf "MyClass.jar" com/YourPackage/MyClass.class
- And finally translate it for Dalvik system with "dx" tool
call C:\Users\user_account\AppData\Local\Android\Sdk\build-tools\27.0.3\dx --dex --output "MyClass.dex" "MyClass.jar"
On the Android application I can call a method inside the library by :
final String libPath = Environment.getExternalStorageDirectory() + "/DexFile/MyClass.dex";
final File tmpDir = getDir("DexFile", 0);
DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
classToLoad = (Class<?>) classloader.loadClass("com.YourPackage.MyClass");
Object myInstance = classToLoad.newInstance();
Method mainMethod= classToLoad.getMethod("main");
mainMethod.invoke(myInstance);
A tricky things, this code doesn't work if you don't add some permission in your main :
/**
* Checks if the app has permission to write to device storage
* <p>
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
And in your manifest :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
At this point I am able to call a method inside my custom library. But now I need to call a method of my main activity from the library. A simplify view of my problem is :
First problem, what I need is an aberration from a library point a view, I want to attach and make a dependency between my library and my application. Because of that I didn't found anything that can help me. The only idea I have come with, is to pass an object argument to my "main()" and invoke a method inside this object, but that doesn't work :
package com.YourPackage;
public class MyClass{
public void main(Object object){
try{
Class cls = obj.getClass();
Method mainMethod = cls.getMethod("methodToCall",null);
mainMethod.invoke(obj,null);
}catch(Exception e){}
}
}
If you have any idea to do this properly, I will be pleased to ear it.
Hope this post will at least help people working on "Dex" library... Sincerely, a little programmer
Thanks to this link How do I invoke a Java method when given the method name as a string? My solution works even it's not really clean. The reason my code doesn't work is because I stored the class object, if you do it directly the error disappear. If any explanation exist come and comment !
package com.YourPackage;
public class MyClass{
public void main(Object obj){
try{
Method mainMethod = obj.getClass().getMethod("methodToCall");
mainMethod.invoke(obj); // Works, invoke the right method
}catch(Exception e){}
}
}