¿Es posible cargar dinámicamente una biblioteca en tiempo de ejecución desde una aplicación de Android?

¿Hay alguna manera de hacer una aplicación Android para descargar y usar una biblioteca Java en tiempo de ejecución?

Aquí hay un ejemplo:

Imagine que la aplicación necesita hacer algunos cálculos dependiendo de los valores de entrada. La aplicación solicita estos valores de entrada y luego verifica si están disponibles los Classe s o Method s necesarios.

De lo contrario, se conecta a un servidor, descarga la biblioteca necesaria y la carga en tiempo de ejecución para llamar a los métodos necesarios utilizando técnicas de reflexión. La implementación podría cambiar según varios criterios, como el usuario que está descargando la biblioteca.

Lo siento, llegué tarde y la pregunta ya tiene una respuesta aceptada, pero , puedes descargar y ejecutar bibliotecas externas. Así es como lo hice:

Me preguntaba si esto era factible, así que escribí la siguiente clase:

 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."); } } 

Y lo empaqué en un archivo DEX que /sdcard/shlublu.jar tarjeta SD de mi dispositivo como /sdcard/shlublu.jar .

Luego escribí el “progtwig estúpido” a continuación, después de haber eliminado MyClass de mi proyecto Eclipse y haberlo limpiado:

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

Básicamente carga la clase MyClass esa manera:

  • crear un DexClassLoader

  • "/sdcard/shlublu.jar" para extraer la clase MyClass de "/sdcard/shlublu.jar"

  • y almacene esta clase en el directorio privado "dex" la aplicación (almacenamiento interno del teléfono).

Luego, crea una instancia de MyClass e invoca doSomething() en la instancia creada.

Y funciona … Veo los rastros definidos en MyClass en mi LogCat:

enter image description here

He probado tanto un emulador 2.1 como mi teléfono móvil físico HTC (que está ejecutando Android 2.2 y que NO está rooteado).

Esto significa que puede crear archivos DEX externos para que la aplicación los descargue y ejecute. Aquí se hizo de la manera difícil (feo Object moldes, Method.invoke() feo llamadas …), pero debe ser posible jugar con Interface s para hacer algo más limpio.

Guau. Soy el primero sorprendido. Esperaba una SecurityException .

Algunos hechos para ayudar a investigar más:

  • Mi DEX shlublu.jar se firmó, pero no mi aplicación
  • Mi aplicación se ejecutó desde una conexión Eclipse / USB. Así que este es un APK sin firmar comstackdo en modo DEBUG

El sombrero de Shlublu es realmente agradable. Algunas pequeñas cosas que ayudarían a un principiante:

  • para el archivo de biblioteca “MyClass”, haga un proyecto de aplicación Android separado que tenga el archivo MyClass como único archivo en la carpeta src (otras cosas, como project.properties, manifest, res, etc. también deberían estar allí)
  • en el manifiesto del proyecto de la biblioteca, asegúrese de tener: (” .NotExecutable “no es una palabra reservada. Es solo que tuve que poner algo aquí)

  • Para crear el archivo .dex, simplemente ejecute el proyecto de la biblioteca como aplicación de Android (para la comstackción) y ubique el archivo .apk desde la carpeta bin del proyecto.

  • Copie el archivo .apk a su teléfono y renómbrelo como archivo shlublu.jar (sin embargo, una APK es en realidad una especialización de un jar)

Otros pasos son los mismos descritos por Shlublu.

  • Muchas gracias a Shlublu por la cooperación.

No estoy seguro de si puede lograr esto cargando dinámicamente el código de Java. Puede ser que intentes incrustar un motor de script con tu código como rhino, que puede ejecutar scripts Java que se pueden descargar y actualizar dinámicamente.

seguro, es posible. apk que no está instalado puede ser invocado por la aplicación host android. En general, resuelve el recurso y el ciclo de vida de la actividad, entonces, puede cargar jar o apk dinámicamente. detalle, consulte mi investigación de fuente abierta en github: https://github.com/singwhatiwanna/dynamic-load-apk/blob/master/README-en.md

también, se necesita DexClassLoader y reflexión, ahora mira un código clave:

 /** * Load a apk. Before start a plugin Activity, we should do this first.
* NOTE : will only be called by host apk. * @param dexPath */ public DLPluginPackage loadApk(String dexPath) { // when loadApk is called by host apk, we assume that plugin is invoked by host. mFrom = DLConstants.FROM_EXTERNAL; PackageInfo packageInfo = mContext.getPackageManager(). getPackageArchiveInfo(dexPath, PackageManager.GET_ACTIVITIES); if (packageInfo == null) return null; final String packageName = packageInfo.packageName; DLPluginPackage pluginPackage = mPackagesHolder.get(packageName); if (pluginPackage == null) { DexClassLoader dexClassLoader = createDexClassLoader(dexPath); AssetManager assetManager = createAssetManager(dexPath); Resources resources = createResources(assetManager); pluginPackage = new DLPluginPackage(packageName, dexPath, dexClassLoader, assetManager, resources, packageInfo); mPackagesHolder.put(packageName, pluginPackage); } return pluginPackage; }

sus demandas son solo parcialmente de función en el proyecto de código abierto mencionado al principio.

Si mantiene sus archivos .DEX en la memoria externa del teléfono, como la tarjeta SD (no se recomienda! Cualquier aplicación con los mismos permisos puede sobrescribir fácilmente su clase y realizar un ataque de inyección de código) asegúrese de haber dado el permiso de la aplicación para leer la memoria externa. La excepción que se produce si este es el caso es ‘ClassNotFound’, que es bastante engañosa, ponga algo como lo siguiente en su manifiesto (consulte Google para la versión más actualizada).

   ...  

Técnicamente debería funcionar, pero ¿qué pasa con las reglas de Google? De: play.google.com/intl/en-GB/about/developer-content-policy-pr int

Una aplicación distribuida a través de Google Play no puede modificarse, reemplazarse o actualizarse a sí misma mediante un método que no sea el mecanismo de actualización de Google Play. Del mismo modo, una aplicación no puede descargar código ejecutable (por ejemplo, dex, JAR, .so archivos) de una fuente que no sea Google Play. Esta restricción no se aplica al código que se ejecuta en una máquina virtual y tiene acceso limitado a las API de Android (como JavaScript en una WebView o un navegador).