java - Android如何添加动态库?

标签 java android shared-libraries

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

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

有什么方法可以在 Android 上组织共享库吗?

更新:在此澄清一下,我不需要应用程序之间的交互。我需要可以在任何应用程序中重用的类。静态库也不太适合我的需求,因为这会使应用程序膨胀。

最佳答案

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

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

  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>

测试核心.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

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

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

关于java - Android如何添加动态库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3029783/

相关文章:

java - 使用 jackson 和 parcelable 解析嵌套的自定义对象数组

android - ViewPager 和 ActionBar 的奇怪错误/行为 (Sherlock)

java - BadParcelableException : ClassNotFoundException

c# - 引用库二进制 - 调试或发布版本?

javascript - JS - 无法合并 lib 文件

java - 将 Eclipse 中的 "Find References"限制为仅引用我的代码

java - 为什么我无法在 'SettingActivity' 中获取个人资料图片?

java - 文件删除/移动失败

java - 错误: unknown type name 'ClassObject'

linux - 如何显示 Linux 中可执行文件使用的所有共享库?