是否可以在运行时从Android应用程序动态加载库?

llu*_*ero 69 reflection android classloader dalvik android-library

有没有办法让Android应用程序在运行时下载和使用Java库?

这是一个例子:

想象一下,应用程序需要根据输入值进行一些计算.应用程序请求输入这些值,然后检查所需的Classes或Methods是否可用.

如果没有,它将连接到服务器,下载所需的库,并在运行时加载它以使用反射技术调用所需的方法.实施可能会根据各种标准(例如下载库的用户)而发生变化.

Shl*_*blu 91

对不起,我来晚了,问题已经有一个公认的答案,但肯定的,你可以下载并执行外部库.这是我的方式:

我想知道这是否可行,所以我编写了以下课程:

package org.shlublu.android.sandbox;

import android.util.Log;

public class MyClass {
    public MyClass() {
        Log.d(MyClass.class.getName(), "MyClass: constructor called.");
    }

    public void doSomething() {
        Log.d(MyClass.class.getName(), "MyClass: doSomething() called.");
    }
}
Run Code Online (Sandbox Code Playgroud)

我把它打包成一个DEX文件,我保存在设备的SD卡上/sdcard/shlublu.jar.

然后,在MyClass从Eclipse项目中删除并清除它后,我在下面写了"愚蠢的程序" :

public class Main extends Activity {

    @SuppressWarnings("unchecked")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            final String libPath = Environment.getExternalStorageDirectory() + "/shlublu.jar";
            final File tmpDir = getDir("dex", 0);

            final DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
            final Class<Object> classToLoad = (Class<Object>) classloader.loadClass("org.shlublu.android.sandbox.MyClass");

            final Object myInstance  = classToLoad.newInstance();
            final Method doSomething = classToLoad.getMethod("doSomething");

            doSomething.invoke(myInstance);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它基本上以MyClass这种方式加载类:

  • 创建一个 DexClassLoader

  • 用它来提取类MyClass"/sdcard/shlublu.jar"

  • 并将此类存储到应用程序的"dex"私有目录(手机的内部存储).

然后,它创建一个实例MyClassdoSomething()在创建的实例上调用.

它工作......我看到MyClass我的LogCat中定义的痕迹:

在此输入图像描述

我试过仿真器2.1和我的物理HTC手机(运行Android 2.2并且没有生根).

这意味着您可以为应用程序创建外部DEX文件以下载和执行它们.在这里它是艰难的方式(丑陋的Object演员,Method.invoke()丑陋的电话......),但必须有可能与Interfaces 玩,使事情更清洁.

哇.我是第一个感到惊讶的人.我在期待一个SecurityException.

一些事实有助于调查更多:

  • 我的DEX shlublu.jar已签名,但不是我的应用程序
  • 我的应用程序是从Eclipse/USB连接执行的.所以这是在DEBUG模式下编译的未签名APK

  • 大!这真的是我想要的!! 正如您在此处所见(http://groups.google.com/group/android-security-discuss/browse_thread/thread/e928d79627867246),确实没有安全问题,因为代码将在您的应用程序的许可下执行. (4认同)
  • 看看这个:http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+blogspot%2FhsDu+%28Android +开发商+博客29% (3认同)

小智 15

Shlublu的anwser非常好.一些小东西虽然有助于初学者:

  • 对于库文件"MyClass"创建一个单独的Android应用程序项目,它将MyClass文件作为src文件夹中的唯一文件(其他东西,如project.properties,manifest,res等也应该在那里)
  • 在库项目清单中确保你有:( <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".NotExecutable" android:label="@string/app_name"> </activity> </application> ".NotExecutable"不是保留字.只是我必须在这里放东西)

  • 要制作.dex文件,只需将库项目作为android应用程序运行(用于编译),然后从项目的bin文件夹中找到.apk文件.

  • 将.apk文件复制到手机并将其重命名为shlublu.jar文件(虽然APK实际上是jar的特殊化)

其他步骤与Shlublu描述的相同.

  • 非常感谢Shlublu的合作.