Android Activity in OSGI Bundle
Asked Answered
B

3

3

I am working on developing OSGI bundles that have a full support for android. So far, by my previous questions, I was able to use android API inside OSGI bundle. It works fine and I tried it. I am using Felix framework.

However, I am stuck now at the mission of making an OSGI bundle to have an android activity and to start that activity. I also need these activities to be able to request permissions so I guess I will need an AndroidManifest.xml in the OSGI bundle.

While doing a research, I was able to find only one person describing his experience in achieving this. Unfortunately, the steps he mentioned is ambiguous to me.

In his question "Full Android Support for OSGI" , Here's what he said:

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

Where he says:

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

All I did is to create an android project (APK) and to follow the first two steps. But at this third step above, I couldn't find "bundle.manifest" to edit it. It is not there at all, so how come he says edit it?

Also, when I Export Unsigned Android Package, from where to where should I copy the manifest file?

Finally, is the final signed APK file my bundle that should be loaded by the framework? This seems odd because It is not even a jar file.

If these steps would not help me, then can someone lead me in the right direction? Thank you.

UPDATE:

No one answers my question, so I did the following:

1- In my android application project (which I am trying to make it act as a bundle), I included my Activator class in the same package mentioned in the AndroidManifest.xml. Here's my Activator.java class:

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;



    }

}

and here's my 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- I added a Reference Library entry to the project Build Path for my OSGi framework (felix.jar)

3- I generated an unsigned copy of my project using Android Tools.

4- I added a folder to the root directory of the unsigned copy called META-INF, and inside that folder, I added a file called MANIFEST.MF, below is the content of that file:

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- I manually signed the unsigned copy using command line and jar signer tool. Something like:

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

6- I installed the signed copy on my PC and on my tab.

7- Finally, I run my application, and let the OSGI framework load the same signed apk file.

NO USE, although the bundle status is active, but I do NOT see the message in the activator start() method, meaning that, my bundle is not loaded correctly. Where did I go worng? Please help.

UPDATE 25-11-2013

I made sure to do the steps correctly, and now I got this:

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

Meaning that my bundle does not contain the Activator class, but I am sure it does. What could be wrong?

UPDATE 26-11-2013

I opened the signed APK using WinZip. I noticed that unlike the bundles I used to build, the signed APK does not contain the .class files including the "Activator.class", so I copied the com directory that contains all the .class files of the project, and I pasted it in the signed APK. Next, I signed that APK again. Now, when I install the APK, I get the following log which contains many errors:

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
Basket answered 12/11, 2013 at 6:55 Comment(0)
B
1

There were two problems, and by solving them I managed to finally get my APK bundle installed and started on Felix.

1- Unlike OSGI bundles, the final signed APK does not contain the .class files. That's why I was getting: Not found: com.example.patient.Activator. By manually copying the com directory from my android project to the signed APK, and then signing it again, I managed to solve this problem.

2- The second step mentioned by @slash33 which is:

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

was causing me the following error:

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

With help of this post, I simply deleted the reference to the library,and removed felix.jar from my build path. Then I did this: Build Path->Configure Build Path->Projects, and then I added my application project that will load the bundle, and which already has felix.jar in its build path. This as far as I understand will make the application and the APK bundle use the same felix.jar. (Instead of keeping different one in both, which makes Dalvik complains).

Therefore, I believe that the correct steps to create an APK android bundle, and then to load it to the framework would be:

  • Create a regular APK, for example by creating Eclipse Android Project.
  • Make your bundle use the same OSGI framework library used by your application by: Build Path->Configure Build Path->Projects, and then add your application project that will load the bundle. Your application project should contain the OSGI framework jar file in its build path, (in my case felix.jar).
  • Create the bundle manifest file describing the bundle. You can call it bundle.manifest.
  • Say your application package is com.acme.helloworld (this value is set with manifest:package in AndroidManifest.xml), your OSGI bundle's Activator class MUST be placed in the package com.acme.helloworld and you MUST set Bundle-SymbolicName: com.acme.helloworld in the bundle manifest. If any of these conditions is not met then will result in a java.lang.NoClassDefFoundError on runtime.
  • Use Android Tools > Export Unsigned Android Package
  • Copy bundle.manifest to the root directory of the generated unsigned APK as META-INF/MANIFEST.MF. You can use Winzip to open the unsigned APK and add the folder META-INF.
  • Sign the APK using the command: jarsigner -verbose -keystore /path_to_keystore/mykeystore.keystore my_application.apk my_keystore_alias.
  • Copy your directory that contains all the .class files from your android project to the root directory of your signed apk. In my case: it is the com directory.
  • Sign your APK once again.
  • Install the APK bundle.
  • Have the OSGi framework load and start the APK bundle (the very same APK file)
Basket answered 26/11, 2013 at 8:2 Comment(3)
Thanks for clarifying my development process. I will borrow your explanations in order to update my subject for future users. Sorry, I might have overlooked a few steps because I have written the guide quite after implementing it. Also, I have written my own OSGi container embedding the OSGi framework provider. This makes a few differences from a "regular" OSGi-based solution. Still, keep in mind that this method is spawning activities from the APK managed by android OS, not the ones from the OSGi bundle counterpart.Despairing
If you are really interested in android/OSGi development then take a look to this project, as I'm doing myself: ist-music.berlios.de/site/middleware-osgi.html . It has a great potential, even if not maintained since quite a number of android versions.Despairing
Thanks. I will check it. Can you please take a look this? You might be able to help. #20223120Basket
D
0

Finally, is the final signed APK file my bundle that should be loaded by the framework? This seems odd because It is not even a jar file. Yes it is. As an APK, it is still a compatible JAR except that it contains dex files too.

The steps you have followed seem legit to me. According to my experience, it should have worked. Do you have any logtrace we can exploit? Knopflerfish console allows you to see the stacktrace when starting and stopping the bundles manually. It is extremely valuable here.

Despairing answered 25/11, 2013 at 11:19 Comment(1)
Should I save the final signed APK file as a jar file? Something like "myAPKFile.jar"? or I keep it "myAPKFile.apk"?Basket
E
0

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

You don't have to make the symbolic name of the bundle and the bundle's code to be in the same package as the android application, as long as the export-package and the import-package in the manifest.mf is correctly set. You can use bndtools(http://bndtools.org) to help generate the correct manifest.mf automatically(for an android application, bndtool doesn't seem to work though. I have to use its obsolete one bnd.jar to do the job. bnd.jar can be downloaded here: http://www.java2s.com/Code/Jar/b/Downloadbndjar.htm)

Extrorse answered 18/5, 2014 at 14:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.