¿Cómo evitar que Xcode 11 cambie CFBundleVersion y CFBundleShortVersionString a $ (CURRENT_PROJECT_VERSION) y $ (MARKETING_VERSION)?

14

Desde la versión 11, Xcode establece mi CFBundleVersionvalor $(CURRENT_PROJECT_VERSION)y mi CFBundleShortVersionStringvalor $(MARKETING_VERSION)cada vez que ingreso los valores de Versión o Compilación en la configuración de destino (pestaña "General").

La versión real y los valores de compilación que ingreso ahora se almacenan en el archivo project.pbxproj. No quiero o me gusta este comportamiento, ya que uso scripts de shell para modificar los valores en tiempo de compilación.

Puedo configurar manualmente los valores correctos en el archivo Info.plist, pero tan pronto como cambio los números de Versión o Compilación en la configuración de destino, Xcode vuelve a cambiar el archivo Info.plist.

¿Cómo evito que Xcode 11 haga esto?

Cuando modifique mi script de compilación para cambiar el archivo del proyecto en sí, Xcode cancelará inmediatamente la compilación tan pronto como se cambie el archivo del proyecto.

Sr. Zystem
fuente
¿Por qué querrías que Xcode 11 dejara de hacer esto, en lugar de modificar tu script de shell para recuperar el valor?
Manuel
1
@Manuel Creo que modificar un plist usando plistbuddyes agradable y limpio, mientras que modificar el archivo del proyecto es mucho más desordenado, poco confiable y propenso a cambios inesperados en el formato del archivo.
Sr. Zystem
1
Manipular el archivo project.pbxproj no es complicado cuando comprende el formato del archivo. Es solo una lista de estilo Next que está bien documentada. Incluso puede modificar el archivo con plistbuddy, es compatible con este formato.
Manuel
Actualicé mi respuesta con una sugerencia para su caso de uso.
Manuel

Respuestas:

1

El camino hasta ahora

Mi caso de uso fue que:

  1. Estoy sincronizando la versión y los números de compilación en varios objetivos.
  2. Estoy sincronizando la versión y los números de compilación con los del objetivo Settigns.bundle
  3. Estoy leyendo y modificando el número de compilación de un servidor CI.

Solía ​​ejecutar los puntos 1 y 2 como un script de compilación de destino y el punto 3 como un script personalizado en el propio CI.

La nueva forma de almacenar la versión y la compilación dentro de la configuración de compilación de Xcode estaba causando problemas con los scripts, porque ya no podían modificar efectivamente los valores. Al menos la lectura era posible.

Desafortunadamente, no pude descubrir una forma legítima de evitar que Xcode almacene la versión y los números de compilación en la configuración de compilación del proyecto, sin embargo, he logrado crear una solución alternativa.

Resulta que cuando se crea una compilación o un archivo, Info.plistse utiliza el valor escrito en el . Esto significa que el valor se sustituye durante el tiempo de construcción, lo que no nos permite modificarlo durante el mismo tiempo de construcción.

También intenté modificar el proyecto usando xcodeproj cli, sin embargo, cualquier cambio en el proyecto causó que las compilaciones se detuvieran, por lo que esta solución no funcionaba.

Finalmente, después de muchos enfoques diferentes que probé, finalmente logré encontrar un compromiso que no estaba violando el nuevo comportamiento del Xcode.

Respuesta corta:

Como acción previa del objetivo, se ejecuta un script que escribe los valores respectivos en CFBundleShortVersionStringy CFBundleVersionpara el objetivoInfo.plist

Como fuente de verdad, uso la configuración de compilación de Xcode para leer los valores de MARKETING_VERSIONyCURRENT_PROJECT_VERSION de la meta deseada.

De esta manera, cuando modifique los valores de la configuración del proyecto, en la próxima compilación / archivo, se escribirán en el Info.plist , permitiendo que su lógica de secuencias de comandos existente continúe funcionando.

Respuesta detallada

La única forma de modificar un recurso en una acción de compilación es mediante un pre-actionscript. Si intenta hacerlo desde un script de compilación, los cambios no tendrán efecto de inmediato y no estarán presentes al final de la compilación / archivo.

Para agregar una acción previa a la construcción, vaya al esquema de edición.

ingrese la descripción de la imagen aquí

Luego expanda las secciones Construir y Archivar. Debajo Pre-action, haga clic en el Provide build and settings frommenú desplegable y seleccione la fuente del objetivo de verdad desde el que desea leer los valores.

ingrese la descripción de la imagen aquí

Agregue el siguiente script:

# 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

Las líneas de script hacen lo siguiente:

  1. Vaya al directorio donde se encuentra el script de sincronización para ejecutarlo
  2. Permite que se escriba un registro durante la acción previa; de lo contrario, cualquier salida se silencia de forma predeterminada
  3. Ejecute el script de sincronización proporcionando el MARKETING_VERSIONyCURRENT_PROJECT_VERSION

El último paso es escribir su propio guión de sincronización que lee los valores de la prevista MARKETING_VERSIONyCURRENT_PROJECT_VERSION al objetivo / s respectivo y siempre que lo desee.

En mi caso, el script es el siguiente:

#!/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

Uso compartido Info.plisty Settings.bundleentre mis dos objetivos de aplicación, así que tengo que actualizar esto una vez.

También uso una extensión de servicio de notificación BadgeCounter, que tiene que tener exactamente la misma versión y compilación que el objetivo en el que está incrustado. Así que actualizo esto también.

KoCMoHaBTa
fuente
1

No lo hagas

Presumiblemente hay una razón por la cual este comportamiento cambió. Si las características posteriores de Xcode se basan en este comportamiento, las cosas se "construyen" más y más en el futuro.

En lugar de intentar doblar Xcode, cambie cómo el script de compilación recupera estos valores:

Cómo leer la versión actual de la aplicación en Xcode 11 con script

Si necesita manipular el project.pbxprojarchivo, es una lista de estilo Siguiente que está bien documentada. Puede usar plistbuddycuál es compatible con este formato antiguo. También puede usar awkcon más secuencias de comandos si tiene manipulaciones más complejas.

Si entiendo su caso de uso, podría escribir un script que obtenga los números de versión más altos awky luego actualice todos los números de versión más bajos que pueda encontrar en el archivo sed.

Manuel
fuente
PlistBuddy parece que la impresión de valores funciona bien, pero cuando uso el setcomando todo el project.pbxproj se convierte en un archivo XML .plist y Xcode ya no puede leerlo. ejemplo:PlistBuddy -c "Set :objects:$configurationId:buildSettings:CURRENT_PROJECT_VERSION $newProjectVersion" "$projectFile"
Sr. Zystem
Dependiendo de qué es exactamente lo que desea lograr, es posible que tenga que usar una combinación de herramientas
Manuel
Reiniciar Xcode solucionó el problema de XML. Als descubrió que cuando ejecuta un script de compilación que cambia el pbxprojarchivo, cancelará la compilación. Así que realmente no va a funcionar, me temo.
Sr. Zystem
Actualicé mi pregunta original con la información anterior.
Sr. Zystem
1
Por ejemplo, mi caso de uso es sincronizar la versión y compilar en varios objetivos; me gustaría configurar la versión y compilar en el primer objetivo y que se actualice automáticamente a todos los demás. Funcionaba bien antes, porque solo modificabas un recurso. Ahora no puedo modificar el proyecto durante la fase de compilación de ningún objetivo, porque la compilación se cancela.
KoCMoHaBTa