OSGI Bundle 中的 Android Activity

Posted

技术标签:

【中文标题】OSGI Bundle 中的 Android Activity【英文标题】:Android Activity in OSGI Bundle 【发布时间】:2013-11-24 05:22:40 【问题描述】:

我正在开发完全支持 android 的 OSGI 包。到目前为止,根据我之前的问题,我能够在 OSGI 包中使用 android API。它工作正常,我试过了。我正在使用 Felix 框架。

但是,我现在的任务是制作一个 OSGI 包以具有一个 android 活动并启动该活动。我还需要这些活动才能请求权限,所以我想我需要在 OSGI 包中添加一个AndroidManifest.xml

在进行研究时,我只能找到一个人描述了他实现这一目标的经历。不幸的是,他提到的步骤对我来说是模棱两可的。

在他的问题"Full Android Support for OSGI" 中,他是这样说的:

I have found a way to start activities owned by android bundles:

•the android bundle MUST be an APK which can be created using Eclipse Android Project
•add a Reference Library entry to the project Build Path for your OSGi framework (in my case framework.jar)
•edit bundle.manifest describing the bundle. The file is not part of the APK but will be used on build
•the bundle's code, especially the Activator class, MUST be in the same package as defined in AndroidManifest.xml AND the symbolic name of the bundle MUST be the package name as well. If these conditions are met then all of the classes will be correctly loaded. If not, it will result in seeing java.lang.NoClassDefFoundError on runtime
•Use Android Tools > Export Unsigned Android Package
•copy bundle.manifest in the unsigned APK as META-INF/MANIFEST.MF
•sign the APK using whatever certificate you want
•install the signed APK like any standard android application. Installation is required in order to have the Activity resolved. Without this the activity won't resolve and the bundle will fail
•have the OSGi framework load the bundle APK

他说的地方:

•edit bundle.manifest describing the bundle. The file is not part of the APK but will be used on build

我所做的只是创建一个 android 项目 (APK) 并遵循前两个步骤。但是在上面的第三步,我找不到"bundle.manifest" 来编辑它。根本不存在,他怎么会说编辑呢?

另外,当我Export Unsigned Android Package时,我应该从哪里复制清单文件?

最后,最终签名的 APK 文件是我应该由框架加载的包吗?这看起来很奇怪,因为它甚至不是一个 jar 文件。

如果这些步骤对我没有帮助,那么有人可以引导我走向正确的方向吗?谢谢。

更新:

没有人回答我的问题,所以我做了以下操作:

1- 在我的 android 应用程序项目中(我试图让它充当一个包),我将我的 Activator 类包含在 AndroidManifest.xml 中提到的同一个包中。 这是我的Activator.java 课程:

package com.example.patient;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator 

    private static BundleContext context;

    static BundleContext getContext() 
        return context;
    


    public void start(BundleContext bundleContext) throws Exception 
        Activator.context = bundleContext;

   //I WOULD LIKE TO START THE ACTIVITY HERE TO DISPLAY THE TOAST MESSAGE
        System.out.println("Android APK Bundle Started");

    


    public void stop(BundleContext bundleContext) throws Exception 
        Activator.context = null;



    


这是我的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.patient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.patient.View_Patient_File_Activity"
            android:label="View Patient File" >


        </activity>
        <activity
            android:name="com.example.patient.Enter_Patient_ID_Activity"
            android:label="View Patient File" >

                        <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>
        </activity>
    </application>

</manifest>

2- 我在我的 OSGi 框架 (felix.jar) 的项目构建路径中添加了一个参考库条目

3- 我使用 Android 工具生成了我的项目的未签名副本。

4- 我在未签名副本的根目录中添加了一个名为META-INF 的文件夹,并在该文件夹中添加了一个名为MANIFEST.MF 的文件,以下是该文件的内容:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Patient
Bundle-SymbolicName: com.example.patient
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.example.patient.Activator
Import-Package: org.osgi.framework;version="1.3.0"
Bundle-RequiredExecutionEnvironment: OSGi/Minimum-1.0

5- 我使用命令行和 jar 签名工具手动签署了未签名的副本。比如:

jarsigner -verbose -keystore /path_to_keystore/mykeystore.keystore my_application.apk my_keystore_alias 

6- 我在我的电脑和标签上安装了签名副本。

7- 最后,我运行我的应用程序,并让 OSGI 框架加载相同的签名 apk 文件。

NO USE,虽然捆绑包状态是活动的,但我没有在激活器的 start() 方法中看到消息,这意味着我的捆绑包没有正确加载。我去哪儿了? 请帮忙。

2013 年 11 月 25 日更新

我确保正确执行了这些步骤,现在我得到了这个:

11-25 17:54:08.600: W/System.err(2714): org.osgi.framework.BundleException: Not found: com.example.patient.Activator
11-25 19:22:36.590: W/System.err(6652): Caused by: java.lang.ClassNotFoundException: com.example.patient.Activator not found by com.example.patient

