Explicación de la integración continua de iOS con Xcode Server

Publicado: 2022-03-11

Introducción

Antes de Xcode 9, usar las herramientas de integración continua de Apple era un proceso tedioso y complejo que requería la compra e instalación de una aplicación adicional de macOS Server. Esto llevó a muchos desarrolladores a abandonar la idea de integración continua para sus proyectos de iOS o recurrir a soluciones de terceros, con niveles de éxito muy variables.

Sin embargo, después del lanzamiento de Xcode 9.0 en septiembre de 2017, el proceso se simplificó enormemente, incluida la opción de firma de código automatizada, y ahora está completamente integrado en Xcode. Por lo tanto, no requiere ninguna aplicación o herramienta adicional.

Si bien las soluciones de terceros como Fastlane, Bluepill, etc. son de gran ayuda y pueden hacer mucho trabajo duro por usted, este artículo explorará las capacidades de usar las herramientas de Xcode y Apple solo para sus necesidades de integración continua. También usaremos la firma de código manual, ya que a menudo parece ser un problema para muchas personas, y la firma automática tampoco tiende a ser la solución óptima cuando se trata de múltiples configuraciones de compilación.

Nota: este artículo se basa en Xcode 9.4.1 y se centra en el desarrollo de aplicaciones para iOS, pero gran parte se aplica a Xcode 10 (actualmente disponible como versión beta 5) y al desarrollo de aplicaciones para macOS.

Configuración del servidor Xcode

Además de simplificar el proceso de integración real, Xcode 9 también simplificó el proceso de configuración del servidor Xcode.

Inicie la aplicación Xcode en su máquina macOS que ha sido designada como su servidor CI y abra Preferencias.

Navegue a la última pestaña, llamada Servidor y Bots .

Herramientas de integración continua: captura de pantalla de la pestaña Servidores y bots

Active las capacidades del servidor Xcode haciendo clic en el interruptor en la esquina superior derecha. Luego, se le pedirá que seleccione un usuario para ejecutar y ejecutar scripts de compilación en esta máquina. Probablemente sea una buena idea tener un usuario dedicado solo para este propósito, en lugar de usar uno preexistente.

Tenga en cuenta que este usuario debe iniciar sesión en el sistema para que se ejecute cualquier bot de Xcode. Después de iniciar sesión, debería ver un círculo verde junto al nombre de usuario.

Xcode Server y Bots después de un inicio de sesión exitoso

¡Eso es todo! Echemos un vistazo más de cerca a los bots de Xcode.

Cómo configurar los bots de Xcode

Ahora está listo para comenzar a configurar los bots de Xcode para que se ejecuten en este servidor. Esto se puede hacer en cualquier máquina de desarrollo conectada a la misma red que el servidor.

Abra Xcode en su máquina de desarrollo y haga clic en Xcode > Preferencias en el menú superior. Luego, vaya a la pestaña Cuentas y haga clic en el ícono + en la esquina inferior izquierda. Seleccione Servidor Xcode en el cuadro de diálogo que aparece.

Captura de pantalla de la selección del tipo de cuenta

Para crear un bot, simplemente abra su proyecto en Xcode y elija la opción Producto > Crear bot… del menú superior. La configuración del bot tiene una serie de pasos y los exploraremos en las próximas secciones.

Automatización de la distribución de aplicaciones

Una de las aplicaciones más frecuentes de automatización de compilación de aplicaciones de iOS es configurar un bot para cargar una aplicación en una plataforma de distribución de iOS como TestFlight, Fabric, etc.

Como expliqué anteriormente, este artículo solo explorará la carga en App Store Connect y la descarga directamente desde su servidor Xcode, ya que esas son las herramientas nativas de Apple para la distribución de aplicaciones iOS.

Distribución de App Store Connect usando Xcode

Antes de configurar un bot, asegúrese de tener un registro de la aplicación App Store Connect que coincida con el ID del paquete de su proyecto de desarrollo de aplicaciones. También vale la pena señalar que cada compilación debe tener un identificador único que consiste en la versión de compilación y el número de compilación. Exploraremos cómo garantizar que se cumplan estas condiciones cuando analicemos la configuración del bot de Xcode más adelante.

Paso 1: establecer la configuración de compilación correcta es el paso crucial para obtener lo que desea. Asegúrese de seleccionar el esquema y la configuración que producen la aplicación que desea cargar en App Store Connect. Esto incluye asegurarse de que la configuración de compilación use la identificación de paquete adecuada que está registrada en el portal de desarrolladores de Apple de su equipo (esto se usa para la firma de código), así como en su portal App Store Connect (esto se usa para cargar automáticamente la aplicación) .

