Jak zatrzymać Xcode 11 przed zmianą CFBundleVersion i CFBundleShortVersionString na $ (CURRENT_PROJECT_VERSION) i $ (MARKETING_VERSION)?

14

Od wersji 11 Xcode ustawia moją CFBundleVersionwartość na $(CURRENT_PROJECT_VERSION)i moją CFBundleShortVersionStringwartość, $(MARKETING_VERSION)ilekroć wprowadzę wartości wersji lub kompilacji w ustawieniach docelowych (karta „Ogólne”).

Rzeczywiste wartości wersji i kompilacji, które wprowadzam, są teraz przechowywane w pliku project.pbxproj. Nie chcę ani nie podoba mi się to zachowanie, ponieważ używam skryptów powłoki do modyfikowania wartości podczas kompilacji.

Mogę ręcznie ustawić prawidłowe wartości w pliku Info.plist, ale jak tylko zmienię numery wersji lub kompilacji w ustawieniach docelowych, plik Info.plist zostanie ponownie zmieniony przez Xcode.

Jak powstrzymać Xcode 11 przed zrobieniem tego?

Po zmodyfikowaniu skryptu kompilacji w celu zmiany samego pliku projektu Xcode natychmiast anuluje kompilację, gdy tylko plik projektu zostanie zmieniony.

Pan Zystem
źródło
Dlaczego chcesz, aby Xcode 11 przestał to robić, zamiast modyfikować skrypt powłoki w celu odzyskania wartości?
Manuel
1
@Manuel Myślę, że modyfikowanie listy odtwarzania plistbuddyjest miłe i czyste, podczas gdy modyfikowanie pliku projektu jest znacznie bardziej niechlujne, zawodne i podatne na nieoczekiwane zmiany formatu pliku.
Pan Zystem
1
Manipulowanie plikiem project.pbxproj nie jest bałaganiarskie, gdy rozumiesz format pliku. Jest to po prostu dobrze udokumentowany plist w stylu Next. Możesz nawet zmodyfikować plik za pomocą Plistbuddy, jest on zgodny z tym formatem.
Manuel
Zaktualizowałem swoją odpowiedź, sugerując przypadek użycia.
Manuel

Odpowiedzi:

1

Droga do tej pory

Mój przypadek użycia był taki:

  1. Synchronizuję wersję i numery wersji między kilkoma celami.
  2. Synchronizuję wersję i numery kompilacji z celami Settigns.bundle
  3. Czytam i modyfikuję numer kompilacji z serwera CI.

Kiedyś wykonywałem punkt 1 i 2 jako docelowy skrypt kompilacji, a punkt 3 jako skrypt niestandardowy w samym CI.

Nowy sposób przechowywania wersji i kompilacji w ustawieniach kompilacji Xcode powodował problemy ze skryptami, ponieważ nie były one już w stanie skutecznie modyfikować wartości. Możliwe było przynajmniej czytanie.

Niestety nie byłem w stanie odkryć prawidłowego sposobu zapobiegania przechowywaniu przez Xcode wersji i numerów kompilacji w ustawieniach kompilacji projektu, jednak udało mi się stworzyć obejście.

Okazuje się, że przy tworzeniu kompilacji lub archiwum Info.plistużywana jest wartość zapisana w . Oznacza to, że wartość jest zastępowana w czasie kompilacji, co nie pozwala nam jej modyfikować w tym samym czasie kompilacji.

Próbowałem również zmodyfikować projekt przy użyciu xcodeprojcli, jednak wszelkie zmiany w projekcie powodowały zatrzymanie wszelkich kompilacji, więc to rozwiązanie nie działało.

W końcu, po wielu różnych podejściach, które wypróbowałem, w końcu udało mi się znaleźć kompromis, który nie naruszał nowego zachowania Xcode.

Krótka odpowiedź:

Jako cel przed działaniem wykonywany jest skrypt, który zapisuje odpowiednie wartości do CFBundleShortVersionStringi CFBundleVersiondo celuInfo.plist

Jako źródło prawdy używam ustawień kompilacji Xcode do odczytywania wartości MARKETING_VERSIONi CURRENT_PROJECT_VERSIONpożądanego celu.

W ten sposób, gdy zmodyfikujesz wartości z ustawień projektu - przy następnym kompilacji / archiwum - zostaną one zapisane w Info.plist, pozwalając na dowolne, jeśli twoja logika skryptowa będzie dalej działać.

Szczegółowa odpowiedź

Jedynym sposobem modyfikacji zasobu po akcji kompilacji jest użycie pre-actionskryptu. Jeśli spróbujesz to zrobić ze skryptu kompilacji - zmiany nie zostaną zastosowane natychmiast i nie będą obecne na końcu kompilacji / archiwum.

Aby dodać akcję przed kompilacją - przejdź do schematu edycji.

wprowadź opis zdjęcia tutaj

Następnie rozwiń sekcje Kompilacja i Archiwum. Poniżej Pre-actionkliknij Provide build and settings frommenu rozwijane i wybierz źródło prawdy, z którego chcesz odczytać wartości.

