Skonfigurowałem Gradle, aby dodać sufiks nazwy pakietu do mojej aplikacji do debugowania, dzięki czemu mogę mieć wersję używaną przeze mnie i wersję debugowania na jednym telefonie. Odnosiłem się do tego: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types
Mój plik build.gradle wygląda następująco:
...
android
{
...
buildTypes
{
debug
{
packageNameSuffix ".debug"
versionNameSuffix " debug"
}
}
}
Wszystko działa dobrze, dopóki nie zacznę używać ContentProvider w mojej aplikacji. Dostaję:
Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]
Rozumiem, że dzieje się tak, ponieważ dwie aplikacje (wydanie i debugowanie) rejestrują ten sam organ ContentProvider.
Widzę jedną możliwość rozwiązania tego problemu. Jeśli dobrze rozumiem, powinieneś być w stanie określić różne pliki do użycia podczas budowania. Następnie powinienem być w stanie umieścić różne uprawnienia w różnych plikach zasobów (i ustawić uprawnienia w pliku Manifest jako zasób ciągu) i powiedzieć Gradle, aby użył innego zasobu do kompilacji debugowania. Czy to jest możliwe? Jeśli tak, to wszelkie wskazówki, jak to osiągnąć, byłyby niesamowite!
A może można bezpośrednio zmodyfikować Manifest za pomocą Gradle? Każde inne rozwiązanie dotyczące uruchamiania tej samej aplikacji z ContentProvider na jednym urządzeniu jest zawsze mile widziane.
Odpowiedzi:
Żadna z istniejących odpowiedzi mnie nie satysfakcjonowała, jednak Liberty była blisko. Więc tak to robię. Przede wszystkim w tej chwili pracuję z:
Moim celem jest uruchomienie
Debug
wersji razem zRelease
wersją na tym samym urządzeniu przy użyciu tego samegoContentProvider
.W build.gradle sufiksu zestawu aplikacji dla kompilacji debugowania:
W pliku AndroidManifest.xml ustaw
android:authorities
właściwość TwojegoContentProvider
:We właściwości zestawu kodu,
AUTHORITY
której można użyć w dowolnym miejscu w implementacji:Wskazówka: wcześniej
BuildConfig.PACKAGE_NAME
Otóż to! Będzie działać jak urok. Czytaj dalej, jeśli używasz SyncAdapter!
Aktualizacja dla SyncAdapter (14.11.2014)
Jeszcze raz zacznę od mojej obecnej konfiguracji:
Zasadniczo, jeśli chcesz dostosować niektóre wartości dla różnych kompilacji, możesz to zrobić z pliku build.gradle:
BuildConfig.java
klasyAlternatywą dla zasobów jest tworzenie osobnych katalogów buildType lub smaków i nadpisywanie zawartych w nich XML lub wartości. Jednak nie zamierzam tego używać w poniższym przykładzie.
Przykład
W pliku build.gradle dodaj:
Wyniki zobaczysz w klasie BuildConfig.java
oraz w build / generated / res / generated / debug / values / generated.xml
W pliku uwierzytelniającym.xml użyj zasobu określonego w pliku build.gradle
W swojej syncadapter.xml używać tego samego zasobu ponownie @ ŁAŃCUCH / władze zbyt
Wskazówka: autouzupełnianie (Ctrl + spacja) nie działa dla tych wygenerowanych zasobów, więc musisz wpisać je ręcznie
źródło
Nowa wskazówka dotycząca systemu kompilacji Androida: zmiana nazwy organu ContentProvider
Myślę, że wszyscy słyszeliście o nowym systemie kompilacji opartym na Androidzie Gradle. Bądźmy szczerzy, ten nowy system kompilacji to ogromny krok naprzód w porównaniu z poprzednim. Nie jest jeszcze ostateczna (w chwili pisania tego najnowsza wersja to 0.4.2), ale możesz już bezpiecznie używać jej w większości swoich projektów.
Osobiście przerzuciłem większość swojego projektu na nowy system kompilacji i miałem pewne problemy z powodu braku wsparcia w niektórych sytuacjach. Jednym z nich jest obsługa zmiany nazwy uprawnień ContentProvider
Nowy system Android pozwala radzić sobie z różnymi typami aplikacji, po prostu modyfikując nazwę pakietu w czasie kompilacji. Jedną z głównych zalet tego ulepszenia jest to, że teraz możesz mieć dwie różne wersje swojej aplikacji zainstalowane na tym samym urządzeniu w tym samym czasie. Na przykład:
Korzystając z takiej konfiguracji Gradle, możesz zebrać dwa różne pliki APK:
• Plik APK do debugowania z nazwą pakietu com.cyrilmottier.android.app.debug • Wydany plik APK z nazwą pakietu com.cyrilmottier.android.app
Jedynym problemem jest to, że nie będzie można zainstalować dwóch pakietów APK w tym samym czasie, jeśli oba udostępniają dostawcę treści z tymi samymi uprawnieniami. Całkiem logicznie musimy zmienić nazwę uprawnienia w zależności od bieżącego typu kompilacji… ale nie jest to obsługiwane przez system kompilacji Gradle (jeszcze?… Jestem pewien, że wkrótce zostanie to naprawione). Oto sposób:
Najpierw musimy przenieść deklarację ContentProvider manifestu dostawcy dla systemu Android do odpowiedniego typu kompilacji. W tym celu będziemy mieli po prostu:
src / debug / AndroidManifest.xml
src / release / AndroidManifest.xml
Pamiętaj, aby usunąć deklarację ContentProvider z AndroidManifest.xml w src / main /, ponieważ Gradle nie wie, jak scalić ContentProvider o tej samej nazwie, ale z innym uprawnieniem.
Wreszcie może być konieczne uzyskanie dostępu do organu w kodzie. Można to zrobić dość łatwo za pomocą pliku BuildConfig i metody buildConfig:
Dzięki temu obejściu będziesz mógł korzystać z BuildConfig.PROVIDER_AUTHORITY w umowie ProviderContract i jednocześnie zainstalować dwie różne wersje swojej aplikacji.
Oryginał w Google+: https://plus.google.com/u/0/118417777153109946393/posts/EATUmhntaCQ
źródło
Chociaż przykład Cyrila działa świetnie, jeśli masz tylko kilka typów kompilacji, szybko się komplikuje, jeśli masz wiele typów kompilacji i / lub smaków produktów, ponieważ musisz utrzymywać wiele różnych plików AndroidManifest.xml.
Nasz projekt składa się z 3 różnych typów kompilacji i 6 smaków, w sumie 18 wariantów kompilacji, więc zamiast tego dodaliśmy obsługę „.res-auto” w organach ContentProvider, które rozszerzają się do bieżącej nazwy pakietu i eliminują potrzebę utrzymywania różnych plików AndroidManifest.xml
Przykładowy kod można znaleźć tutaj: https://gist.github.com/cmelchior/6988275
źródło
Od wersji wtyczki 0.8.3 (właściwie 0.8.1, ale nie działała poprawnie) możesz zdefiniować zasoby w pliku kompilacji, więc może to być czystsze rozwiązanie, ponieważ nie musisz tworzyć plików ciągów ani dodatkowego debugowania / wydania lornetka składana.
build.gradle
AndroidManifest.xml
źródło
Nie wiem, czy ktoś o tym wspomniał. Właściwie po wtyczce Android Gradle w wersji 0.10+, manifest fuzji zapewni oficjalne wsparcie dla tej funkcji: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger
W AndroidManifest.xml możesz użyć $ {packageName} w ten sposób:
W pliku build.gradle możesz mieć:
Zobacz pełny przykład tutaj: https://code.google.com/p/anymemo/source/browse/AndroidManifest.xml#152
i tutaj: https://code.google.com/p/anymemo/source/browse/build.gradle#41
źródło
Użyj
${applicationId}
symboli zastępczych w XML iBuildConfig.APPLICATION_ID
w kodzie.Będziesz musiał rozszerzyć skrypt kompilacji, aby włączyć symbole zastępcze w plikach xml innych niż manifest. Możesz użyć katalogu źródłowego dla każdego wariantu kompilacji, aby zapewnić różne wersje plików xml, ale konserwacja stanie się bardzo szybko uciążliwa.
AndroidManifest.xml
Możesz użyć symbolu zastępczego applicationId po wyjęciu z pola w manifeście. Zadeklaruj swojego dostawcę w ten sposób:
Zwróć uwagę na
${applicationId}
trochę. Jest on zastępowany w czasie kompilacji przez rzeczywisty identyfikator aplikacji dla budowanego wariantu kompilacji.W kodzie
Twój dostawca treści musi skonstruować ciąg autoryzacji w kodzie. Może używać klasy BuildConfig.
Zwróć uwagę na
BuildConfig.APPLICATION_ID
trochę. Jest to wygenerowana klasa z rzeczywistym identyfikatorem applicationId dla budowanego wariantu kompilacji.res / xml / files, np. syncadapter.xml, accountauthenticator.xml
Jeśli chcesz użyć adaptera synchronizacji, musisz podać metadane dla ContentProvider i AccountManager w plikach xml w katalogu res / xml /. Symbol zastępczy applicationId nie jest tutaj obsługiwany. Ale możesz samodzielnie rozszerzyć skrypt kompilacji, aby go zhakować.
Ponownie zwróć uwagę na
${applicationId}
. Działa to tylko wtedy, gdy dodasz poniższy skrypt gradle do katalogu głównego modułu i zastosujesz go z pliku build.gradle.build.gradle
Zastosuj dodatkowy skrypt kompilacji ze skryptu build.gradle modułu. Dobre miejsce znajduje się pod wtyczką Android Gradle.
build-processApplicationId.gradle
Poniżej znajduje się działające źródło skryptu kompilacji res / xml / placeholder. Lepiej udokumentowana wersja jest dostępna na github . Ulepszenia i rozszerzenia są mile widziane.
Strings.xml
Moim zdaniem nie ma potrzeby dodawania zastępczej obsługi ciągów zasobów. Przynajmniej w powyższym przypadku nie jest to potrzebne. Jednak można łatwo zmienić skrypt, aby nie tylko zastępował symbole zastępcze w katalogu res / xml /, ale także w katalogu res / values /.
źródło
Wolałbym raczej mieszankę Cyrila i rciovati. Myślę, że jest prostszy, masz tylko dwie modyfikacje.
Do
build.gradle
wygląda następująco:Oraz
AndroidManifest.xml
:źródło
gradle.build
autentykator.xml
sync_adapter.xml
AndroidManifest.xml
Kod:
źródło
Na podstawie próbki autorstwa @ChristianMelchior, oto moje rozwiązanie, które rozwiązuje dwa problemy z poprzednich rozwiązań:
rozwiązania, które zmieniają values.xml w katalogu kompilacji, powodują pełną przebudowę zasobów (w tym aapt wszystkich drawables)
z nieznanego powodu IntelliJ (i prawdopodobnie Android Studio) nie przetwarza niezawodnie zasobów, przez co kompilacja zawiera niezmienione
.res-auto
uprawnienia dostawcyTo nowe rozwiązanie działa bardziej w sposób Gradle, tworząc nowe zadanie i pozwala na przyrostowe kompilacje poprzez definiowanie plików wejściowych i wyjściowych.
utwórz plik (w przykładzie umieściłem go w
variants
katalogu), sformatowany jak plik zasobów xml, który zawiera zasoby ciągów. Zostaną one scalone z zasobami aplikacji, a każde wystąpienie.res-auto
w wartościach zostanie zastąpione na przykład nazwą pakietu wariantu<string name="search_provider">.res-auto.MySearchProvider</string>
dodaj
build_extras.gradle
plik z tej treści do swojego projektu i odwołaj się do niego z głównegobuild.gradle
, dodającapply from: './build_extras.gradle'
gdzieś nadandroid
blokiemupewnij się, że ustawiłeś domyślną nazwę pakietu, dodając ją do
android.defaultConfig
blokubuild.gradle
in
AndroidManifest.xml
i inne pliki konfiguracyjne (na przykładxml/searchable.xml
dla dostawców wyszukiwania automatycznego uzupełniania), należy odwołać się do dostawcy (na przykład@string/search_provider
)jeśli potrzebujesz uzyskać taką samą nazwę, możesz
BuildConfig.PACKAGE_NAME
na przykład użyć zmiennejBuildConfig.PACKAGE_NAME + ".MySearchProvider"
https://gist.github.com/paour/9189462
Aktualizacja: ta metoda działa tylko w systemie Android 2.2.1 i nowszych. W przypadku wcześniejszych platform zobacz tę odpowiedź , która ma swój własny zestaw problemów, ponieważ nowe manifestacyjne połączenie jest nadal bardzo szorstkie na krawędziach…
źródło
variants/res-auto-values.xml
odniesieniu do/Applications/Android Studio.app/bin/
. tj. nie otrzymuję wyjątku FileNotFoundException dla/Applications/Android Studio.app/bin/variants/res-auto-values.xml
. Biegam na Macu. To świetne rozwiązanie, ale chciałbym, aby działało w IDE dla innych członków zespołu.System.getProperty("user.dir")
, co zwraca inny wynik po wywołaniu przez kompilację Android Studio. Rozwiązaniem jest użycie ścieżki względnej do katalogu projektu, który jest zwracany zgradle.startParameter.getProjectDir()
. Zobacz także mój komentarz w powiązanej treści Paoura.Napisałem post na blogu z przykładowym projektem Githuba, który traktuje ten problem (i inne podobne problemy) w nieco inny sposób niż Cyril.
http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html
źródło
Niestety, obecna wersja (0.4.1) wtyczki Androida nie wydaje się być dobrym rozwiązaniem. Nie miałem czasu, aby spróbować tego jeszcze, ale możliwe obejście tego problemu byłoby wykorzystanie zasobu ciąg
@string/provider_authority
i użyć jej w manifeście:android:authority="@string/provider_authority"
. Wres/values/provider.xml
folderze res każdego typu kompilacji masz wtedy plik, który powinien nadpisywać uprawnienia, w twoim przypadku tak będziesrc/debug/res
Rozejrzałem się nad generowaniem pliku xml w locie, ale znowu wydaje się, że w obecnej wersji wtyczki nie ma dla niego żadnych dobrych punktów zaczepienia. Poleciłbym jednak zgłosić prośbę o funkcję, wyobrażam sobie, że więcej osób napotka ten sam problem.
źródło
Odpowiedź w tym poście mi odpowiada.
http://www.kevinrschultz.com/blog/2014/03/23/using-android-content-providers-with-multiple-package-names/
Używam 3 różnych smaków, więc tworzę 3 manifesty z dostawcami treści dla każdego smaku, jak powiedział Kevinrschultz:
Twój główny manifest nie obejmuje dostawców:
I twój manifest w każdym twoim smaku, w tym dostawcy.
Wolny:
Płatny:
Inny:
źródło
Dlaczego po prostu tego nie dodać?
źródło
Moje rozwiązanie polega na użyciu zastępowania symboli zastępczych w programie
AndroidManifest.xml
. Obsługuje równieżpackageNameSuffix
atrybuty, dzięki czemu możesz mieć,debug
arelease
także inne niestandardowe kompilacje na tym samym urządzeniu.Mam to na
gist
też, jeśli chcesz zobaczyć, czy rozwinie się później.Okazało się, że jest to bardziej eleganckie podejście niż podejście do wielu zasobów i analizowania XML.
źródło