Paso 2: mientras aún estamos en la pestaña "Configuración", debemos especificar las opciones de exportación. Vamos a explorar la lista de propiedades de opciones de exportación, así que asegúrese de que esté seleccionado "Usar lista de opciones de exportación personalizada".

Paso 3: ahora es el momento de hacer nuestra lista de propiedades de opciones de exportación. Una lista completa de claves que se usarán en este archivo está disponible si ingresa xcodebuild --help , pero exploraremos las que se usan en esta configuración de bot aquí:

  • compileBitcode : Bitcode es el formato de salida provisional de Apple para el código fuente de la aplicación. En otras palabras, es el formato en el que se convierte su código fuente antes de compilarlo en código de máquina para una arquitectura específica. Pretende tener un contenedor de código único que pueda optimizarse aún más si se realiza una optimización en el conjunto de instrucciones, y también poder compilarlo a futuras arquitecturas desde este mismo formato. Sin embargo, esto no tiene ningún efecto en su aplicación. Depende de usted decidir si desea habilitarlo o no.
  • method : este argumento especifica qué tipo de producto está exportando. Apple distingue los productos por su audiencia designada: el desarrollo solo le permite instalarlo en los dispositivos especificados en el perfil de aprovisionamiento, la empresa permite que todos lo instalen, pero deben confiar explícitamente en este perfil de desarrollo antes de ejecutar la aplicación, y la tienda de aplicaciones es para distribuyéndolo a App Store o App Store Connect, así que vamos a usar este valor.
  • provisioningProfiles : esto se explica por sí mismo. Pero hay un par de cosas a tener en cuenta aquí: los perfiles de aprovisionamiento en la lista de propiedades de opciones de exportación son un diccionario donde una clave corresponde a la identificación del paquete de un producto y el valor corresponde al nombre del perfil de aprovisionamiento utilizado para firmarlo en código.
  • signingCertificate : otro argumento que se explica por sí mismo. El valor de este campo puede ser un nombre de certificado completo o un hash SHA-1.
  • teamID : otro argumento que se explica por sí mismo. Este es el identificador largo de 10 caracteres que Apple emitió a su organización cuando se registró en el programa Apple Developer.
  • uploadBitcode : si debe o no cargar bitcode (si ha optado por compilarlo) para que pueda usarse en AppStore Connect para generar nuevas compilaciones optimizadas o compilaciones para arquitecturas futuras.
  • uploadSymbols : carga sus símbolos de depuración para que pueda obtener un informe de bloqueo significativo en lugar de solo un volcado de memoria y una pila de ensamblaje.

Así que ahora, su lista de propiedades de opciones de exportación podría verse así:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>compileBitcode</key> <false/> <key>method</key> <string>app-store</string> <key>provisioningProfiles</key> <dict> <key>com.bundle.id</key> <string>ProvisioningProfileName</string> </dict> <key>signingCertificate</key> <string>Signing Certificate Exact Name or SHA-1 hash value</string> <key>teamID</key> <string>??????????</string> <key>uploadBitcode</key> <false/> <key>uploadSymbols</key> <true/> </dict> </plist>

Paso 4: Elija el .plist que creó como la lista de propiedades de opciones de exportación.

Paso 5: Lo siguiente es la pestaña "Programar": configúralo según tus preferencias.

Paso 6: en la pestaña Firma, asegúrese de desmarcar la opción "Permitir que Xcode Server administre mis certificados y perfiles" y cargue usted mismo un certificado de firma y un perfil de aprovisionamiento coincidentes, en la página Certificados y perfiles .

Paso 7: la pestaña Dispositivos debe dejarse como está, ya que estamos cargando la aplicación en lugar de probarla.

Paso 8: la pestaña Argumentos le permite establecer explícitamente argumentos de xcodebuild o variables de entorno que se pueden usar en su compilación o scripts de preintegración y posintegración.

Paso 9: Finalmente, llegamos a la pestaña Triggers , que también es la última pestaña para configurar el bot de integración continua de Xcode. Esta es la herramienta más poderosa en el arsenal de Xcode Server. Para empezar, me gusta agregar los siguientes dos comandos como un script previo a la integración:

 #!/bin/sh set printenv

El primero imprime todas las variables que usa Xcode Server y sus valores en la ejecución de integración actual. El segundo imprime todas las variables de entorno y sus valores. Como era de esperar, esto puede ser útil para depurar sus scripts, por lo que lo llamo acertadamente "información de depuración".

