web-dev-qa-db-ja.com

フルAndroid OSGiバンドルのサポート

このトピックでは、OSGIフレームワークをAndroidで実行するように変換する方法について説明します。次に、AndroidパッケージをAndroidAPIを呼び出すことができるOSGIバンドルとして変換するためのヒントを示します。

現段階では、これらのAndroid OSGIバンドルで実行できないのは、アクティビティを操作し、リソースとアセットを使用することだけです。私はこの制限の修正に継続的に取り組んでいます。この件について良いニュースがあればいいのですが。

標準のAndroidパッケージをOSGIバンドルとして変換するよりも、Eclipseでプラグインの作成プロジェクト機能を使用する方が難しいことがわかったので、それについてはあまり説明しません。

このメッセージの最後にある[ログ]セクションで、私の成果を追跡できます。

それが私の仕事の基礎だったので、私は Knopflerfish プロジェクトについて言及しています。変更は Knopflerfish OSGi Androidプロジェクト で実行されることを意図していますが、実際には他のOSGIフレームワークに適用できます。 OSGiフレームワーク自体を変更する必要はありません。KnopflerfishディストリビューションのKfServiceLibディレクトリにあるプロジェクトKfBasicApptoolのみを更新します。

基本的なAndroidサポートをバンドルに追加します

機能と制限

これは、Android用フレームワークのカスタマイズの最初のレベルです。これらの変更は、コンテキストや呼び出しスレッドとは関係ありませんが、_Android.util.Log_などの限られたAndroidAPIクラスのセットを使用できます。

これらの変更のおかげで、バンドルはプロトタイプと実装でAndroidクラスを使用できるようになります。それでも、必須の参照がないため、グラフィカルユーザーインターフェイス、コンテンツプロバイダー、システムサービスなどに関連することは何もできません。

Knopflerfishアプリの変更

現状では、tools/Android/apkの下のアプリケーションは、AndroidでOSGiフレームワークを実行できますが、バンドルがJavaクラスのみを呼び出している場合に限ります。これは、Knopflerfishフレームワークの一部であるバンドルの場合ですが、AndroidAPIを呼び出したいカスタムバンドルはどうでしょうか。バンドルがAndroidクラスを解決できるようにするためにフレームワークで行う変更は次のとおりです。

まず、Androidパッケージは、解決できるようにフレームワークパッケージの一部である必要があります。これがOSGiプロパティの目的です_org.osgi.framework.system.packages.extra_

フレームワークを作成する前に、エクスポートするAndroidパッケージのリストにプロパティを設定すると、設定が完了します。ワイルド文字_Android.*_は効果がないように見えることに注意してください。以下のように、各パッケージに1つずつ伝える必要があります。

ファイルsrc/org/knopflerfish/Android/service /KfApk.JavaのKfServiceLibに追加するには

_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パッケージが追加された場合でも、他のインポートされたパッケージと同様に、バンドルはそれらをインポートして解決する必要があります。

例:

インポートパッケージ:org.osgi.framework、Android.content、Android.widget、Android.util

備考:Knopflerfish Eclipseプラグインの"自動"ボタンを使用して、インポートを本来のように自動的に更新できます。

コンテキストをバンドルに渡す

Knopflerfishアプリのその他の変更

これらの変更後、バンドルを実行して、独自にアクティビティを開始したり、コンテキストのリソースにアクセスしたりできるようになります。これで、AndroidAPIクラスのセット全体がバンドルで完全に利用できるようになります。しかし、これを達成するためにバンドルコーディングに適用されるいくつかの制約があります。必要なのはアプリケーションのコンテキストの参照だけなので、フレームワークにプッシュします。

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;
}
_

アプリケーションのコンテキストを渡しますが、これはアプリケーションの存続期間全体にわたって存在する唯一のコンテキストであるためです。アプリケーションが起動するとすぐに、つまりインストールまたはシステムの起動後に設定されます。バンドルは、このコンテキストで強力な参照を維持できます。問題ありません。

バンドルがコンテキストを使用する方法

バンドルは、アクティベーターに渡されたContextからBundleContextを取得します。

_static Context context;

public void start(BundleContext bc) throws Exception {
  ServiceReference<Context> ref = bc.getServiceReference(Context.class);
  context = bc.getService(ref);
}
_

バンドルは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();
    }
  });
}
_

バンドルなどのアプリケーションを使用する安価な方法

