我正在开发一个可以与外部 apk 一起使用的应用程序。为此,我使用 DexClassLoader 将类从外部 apk 加载到classes
-Array 中,并使用如下类:
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");
}
}
}
}
外部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();
}
}
和proguard,以防止未组装未使用的方法:
-keepclassmembers class dexloader.openquestion.OpenQuestionFragment {
public *;
}
我已经知道,加载的类没有问题,因为“newInstance”函数可以以完全相同的方式调用,除了稍微调整 cArg-Array 以匹配寻求的方法,如下所示:
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);
进入
Class[] cArg = new Class[1];
cArg[0] = String.class;
m = cls.getMethod("newInstance",cArg);
xb = (Fragment) m.invoke(null,STRINGNULL);
当我启动应用程序时,它仍然会抛出一个NoSuchMethodException
,当我调用它时m.invoke();
,它会被捕获,并且......这不应该发生。我能看到的唯一区别是,它没有getInstance()
被使用,但proguard-rule
应该阻止它。
帮助表示赞赏
干杯,雅各布斯