I'm trying to build an plugin-system which is importing Fragments from other apks as described here.
Eclipse keeps telling me:
12-01 15:17:18.609: W/dalvikvm(23425): Class resolved by unexpected DEX: Lde/anthropotec/activityapp/firstplugin/UI;(0x42901520):0x57d93000 ref [Lde/anthropotec/activityapp/api/PluginAPI;] Lde/anthropotec/activityapp/api/PluginAPI;(0x428eb2b8):0x527e1000
(Lde/anthropotec/activityapp/firstplugin/UI; had used a different Lde/anthropotec/activityapp/api/PluginAPI; during pre-verification)
Which isn't a suprise, as I'm importing my PluginAPI-libary in both, the Host and the Plugin. As far as I understand, Eclipse seems to be afraid, that these libaries aren't identical. Is there a way to tell Eclipse to not import the libary, if it's already there in the other apk? Or is there any other way to go around this. Please tell me if you need more information. Here's my source:
The Host:
package de.anthropotec.activityapp.host;
import java.io.File;
import dalvik.system.DexClassLoader;
import de.anthropotec.activityapp.api.PluginAPI;
import de.anthropotec.activtiyapp.host.R;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
public class MainActivtiy extends Activity{
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
Class<?> requiredClass = null;
final ApplicationInfo info = getPackageManager().getApplicationInfo("de.anthropotec.activityapp.firstplugin",0);
final String apkPath = info.sourceDir;
final File dexTemp = getDir("temp_folder", 0);
final String fullName = "de.anthropotec.activityapp.firstplugin.UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final PluginAPI holder = PluginAPI.class.cast(requiredClass.newInstance());
if (null != holder) {
final Fragment fragment = holder.getFragment();
if (null != fragment) {
final FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.add(R.id.pluginPlace, fragment, "MyFragment").commit();
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
The PluginApi:
package de.anthropotec.activityapp.api;
import android.app.Fragment;
public interface PluginAPI {
public Fragment getFragment();
}
And the Plugin-Fragment itself:
package de.anthropotec.activityapp.firstplugin;
import de.anthropotec.activityapp.api.PluginAPI;
import android.app.Fragment;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.view.View;
import android.view.LayoutInflater;
import android.view.ViewGroup;
public class UI extends Fragment implements PluginAPI{
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
// Note that loading of resources is not the same as usual, because it loaded actually from another apk
final XmlResourceParser parser = container.getContext().getPackageManager().getXml("de.anthropotec.testplugin", R.layout.ui, null);
return inflater.inflate(parser, container, false);
}
@Override
public Fragment getFragment() {
return this;
}
}
Each of the above as it's own Project (PluginAPI as libary). The question isn't quite new (e.g. here), but the already given answers advice to remove on of the imports, what doesn't seem to be a option in my case, as I need the API on both sides (Plugin and Host).