40

私は、特定のブランディングでのみ区別される一連のアプリを開発しています (さまざまなスポーツ チームを考えてみてください)。ただし、特定のブランドのアプリすべてに 1 つのライブラリ プロジェクトを使用していて、それらすべてに同じ ContentProvider を使用したいという問題が発生しています。ContentProvider を作成したとき、AUTHORITY をクラス内の定数として宣言し (開発サンプル コードに従って)、マニフェスト ファイル内のすべての特定のアプリで同じ権限を使用しています。2 番目のアプリをインストールしようとするとこのエラーが発生するため、すべてのアプリで同じ権限を使用できないようです (ブランド化されたものは問題なくインストールできますが、2 番目のインストールはインストールされます)。

WARN/PackageManager(66): Can't install because provider name com.xxx.Provider (in package com.xxx) is already used by com.zzz

いくつかのアプローチを試しましたが、どれもうまくいかないようです。私がまだ行っていないアイデアの 1 つは、ライブラリ jar を作成し、私が持っている Provider クラスを省略して、特定のアプリごとにカスタマイズすることでした。それに頼らずにこの問題を回避する方法についてのアイデアはありますか?

4

5 に答える 5

22

ContentProvider は機関によって識別されるため、一意である必要があります。そのあたりの裏技はないと思います。

さらに、Android プラットフォームにはバグがあり、2 つの異なる ContentProvider に同じクラス名を使用することもできません。これは、それらが異なる権限を持ち、別々の APK に含まれている場合でも同様です。ここでバグを参照してください。

私がお勧めする解決策は、ライブラリ プロジェクトで抽象プロバイダー クラスを作成し、個々のアプリケーションごとに一意の名前でそれを拡張することです。これを実用的にするには、個々のマニフェストと contentprovider クラスを生成/変更するスクリプトを作成する必要があります。

お役に立てれば。

于 2011-05-27T21:06:09.900 に答える
6

あなたはできる!

この投稿で述べたように(Firebase がメソッドからコンテキストを与えずにライブラリを初期化する方法を説明していますApplication#onCreate())、次のようにマニフェストでプレースホルダーを使用できます。

    <provider
         android:authorities="${applicationId}.yourcontentprovider"
         android:name=".YourContentProvider" />
于 2017-01-31T18:11:13.317 に答える
4

あなたのライブラリパッケージがcom.android.app.library 無料パッケージであるとしましょうパッケージはcom.android.app.free 有料ですcom.android.app.paid

無料プロジェクトと有料プロジェクトで、パッケージ内に同一のファイルを作成します。これは何でもかまいませんが、同じでなければなりません。

例:

  1. 無料版で com.android.app.data を使用して新しいパッケージを作成します

  2. Authority.java というファイルを作成し、その中に (Authority.java) を入れます。

    public class Authority {

    `public static final String CONTENT_AUTHORITY = "YOUR PROVIDER";`
    

    }

  3. 有料版でもこれを繰り返します。パッケージ名とクラス名は同じにしてください。

ここで、契約ファイルのライブラリで次を使用します。

public static String AUTHORITY = initAuthority();

    private static String initAuthority() {
        String authority = "something.went.wrong.if.this.is.used";

        try {

            ClassLoader loader = Contract.class.getClassLoader();

            Class<?> clz = loader.loadClass("com.android.app.data.Authority");
            Field declaredField = clz.getDeclaredField("CONTENT_AUTHORITY");

            authority = declaredField.get(null).toString();
        } catch (ClassNotFoundException e) {} 
        catch (NoSuchFieldException e) {} 
        catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        }

        return authority;
    }

    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);

これで、2 つの権限を使用できるようになります。

クレジット: Ian Warick (コード作成) Android - アプリ プロジェクトでプロバイダー権限を持つ 免責事項: ここにも投稿しました: Android 重複したプロバイダー権限の問題- 同じ種類の質問に同じ回答で回答できるかどうかわからない.

于 2014-01-12T00:41:42.300 に答える
1

次の方法を使用して、ライブラリ内に ContentProvider をパッケージ化し、実行時に ContentProvider の権限を設定して、ContentProvider 権限の競合なしで複数のプロジェクトに含めることができます。これが機能するのは、実際の「権限」が ContentProvider クラスではなく AndroidManifest に由来するためです。

基本的な ContentProvider 実装から始めます..AUTHORITY、CONTENT_URI、および UriMatcher は静的ですが、「最終」ではありません....

public class MyContentProvider extends ContentProvider {
    public static String  AUTHORITY = "com.foo.bar.content";
    public static Uri     CONTENT_URI = Uri.parse("content://" + AUTHORITY);
    protected static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

次に、「attachInfo」メソッドをオーバーライドして、ContentProvider が最初に初期化されるときに、AndroidManifest から収集された ProviderInfo を使用して ContentProvider が呼び出されるようにします。これは、可能性のあるクエリが行われる前に発生します。ほとんどの場合、最初の Application クラスのセットアップ中に発生します。この機会を利用して、ContentProvider ライブラリを使用しているアプリケーションによって提供されるように、AUTHORITY、CONTENT_URI、および UriMatcher を「実際の」値にリセットします。

    @Override
public void attachInfo(Context context, ProviderInfo info) {
    super.attachInfo(context, info);
    AUTHORITY = info.authority;
    CONTENT_URI = Uri.parse("content://" + AUTHORITY);
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(AUTHORITY, AlarmTable.TABLENAME, ALARMS);
    uriMatcher.addURI(AUTHORITY, AttributeTable.TABLENAME, ATTRIBUTES);
    uriMatcher.addURI(AUTHORITY, DeepLinkTable.TABLENAME, DEEPLINKS);
    uriMatcher.addURI(AUTHORITY, NotificationTable.TABLENAME, NOTIFICATIONS);
    uriMatcher.addURI(AUTHORITY, MetaDataTable.TABLENAME, RESOURCE_METADATA);
    uriMatcher.addURI(AUTHORITY, ResourceTable.TABLENAME, RESOURCES);
    uriMatcher.addURI(AUTHORITY, ResourceAttributeTable.TABLENAME, RESOURCES_ATTRIBUTES);
    uriMatcher.addURI(AUTHORITY, ResourceTagTable.TABLENAME, RESOURCES_TAGS);
    uriMatcher.addURI(AUTHORITY, TagTable.TABLENAME, TAGS);
    uriMatcher.addURI(AUTHORITY, UserTagTable.TABLENAME, USER_TAGS);
    uriMatcher.addURI(AUTHORITY, UserTable.TABLENAME, USERS);
    uriMatcher.addURI(AUTHORITY, CUSTOM, RAW);
}

Application が開始されると、ContentProvider は Application クラスとともに実際にインスタンス化されるため、必要なすべてのパッケージ情報にアクセスできます。ProviderInfo オブジェクトには、AndroidManifest で提供される情報が含まれます...最終的なアプリケーションに含まれるリスト。

        <provider android:authorities="com.foo.barapp.content"
              android:name="com.foo.bar.MyContentProvider"/>

Authority はデフォルト値ではなく「com.foo.barapp.content」で書き換えられ、UriMatcher はデフォルト値ではなくアプリケーションの値に更新されます。「AUTHORITY」に依存するクラスは更新された値にアクセスするようになり、UriMatcher は「com.foo.barapp.content」の着信クエリを適切に区別します。

これをサンプル アプリケーションと androidTest パッケージの両方で同時にテストしたところ、正しく動作することがわかりました。

于 2016-08-09T18:41:43.200 に答える