Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android duplicate provider authority problem

We're trying to publish a pay ad-free version of a casual app that's currently published free with ads. We refactored all package names to com.mycompanyname.appname.pro, the free one on market doesn't have the .pro at the end, basically. We also went into our content provider and changed the authority to the same as the package name. So the "free version" has

AUTHORITY = "com.mycompanyname.appname" 

and the "ad-free pay version has

AUTHORITY = "com.mycompanyname.appname.pro" 

but still we are unable to install both the free and the "pro" version on the same device. For whatever it's worth, the class name for the provider is the same in both apps.

We can't install from an apk directly, and if we try to download from Android market we get a "duplicate provider authority" error message.

What are we missing? Is there another place we need to look for problems, or have we got something fundamentally wrong here?

like image 834
thefish7 Avatar asked Jun 21 '11 03:06

thefish7


People also ask

What is the use of android authorities?

android:authorities A list of one or more URI authorities that identify data offered by the content provider. Multiple authorities are listed by separating their names with a semicolon. To avoid conflicts, authority names should use a Java-style naming convention (such as com.example.provider.cartoonprovider).

What is an Android content provider authority string?

The Android system stores references to content providers according to an authority string, part of the provider's content URI. For example, suppose you want to access a content provider that stores information about health care professionals.

Should I declare content providers in my Android application?

You only declare content providers that are part of your application. Content providers in other applications that you use in your application should not be declared. The Android system stores references to content providers according to an authority string, part of the provider's content URI.

How are multiple authorities listed in a contentprovider?

Multiple authorities are listed by separating their names with a semicolon. To avoid conflicts, authority names should use a Java-style naming convention (such as com.example.provider.cartoonprovider ). Typically, it's the name of the ContentProvider subclass that implements the provider


2 Answers

Basically what I did is, create an abstract base class for each of my ContentProviders and inherit from that for each app I want to make, overriding the authority path. So in my AbstractContentProvider I have:

public AbstractContentProvider() {
    sURIMatcher.addURI(getAuthority(), BASE_PATH, ITEMS);
    sURIMatcher.addURI(getAuthority(), BASE_PATH + "/#", ITEM_ID);
}

protected abstract String getAuthority();

and then in each subclass I have:

private static final String AUTHORITY = "my.package.app1.ContentProvider";

@Override
protected String getAuthority() {
    return AUTHORITY;
}

In the AndroidManifest I register these with:

    <provider
          android:name="my.package.app1.ContentProvider"
          android:authorities="my.package.app1.ContentProvider">
    </provider>

Now the trick is, I want to access these content providers in common (library) code, that doesn't know about the app specific classes. To do that, I define a String in my strings.xml, that I override for each app. Then I can use:

Uri.parse(getString(R.string.contentProviderUri))

and in every app the right ContentProvider is used without any conflicts. So basically using the configuration mechanism for dependency injection.

like image 93
koljaTM Avatar answered Oct 01 '22 20:10

koljaTM


Lets say your library package is com.android.app.library free package is com.android.app.free paid package is com.android.app.paid

In your free project and paid project, make an identical file in a package which can be anything, but must be the same.

Example:

  1. Create a new package in your free version with com.android.app.data

  2. Create a file called Authority.java and inside (Authority.java) put:

    public class Authority {

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

    }

  3. Repeat this for the paid version, remember to keep the package name the same and class name.

Now, in your contract file, in your library use the following:

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);

Now you should be able to use two authorities.

Credit: Ian Warick Android - Having Provider authority in the app project

like image 37
Jerryl15 Avatar answered Oct 01 '22 19:10

Jerryl15