Ok so I have an Android app and I started creating an addon system for the app so developers can code content providers that the app can then use to generate different content, I will not go through the whole procedure but everything works fine like so:
1)
I created a library called com.myaddonlib
that I imported in my project in this library there is an interface and different objects.
2)
Now a developer can create a simple Java project on his end, import the library com.myaddonlib
, and implement the interface on his main class which have methods that return different objects from the library.
3) Back on the android app, I can load the .jar file created by the developer (after the classes.dex is added to the jar file) and with the android DexClassLoader I can load the implemented interface like so :
DexClassLoader classloader = new DexClassLoader(jarFilePath, tempDirectory, null, context.getClass().getClassLoader());
Class classToLoad = classloader.loadClass("com.apackage.Addon");
where Addon
is the class created by the addon developer that implements the interface from the library residing in a package named com.apackage
.
I can then cast the interface from the library com.myaddonlib
to a new instance of classToLoad
and call the functions that the addon developer implemented.
Now here is the issue lets say I decided to update the addon library and remove one of the variables from a class, meaning that the addon's class is now different from the class in the updated library (used in the app). Even when the changed variable is not used something causes the app to crash without any error. Just the fact that both classes are different (even when the only difference is just a missing variable ) causes something to malfunction. Now this is not an easy procedure to explain so I would understand that given my bad english some have trouble following. My issue is that I need to know how to avoid this crash due to the change of the library on one of both ends. And also how java treats object changes in a situation like this
It's very bad because it ties your UI to your method names, which should be completely unrelated. Making an seemingly innocent change later on can have unexpected disastrous consequences. Using reflection is not a bad practice. Doing this sort of thing is a bad practice.
Java 11 does not have API to dynamically augment the classpath at runtime but it can be done through reflection, with the obvious caveats about using internal API.
Reflection is a feature in the Java programming language. It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.
My solution does not solve the problem, but instead makes sure it will never happen. The problem you are describing resembles the classic server-client problem. You have a server (in your case the app you are developing) and clients (the addons that are written by the developers). You can define an interface with many functions and pass data in binary structures. This would be more efficient from a traffic/parsing perspective, however whenever you change the API on the server you will have to update all the clients (or else crashes or other issues might occur).
So to solve this problem on the server-client many choose to use HTTP calls with JSON objects that describe the data. Although this way is less efficient, it allows adding APIs and supporting many client versions at the same time.
Using this approach in Android is quite simple. Define an API with two functions and a single interface:
public String sendDataToLibrary(String jsonString) {
// Parse data, perform operation and return a JSON string as the result
}
public interface GetDataFromLibrary {
String onDataFromLibrary(String jsonString);
}
public void init startLibrary(GetDataFromLibrary callback) {
// Set callback in library and call it whenever you have data that needs to be sent out from the library asynchronously
}
As you can see, if you implement this interface, you can pass any data around between the library and addons and it will never change so no crashes would occur. An improvement can be to force passing version number to allow the library to support multi-versioning).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With