OSGI Bundle中的Android Activity

时间:2013-11-12 06:55:36

标签: android android-activity osgi apache-felix osgi-bundle

我正在开发完全支持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 Tools生成了我的项目的未签名副本。

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签名者工具手动签名了unsigned copy。类似的东西:

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

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

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

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

更新25-11-2013

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

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

这意味着我的bundle不包含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

3 个答案:

答案 0 :(得分:1)

有两个问题,通过解决这些问题,我设法最终安装了我的APK包并在Felix上启动。

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。然后我做了这个:Build Path-&gt; Configure Build Path-&gt; Projects,然后我添加了我的应用程序项目,它将加载bundle,并且在其构建路径中已经有felix.jar。据我所知,这将使应用程序和APK包使用相同的felix.jar。 (而不是在两者中保持不同,这使得Dalvik抱怨)。

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

您不必将捆绑包的符号名称和捆绑包的代码与Android应用程序放在同一个包中,只要export-package和import-package in manifest.mf已正确设置。您可以使用bndtools(http://bndtools.org)来帮助自动生成正确的manifest.mf(对于Android应用程序,bndtool似乎无法工作。我必须使用其过时的bnd.jar来执行job.bnd.jar可以在这里下载:http://www.java2s.com/Code/Jar/b/Downloadbndjar.htm