Soporte completo de Android para paquetes OSGi

Este tema explica cómo puede transformar un marco OSGI para ejecutarse en android. A continuación, ofrece consejos para convertir los 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 utilizar recursos y activos. Estoy trabajando continuamente en la fijación de esta limitación. Espero tener buenas noticias sobre este tema.

Encontré más difícil usar la facilidad de proyecto Create Plugin en Eclipse que convertir paquetes estándar de Android como paquetes de OSGI, así que no hablaré mucho sobre ello.

Usted puede hacer un seguimiento de mis logros en la sección de registro al final de este mensaje.

Me refiero a los proyectos de Knopflerfish porque era la base para mi trabajo. Las modificaciones están destinadas a ser realizadas en Knopflerfish OSGi android proyectos, pero son realmente aplicables a otros frameworks OSGI. No es necesario modificar el marco de OSGi, solo actualizaremos los proyectos KfServiceLib y KfBasicApp en el directorio de tool de la distribución de Knopflerfish.

Añadir soporte básico de Android a paquetes

Características y límites

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

Gracias a estos cambios, los paquetes podrán usar las clases de android en sus prototipos y en su implementación. Sin embargo, no podrán tener nada relacionado 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

Como son, las aplicaciones bajo las herramientas / android / apk son capaces de ejecutar la estructura OSGi en android, pero sólo si los paquetes sólo están llamando a clases java. Ese es el caso de los paquetes que forman parte del marco Knopflerfish, pero ¿qué hay de paquetes personalizados que quieran llamar a la API de Android? Estos son los cambios a realizar en el marco para habilitar los paquetes que solucionan las clases de android.

En primer lugar, los paquetes de android deben formar parte de los paquetes de framework para que puedan resolverse. Este es el propósito de la propiedad OSGi org.osgi.framework.system.packages.extra

Establezca la propiedad en la lista de paquetes android para exportar antes de crear el marco y se establece. Tenga en cuenta que el android.* wild char android.* parece no tener ningún efecto: tenemos que decir a 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"); 

Entonces estamos fijando 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 es posible, es mucho mejor establecer la configuración adicional con un archivo en lugar de por código en el programa.

Importar paquetes de android en paquetes

Incluso si los paquetes de android se agregaron a los paquetes de sistema declarados por el framework, un bundle todavía tiene que importarlos para resolver, como cualquier otro paquete importado.

Ejemplo:

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

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

Pasar el contexto a los paquetes

Más cambios en las aplicaciones de Knopflerfish

Después de estos cambios, debería ser capaz de ejecutar los bundles iniciando actividades por su cuenta o accediendo a los recursos del contexto. El conjunto completo 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 de paquetes para lograr esto. Todo lo que necesitamos es la referencia en el Contexto de la aplicación por lo que vamos a empujar 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 sólo ésta, 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 instalar o arrancar el sistema. Los paquetes pueden mantener una referencia fuerte en este contexto, está bien.

Cómo los bundles utilizan 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 hilo diferente que el subproceso de UI, las operaciones de interfaz de usuario sólo se pueden realizar si se "empujan" en el subproceso de interfaz de usuario. Para ello, es recomendable 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 servicios públicos ya que debe ser accedido por muchos paquetes androide diferentes de la misma manera.

Por ejemplo, este paquete muestra "Hola" a medida que se inicia:

 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 bundles

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

  • Crear un APK regular, gracias a Eclipse Android Project por ejemplo
  • Agregue una entrada de biblioteca de referencia al proyecto Ruta de construcción para su estructura OSGi (en mi caso, framework.jar)
  • Edite un archivo de manifiesto bundle.manifest describiendo el paquete (consulte el ejemplo a continuación). Este archivo no es realmente parte del APK pero se utilizará durante los pasos de compilación personalizados
  • Digamos que su paquete de aplicación es com.acme.helloworld (este valor se establece con manifesto: package en AndroidManifest.xml), la clase Activator de su paquete OSGI DEBE ser colocada en el paquete com.acme.helloworld y DEBE establecer Bundle-SymbolicName: com.acme.helloworld en el manifiesto del paquete. Si alguna de estas condiciones no se cumple, resultará en un java.lang.NoClassDefFoundError en tiempo de ejecución.

