Multiple Applications Use the Same Content Provider

I am developing a set of applications that differ only in certain branding (I think different sports teams); however, I ran into a problem when I use one library project for all specially branded applications and want to use the same ContentProvider for all of them. When I created the ContentProvider, I declared AUTHORITY as a constant in the class (for example, sample code), and I use the same authority in every specific application in the manifest files. It seems that I can not use the same authority for each application, because I get this error when trying to install the second application (I install one branded only fine, and install the second):

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

I tried several approaches, but none of them seem to work. One idea that I have not yet done was to create a jar library and just omit the Provider class that I have and configure it in each specific application. Any ideas on how to get around this problem without resorting to this?

+27
android android-contentprovider
Jul 22 '10 at 7:28
source share
5 answers

ContentProviders are identified by authority, so it must be unique. I don’t think there are any tricks in this.

In addition, there is an error in the Android platform that also prevents the use of the same class name for two different ContentProviders, even if they have different permissions and are contained in separate APKs. See here the error.

The solution that I advise you is to create an abstract provider class in the library project, and then expand it with a unique name in each individual application. For this, you probably need to create a script to create / modify individual manifest and contentprovider classes.

Hope this helps.

+17
May 27 '11 at 21:06
source share

This is an old question, but I was looking at doing something similar recently. With Build Flavors, it is really right now.

Specify BuildConfigField in the gradle file:

  productFlavors { free { applicationId "com.example.free" buildConfigField 'String', 'AUTHORITY', '"com.example.free.contentprovider"' } paid { applicationId "com.example.paid" buildConfigField 'String', 'AUTHORITY', '"com.example.paid.contentprovider"' } 

Specify vendor authority in the manifest:

  <provider android:name=".ContentProvider" android:authorities="${applicationId}.contentprovider" /> 

Set provider privileges using the BuildConfigField variable:

  public static final String AUTHORITY = BuildConfig.AUTHORITY 
+8
Aug 20 '16 at 22:32
source share

Let's say your library package com.android.app.library free package com.android.app.free paid package com.android.app.paid

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

Example:

  • Create a new package in your free version using com.android.app.data p>

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

    public class Authority {

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

    }

  • Repeat this for the paid version, do not forget to leave the package name the same and the 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); 

You should now be able to use two organs.

Credit: Jan Varick (write the code) Android - availability of provider privileges in the application project Disclaimer: I also posted it here: Problem with dual powers of the Android provider - Not sure if it is allowed to answer the same question with the same answer.

+4
Jan 12
source share

The following method can be used to package the ContentProvider in the library and set ContentProvider permissions at runtime so that it can be included in several projects without a ContentProvider Authority conflict. This works because the real "authority" comes from AndroidManifest ... not the ContentProvider class.

Start with the main implementation of ContentProvider. AUTHORITY, CONTENT_URI and UriMatcher are static, but not "final" ....

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

Then override the 'attachInfo' method so that the first time you initialize the ContentProvider, your ContentProvider is called using ProviderInfo, which is derived from AndroidManifest. This will happen before any possible requests are made, most likely during the initial setup of the application class. Use this feature to reset AUTHORITY, CONTENT_URI and UriMatcher for their "real" values, as provided by the application using the ContentProvider library.

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

When the application is launched, the ContentProvider is actually created along with the Application class, so it will have access to all the necessary information about the package. the ProviderInfo object will contain the information presented in AndroidManifest ... A list included in the final application.

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

Now the administrator will be rewritten using "com.foo.barapp.content" instead of the default value, and UriMatcher will be updated to the application value, and not by default. Classes that rely on "AUTHORITY" will now access the updated value, and UriMatcher will correctly distinguish between incoming requests for "com.foo.barapp.content".

I tested this with both the sample application and the androidTest package at the same time and found that it worked correctly.

+1
Aug 09 '16 at 18:41
source share

YOU CAN!

As said in this post (explains how Firebase initializes its library without providing context from your Application#onCreate() method), you can use a placeholder in your manifest, for example:

  <provider android:authorities="${applicationId}.yourcontentprovider" android:name=".YourContentProvider" /> 
+1
Jan 31 '17 at 18:11
source share



All Articles