意味着我的包不包含 Activator 类,但我确信它包含。有什么问题?

2013 年 11 月 26 日更新

我使用 WinZip 打开了签名的 APK。我注意到与我以前构建的 bundle 不同,签名的 APK 不包含 .class 文件,包括“Activator.class”,所以我复制了包含项目所有 .class 文件的 com 目录,并粘贴了它在已签名的 APK 中。接下来,我再次签署了该 APK。现在,当我安装 APK 时,我得到以下包含许多错误的日志:

11-25 23:16:25.651: D/dalvikvm(5617): DexOpt: --- BEGIN 'bundle.jar' (bootstrap=0) ---
11-25 23:16:26.271: D/dalvikvm(5617): DexOpt: --- END 'bundle.jar' (success) ---
11-25 23:16:26.271: D/dalvikvm(5617): DEX prep '/sdcard/felix-cache-1472376252.tmp/bundle1/version0.0/bundle.jar': unzip in 102ms, rewrite 620ms
11-25 23:16:26.271: W/dalvikvm(5617): Class resolved by unexpected DEX: Lcom/example/patient/Activator;(0x4074fa08):0x18a7b8 ref [Lorg/osgi/framework/BundleActivator;] Lorg/osgi/framework/BundleActivator;(0x40714410):0xbd630
11-25 23:16:26.271: W/dalvikvm(5617): (Lcom/example/patient/Activator; had used a different Lorg/osgi/framework/BundleActivator; during pre-verification)
11-25 23:16:26.271: I/dalvikvm(5617): Failed resolving Lcom/example/patient/Activator; interface 902 'Lorg/osgi/framework/BundleActivator;'
11-25 23:16:26.271: W/dalvikvm(5617): Link of class 'Lcom/example/patient/Activator;' failed
11-25 23:16:26.271: E/dalvikvm(5617): ERROR: defineClass(0x4074fa08, com.example.patient.Activator, 0x4079d468, 0, 955, 0x4073e918)
11-25 23:16:26.271: E/Zaid Log(5617): Problem installing the bundle :s
11-25 23:16:26.271: W/System.err(5617): org.osgi.framework.BundleException: Activator start error in bundle com.example.patient [1].
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.Felix.activateBundle(Felix.java:2196)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.Felix.startBundle(Felix.java:2064)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:942)
11-25 23:16:26.271: W/System.err(5617):     at com.example.patient_application.MainActivity.onCreate(MainActivity.java:136)
11-25 23:16:26.271: W/System.err(5617):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1048)
11-25 23:16:26.271: W/System.err(5617):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1715)
11-25 23:16:26.271: W/System.err(5617):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1767)
11-25 23:16:26.271: W/System.err(5617):     at android.app.ActivityThread.access$1500(ActivityThread.java:122)
11-25 23:16:26.271: W/System.err(5617):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1005)
11-25 23:16:26.271: W/System.err(5617):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-25 23:16:26.271: W/System.err(5617):     at android.os.Looper.loop(Looper.java:132)
11-25 23:16:26.271: W/System.err(5617):     at android.app.ActivityThread.main(ActivityThread.java:4028)
11-25 23:16:26.271: W/System.err(5617):     at java.lang.reflect.Method.invokeNative(Native Method)
11-25 23:16:26.271: W/System.err(5617):     at java.lang.reflect.Method.invoke(Method.java:491)
11-25 23:16:26.271: W/System.err(5617):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
11-25 23:16:26.271: W/System.err(5617):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
11-25 23:16:26.271: W/System.err(5617):     at dalvik.system.NativeStart.main(Native Method)
11-25 23:16:26.271: W/System.err(5617): Caused by: java.lang.UnsupportedOperationException: can't load this type of class file
11-25 23:16:26.271: W/System.err(5617):     at java.lang.VMClassLoader.defineClass(Native Method)
11-25 23:16:26.271: W/System.err(5617):     at java.lang.ClassLoader.defineClass(ClassLoader.java:319)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2279)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1501)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
11-25 23:16:26.271: W/System.err(5617):     at java.lang.ClassLoader.loadClass(ClassLoader.java:500)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.BundleWiringImpl.getClassByDelegation(BundleWiringImpl.java:1374)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.Felix.createBundleActivator(Felix.java:4329)
11-25 23:16:26.271: W/System.err(5617):     at org.apache.felix.framework.Felix.activateBundle(Felix.java:2141)
11-25 23:16:26.271: W/System.err(5617):     ... 17 more

【问题讨论】:

【参考方案1】:

包的代码,尤其是 Activator 类,必须与 AndroidManifest.xml 中定义的包位于同一包中,并且包的符号名称也必须是包名称。如果满足这些条件,则将正确加载所有类。如果没有,它会导致在运行时看到 java.lang.NoClassDefFoundError

