Skip to content
Todas las publicaciones
Blog25 de marzo de 20264 min read
SL

Screenshots.live

Team

Construyendo un pipeline de capturas en tu CI/CD: Guia paso a paso

Aprende a construir un pipeline automatizado de capturas usando la API de Screenshots.live, GitHub Actions y Fastlane. Con configuraciones YAML completas, scripts de renderizado y automatizacion de subida.

Por que las capturas pertenecen a tu pipeline CI/CD

Las capturas de pantalla de la App Store generalmente se tratan como una tarea de diseno, algo que ocurre una vez antes del lanzamiento y luego se actualiza dolorosamente cada pocos meses. Este enfoque falla en cuanto tu equipo lanza con frecuencia. Si lanzas cada dos semanas, tus capturas quedan desactualizadas despues del primer sprint.

La solucion es tratar las capturas como cualquier otro artefacto de build. Deben generarse automaticamente cuando cambia tu UI, versionarse junto con tu codigo y desplegarse en las tiendas como parte de tu proceso de release.

Los beneficios son sustanciales. Tus capturas siempre reflejan el estado actual de tu app. Las capturas localizadas se actualizan automaticamente. Tu equipo de diseno configura el template una vez y los desarrolladores manejan el resto mediante configuracion.

Resumen de la arquitectura

  1. Diseno del template — Tu equipo de diseno crea templates en el editor visual de Screenshots.live.
  2. Configuracion — Un archivo YAML en tu repositorio define que templates renderizar, que idiomas generar y que variables de texto inyectar.
  3. Renderizado — Tu pipeline CI/CD llama a la API de Screenshots.live, que renderiza todas las variaciones y devuelve un archivo ZIP.
  4. Post-procesamiento — El pipeline extrae el ZIP y organiza archivos en la estructura de directorios esperada.
  5. Subida — Fastlane entrega las capturas a App Store Connect y Google Play Console automaticamente.

Configurando tu archivo de configuracion

# .screenshots/config.yml

api_key: ${SCREENSHOTS_API_KEY}
base_url: https://api.screenshots.live/v1

templates:
  - id: tpl_hero_screen
    name: "Hero Screenshot"
    devices:
      - iphone67
      - ipad129
      - android_phone
      - android_tablet

locales:
  - code: en
    variables:
      headline: "Track Your Progress"
      subtitle: "All-in-one fitness companion"
  - code: es
    variables:
      headline: "Sigue tu progreso"
      subtitle: "Tu companero fitness todo-en-uno"

Workflow de GitHub Actions

name: Generate App Store Screenshots

on:
  push:
    branches: [main]
    paths:
      - '.screenshots/**'
  workflow_dispatch:

env:
  SCREENSHOTS_API_KEY: ${{ secrets.SCREENSHOTS_API_KEY }}
  SCREENSHOTS_OUTPUT_DIR: ./fastlane/screenshots

jobs:
  generate-screenshots:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - uses: actions/cache@v4
        with:
          path: .screenshots/cache
          key: screenshots-${{ hashFiles('.screenshots/config.yml') }}
      - run: npm install js-yaml node-fetch@2 adm-zip
      - run: node .screenshots/generate.js
      - name: Verify
        run: |
          TOTAL=$(find $SCREENSHOTS_OUTPUT_DIR -name "*.png" | wc -l)
          echo "Total: $TOTAL"
          [ "$TOTAL" -gt 0 ] || exit 1
      - uses: actions/upload-artifact@v4
        with:
          name: app-store-screenshots
          path: ${{ env.SCREENSHOTS_OUTPUT_DIR }}

  upload-ios:
    needs: generate-screenshots
    runs-on: macos-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          name: app-store-screenshots
          path: fastlane/screenshots
      - run: gem install fastlane
      - run: fastlane ios upload_screenshots
        env:
          APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_PRIVATE_KEY }}

  upload-android:
    needs: generate-screenshots
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          name: app-store-screenshots
          path: fastlane/screenshots
      - run: gem install fastlane
      - run: fastlane android upload_screenshots
        env:
          SUPPLY_JSON_KEY_DATA: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}

El script de renderizado

Crea el archivo .screenshots/generate.js con el script Node.js que lee la configuracion, llama a la API y organiza la salida. El script itera sobre cada template, construye las variables por idioma, realiza la llamada POST a la API de renderizado, recibe el ZIP y extrae los archivos en la estructura de directorios correcta.

Integracion con Fastlane

# fastlane/Fastfile

platform :ios do
  lane :upload_screenshots do
    deliver(
      skip_binary_upload: true,
      skip_metadata: true,
      screenshots_path: "./fastlane/screenshots/ios",
      overwrite_screenshots: true,
    )
  end
end

platform :android do
  lane :upload_screenshots do
    upload_to_play_store(
      skip_upload_apk: true,
      skip_upload_aab: true,
      skip_upload_metadata: true,
      images_path: "./fastlane/screenshots/android",
    )
  end
end

Manejo de idiomas en el pipeline

La gestion de idiomas es una de las mayores ventajas de un pipeline automatizado. Cuando agregas un nuevo idioma, agregas una entrada en config.yml. La siguiente ejecucion del pipeline genera capturas para cada template en el nuevo idioma. Sin trabajo de diseno necesario.

Para equipos que usan sistemas de gestion de traducciones como Lokalise, Phrase o Crowdin, puedes agregar un paso previo al renderizado que obtiene las ultimas traducciones.

Consejos de cache y optimizacion

Claves de cache basadas en contenido. El workflow usa hashFiles('.screenshots/config.yml') como clave de cache. Si la configuracion no ha cambiado, las capturas en cache se reutilizan instantaneamente.

Renderizado selectivo. Si solo cambio un idioma, considera dividir los renders por idioma y cachear cada uno independientemente.

Renderizado paralelo. La API puede manejar solicitudes concurrentes:

const renderPromises = config.templates.map(template =>
  renderTemplate(template, config, apiKey)
);
await Promise.all(renderPromises);

Monitoreo de renders con webhooks

Screenshots.live soporta webhooks que notifican a tus sistemas cuando los renders se completan o fallan. Puedes enviar notificaciones a Slack o Microsoft Teams.

Poniendo todo junto

  1. Un disenador crea o actualiza un template en el editor visual.
  2. Un desarrollador actualiza la configuracion y hace push a main.
  3. GitHub Actions detecta el cambio y ejecuta el workflow de capturas.
  4. El script de renderizado lee la configuracion, llama a la API y descarga las capturas.
  5. Fastlane sube las capturas a App Store Connect y Google Play Console.
  6. Ambas fichas de tienda se actualizan con capturas frescas en minutos.

Todo el proceso funciona sin intervencion manual. Tus capturas siempre estan actualizadas, siempre consistentes entre plataformas y siempre localizadas.

Publicaciones relacionadas