Recuerde que mencionamos que debemos asegurarnos de que cada compilación cargada en App Store Connect debe tener una versión de compilación única y un par de números de compilación. Podemos usar la herramienta PlistBuddy incorporada, pero también necesitamos una forma de tener un número de compilación único. Una cosa que siempre está presente durante la integración de Xcode Server, y también es convenientemente única, es el número de integración, ya que se incrementa automáticamente. Crearemos otra secuencia de comandos previa a la integración, llamada "establecer número de compilación" con los siguientes contenidos para garantizar que tengamos un número de compilación único cada vez:

 #!/bin/sh buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}") buildNumber=$XCS_INTEGRATION_NUMBER /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"

Si está utilizando CocoaPods y optó por no enviar el directorio Pods a su DVCS, también debe incluir un script de preintegración con los siguientes contenidos:

 #!/bin/sh cd $XCS_PRIMARY_REPO_DIR pod install

Paso 10: casi hemos terminado, pero no hemos especificado en ningún lugar que queremos cargar la compilación en AppStore Connect o en qué cuenta. Con este fin, agregaremos un script posterior a la integración y otra herramienta incorporada, denominada Cargador de aplicaciones. Ponga lo siguiente en el script:

 #!/bin/sh /Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool --upload-app -f $XCS_PRODUCT -u $TESTFLIGHT_USERNAME -p $TESTFLIGHT_PASSWORD

$XCS_PRODUCT es una variable de Xcode Server y contiene la ruta a la aplicación que se creó en la ejecución de integración actual. Sin embargo, $TESTFLIGHT_USERNAME y $TESTFLIGHT_PASSWORD no son variables del sistema ni del servidor Xcode. Estos deben ser configurados por usted y tener el valor de su ID y contraseña de Apple. Desafortunadamente, Apple ha suspendido el soporte para generar una clave API para la carga de compilaciones de AppStore Connect. Dado que se trata de información confidencial, la mejor práctica es configurarla directamente en el servidor Mac (suponiendo que sea el suyo) como una variable de entorno en lugar de en la configuración del bot del servidor Xcode.

Distribución del servidor Xcode

El bot de distribución de Xcode Server en realidad usa la misma configuración que la distribución de App Store Connect, con la excepción de los scripts posteriores a la integración. Sin embargo, descargar la aplicación e instalarla aún puede ser complicado. Aún debe asegurarse de que el perfil de aprovisionamiento con el que ha firmado su aplicación permita que la aplicación se instale en el dispositivo que está utilizando.

Con eso en su lugar, deberá abrir Safari en su dispositivo iOS y navegar hasta el panel web del servidor Xcode de su servidor. Por ejemplo, si el nombre de su servidor es "servidor Mac", puede encontrarlo en "mac-server-name.local/xcode" si está en la misma red que el servidor. Allí encontrará una lista de todos sus bots de Xcode y las estadísticas de sus integraciones más recientes.

Seleccione el que ha creado la aplicación que desea descargar. En la siguiente pantalla, tendrá dos botones: Instalar y Perfil . Si es la primera vez que descarga desde este servidor, debe hacer clic en Perfil para agregar su certificado a la lista de fuentes confiables. Luego, haga clic en el botón Instalar en la misma página y aparecerá el cuadro de diálogo de confirmación de iOS "¿Está seguro de que desea instalar * en su dispositivo?" Confírmelo haciendo clic en , y su aplicación se instalará y podrá ejecutarse desde la pantalla de inicio.

Captura de pantalla de las opciones de instalación de la aplicación

Para iOS 10.3 y versiones posteriores , una de las razones por las que puede fallar con "No se puede conectar a *.local" es que se debe confiar en el certificado autofirmado manualmente en Configuración en el dispositivo de prueba.

Sigue estos pasos:

Paso 1: Instale los certificados autofirmados de la página de bots del servidor Xcode en su iPhone.

Paso 2: Vaya a Configuración de iPhone > General > Acerca de > Configuración de confianza del certificado .

Paso 3: busque los certificados autofirmados de su servidor en la sección HABILITAR CONFIANZA COMPLETA PARA CERTIFICADOS RAÍZ y encienda el interruptor.

Paso 4: Regrese a la página de integración del bot en Xcode Server, haga clic en Instalar .

Prueba automática de aplicaciones del servidor Xcode

Otro gran uso de Xcode Server es la prueba automática de aplicaciones, ya sea prueba unitaria o de interfaz de usuario. Para hacer esto, debe tener el objetivo adecuado configurado para su proyecto. Es decir, debe tener un objetivo que ejecute pruebas unitarias o de IU, según su objetivo.

