2012-01-25 15 views
2

私は、アプリケーションのパッケージに含まれているサービスを使用するアプリケーションを持っています。インテントを処理するサービスを選択する方法

私は今、新しいバージョンの同じサービスを使用して、独自のアプリケーションパッケージ内にバンドルされた新しいアプリケーションを作成しています。

デバイスにインストールされているアプリが1つだけの場合は正常です。しかし、両方のアプリがデバイスにインストールされている場合は、最も古いものがインストールされていないもの、つまり最も古いパッケージのサービスを使用します。 1)古いサービスが新しい呼び出しを処理しない(明らかに) 2)他のアプリケーションにバンドルされているサービスを使用すると、そのサービスは自分の代わりにその他のアプリケーションの保存されたデータを使用して終了します。

短期間では、私は実際にはそれぞれのアプリケーションが独自のバージョンのサービスと対話したいと思っています。それぞれのバンドルされたサービスを一意の意図に対応させずに、各アプリケーションがそのユニークな意図を使用することなく、これを行うことは可能ですか?

長期的には、オプションで両方のアプリケーションが最新のバージョンのサービスと対話してデータを共有し、いずれかのアプリケーションがアンインストールされていてもうまくいくのは良いことです。それを行う正しい方法は何ですか?データは主にSQLiteデータベースに格納され、Context.getDatabasePath()が指定されています。もちろんアプリケーション固有であり、アプリケーションがアンインストールされている場合は消去されます。

を、私はサービスの両方のバージョンでResolveInfoのリストを取得するにはPackageManager.queryIntentServices()を使用することができます。ここでは

は、私がこれまで試したものです。 ResolveInfo.serviceInfo.applicationInfo.packageNameを見ると、どちらがどちらであるかわかります。しかし、そのResolveInfoを使用して、2つのサービスのどちらを意図したいのかを指定する方法はありません。それのpackageNameは私が一致させたいものと同じであるよう

serviceIntent.setPackage(context.getApplicationContext().getApplicationInfo().packageName); 

これは、それが正しいことを行う必要があるように思えます。実際、queryIntentServicesに変更されたインテントを呼び出すと、私のパッケージ内のサービスだけを含むリストが返されます。しかし、そのインテントでbindServiceを試みると、セキュリティ例外がスローされます。いくつかのグーグルに基づいて

java.lang.RuntimeException: Unable to bind to service [email protected] with Intent { act=my.intent.string pkg=my.app.package.name }: java.lang.SecurityException: Not allowed to start service Intent { act=RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass } without permission private to package 

、私も行って、意図作成しようとしている:すべてのいずれかのサービスに解決されません

Intent serviceIntent = new Intent().setClassName(
    "my.service.package.name", 
    "my.service.package.name.ServiceClassName"); 

を。

また、AndroidManifest.xmlのサービスエントリ内のandroid:exported=をtrue、false、または指定しないで、両方のアプリケーションでさまざまな組み合わせで変更してみましたが、無駄です。 (私はそれらを両方ともfalseに設定すると、各アプリケーションはサービスのコピーを見ることしかできないことを期待していました)。

+0

私は上記の試みの1つに問題を認識しました。 'Intent.setClassName()'アプローチの場合は、次のようになります。 'serviceIntent = new Intent()。setClassName( context.getApplicationContext()。getApplicationInfo()。packageName、 " my.service.package.name .ServiceClassName ");' 正しいサービスであるが、サービスをバインドしようとするが、 'Intent.setPackage()'と同じセキュリティ例外がスローされる。 – benkc

答えて

3

次のような解決策があります。

サービスにサービスのメタデータを追加します。名前は "サービスランチャー"のようなものでなければならず、値はインテントフィルターのアクション名と同じでなければなりません。

<meta-data android:name="Service Launcher" 
      android:value="your.service.action.string.here" /> 

<intent-filter> 
    <action android:name="your.service.action.string.here" /> 
</intent-filter> 

あなたのコードでは、メタデータを取得してそれを使用してインテントを構築するアクセス方法を追加します。

public static String getServiceIntentAction(Context context) { 
    String action = ""; 
    try { 
     PackageManager pm = context.getPackageManager(); 
     android.content.ComponentName cn = new android.content.ComponentName(context.getPackageName(), "com.your.ServiceClass"); 
     android.content.pm.ServiceInfo si = pm.getServiceInfo(cn, PackageManager.GET_META_DATA); 
     action = si.metaData.getString("Service Launcher"); 
    } catch(android.content.pm.PackageManager.NameNotFoundException nnfe) {} 
    return action; 
} 

サービスを起動するインテントを構築しているものは、このメソッドを呼び出します。アプリ内のサービスのすべてのユーザーは、ライブラリの1つのバージョンだけで、マニフェストへの変更だけで、自分のアプリと通信するだけの別のアクションを持つことができます。

両方のアプリに同じサービスを使用させるには、サービスを自分のエンティティとしてインストールする必要があります。

0

カテゴリを試しましたか?インテントのすべてのカテゴリについて、潜在的に受信するコンポーネントは、受信者とみなされる各カテゴリに一致する必要があります。

サービスAはカテゴリ "1"を持ち、カテゴリ "1"へのインテントはそこに行きます。 サービスBは、カテゴリ "1"とカテゴリ "2"(バージョン "1"のすべてをサポートしていることを前提としています)を使用しています。

+0

これで、新しいアプリに新しいバージョンのサービスを使用させることができましたが、古いアプリは引き続きインストール順序に基づいて任意のサービスとデータを使用していました。 (サービスAのみに「1ではなく2でない」カテゴリを追加しない限り、それは悪いことになります)。 – benkc

関連する問題