wprowadź opis zdjęcia tutaj

Dodaj następujący skrypt:

# 1) 
cd ${PROJECT_DIR}

# 2) 
exec > Pruvit-Int.prebuild.sync_project_version_and_build_with_info_plists.log 2>&1

# 3) 
./sync_project_version_and_build_with_info_plists.sh $MARKETING_VERSION $CURRENT_PROJECT_VERSION

Linie kreski wykonują następujące czynności:

  1. Przejdź do katalogu, w którym znajduje się skrypt synchronizacji, aby go wykonać
  2. Pozwala na zapisanie dziennika podczas akcji wstępnej, w przeciwnym razie dane wyjściowe są domyślnie wyciszane
  3. Uruchom skrypt synchronizacji, podając MARKETING_VERSIONiCURRENT_PROJECT_VERSION

Ostatnim krokiem jest napisanie własnego skryptu synchronizacji, który odczytuje wartości podanego MARKETING_VERSIONi CURRENT_PROJECT_VERSIONodpowiedniego celu / ów i kiedy tylko chcesz.

W moim przypadku skrypt jest następujący:

#!/bin/bash

#IMPORTANT - this script must run as pre-action of each target's Build and Archive actions

version_number=$1
build_number=$2

echo "version_number is $version_number"
echo "build_number is $build_number"

#update Pruvit/Info.plist
pruvitInfoPlist="Pruvit/Info.plist"
/usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $version_number" $pruvitInfoPlist
/usr/libexec/PlistBuddy -c "Set CFBundleVersion $build_number" $pruvitInfoPlist

#update Pruvit/Settings.bundle
settingsPlist="Pruvit/Settings.bundle/Root.plist"
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version_number" $settingsPlist
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $build_number" $settingsPlist

#update BadgeCounter/Info.plist
badgeCounterInfoPlist="BadgeCounter/Info.plist"
/usr/libexec/PlistBuddy -c "Set CFBundleShortVersionString $version_number" $badgeCounterInfoPlist
/usr/libexec/PlistBuddy -c "Set CFBundleVersion $build_number" $badgeCounterInfoPlist

Używam współdzielonych Info.plisti Settings.bundlemiędzy dwoma celami mojej aplikacji, więc muszę to zaktualizować raz.

Używam również rozszerzenia usługi powiadomień BadgeCounter, które musi mieć tę samą wersję i kompilację, co obiekt docelowy, w którym jest osadzone. Więc aktualizuję to również.

KoCMoHaBTa
źródło
1

Nie rób

Przypuszczalnie istnieje powód, dla którego to zachowanie się zmieniło. Jeśli późniejsze funkcje Xcode opierają się na tym zachowaniu, rzeczy stają się coraz bardziej „konstruowane” wzdłuż linii.

Zamiast próbować zginać Xcode, zmień sposób, w jaki skrypt kompilacji pobiera te wartości:

Jak czytać aktualną wersję aplikacji w Xcode 11 ze skryptem

Jeśli chcesz zmanipulować project.pbxprojplik, jest to dobrze udokumentowana lista stylów Next. Możesz użyć, plistbuddyktóry jest zgodny z tym starym formatem. Możesz także używać awkz większą liczbą skryptów, jeśli masz bardziej złożone manipulacje.

Jeśli rozumiem twój przypadek użycia, możesz napisać skrypt, który otrzyma najwyższe numery wersji, awka następnie zaktualizuje wszystkie niższe numery wersji, które może znaleźć w pliku sed.

Manuel
źródło
wypisywanie wartości z PlistBuddy wydaje się działać dobrze, ale kiedy używam setpolecenia, cały projekt.pbxproj zostaje przekonwertowany na plik XML .plist i nie może być już odczytany przez Xcode. przykład:PlistBuddy -c "Set :objects:$configurationId:buildSettings:CURRENT_PROJECT_VERSION $newProjectVersion" "$projectFile"
Pan Zystem
W zależności od tego, co dokładnie chcesz osiągnąć, być może będziesz musiał użyć kombinacji narzędzi
Manuel
Ponowne uruchomienie Xcode naprawiło problem XML. Als stwierdził, że po uruchomieniu skryptu kompilacji, który zmienia pbxprojplik, anuluje kompilację. Obawiam się, że to tak naprawdę nie zadziała.
Pan Zystem
Zaktualizowałem swoje oryginalne pytanie o powyższe informacje.
Pan Zystem
1
Na przykład - moim przypadkiem użycia jest zsynchronizowanie wersji i kompilacja między wieloma celami - chciałbym ustawić wersję i kompilację na pierwszy cel, który zostanie automatycznie zaktualizowany do wszystkich innych. Wcześniej działało to dobrze, ponieważ po prostu modyfikujesz zasób. Teraz nie mogę modyfikować projektu podczas fazy kompilacji dowolnego celu, ponieważ kompilacja zostaje anulowana.
KoCMoHaBTa