Integración continua: Creación de scripts de Xcode
Spanish (Español) translation by Steven (you can also view the original English article)
En esta serie de tutoriales exploraremos un proceso de desarrollo de software poco discutido (pero muy valioso) que está lamentablemente ausente en el mundo de iOS y móvil: La integración continua.
También disponible en esta serie:
- Integración continua: Introducción a la serie
- Integración continua: Configuración de Tomcat
- Integración continua: Configuración de Hudson
- Integración continua: Creación de scripts de Xcode
- Integración continua: Mejoras en el script
Donde lo habíamos dejado
En la parte 1, discutimos el concepto de Integración continua y cómo puede ayudarnos a desarrollar software más rápido. La parte 2 pasó por la instalación de "Apache Tomcat", el servidor web que ejecuta nuestro software de servidor CI. En la Parte 3, instalamos y configuramos Hudson para monitorear nuestro proyecto y comenzar el proceso de compilación cada vez que actualizamos nuestro repositorio de proyectos.
Introducción al Bash
El tema principal de este tutorial será el script Bash. Los scripts bash nos permiten automatizar muchas cosas, como agregar usuarios a un sistema, iterar y verificar todos los archivos en un grupo de carpetas, realizar el archivado automático de archivos antiguos y mucho más. En este tutorial, discutiremos cómo escribir un script Bash para que compile y firme automáticamente un archivo ".ipa" de nuestro proyecto Xcode.
Los scripts Bash funcionan como cualquier otro script o código que hayas escrito antes. Especificamos los comandos de la terminal para que se ejecuten en un orden específico y el sistema operativo es responsable de ejecutarlos.
Paso 1: Escribe un script Bash básico
Como siempre, la mejor manera de aprender sobre algo es adentrarse en él, así que practiquemos escribiendo un script muy básico que imprimirá tu nombre en la terminal.
Abre un editor de texto y crea un nuevo archivo en tu escritorio llamado 'BashScript.sh' y luego ingresa el siguiente texto:
1 |
|
2 |
#!/bin/sh
|
3 |
echo "Hello world from Bash!" |
Deberías poder averiguar qué sucede en este script. Primero (y menos obvio) especificamos el shell que usaremos para el script, en este caso 'sh' (si no sabes qué es un 'shell' no te preocupes demasiado, no es necesario escribir scripts básicos Bash. Solo necesitas saber que la línea está ahí por ahora) La segunda línea simplemente imprime un '¡Hola!' en la ventana de tu terminal.
Intentemos ejecutarlo. Abre una nueva ventana de terminal y escribe lo siguiente:
. /Users/username/Desktop/BashScript.sh
Si ves un "Hello world from Bash!" ¡significa que todo funcionó!



