Search code examples
c#xamarinxamarin.formsxamarin.androidandroid-contentprovider

ContentResolver does not see the ContentProvider URI in another application


I have 2 Xamarin Forms applications. One of them implements ContentProvider and in the other one I use ContentResolver. On Android version 10 (API 29) Everything works without problems, however on later versions (I tested on 12.1 and 14) - the application in which ContentResolver gives the following error: Java.Lang.IllegalArgumentException: 'Unknown URL content://com.nts.user_screen_provider/products' Here is the provider code:

[ContentProvider(new string[] {AUTHORITIES}, Exported = true)]
public class ProductProvider : ContentProvider
{
    public const string NAME = "ProductProvider";
    public const string PRODUCT_PATH = "products";
    public const string AUTHORITIES = "com.nts.user_screen_provider";
    public static readonly Android.Net.Uri PRODUCTS_URI = Android.Net.Uri.Parse("content://" + AUTHORITIES + "/" + PRODUCT_PATH);
    public const int PRODUCTS_URI_ID = 1;
    UriMatcher uriMatcher;
    public static class ColumnNames
    {
        public const string Name = "Name";
        public const string Price = "Price";
        public const string Weight = "Weight";
        public const string Barcode = "Barcode";
        public const string Type = "Type";
    }
    public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)
    {
        System.Diagnostics.Debug.WriteLine("Insert provider");
        int uriType = uriMatcher.Match(uri);
        int id = 0;
        switch (uriType)
        {
        case PRODUCTS_URI_ID:
            id = IndexOf(values);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        Context.ContentResolver.NotifyChange(uri, null);
        return Android.Net.Uri.Parse(PRODUCTS_URI + "/" + id.ToString());
    }

    public int IndexOf(ContentValues values)
    {
        int result = -1;
        string name = (string)values.Get(ColumnNames.Name);
        string priceS = (string)values.Get(ColumnNames.Price);
        string weightS = (string)values.Get(ColumnNames.Weight);
        string barcodeS = (string)values.Get(ColumnNames.Barcode);
        string typeS = (string)values.Get(ColumnNames.Type);
        double price = 0;
        double weight = 0;
        long barcode = 0;
        if (!double.TryParse(priceS, out price) || !double.TryParse(weightS, out weight) || !long.TryParse(barcodeS, out barcode)) return result;
        Product.CountType type = 0;
        try
        {
            type = typeS switch
            {
                "Counted" => Product.CountType.Counted,
                "Weighted" => Product.CountType.Weighted,
                _ => throw new NotImplementedException()
            };
        }
        catch { return result; }
        result = AppManager.UserPage.AddProductInt(name, price, weight, barcode, type);
        return result;
    }
    //implement other ovveride voids
 }

ContentResolver:

public class ProductSender : IProductSender
{
    public const string NAME = "ProductProvider";
    public const string PRODUCT_PATH = "products";
    public const string AUTHORITIES = "com.nts.user_screen_provider";
    public static readonly Android.Net.Uri PRODUCTS_URI = Android.Net.Uri.Parse("content://" + AUTHORITIES + "/" + PRODUCT_PATH);
    public void Add(Product product)
    {
        ContentResolver resolver = Android.App.Application.Context.ContentResolver;
        ContentValues values = new ContentValues();
        values.Put("Name", product.Name);
        values.Put("Price", product.Price.ToString());
        values.Put("Weight", product.Weight.ToString());
        values.Put("Barcode", product.Barcode.ToString());
        values.Put("Type", product.Type.ToString());

        Android.Net.Uri uri = resolver.Insert(PRODUCTS_URI, values);
    }
}

First app AndroidManifest:

<application android:label="UserScreen.Android" android:theme="@style/MainTheme" android:icon="@mipmap/icon">
  <service android:name=".user_screen_service" />
  <provider 
    android:name="com.nts.user_screen.ProductProvider"
    android:authorities="com.nts.user_screen_provider"
    android:enabled="true"
    android:exported="true"
    android:grantUriPermissions="true"
    android:readPermission="android.permission.BIND_DIRECTORY_SEARCH" 
    android:writePermission="true"
    />
</application>

Seckond:

<application android:label="TestProductDataBase.Android" android:theme="@style/MainTheme" android:icon="@mipmap/icon"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />

I've tried adding and changing permissions in AndroidManifest - no luck, tested on other devices (Android 10 - works, Android 14 - doesn't work).


Solution

  • I replaced the namespace of the class implementing the ContentProvider with this

    namespace com.nts.user_screen 
    {
        [ContentProvider(new string[] {AUTHORITIES}, Exported = true)]
        public class ProductProvider : ContentProvider
        {
            //...