There are two tricks to create dynamic load library in Android
package com.example.testlib;
public interface ITestCore {
String testString(String arg);
}
- Use of sharedUserId in AndroidManifest for your applications and library project
- Use of dalvik.system.DexClassLoader to load library
Library Code:
It contains just java code without any Android specific entry points. AndroidManifest.xml just contains this android:sharedUserId attributeAndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testlib"
android:sharedUserId="com.example.testlib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minsdkversion="15" android:targetsdkversion="15" />
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme">
</application>
</manifest>
package="com.example.testlib"
android:sharedUserId="com.example.testlib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minsdkversion="15" android:targetsdkversion="15" />
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme">
</application>
</manifest>
TestCore.java
package com.example.testlib;
public class TestCore implements ITestCore{
private int count = 0;
public String testString(String arg) {
String res = arg + count;
count++;
return res;
}
}
public class TestCore implements ITestCore{
private int count = 0;
public String testString(String arg) {
String res = arg + count;
count++;
return res;
}
}
Sample Application Code
Application that uses the library. Here is just the AndroidManifest.xml and TestApplication.java which do the trick. All other application staff is as usual.AndroidManifest.xml
Be carefull to use same android:sharedUserId value in AndroidManifest.xml as library one
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testapp"
android:sharedUserId="com.example.testlib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk= android:minsdkversion="15" android:targetsdkversion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name=".TestApplication" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="android.app.Activity" />
<intent-filter
<action android:name="android.intent.action.MAIN"/ >
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
package="com.example.testapp"
android:sharedUserId="com.example.testlib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk= android:minsdkversion="15" android:targetsdkversion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name=".TestApplication" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="android.app.Activity" />
<intent-filter
<action android:name="android.intent.action.MAIN"/ >
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
ITestCore.java
Library interface has to be declared in application to avoid use reflectionpackage com.example.testlib;
public interface ITestCore {
String testString(String arg);
}
TestApplication.java
In applicatiopn's onCreate handler there is real work happens
package com.example.testapp;
import com.example.testlib.ITestCore;
import dalvik.system.DexClassLoader;
import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
public class TestApplication extends Application {
ClassLoader libClassLoader;
@Override
public void onCreate() {
PackageManager pm = getPackageManager();
String libSrcPath = null;
for (ApplicationInfo app : pm.getInstalledApplications(0)) {
if (app.packageName.equals("com.rhomobile.testlibrary")) {
libSrcPath = app.sourceDir;
Log.d("TestApplication", "package: " + app.packageName + ", sourceDir: " + app.sourceDir);
}
}
try {
libClassLoader = new DexClassLoader(libSrcPath, getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
Class clazz = libClassLoader.loadClass("com.rhomobile.testlib.TestCore");
ITestCore core = (ITestCore)clazz.newInstance();
String str = core.testString("TestApplication 1:");
Log.i("TestApplication", "output: " + str);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
Log.e("TestApplication", libClassLoader.toString());
e.printStackTrace();
}
}
}
import com.example.testlib.ITestCore;
import dalvik.system.DexClassLoader;
import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
public class TestApplication extends Application {
ClassLoader libClassLoader;
@Override
public void onCreate() {
PackageManager pm = getPackageManager();
String libSrcPath = null;
for (ApplicationInfo app : pm.getInstalledApplications(0)) {
if (app.packageName.equals("com.rhomobile.testlibrary")) {
libSrcPath = app.sourceDir;
Log.d("TestApplication", "package: " + app.packageName + ", sourceDir: " + app.sourceDir);
}
}
try {
libClassLoader = new DexClassLoader(libSrcPath, getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
Class clazz = libClassLoader.loadClass("com.rhomobile.testlib.TestCore");
ITestCore core = (ITestCore)clazz.newInstance();
String str = core.testString("TestApplication 1:");
Log.i("TestApplication", "output: " + str);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
Log.e("TestApplication", libClassLoader.toString());
e.printStackTrace();
}
}
}
Central idea is borrowed from here: Android Developers Blog: Custom Class Loading in Dalvik