Имеем:
- использование BuildVariants ( Build Types и/или Product Flavors) для создания разных версий приложения с одной кодовой базой (проектом)
- использование ContentProvider (например, FileProvider или SuggestionsProvider), описанного в манифесте
Получаем:
При попытке установки 2-х разных версий приложения на одном устройстве получаем ошибку:
1 2 3 |
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 у нас есть:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
android { defaultConfig { applicationId "com.example.myapp" } productFlavors { free { applicationIdSuffix ".free" } pro { applicationIdSuffix ".pro" } } } |
Теперь в манифесте у ContentProvider можно указать:
1 2 3 4 |
<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 тоже нужно сделать уникальным:
1 2 3 |
<provider android:name=".MySuggestionProvider" android:authorities="${applicationId}.MySuggestionProvider"/> |
В коде:
1 2 3 |
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 со строкой:
1 |
<string name="search_suggest_authorities" translatable="false">com.example.myapp.free.MySuggestionProvider</string> |
- файл /src/pro/res/values/string.xml с аналогичной строкой, только с pro вместо free.
Файл searchable.xml теперь должен выглядеть так:
1 2 3 |
<searchable ... android:searchSuggestAuthority="@string/search_suggest_authorities"/> |