代码之家  ›  专栏  ›  技术社区  ›  Malcolm

如何在Android中添加动态库?

  •  12
  • Malcolm  · 技术社区  · 14 年前

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

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

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

    更新: 我只是想澄清一下 不要 需要应用程序之间的交互。我需要可以在任何应用程序中重用的类。另外,静态库并不真正适合我的需要,因为这会使应用程序膨胀。

    4 回复  |  直到 12 年前
        1
  •  10
  •   khr055 Eduardo    12 年前

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

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

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

    图书馆代码:

    它只包含Java代码而没有任何Android特定的入口点。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>
    

    爪哇

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

    小心使用与库1相同的android:sharedUserID值androidmanifest.xml

    <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.testlib;
    
    public interface ITestCore {
        String testString(String arg);
    }
    

    测试应用程序.java

    在应用程序的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();
            }
        }
    }
    
        2
  •  3
  •   Malcolm    13 年前

    Recent post 在Android博客上,我准确地解释了我需要什么:

    Dalvik虚拟机为开发人员提供了执行自定义类加载的工具。不是从默认位置加载dalvik可执行文件(__dex_),应用程序可以从其他位置(如内部存储或通过网络)加载它们。

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

        3
  •  2
  •   adamp    14 年前

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

        4
  •  0
  •   Yann Ramin    14 年前

    即使你得到一个类对象,安卓系统上的安全模型(binder)也会禁止应用程序读取到另一个应用程序的目录中。

    在非根电话上最好的方法是通过intent创建库。