OSGIバンドルに変換されたAPKを略してバンドルAPKと呼びます。

  • たとえばEclipseAndroid Projectのおかげで、通常のAPKを作成できます
  • OSGiフレームワーク(私の場合はframework.jar)のプロジェクトビルドパス参照ライブラリエントリを追加します
  • バンドルを説明するバンドルマニフェストファイル_bundle.manifest_を編集します(以下の例を参照)。このファイルは実際にはAPKの一部ではありませんが、カスタムビルドステップで使用されます
  • アプリケーションパッケージが_com.acme.helloworld_(この値はAndroidManifest.xmlのmanifest:packageで設定されます)であるとすると、OSGIバンドルのアクティベータークラス[〜#〜] must [〜#〜] パッケージ_com.acme.helloworld_に入れて、あなた[〜#〜] must [〜#〜]バンドルマニフェストに_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
_
  • 使用Androidツール>署名なしのエクスポートAndroidパッケージ
  • 生成された署名されていないAPKの_bundle.manifest_を_META-INF/MANIFEST.MF_としてコピーします
  • 必要な証明書を使用してAPKに署名します。これでバンドルAPKの準備ができました
  • 通常どおりバンドルAPKをインストールします。アクティビティを解決するには、インストールが必要です。これがないと、アクティビティは解決されず、バンドルは失敗します
  • OSGiフレームワークをロードしてバンドルAPK(まったく同じAPKファイル)を開始します

バンドル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バンドル:

  • androidManifest.xmlでのリソースや宣言を必要としない限り、AndroidSDKクラスを呼び出すことができます。
  • アプリケーションの_Android.content.Context_にアクセスできます。これは、OSGiフレームワークからアクティビティを開始するために使用できます。

バンドルはできません:

  • リクエストAndroid許可、
  • レイアウトからアクティビティを構築しても、まったく開始しません。
  • _AndroidManifest.xml_で宣言された静的ブロードキャストレシーバーを定義しますが、コードによってインスタンス化されたレシーバーは問題ないはずです。

これは、私がこれまでに経験した制限を克服しようとしていることと、助けを求める私の目標のためです。

私が目指していること:

  • 内部リソース、特にレイアウトをサポートしている、
  • xMLビルダーで不可能な場合は、コードで内部アクティビティを作成および開始できます。

トライアルを通してのこれまでの私の成果は何ですか?

  • jarsignerで署名する前に、Builderを混合し、署名されていないバイナリをエクスポートし、_bundle.manifest_をMANIFEST.MFに手動でマージして、AndroidプロジェクトをOSGiバンドルとAPK/Androidライブラリの両方として表示します。結果は、APKがOSGiフレームワークによってロードされ、状態resolvedになりますが、アクティベータークラスの_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:ステータスとフレームワークの全体的な比較

優先順位の変更により、このプロジェクトはしばらく脇に置いておく必要があります。ただし、これまでに次のソリューションを評価しました。

  • Knopflerfish OSGi [オープンソース]、
  • FelixとFelixDroid [オープンソース]、
  • ProSyst mBS SDK(Equinoxベースの商用利用)

要約すると、GUIサポートに関しては、どれも優れた利点はありません。アセットやリソース(文字列、レイアウト、画像)をAndroidの方法で処理することはできませんが、それでも処理できます。それらはOSGiAPIを使用してOSGiリソースとして使用されますが、通常どおりAndroidで使用することはできません。

私は個人的にKnopflerfishの管理コンソールサーブレットが好きですが、そのGUIサポートは何もありません。 Felix + FelixDroidは、無料のOSGiソリューションとのバランスが取れていますが、mBS SDKは、さまざまなVMターゲットをサポートし、プロの開発者の好みに合う可能性のあるインテントベースのアプリケーションフレームワークを定義します。

KnopflerfishとFelixはほぼ同じように使用されますが、mBSSDKは多くの点で大きく異なります。 KnopflerfishとFelixは交換可能です。OSGiフレームワークの選択は、別の手作りのJAR依存関係を選択するだけのコンテナプログラムを作成しました。

GUIに関しては、Knopflerfishは何も提供しません。もう少しサポートを受けるには、私のガイドラインを確認する必要があります。 FelixDroidの主なアイデアは優れており、実際にはmBS SDKに実装されているものと似ていますが、実装をバンドルとして使用しないのは少し無駄です。さらに言えば、mBS SDKは、特定のインテントによって開始されたOSGiアプリケーションフレームワークを定義することにより、よりうまく機能しました。どちらも、ほぼ同じ方法でメインアクティビティにビューを統合しています。

MBS SDKのもう1つの驚くべき違いは、Androidフレームワークの依存関係を追加したり、バンドルにそれらのImport-Packageディレクティブを追加したりする必要がないことです。 KnopflerfishまたはFelixにしばらく頼った後、それは確かに気がかりです。また、Eclipseに完全に統合されており、開発者に多くの便利なタスクを提供します。PCからターゲットへのOSGiフレームワークの監視(KfとFelixはオンターゲットの管理コンソールのみを提供します)と迅速な展開です。ピットは本質的に無料ではなく、コンテナアプリケーションをカスタマイズすることはほぼ不可能です。

37
slash33

運が良ければ、興味深いオープンソース(Apache License 2)フレームワークがいくつか見つかりました。それは DEMUX Framework と呼ばれます。このソリューションを自由に評価してください。私自身はそうではありませんが、機能とソースコードを閲覧することで、それが優れた可能性ときちんとした統合を持っていると思います。 GUIサポートに関しては、FelixDroidと同様のアプローチを使用します。これは、Prosyst mBSSDKのオープンソースの代替手段になる可能性があります。

これは、その設計者がフレームワークを定義する方法です。

DEMUX Frameworkを使用すると、Java開発者は、単一のコードベースからデスクトップ、Web、およびモバイルデバイス用のアプリケーションを簡単に構築できます。OSGIに基づくモジュラーアプリケーションアーキテクチャを提供するため、堅牢で拡張性のあるものを簡単に構築できます。アプリケーション。

ただし、Androidは、この段階でサポートされている唯一のモバイルOSであり、他の2つのモバイルOSの幸運を祈っています(この件に関して過去にいくつかの苦痛な経験をしました)

1
slash33