你不必让bundle的符号名和bundle的代码与android应用在同一个包中,只要manifest.mf中的export-package和import-package正确即可放。您可以使用 bndtools(http://bndtools.org) 帮助自动生成正确的 manifest.mf(对于 android 应用程序,bndtool 似乎不起作用。我必须使用它过时的一个 bnd.jar 来完成这项工作。bnd。 jar可以在这里下载:http://www.java2s.com/Code/Jar/b/Downloadbndjar.htm)

【讨论】:

【参考方案2】:

有两个问题,通过解决它们,我终于在 Felix 上安装并启动了我的 APK 包。

1- 与 OSGI 包不同,最终签名的 APK 不包含 .class 文件。这就是为什么我得到:Not found: com.example.patient.Activator。通过手动将我的android项目中的com目录复制到签名的APK,然后再次签名,我设法解决了这个问题。

2- @slash33 提到的第二步是:

•add a Reference Library entry to the project Build Path for your OSGi framework

导致我出现以下错误:

 (Lcom/example/patient/Activator; had used a different Lorg/osgi/framework/BundleActivator; during pre-verification)

在this 帖子的帮助下,我只是删除了对库的引用,并从我的构建路径中删除了felix.jar。然后我这样做了:构建路径->配置构建路径->项目,然后我添加了将加载捆绑包的应用程序项目,它的构建路径中已经有felix.jar。据我了解,这将使应用程序和 APK 包使用相同的 felix.jar。 (而不是在两者中保留不同的一个,这让 Dalvik 抱怨)。

因此,我认为创建 APK android 包然后将其加载到框架的正确步骤是:

创建常规 APK,例如通过创建 Eclipse Android 项目。 通过以下方式使您的包使用与您的应用程序相同的 OSGI 框架库: Build Path->Configure Build Path->Projects,然后添加将加载包的应用程序项目。您的应用程序项目应在其构建路径中包含 OSGI 框架 jar 文件(在我的情况下为 felix.jar)。 创建描述包的包清单文件。你可以叫它bundle.manifest。 假设你的应用程序包是com.acme.helloworld(这个值是用AndroidManifest.xml中的manifest:package设置的),你的OSGI包的Activator类必须放在包com.acme.helloworld中并且你必须在捆绑清单中设置 Bundle-SymbolicName: com.acme.helloworld。如果不满足这些条件中的任何一个,则会在运行时产生java.lang.NoClassDefFoundError。 使用Android 工具> 导出未签名的Android 包bundle.manifest复制到生成的未签名APK的根目录下为META-INF/MANIFEST.MF。您可以使用Winzip打开未签名的APK并添加文件夹META-INF。 使用以下命令对 APK 进行签名: jarsigner -verbose -keystore /path_to_keystore/mykeystore.keystore my_application.apk my_keystore_alias。 将包含所有.class 文件的目录从您的android 项目复制到已签名apk 的根目录。在我的例子中:它是 com 目录。 再次签署您的 APK。 安装 APK 包。 让 OSGi 框架加载并启动 APK 包(同一个 APK 文件)

【讨论】:

感谢您阐明我的开发过程。我将借用您的解释,以便为将来的用户更新我的主题。抱歉,我可能忽略了一些步骤,因为我在实施指南之后就编写了指南。另外,我编写了自己的 OSGi 容器,嵌入了 OSGi 框架提供程序。这与“常规”的基于 OSGi 的解决方案有一些不同。不过,请记住,此方法是从由 android OS 管理的 APK 中生成活动,而不是来自 OSGi 捆绑包对应的活动。 如果你真的对 android/OSGi 开发感兴趣,那么看看这个项目,就像我自己做的那样:ist-music.berlios.de/site/middleware-osgi.html。它有很大的潜力,即使在相当多的安卓版本之后都没有维护。 谢谢。我会查一下。你能看看这个吗?你也许能帮上忙。 ***.com/questions/20222620/…【参考方案3】:

最后,最终签名的 APK 文件是我应该由框架加载的包吗?这看起来很奇怪,因为它甚至不是一个 jar 文件。是的。作为一个APK,它仍然是一个兼容的JAR,只是它也包含dex文件。

您所遵循的步骤在我看来是合法的。根据我的经验,它应该有效。你有我们可以利用的日志跟踪吗? Knopflerfish 控制台允许您在手动启动和停止捆绑包时查看堆栈跟踪。它在这里非常有价值。

【讨论】:

我应该将最终签名的 APK 文件保存为 jar 文件吗?像“myAPKFile.jar”这样的东西?还是我保留它“myAPKFile.apk”?

以上是关于OSGI Bundle 中的 Android Activity的主要内容,如果未能解决你的问题,请参考以下文章

我为啥不在osgi中使用spring

在 OSGI Bundle 中创建 JAXBContext 的问题

OSGi中的ServletContext

让 OSGi 服务使用最新版本的 bundle,即使安装了多个 bundle 版本

osgi笔记

使用 maven-bundle-plugin 安装 OSGi 依赖项