BuildVariants, ContentProvider и authorities (Android)

Имеем:

  • использование BuildVariants (Build Types и/или Product Flavors) для создания разных версий приложения с одной кодовой базой (проектом)
  • использование ContentProvider (например, FileProvider или SuggestionsProvider), описанного в манифесте

Получаем:

При попытке установки 2-х разных версий приложения на одном устройстве получаем ошибку:

Installation did not succeed.
The application could not be installed: INSTALL_FAILED_CONFLICTING_PROVIDER
Installation failed due to: 'null'


Причина

У ContentProvider есть атрибут authorities, который должен быть уникальным для всех установленных приложений на устройстве. Но при использовании BuildVariants этот уникальный идентификатор становится в системе уже “не таким уникальным”, как хотелось бы. Нужно это исправить.

Варианты решения проблемы:

1) в поле authorities можно добавить динамически формируемый идентификатор приложения ${applicationId}.

Допустим, в build.gradle у нас есть:

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

Теперь в манифесте у ContentProvider можно указать:

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

Для получения текущего идентификатора приложения в коде можно использовать автоматически генерируемую константу BuildConfig.APPLICATION_ID.

2) для каждого BuildVariant можно использовать (переопределить) свой файл манифеста.

Например:

  • /src/main/AndroidManifest.xml – манифест “по-умолчанию” (нужен обязательно)
  • /src/free/AndroidManifest.xml – для версии com.example.myapp.free
  • /src/pro/AndroidManifest.xml – для версии com.example.myapp.full

В каждом манифесте прописываем свой уникальный идентификатор authoriries.


Примечание

Если в манифесте, кроме FileProvider, используется и SuggestionProvider (например, SearchRecentSuggestionsProvider), то его authorities тоже нужно сделать уникальным:

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

В коде:

public final static String AUTHORITY = BuildConfig.APPLICATION_ID + ".MySuggestionProvider";
...
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(context, AUTHORITY, MODE);

При этом, в searchable.xml атрибут searchSuggestAuthority должен совпадать с атрибутом authorities из манифеста. Но в нем нельзя использовать свойство ${applicationId}, т.к. это уже обычный ресурсный файл, а не файл манифеста или файл сборки проекта (типа build.gradle).

Для этого идентификаторы каждой версии приложения можно сохранить в виде строки в  отдельных string.xml. Например, создать:

  • файл /src/fre/res/values/string.xml со строкой:
<string name="search_suggest_authorities" translatable="false">com.example.myapp.free.MySuggestionProvider</string>
  • файл /src/pro/res/values/string.xml с аналогичной строкой, только с pro вместо free.

Файл searchable.xml теперь должен выглядеть так:

<searchable
    ...
    android:searchSuggestAuthority="@string/search_suggest_authorities"/>

Добавить комментарий

Ваш адрес email не будет опубликован.