Reputation: 378
I am working on an Application, which can work with external apks. For this i used the DexClassLoader , to load classes, from external apks into an classes
-Array, and work with the classes like this:
getFragment(){
for (Class<?> cls : classes) {
Log.v("loadDexClasses", "Class loaded " + cls.getName());
if (cls.getName().contains("OpenQuestionFragment")) {
Method m = null;
Fragment xb = null;
try
{
Class[] cArg = new Class[3];
cArg[0] = Integer.class;
cArg[1] = String.class;
cArg[2] = String[].class;
m = cls.getMethod("getInstance",cArg);
xb = (Fragment) m.invoke(null,INTNULL,STRINGNULL,STRINGARRAYNULL);
showFragment(xb);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if(xb==null){
return;
}
if (xb.equals(ClassLoader.getSystemClassLoader()))
Log.v("loadDexClasses", "Same ClassLoader");
else
Log.v("loadDexClasses", "Different ClassLoader");
}
}
}
}
external apk:
public class OpenQuestionFragment extends Fragment{
//flags
final static int INTNULL = -1;
final static String STRINGNULL = null;
final static String[] STRINGARRAYNULL = null;
static View view;
static String setter;
static boolean run = true;
private static int edittextid;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
RelativeLayout rl = new RelativeLayout(getActivity());
EditText et = new EditText(getActivity());
edittextid = view.generateViewId();
et.setId(edittextid);
rl.addView(et);
et.setTextSize(70);
//blub
et.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)et.getLayoutParams();
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE);
et.setLayoutParams(layoutParams);
et.setHint("hier eingeben");
view = rl; //inflater.inflate(R.layout.testlayout, container, false);
if(setter!=STRINGNULL && setter != ""){
((EditText) view.findViewById(edittextid)).setText(setter);
}
//initializeListenerThread();
return view;
}
public static OpenQuestionFragment newInstance(String seter){
/*setter=seter;
run = true;*/
return new OpenQuestionFragment();
}
public static Fragment getInstance(int intloader, String stringloader, String[] arrayloader){
setter = stringloader;
return newInstance(null);
}
public String getResult(){
EditText ET = (EditText) view.findViewById(edittextid);
return ET.getText().toString();
}
public String getQuestionTag(){
return "OpenQuestion";
}
public boolean isAnswered(){
EditText ET = (EditText) view.findViewById(edittextid);
if(ET.getText().toString()!=""){
return false;
}else{
return true;
}
}
@Override
public void onDestroy(){
run = false;
super.onDestroy();
}
}
and the proguard, to prevent unused methods to not be assembled:
-keepclassmembers class dexloader.openquestion.OpenQuestionFragment {
public *;
}
i already know, that there isnt a problem with the loaded class, as the "newInstance" function can be called the EXACT same way, except tweaking the cArg-Array slightly, to match the sought after method, like follows:
Class[] cArg = new Class[3];
cArg[0] = Integer.class;
cArg[1] = String.class;
cArg[2] = String[].class;
m = cls.getMethod("getInstance",cArg);
xb = (Fragment) m.invoke(null,INTNULL,STRINGNULL,STRINGARRAYNULL);
into
Class[] cArg = new Class[1];
cArg[0] = String.class;
m = cls.getMethod("newInstance",cArg);
xb = (Fragment) m.invoke(null,STRINGNULL);
When i start the Application, it still throws a NoSuchMethodException
, when i call m.invoke();
, which gets caught, and well... that isnt supposed to happen. The only difference, i can see is, that getInstance()
isnt used, but the proguard-rule
should have prevented that.
Help is appreciated
Cheers, Jacobus
Upvotes: 0
Views: 62
Reputation: 378
I solved it myself, after trying literally everything. It turns out, that Integer.class != int
it should have been
Class[] cArg = new Class[3];
cArg[0] = int.class;
cArg[1] = String.class;
cArg[2] = String[].class;
Upvotes: 1