全面支持OSGi捆绑软件
本主题说明如何将OSGI框架转换为在android上运行。 然后它提供了将android包转换为能够调用android API的OSGI包的提示。
在现阶段,这些Android OSGI捆绑软件无法做的唯一事情就是操纵活动并使用资源和资产。 我一直在努力解决这个限制。 我希望在这个问题上有好消息。
我发现在Eclipse中使用Create Plugin项目工具比在OSGI包中转换标准的android包要困难得多,所以我不会谈论太多。
您可以在本邮件末尾的“日志”部分中追踪我的成就。
我指的是Knopflerfish项目,因为它是我工作的基础。 这些修改旨在在Knopflerfish OSGi android项目上执行,但实际上适用于其他OSGI框架。 不需要修改OSGi框架本身,我们只会更新Knopflerfish发行版的tool
目录中的项目KfServiceLib
和KfBasicApp
。
添加基本的Android支持捆绑
功能和限制
这是android框架的第一级定制。 这些更改与上下文或调用线程无关,但它们允许使用android.util.Log
等有限的android API类。
由于这些变化,bundle将能够在他们的原型和实现中使用android类。 尽管如此,它们将无法与图形用户界面,内容提供商和系统服务等相关,因为它们缺少强制参考。
Knopflerfish应用程序中的更改
就像它们一样,tools / android / apk下的应用程序能够在android上执行OSGi框架,但前提是捆绑只是调用java类。 这就是Knopflerfish框架的一部分,但是想要调用android API的自定义包是什么? 以下是在框架中进行的更改,以使bundle能够解析android类。
首先,android包必须是框架包的一部分,这样才能解决它们。 这是OSGi属性org.osgi.framework.system.packages.extra
的用途
将该属性设置为在创建框架之前要导出的Android包列表,然后进行设置。 请注意,wild char android.*
似乎没有任何作用:我们必须像下面一样告诉每个包。
要添加到KfServiceLib
文件SRC /组织/ knopflerfish /安卓/服务/ 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");
然后我们在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);
备注:如果可以的话,最好用一个文件而不是程序中的代码来设置额外的配置。
捆绑包中导入android包
即使android包被添加到框架声明的系统包中,bundle也必须导入它们才能解析,就像任何其他导入的包一样。
例:
导入包:org.osgi.framework,android.content,android.widget,android.util
备注:您可以使用Knopflerfish Eclipse插件的“auto”按钮来自动更新导入。
将上下文传递给捆绑包
Knopflerfish应用程序中的更多更改
完成这些更改后,您应该能够运行捆绑包,从而开始自己的活动或访问上下文的资源。 整套android API类应该完全可用于捆绑。 但是为了达到这个目的,捆绑编码有一些限制。 我们所需要的就是应用程序上下文中的引用,所以我们将在框架中将其推入!
要添加到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;
}
我们正在传递应用程序的上下文,只有这个上下文,因为它是应用程序整个生命周期中唯一存在的上下文。 它将在应用程序启动后立即设置,这意味着安装或系统引导后。 捆绑可以在这个上下文中保持强有力的参考,这很好。
捆绑如何使用上下文
一个bundle从传递给其激活器的BundleContext
获取Context
:
static Context context;
public void start(BundleContext bc) throws Exception {
ServiceReference<Context> ref = bc.getServiceReference(Context.class);
context = bc.getService(ref);
}
由于bundle运行在与UI线程不同的线程中,UI操作只能在UI线程上“推送”时才能执行。 为此,设计一个可重用的实用程序方法是明智的:
public static void runOnContext(Context context, Runnable runnable) {
Handler handler = new Handler(context.getMainLooper());
handler.post(runnable);
}
这个方法应该是实用程序包的服务的一部分,因为它应该以相同的方式被许多不同的android包所访问。
例如,该包在启动时显示“Hello”:
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();
}
});
}
便宜的方法来使用捆绑应用程序
我将把APK转换为OSGI捆绑包简称为捆绑APK。
bundle.manifest
(请参见下面的示例)。 这个文件并不是APK的一部分,但会在自定义构建步骤中使用 com.acme.helloworld
(这个值在AndroidManifest.xml中用manifest:package设置),你的OSGI bundle的Activator类务必放在com.acme.helloworld
包中,你必须设置Bundle-SymbolicName: com.acme.helloworld
在捆绑清单中。 如果没有满足这些条件中的任何一个,那么将在运行时导致java.lang.NoClassDefFoundError
。 提醒一下,你的软件包清单文件应该是这样的:
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
bundle.manifest
作为META-INF/MANIFEST.MF
复制 要从捆绑包APK启动活动,请使用以下代码。
// 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);
日志
初始
在我的努力的这一点上,Android捆绑:
android.content.Context
,它可以用来从OSGi框架中启动活动。 软件包不能:
AndroidManifest.xml
声明,尽管通过代码实例化的接收器应该没问题。 这就是我迄今为止所经历的局限性,即我正努力克服的问题以及我寻求帮助的目标。
我的目标是:
到目前为止,我通过试验取得了哪些成就:
jarsigner
签名之前手动将bundle.manifest
合并到MANIFEST.MF中,将一个Android项目看作OSGi包和APK / android库。 结果是APK由OSGi框架加载,并且由于我的激活器类上的java.lang.NoClassDefFoundError
而起了解决状态,但无法启动,即使该类是classes.dex的一部分,并且没有路径上的明显错误。 使项目成为具有android依赖关系的OSGi包可以访问激活码,但不能访问JAR中的android资源。 令人费解。 编辑2013-09-03
我找到了一种方法来启动Android捆绑所拥有的活动。 请参阅相应章节。
编辑2013-09-10:通用OSGI框架容器
几天后,我使Knopflerfish程序变得通用,以运行我想要的任何OSGi框架。 例如,我现在以同样的方式运行Knopflerfish或Felix。 仍然需要特定的框架配置。
这意味着该主题不再只是Knopflerfish,即使所需的程序是由Knopflerfish发布的。
2013-09-27:地位和框架整体比较
由于优先级的改变,我必须搁置一段时间。 不过,我目前评估了以下解决方案:
总而言之,在GUI支持方面,它们都没有一个整洁的优势:它们都不能以android方式处理资源或资源(字符串,布局,图像),但仍然可以将它们作为OSGi资源处理OSGi API,但你将无法像往常一样在android中使用它们。
我个人喜欢Knopflerfish的管理控制台servlet,但它的GUI支持毫无用处。 Felix + FelixDroid在免费的OSGi解决方案方面具有很好的平衡性,而mBS SDK支持大量不同的VM目标,并定义了一种基于意图的应用程序框架,可能适合专业开发人员的品味。
鉴于Knopflerfish和Felix的使用方式几乎相同,mBS SDK在很多方面都有很大的不同。 Knopflerfish和Felix是可交换的:我写了一个容器程序,在其中选择OSGi框架只是选择不同的手工JAR依赖关系!
当谈到GUI时,Knopflerfish一无所获。 你需要通过我的指导方针,以获得更多的支持。 FelixDroid的主要思想是好的,它实际上是在mBS SDK中实现的类似的东西,但是如果没有将实现作为一个捆绑包,那将是一种浪费。 更重要的是,通过定义由特定意图启动的OSGi应用程序框架,mBS SDK已经做得更好。 两者都以同样的方式在主要活动中整合观点。
在mBS SDK中另一个惊人的区别是你不需要添加android框架依赖关系,也不需要为你的bundle添加Import-Package指令。 在依靠Knopflerfish或Felix一段时间后,这当然令人不安。 此外,它完全集成在Eclipse中,并为开发人员提供了许多便利的任务:PC到目标OSGi框架监控(Kf和Felix仅提供目标管理控制台)和快速部署。 这些坑基本上不是免费的,容器应用几乎不可能定制。
我已经通过纯粹的运气找到了一些有希望的开源(Apache许可证2)框架。 它被称为DEMUX框架。 随时评估这个解决方案。 我没有自己,但浏览功能和源代码让我觉得它有一个很好的潜力和整洁的整合。 关于GUI支持,它使用类似于FelixDroid的方法。 它可能成为Prosyst mBS SDK的开源替代品。
这是它的设计者如何定义框架的:
DEMUX Framework使Java开发人员可以轻松地从单个代码库构建桌面,Web和移动设备的应用程序。 它提供了基于OSGI的模块化应用程序体系结构,这使得构建健壮和可扩展的应用程序变得很容易。
不过,Android是现阶段唯一支持的移动操作系统,我希望他为其他两个人带来好运(我在过去的这个问题上有过一些痛苦的经历)
链接地址: http://www.djcxy.com/p/74735.html上一篇: Full Android support for OSGi bundles
下一篇: start an OSGI bundle