37

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

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

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

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

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

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

機能と制限

これは、Android 用フレームワークのカスタマイズの最初のレベルです。これらの変更は、コンテキストや呼び出しスレッドとは関係ありませんが、android.util.Log.

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

Knopflerfish アプリの変更点

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

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

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

KfServiceLibファイル src/org/knopflerfish/android/service/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 パッケージが追加された場合でも、バンドルは、他のインポートされたパッケージと同様に、それらを解決するためにインポートする必要があります。

例:

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

注意: Knopflerfish Eclipse プラグインのボタン « auto » を使用して、インポートを自動的に更新することができます。

Context をバンドルに渡す

Knopflerfish アプリのその他の変更点

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

追加するには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と呼びます。

  • たとえばEclipse Android Projectのおかげで、通常のAPKを作成します
  • OSGi フレームワーク (私の場合は Framework.jar)のプロジェクトビルド パスに参照ライブラリエントリを追加します。
  • バンドルを説明するバンドル マニフェスト ファイルを編集しますbundle.manifest(以下の例を参照)。このファイルは実際には APK の一部ではありませんが、カスタム ビルド手順で使用されます
  • アプリケーション パッケージがcom.acme.helloworld(この値は AndroidManifest.xml の manifest:package で設定されている) 場合、OSGI バンドルの Activator クラスをパッケージに配置する必要があり、バンドル マニフェストに設定する必要com.acme.helloworldがあります。これらの条件のいずれかが満たされない場合、実行時になります。Bundle-SymbolicName: com.acme.helloworldjava.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 パッケージをエクスポートする
  • bundle.manifest生成された未署名の APK を次のようにコピーします。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 でリソースや宣言を必要としない限り、Android SDK クラスを呼び出すことができます。
  • android.content.ContextOSGi フレームワークからアクティビティを開始するために使用できるアプリケーションの にアクセスできます。

バンドルはできません:

  • アンドロイドの許可を要求し、
  • レイアウトからアクティビティを構築し、それらをまったく開始しません。
  • で宣言されている静的ブロードキャスト レシーバーを定義しますAndroidManifest.xmlが、コードによってインスタンス化されたレシーバーでも問題ありません。

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

私が目指していること:

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

試練を通して、これまでの私の成果は何ですか:

  • Builder を混合し、署名されていないバイナリをエクスポートし、手動でbundle.manifestMANIFEST.MF にマージしてから、OSGi バンドルと APK/Android ライブラリの両方として表示される Android プロジェクトを作成しjarsignerます。その結果、APK は OSGi フレームワークによってロードされ、解決java.lang.NoClassDefFoundError済みの状態になりますが、クラスが classes.dex の一部であり、パスに明らかなエラーがない場合でも、アクティベーター クラスが原因で起動できません。 . プロジェクトを Android 依存関係を持つ OSGi バンドルにすると、アクティベーターにはアクセスできますが、JAR 内の Android リソースにはアクセスできません。不可解。
  • このガイドの「できること」セクションに記載されているすべての機能を検証します。

編集 2013-09-03

Android バンドルが所有するアクティビティを開始する方法を見つけました。対応する章を参照してください。

編集 2013-09-10: 汎用 OSGI フレームワーク コンテナー

数日後、必要な OSGi フレームワークを実行できるように、Knopflerfish プログラムを汎用にしました。たとえば、私は現在 Knopflerfish や Felix を同じ方法で実行しています。特定のフレームワーク構成の必要性がまだあります。

つまり、必要なプログラムが Knopflerfish によって発行されたとしても、トピックはもはや Knopflerfish だけではありません。

2013-09-27: ステータスとフレームワークの全体的な比較

優先度の変更により、このプロジェクトをしばらく脇に置かなければなりません。ただし、これまでに次のソリューションを評価しました。

  • ノップラーフィッシュ OSGi [オープン ソース]、
  • Felix と FelixDroid [オープン ソース]、
  • ProSyst mBS SDK (Equinox ベース、商用利用)

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

個人的には、Knopflerfish の管理コンソール サーブレットが気に入っていますが、その GUI サポートは何の役にも立ちません。Felix + FelixDroid は無料の OSGi ソリューションとしてバランスが取れているのに対し、mBS SDK は多数の異なる VM ターゲットをサポートし、プロの開発者の好みにより適したインテント ベースのアプリケーション フレームワークを定義します。

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

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

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

4

1 に答える 1

1

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

これは、デザイナーがフレームワークを定義する方法です。

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

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

于 2015-01-28T09:08:36.123 に答える