如何向Android添加动态库?

时间:2010-06-12 19:04:50

标签: java android shared-libraries

我想向Android添加一个非本机共享库,以便设备上的每个应用程序都可以使用它。我的意思是像使用核心库一样使用打包的类,就好像它们存在于应用程序本身中一样。

我研究了Android源代码,找出了一种向应用程序ClassLoader添加新路径的方法,并发现它是在启动时创建的,之后无法更改路径。我可以使用我自己的ClassLoader,但加载一个类后我将得到的只是对Class对象的引用。这样我就会通过反射机制来工作,这种机制比本机执行系统慢。

有没有办法在Android上组织共享库?

更新:只是为了清楚这一点,我需要在应用程序之间进行交互。我需要可以在任何应用程序中重用的类。静态库也不能满足我的需求,因为这会使应用程序膨胀。

4 个答案:

答案 0 :(得分:10)

在Android中创建动态加载库有两个技巧

  1. 在AndroidManifest中使用sharedUserId作为您的应用程序和库项目

  2. 使用dalvik.system.DexClassLoader加载库

  3. 图书馆代码:

    它只包含没有任何Android特定入口点的java代码。 AndroidManifest.xml只包含此android:sharedUserId属性

    的AndroidManifest.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>
    

    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;
        }
    }
    

    示例应用程序代码

    使用该库的应用程序。这里只是AndroidManifest.xml和TestApplication.java。所有其他申请人员都照常。

    的AndroidManifest.xml

    小心在AndroidManifest.xml中使用相同的android:sharedUserId值作为库一

    <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>
    

    ITestCore.java

    必须在应用程序中声明库接口以避免使用反射

    package com.example.testlib;
    
    public interface ITestCore {
        String testString(String arg);
    }
    

    TestApplication.java

    在applicatiopn的onCreate处理程序中,实际工作正在进行中

    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");            
                try {
                    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();
            }
        }
    }
    

答案 1 :(得分:3)

Android博客上的

Recent post完全解释了我的需求:

  

Dalvik VM为开发人员提供了执行自定义类加载的工具。应用程序可以从其他位置(如内部存储器或网络)加载它们,而不是从默认位置加载Dalvik可执行文件(“dex”)文件。

关键是使用DexClassLoader加载所需的库。之后,可以通过接口或使用反射来访问代码。

答案 2 :(得分:2)

对于可重用类的静态库,您可以使用library projects。为了安全地与其他应用程序动态交互,您可以bind to a service

答案 3 :(得分:0)

即使您获得了Class对象,Android上的安全模型(binder)也会禁止应用程序读入另一个应用程序的目录。

您可以在非root手机上做的最好的事情就是通过Intents创建库。