Paso 2: Usando variables en scripts Bash
Los scripts bash pueden hacer uso de variables, pero pueden ser un poco complicados de usar si no los has trabajado antes, por lo que cubriremos esto muy brevemente antes de continuar.
Edita tu código para que diga lo siguiente:
1 |
|
2 |
#!/bin/sh
|
3 |
|
4 |
name="Frank" |
5 |
|
6 |
echo "Hello world from $name" |
Si ejecutas el script de nuevo, deberías ver "Hello world from Frank" (o el nombre que hayas decidido poner allí). También podemos pasar variables al script desde la línea de comandos. Cambia tu línea 'name="frank"' a:
1 |
|
2 |
name=$1 |
y luego ejecuta el script desde la ventana del terminal pero agrega un nombre al final:
. /Users//Desktop/BashScript.sh Frank
El script utilizará la variable que se pasó como variable '1' (en este caso, 'Frank').
Estos son los conceptos básicos del uso de variables en Bash. Algunos errores comunes que se deben evitar son:
- Debes utilizar comillas dobles (") cuando imprimas una cadena que contenga variables, o no funcionará correctamente.
- Las declaraciones de variables no pueden tener un espacio entre el nombre y el valor. Por ejemplo,
name = "Frank"no se analizará correctamente.
¡Ya tienes los conceptos básicos del Bash! Ahora vamos a darle algún uso.
Paso 3: Compilar y generar tu ".app"
Hay dos pasos principales para automatizar tu compilación desde un script Bash:
- Crea tu archivo .app y dsym
- Empaquetar y firmar tu .app en un .ipa
Usamos el comando "xcodebuild" para compilar nuestros proyectos en un archivo ".app", y usamos "xcrun" para firmar la aplicación usando tu certificado de desarrollador y agruparla en un archivo IPA.
Antes de compilarlo a través de nuestro script, ejecutemos xcodebuild desde la línea de comandos. Abre una nueva ventana de terminal en tu estación de trabajo Mac y cambia los directorios a uno de tus proyectos. Una vez allí, ingresa el siguiente comando:
1 |
|
2 |
xcodebuild -target <Target Name>
|
Si proporcionas un nombre de destino apropiado, verás que la aplicación se compila en la ventana de la terminal:



Esto crea el .app y lo coloca en el directorio de datos derivados de Xcode ubicado en:
/Users/usernameLibrary/Developer/DerivedData/appname.*/
Sin embargo, este no es un gran lugar para almacenar los archivos de compilación. Si observas la ubicación de los datos derivados, probablemente verás una gran colección de carpetas, ¡a veces con varias versiones de la misma aplicación! No es nada práctico. En su lugar, decidiremos dónde almacenar el nuestro usando parámetros opcionales:
1 |
|
2 |
xcodebuild -target <target name> OBJROOT=/Users/<username>/Desktop/Obj.root SYMROOT=/Users/<username>/Desktop/sym.root |
Ejecuta la compilación nuevamente y notarás dos nuevas carpetas en tu escritorio, obj.root y sym.root. El obj.root no es demasiado importante para lo que queremos hacer, pero si buscas en sym.root verás nuestro archivo .app junto con un archivo .dysm.
Para aquellos de ustedes que no lo saben, un archivo .dysm permite simbolizar los registros de fallas. Cuando cargas tu binario en Apple (o un servicio como TestFlight), generalmente se recomienda que cargues las aplicaciones que acompañan al archivo .dysm, por lo que es importante estar al tanto de esto.
Paso 4: Firma y empaqueta la aplicación
Ahora tenemos el archivo .app que necesitamos para firmar y empaquetar. En la ventana de tu terminal, navega hasta tu carpeta sym.root:
cd /Users//Desktop/sym.root/Release-iphoneos
Y ejecuta el siguiente comando:
1 |
|
2 |
xcrun -sdk iphoneos PackageApplication -v "AwesomeApp.app" -o |
3 |
"/Users/<username>/Desktop/AwesomeApp.ipa" --sign "<certificate name here>" |
Si todo va bien, verás tu .ipa en tu escritorio. Si no estás seguro de cuál es el nombre de tu certificado, puedes abrir tu proyecto Xcode y ver cuáles son los nombres de tus certificados disponibles. En el siguiente ejemplo, el nombre de mi certificado es "Desarrollador de iPhone: Aron Bury" (aunque técnicamente debería usar un Certificado de distribución para compilaciones ad-hoc, desafortunadamente no tenía uno en este sistema).



Es importante tener en cuenta que no hemos especificado un perfil de aprovisionamiento que se utilizará. Xcodebuild y xcrun utilizan el perfil que se seleccionó por última vez en la configuración del proyecto Xcode.
Paso 5: Escribe el script de compilación
Ahora que sabemos cómo hacerlo desde la línea de comandos, actualiza nuestro script de compilación. Abre tu archivo "build_script.sh" (debe estar ubicado en la carpeta 'Scripts' en el nivel superior del directorio de trabajo de tus proyectos).
Elimina la línea 'echo' para que tengamos un script en blanco. En primer lugar, vamos a agregar algunas variables que facilitarán la reutilización del script:
1 |
|
2 |
#!/bin/sh
|
3 |
|
4 |
appname="AwesomeApp" |
5 |
target_name="$appname" |
6 |
sdk="iphoneos" |
7 |
certificate="iPhone Distribution: Aron Bury" |
8 |
project_dir="$HOME/Documents/Apps/iOS/awesomeapp/$appname" |
9 |
build_location="$Home/Builds/$appname |
Una explicación de las variables son:
appname: El nombre de la aplicación que usamos principalmente para nuestras propias referencias y estructuras de directorio.
target: Es el objetivo para el que crearemos (en este ejemplo, es el mismo que el nombre de la aplicación, así que acabo de pasarle esa variable).
sdk: Este es el SDK para el que construiremos. En términos generales, es el sistema operativo del iPhone o el simulador. Obviamente, queremos construir para iPhone OS.
certificate: Este es el nombre del certificado en el llavero con el que firmaremos la aplicación.
project_dir: Este es el directorio del proyecto en tu computadora. La variable '$HOME' es una variable de sistema incorporada que se relaciona con el directorio de inicio del usuario que ha iniciado sesión actualmente.
build_location: Aquí es donde almacenaremos los archivos de compilación en el sistema; los archivos .app y .ipa se ubicarán aquí después de la compilación.
Obviamente, deberás modificar los valores de las variables para adaptarlos a los valores de tu propio proyecto. Una vez que hayas hecho esto (y hayas comprobado que son correctos) agrega lo siguiente a tu script, debajo de las declaraciones de variables:
1 |
|
2 |
if [ ! -d "$build_location" ]; then |
3 |
mkdir -p "$build_location" |
4 |
fi
|
5 |
|
6 |
cd "$project_dir" |
En el código anterior, verificamos si existe la ubicación de compilación. Si no es así, lo creamos. Luego le decimos al script que cambie el directorio al directorio de nuestro proyecto.
Finalmente agregamos los dos comandos para compilar, empaquetar y firmar nuestra aplicación. Agrega lo siguiente debajo del comando 'cd':
1 |
|
2 |
xcodebuild -target "$appname" OBJROOT="$build_location/obj.root" SYMROOT="$build_location/sym.root" |
3 |
|
4 |
xcrun -sdk iphoneos PackageApplication -v "$build_location/sym.root/Release-iphoneos/$appname.app" -o "$build_location/$appname.ipa" --sign "$certificate" |
¡Y ese es un script de compilación! Asegurémonos de que funcione. Guarda el script, abre una ventana de terminal y ejecuta el script. Si todo va bien, tendrás los archivos de compilación en la ubicación que especificamos. Si recibes algún error, no te preocupes. Asegúrate de haber especificado tus valores correctamente y asegúrate de que la aplicación realmente se compile (abre el proyecto en Xcode y asegúrate de que la compilación sea exitosa).
Paso 6: Usar el script con Hudson
Si bien el script anterior funciona muy bien, la ruta del directorio no será correcta en nuestro servidor CI. Necesitamos hacer un pequeño ajuste antes de enviarlo al repositorio. ¿Recuerdas la última vez que usamos la variable '$WORKSPACE' en Hudson? Vamos a pasar ese valor al script través de Hudson. Primero cambia tu línea 'project_dir' por:
1 |
|
2 |
project_dir="$1/$appname" |
Y en Hudson, abre la configuración del sistema de trabajos y cambia el comando a lo siguiente:
$WORKSPACE/Scripts/build_script.sh $WORKSPACE
Guarda los cambios en tu script y la configuración del trabajo de Hudson y confirma tus cambios en el repositorio. Cuando Hudson detecta un cambio, actualizará el script y lo ejecutará. Si todo va bien, deberías ver que la compilación se realizó correctamente y todos los archivos deseados que lo esperan en el directorio "Build" de los servidores conectados al usuario.
Paso 7: Organiza un método para administrar varios certificados de desarrollador
Si hay algo que estropeará constantemente un servidor de CI de iOS, es no tener los certificados y/o perfiles de aprovisionamiento adecuados instalados en el sistema. Si un miembro del equipo envía un "commit" al espacio de trabajo de Xcode seleccionando un certificado que el servidor de CI no tiene en el sistema, no se podrá compilar y la compilación se interrumpirá. Esto se debe a que Apple requiere que cualquier código compilado para un dispositivo esté firmado por un certificado (por separado de la firma de la aplicación en un .ipa). Por esta razón, es aconsejable que los desarrolladores tengan un sistema para gestionar esto.
Si todo tu equipo está desarrollando con un solo certificado y clave privada, entonces esto no es un gran problema. Si todos usan un certificado diferente, todos deben exportar su certificado de desarrollador y distribución con sus claves privadas adjuntas e importarlas al llavero de inicio de sesión del servidor. Esto significa que sin importar con qué espacio de trabajo de Xcode trabaje Hudson, se tendrá el certificado para firmarlo.
Hay formas más elegantes de lidiar con este problema, que discutiremos en detalle en el próximo tutorial.
Para la próxima vez
Tenemos un servidor de compilación que funciona, y eso es fantástico, ¡pero solo estamos rascando la superficie de lo que podemos lograr! En el siguiente tutorial cubriremos cómo implementar la ejecución automática, leyendo y escribiendo en el info.plist, trabajando con diferentes configuraciones y trabajando con el llavero. Va a ser increíble. ¡Nos vemos la próxima vez!
Posdata: Puedes ver y descargar el script completo aquí:



