android osgi knopflerfish

Soporte completo de Android para paquetes OSGi



knopflerfish (1)

He encontrado por pura suerte algún marco prometedor de Código Abierto (Apache License 2) que podría ser de interés. Se llama Marco DEMUX . Siéntase libre de evaluar esta solución. Yo no tengo más que explorar las características y el código fuente, déjenme pensar que tiene un buen potencial y una buena integración. En cuanto al soporte de la GUI, utiliza un enfoque similar al de FelixDroid. Podría convertirse en una alternativa de código abierto para Prosyst mBS SDK.

Así es como su diseñador define el marco:

DEMUX Framework facilita a los desarrolladores de Java la creación de aplicaciones para escritorio, web y dispositivos móviles desde una única base de código. Proporciona una arquitectura modular de aplicaciones basada en OSGI, lo que facilita la creación de aplicaciones robustas y extensibles.

Sin embargo, Android es el único sistema operativo móvil compatible en esta etapa y le deseo buena suerte para los otros dos (tuve algunas experiencias dolorosas en el pasado sobre este tema)

Este tema explica cómo puede transformar un marco OSGI para ejecutarlo en Android. Luego da consejos para convertir paquetes de Android como paquetes OSGI capaces de llamar a la API de Android.

En la etapa actual, lo único que estos paquetes OSGI de Android no pueden hacer es manipular actividades y usar recursos y activos. Estoy trabajando continuamente para corregir esta limitación. Espero tener buenas noticias sobre este tema.

Me resultó más difícil usar el recurso Crear proyecto de complemento en Eclipse que convertir paquetes estándar de Android como paquetes OSGI, por lo que no hablaré mucho al respecto.

Puede realizar un seguimiento de mis logros en la sección de registro al final de este mensaje.

Me refiero a los proyectos de Knopflerfish porque fue la base de mi trabajo. Las modificaciones están destinadas a realizarse en Knopflerfish OSGi proyectos de Android, pero en realidad son aplicables a otros marcos OSGI. No es necesario modificar el marco OSGi en sí, solo actualizaremos los proyectos KfServiceLib y KfBasicApp en el directorio de tool de la distribución Knopflerfish.

Agrega soporte básico de Android a los paquetes

Características y límites

Este es el primer nivel de personalización del framework para Android. Estos cambios aún no tendrán nada que ver con el contexto o el hilo de llamada, pero permiten el uso de un conjunto limitado de clases de API de Android como android.util.Log .

Gracias a estos cambios, los paquetes podrán usar clases de Android en sus prototipos y en su implementación. Sin embargo, no podrán tener nada que ver con la interfaz gráfica de usuario, los proveedores de contenido y los servicios del sistema, y ​​así sucesivamente, porque carecen de las referencias obligatorias para ello.

Cambios en las aplicaciones de Knopflerfish

Tal como están, las aplicaciones en tools / android / apk pueden ejecutar el framework OSGi en android, pero solo si los bundles solo están llamando a las clases de Java. Ese es el caso de los paquetes que forman parte del framework Knopflerfish, pero ¿qué pasa con los paquetes personalizados que desean llamar a la API de Android? Aquí están los cambios para hacer en el marco para permitir que los paquetes resuelvan las clases de Android.

Primero, los paquetes de Android deben ser parte de los paquetes de framework para que puedan ser resueltos. Este es el propósito de la propiedad OSGi org.osgi.framework.system.packages.extra

Establezca la propiedad en la lista de paquetes de Android para exportar antes de crear el marco y usted está configurado. Tenga en cuenta que el comodín android.* Parece no tener ningún efecto: tenemos que decir cada paquete uno por uno como a continuación.

Para agregar a KfServiceLib en el archivo src / org / knopflerfish / android / service / KfApk.java

static final String ANDROID_FRAMEWORK_PACKAGES = ( "android," + "android.app," + "android.content," + "android.database," + "android.database.sqlite," + "android.graphics," + "android.graphics.drawable," + "android.graphics.glutils," + "android.hardware," + "android.location," + "android.media," + "android.net," + "android.net.wifi," + "android.opengl," + "android.os," + "android.provider," + "android.sax," + "android.speech.recognition," + "android.telephony," + "android.telephony.gsm," + "android.text," + "android.text.method," + "android.text.style," + "android.text.util," + "android.util," + "android.view," + "android.view.animation," + "android.webkit," + "android.widget");

Luego estamos configurando los paquetes adicionales en KfApk.newFramework()

config.put(Constants.FRAMEWORK_STORAGE, fwDir); // Export android packages so they can be referenced by bundles config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, ANDROID_FRAMEWORK_PACKAGES);

Observación : si puede, es mucho mejor establecer la configuración adicional con un archivo en lugar de con un código en el programa.

Importar paquetes de Android en paquetes

Incluso si los paquetes de Android se agregaron a los paquetes del sistema declarados por el marco, un paquete aún tiene que importarlos para resolverlos, como cualquier otro paquete importado.

Ejemplo:

Import-Package: org.osgi.framework, android.content, android.widget, android.util

Observación : puede usar el botón «auto» del plugin Knopflerfish Eclipse para actualizar automáticamente las importaciones como deberían.

Pase el contexto a los paquetes

Más cambios en las aplicaciones Knopflerfish

Después de estos cambios, debería poder ejecutar paquetes iniciando actividades por su cuenta o accediendo a los recursos del contexto. Todo el conjunto de clases de la API de Android debería estar completamente disponible para los paquetes. Pero hay algunas restricciones que se aplican a la codificación del paquete para lograr esto. Todo lo que necesitamos es la referencia en el contexto de la aplicación, ¡así que vamos a empujarlo en el marco!

Para agregar en org.knopflerfish.android.service.Knopflerfish.onStartCommand()

if (fw != null) { // Register the application''s context as an OSGi service! BundleContext bundleContext = fw.getBundleContext(); regContext = bundleContext.registerService(Context.class, getApplicationContext(), new Hashtable()); sendMessage(Msg.STARTED, (Serializable) KfApk.getFrameworkProperties()); } else { // framework did not init/start sendMessage(Msg.NOT_STARTED); stopSelf(); return; }

Estamos pasando el contexto de la aplicación, y solo esta, porque es el único Contexto que existirá durante toda la vida de la aplicación. Se establecerá tan pronto como se inicie la aplicación, es decir, después de la instalación o el inicio del sistema. Los paquetes pueden mantener una referencia fuerte en este contexto, está bien.

Cómo los paquetes usan el contexto

Un paquete obtiene el Context del BundleContext pasado a su activador:

static Context context; public void start(BundleContext bc) throws Exception { ServiceReference<Context> ref = bc.getServiceReference(Context.class); context = bc.getService(ref); }

Como un paquete se ejecuta en un subproceso diferente que el subproceso de interfaz de usuario, las operaciones de la interfaz de usuario solo se pueden realizar si se "presiona" en el subproceso de interfaz de usuario. Para hacerlo, es aconsejable diseñar un método de utilidad reutilizable como este:

public static void runOnContext(Context context, Runnable runnable) { Handler handler = new Handler(context.getMainLooper()); handler.post(runnable); }

Este método debe ser parte de un servicio de un paquete de utilidades, ya que muchos paquetes diferentes de Android deben acceder de la misma manera.

Por ejemplo, este paquete muestra "Hola" cuando comienza:

public void start(BundleContext bc) throws Exception { ServiceReference<Context> ref = bc.getServiceReference(Context.class); final Context context = bc.getService(ref); runOnContext(context, new Runnable() { public void run() { Toast.makeText(context, "Hello", Toast.LENGTH_LONG).show(); } }); }

Método barato para usar aplicaciones como paquetes

Me referiré al APK convertido a un paquete OSGI como paquete APK para abreviar.

  • Crea una APK regular, gracias a Eclipse Android Project por ejemplo
  • Agregue una entrada de biblioteca de referencia a la ruta de compilación del proyecto para su marco OSGi (en mi caso framework.jar)
  • Edite un archivo de manifiesto de paquete bundle.manifest describa el paquete (vea el ejemplo a continuación). Este archivo no es realmente parte de la APK, pero se usará durante los pasos de compilación personalizados.
  • Supongamos que el paquete de su aplicación es com.acme.helloworld (este valor se establece con manifest: package en AndroidManifest.xml), la clase Activator de su paquete OSGI DEBE colocarse en el paquete com.acme.helloworld y usted DEBE establecer Bundle-SymbolicName: com.acme.helloworld en el manifiesto del paquete. Si no se cumple alguna de estas condiciones, se generará java.lang.NoClassDefFoundError en el tiempo de ejecución.

Para recordatorio, el archivo de manifiesto del paquete debe verse así:

Manifest-Version: 1.0 Bundle-Vendor: Acme Bundle-Version: 1.0.0 Bundle-Name: HelloWorldBundle Bundle-ManifestVersion: 2 Bundle-Activator: com.acme.helloworld.Activator Bundle-Description: Hello World Bundle Import-Package: org.osgi.framework Bundle-SymbolicName: com.acme.helloworld Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.0

  • Usa las herramientas de Android> Exportar paquete de Android sin firmar
  • Copie bundle.manifest en el APK sin firmar generado como META-INF/MANIFEST.MF
  • Firme el APK usando el certificado que desee. Aquí tienes tu paquete APK listo
  • Instale el paquete APK como de costumbre. Se requiere instalación para resolver las actividades. Sin esto, la actividad no se resolverá y el paquete fallará
  • Haga que el marco OSGi cargue e inicie el paquete APK (el mismo archivo APK)

Para iniciar la actividad desde el paquete APK, use el siguiente código.

// This is the application''s context provided by the framework // Context ctx = ... Intent intent = new Intent(); String pkgName = YourActivity.class.getPackage().getName(); String clssName = YourActivity.class.getName(); intent.setClassName(pkgName, clssName); // You may add the NEW_TASK flag intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK); // Important: do not use startActivity(Context, Class) version because it will fail to resolve the activity ctx.startActivity(intent);

Iniciar sesión

Inicial

En este punto de mis esfuerzos, paquetes de Android:

  • puede llamar a las clases SDK de Android siempre que no requieran recursos o declaración en AndroidManifest.xml,
  • tener acceso al android.content.Context la aplicación, que se puede usar para iniciar actividades fuera del marco OSGi.

Los paquetes no pueden:

  • solicitar permiso de Android,
  • construir actividades desde el diseño ni siquiera iniciarlas en absoluto,
  • define receptor de difusión estática, declarado en AndroidManifest.xml , aunque un receptor instanciado por código debería estar bien.

Eso es por las limitaciones que he experimentado hasta ahora que estoy tratando de superar y el objetivo de mi solicitud de ayuda.

A lo que me refiero:

  • tener soporte para recursos internos, especialmente diseños,
  • ser capaz de crear y comenzar actividades internas, por código si no es posible mediante el generador de XML.

¿Cuáles son mis logros hasta ahora, a través de pruebas?

  • Haga que un proyecto de Android se vea tanto como un paquete OSGi como una biblioteca APK / Android mezclando los constructores, exportando los binarios sin firmar y fusionando manualmente bundle.manifest en MANIFEST.MF antes de firmar con jarsigner . Los resultados son que el archivo APK es cargado por OSGi framwork y llega al estado resuelto, pero no se puede iniciar debido a java.lang.NoClassDefFoundError en mi clase de activador, incluso si la clase es parte de classes.dex y no hay error aparente en el camino. Hacer que el proyecto sea un paquete OSGi con dependencias de Android obtiene acceso al activador pero no a los recursos de Android en el JAR. Misterioso.
  • Valide todas las características descritas en la sección "puedo hacer" de esta guía.

Editar 2013-09-03

He encontrado una manera de comenzar actividades propiedad de paquetes de Android. Ver el capítulo correspondiente.

Editar 2013-09-10: contenedor marco genérico OSGI

Después de varios días, hice genéricos los programas Knopflerfish para ejecutar cualquier marco OSGi que desee. Por ejemplo, actualmente estoy ejecutando Knopflerfish o Felix de la misma manera. Todavía hay una necesidad de una configuración de marco específico.

Eso significa que el tema ya no es Knopflerfish, incluso si los programas necesarios fueron emitidos por Knopflerfish.

2013-09-27: comparación global de estado y marcos

Tengo que dejar de lado este proyecto por un tiempo debido a un cambio en la prioridad. Sin embargo, evalué las siguientes soluciones hasta el momento:

  • Knopflerfish OSGi [Código abierto],
  • Felix y FelixDroid [Código abierto],
  • ProSyst mBS SDK (uso comercial basado en Equinox)

En resumen, ninguno de ellos tiene una clara ventaja cuando se trata de soporte de GUI: ninguno de ellos puede manejar activos o recursos (cadenas, diseños, imágenes) a la manera de Android, pero aún se puede manejar como recurso OSGi con el OSGi API pero no podrás usarlos en Android como de costumbre.

Personalmente me gusta el servlet de la consola de administración de Knopflerfish, pero su soporte de GUI no significa nada. Felix + FelixDroid tiene un buen equilibrio para una solución OSGi gratuita, mientras que mb SDK admite una amplia variedad de objetivos de VM diferentes y define un marco de aplicaciones basado en intentos que podría adaptarse mejor a los desarrolladores profesionales.

Mientras que Knopflerfish y Felix se usan casi de la misma manera, mBS SDK es muy diferente en muchos aspectos. Knopflerfish y Felix son intercambiables: ¡he escrito un programa de contenedores donde elegir el marco OSGi es solo cuestión de seleccionar una dependencia JAR hecha a mano diferente!

Cuando se trata de GUI, Knopflerfish no ofrece nada. Tendrás que seguir mis pautas para tener un poco más de apoyo. La idea principal en FelixDroid es buena, en realidad es algo similar implementado en mBS SDK, pero es un desperdicio no tener la implementación como un paquete. Más que decir, mBS SDK ha hecho las cosas de forma más agradable al definir un marco de aplicaciones OSGi iniciado por propósitos específicos. Ambos integran vistas en la actividad principal de la misma manera.

Otra sorprendente diferencia en mBS SDK es que no necesita agregar las dependencias de Android Framework ni agregar directivas de paquetes de importación para ellas en sus paquetes. Sin duda es perturbador después de confiar en Knopflerfish o Felix por un tiempo. También está completamente integrado en Eclipse y proporciona al desarrollador muchas tareas útiles: PC para orientar la supervisión del marco OSGi (Kf y Felix proporcionan solo una consola de administración en el objetivo) y una implementación rápida. Los pozos son esencialmente que no es gratis y que la aplicación del contenedor es casi imposible de personalizar.