El proceso de configuración es el mismo que el anterior, pero seleccionaremos diferentes opciones. La primera gran diferencia está en la pestaña Configuración . Obviamente, vamos a marcar las casillas "Analizar" y "Probar" ya que ese es nuestro objetivo principal. También recomendaría no archivar ni exportar el producto con este bot. Es posible lograr tanto la prueba como la distribución con la misma configuración de bot. Sin embargo, estos dos escenarios difieren tanto en su producción como en su cronograma. La distribución a menudo se ejecuta al final del ciclo.

Ya sea que esté trabajando en Scrum o Kanban o algún otro marco, debe haber un ciclo predefinido controlado por tiempo o por eventos al final del cual debería tener un producto exportado y utilizable. Por otro lado, debe ejecutar su bot de prueba en cada confirmación, ya que es su primera línea de defensa contra las regresiones. Dado que el bot de prueba obviamente se ejecuta con más frecuencia, fusionar esos dos bots en uno solo podría agotar rápidamente el espacio en disco de su servidor. Y también tomaría más tiempo completar cada integración.

Con eso fuera del camino, vamos a pasar a la pestaña "Programación", y ya hemos abordado esto en el párrafo anterior. Entonces, el siguiente tema de interés es la firma de código. Tenga en cuenta que, aunque su objetivo de prueba indique que no necesita un perfil de aprovisionamiento en la página de configuración de su proyecto, debe configurarlo para usar el mismo equipo y certificado de firma que la aplicación host. Esto es necesario si desea probar su aplicación en un dispositivo iOS en lugar de solo en un simulador. Si este es su caso, también debe asegurarse de que el dispositivo iOS utilizado para la prueba no se bloquee debido a la inactividad, ya que esto podría hacer que su ejecución de integración se bloquee indefinidamente sin notificarle.

Ahora estamos en la pestaña "Dispositivos" que no necesita una explicación específica. Simplemente seleccione uno, varios o todos los dispositivos (iOS y simulador) con los que desea probar su código. También puede verificar si ejecutar pruebas en múltiples dispositivos en paralelo o secuencialmente. Para configurar esto, debe considerar las necesidades de su proyecto (ya sea que se dirija a un conjunto específico de dispositivos o a todos los dispositivos iOS compatibles) y también a los recursos de hardware del servidor.

En la pestaña Argumentos . no es necesario especificar nada explícitamente, ya que solo usaremos variables de entorno integradas.

Finalmente, en la pestaña Triggers , presentaremos un script previo a la integración y otro posterior a la integración. El primero solo está ahí para ayudarnos a depurar en caso de que tengamos algunos problemas. En realidad es el que ya hemos usado:

 #!/bin/sh set printenv

La segunda es la que nos avisará en caso de que una o varias de nuestras pruebas fallen en la integración actual. Asegúrese de que esté configurado para ejecutarse solo en caso de fallas de prueba. E ingresa lo siguiente:

 #!/bin/sh echo "$XCS_TEST_FAILURE_COUNT test(s) failed for $XCS_BOT_NAME bot on build $XCS_INTEGRATION_NUMBER" echo "You can see bot integration at:" echo "https://$HOSTNAME/xcode/bots/$XCS_BOT_TINY_ID/integrations/$XCS_INTEGRATION_TINY_ID"

Hay un par de cosas que deben ser explicadas aquí. En primer lugar, las variables $HOSTNAME almacenan el valor del siguiente formato: computer-name.local. Obviamente, el enlace solo funcionaría si puede acceder a ese servidor a través de la red local. Además, lo más probable es que reciba una advertencia de seguridad de su navegador cuando visite este enlace, ya que es una conexión https a un destino en el que no se puede confiar. Finalmente, este es solo un punto de partida para su script de "Error de prueba". Puede enviar un correo electrónico a todo el equipo de desarrollo o abrir un problema de JIRA a través de una solicitud de API o cualquier otra cosa que considere más apropiada y productiva.

Terminando

Con suerte, este artículo lo animó a tomarse su tiempo para explorar las capacidades del servidor Xcode más allá de simplemente crear una aplicación. Si bien es posible que esta publicación no lo haya ayudado exactamente de la manera que deseaba o esperaba, el objetivo era presentarle una forma abierta de usar entornos integrados y variables del servidor Xcode para lograr un mayor nivel de automatización.

Hay muchos servicios de terceros que permiten una mayor funcionalidad y pueden hacer mucho más por usted, incluidos Fabric, Bluepill y Fastlane. Pero, inevitablemente, depender de un tercero introduce una nueva dependencia en su proyecto y requiere una instalación y configuración a veces simples, a veces complejas. Las técnicas descritas aquí requieren solo herramientas ya instaladas en cada Mac, por lo que no requiere tiempo de configuración además de configurar los mismos bots que ejecutarán sus compilaciones automatizadas.