Para recordarlo, el archivo de manifiesto del paquete debe tener este aspecto:

 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 
  • Utilizar las herramientas de Android> Exportar paquete de Android sin firmar
  • Copiar bundle.manifest en el APK no firmado generado como META-INF/MANIFEST.MF
  • Firmar el APK utilizando cualquier certificado que desee. Aquí tienes tu paquete APK listo
  • Instale el paquete APK como de costumbre. La instalación es necesaria para que las actividades sean resueltas. Sin esto, la actividad no se resolverá y el paquete fallará
  • Haga que la estructura OSGi cargue e inicie el paquete APK (el mismo archivo APK)

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

 // 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 android:

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

Los paquetes no pueden:

  • Solicitar permiso de android,
  • Construir actividades de diseño ni siquiera iniciar 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.

Lo que estoy apuntando a:

  • Tienen soporte para recursos internos, especialmente diseños,
  • Ser capaz de crear e iniciar actividades internas, por código si no es posible por XML Builder.

¿Cuáles son mis logros hasta ahora, a través de los juicios:

  • Haga que un proyecto androide sea visto como un paquete OSGi y una biblioteca APK / android mezclando los Builders, exportando binarios sin firmar y fusionando manualmente bundle.manifest en MANIFEST.MF antes de firmar con jarsigner . Los resultados son el APK es cargado por la OSGi framwork y obtiene hasta el estado resuelto, pero no es capaz de 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 androides 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 "puede hacer" de esta guía.

Edición 2013-09-03

He encontrado una manera de comenzar las actividades poseídas por los paquetes androides. Ver el capítulo correspondiente.

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

Después de varios días, he hecho los programas Knopflerfish genéricos para ejecutar cualquier marco OSGi que quiero. Por ejemplo, actualmente estoy corriendo Knopflerfish o Félix de la misma manera. Todavía hay una necesidad de una configuración específica del marco.

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

2013-09-27: Comparación general del estado y los marcos

Tengo que dejar este proyecto a un lado durante algún tiempo debido a un cambio en la prioridad. Sin embargo he evaluado hasta el momento las siguientes soluciones:

  • Knopflerfish OSGi [Fuente Abierta],
  • Felix y FelixDroid [Open source],
  • ProSyst mBS SDK (basado en Equinox, uso comercial)

Para resumir, ninguno de ellos tiene una gran ventaja en lo que respecta al soporte de GUI: ninguno de ellos puede manejar recursos o recursos (cadenas, diseños, imágenes) en el modo android, pero todavía puede manejarlos 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 equivale a nada. Felix + FelixDroid tiene un buen equilibrio para una solución OSGi libre, mientras que mBS SDK soporta un gran número de objetivos de VM diferentes y define un marco de aplicación basada en intenciones que podría encajar a los desarrolladores profesionales más gusto.

Mientras que Knopflerfish y Felix se utilizan 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 la elección de la estructura OSGi es sólo una cuestión de seleccionar una mano diferente dependencia JAR!

Cuando se trata de GUI, Knopflerfish proporciona nada. Tendrás que pasar por mis directrices para tener un poco más de apoyo. La idea principal de FelixDroid es buena, en realidad es algo similar implementado en mBS SDK, pero es un poco un desperdicio no tener la implementación como un paquete. Más que decir, SDK de mBS ha hecho la cosa más bien definiendo un marco de las aplicaciones de OSGi comenzado por intentos específicos. Ambos están integrando puntos de vista en la actividad principal de la misma manera.

Otra gran diferencia en el SDK de mBS es que no es necesario agregar las dependencias del framework de Android ni agregar directivas de Import-Package para ellos en sus paquetes. Sin duda es preocupante después de confiar en Knopflerfish o Felix por un tiempo. También está totalmente integrado en Eclipse y proporciona al desarrollador muchas tareas prácticas: PC para orientar el monitoreo de la infraestructura OSGi (Kf y Felix proporcionan sólo una consola de administración en el destino) y una implementación rápida. Los pozos son esencialmente que no es libre y que la aplicación de contenedor es casi imposible de personalizar.

He encontrado por pura suerte algunos prometedores de código abierto (Apache License 2) marco que podría ser de interés. Se llama DEMUX Framework . Siéntase libre de evaluar esta solución. No tengo yo mismo, pero la navegación a través de las características y el código fuente me dejó pensar que tiene un buen potencial y la integración limpia. En cuanto al soporte GUI, utiliza un enfoque similar al de FelixDroid. Podría convertirse en una alternativa Open Source a 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 dispositivos de escritorio, web y móviles a partir de una base de código único. Proporciona una arquitectura de aplicaciones modular basada en OSGI, lo que facilita la creación de aplicaciones robustas y extensibles.

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

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.