El camino para enviar la compilación a la App Store

En la Parte 1 creamos el target de compilación para MAS, y en la Parte 2, los archivos de configuración y la bifurcación de código que separan ambos canales. Ahora el target FocusTimer MAS ya tiene una forma que se puede subir a la App Store.

En esta última parte cerramos la serie preparando el camino para subir esa compilación a App Store Connect y viendo cómo verificar que ambos canales no se rompan en el futuro.

Igual que en las Partes 1 y 2, FocusTimer, com.example.FocusTimer.mas, el Team ID ABCDE12345, etc., son todos valores de ejemplo.

Paso 1 — ExportOptions-MAS.plist para la subida

En la serie de distribución directa dijimos que, al exportar el archivo de archivo (archive) para distribución, el comando xcodebuild -exportArchive lee un ExportOptions.plist. El canal MAS necesita un archivo de opciones de exportación aparte.

Crea un ExportOptions-MAS.plist en el directorio de releases del proyecto.

<?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>method</key>
    <string>app-store</string>
    <key>destination</key>
    <string>upload</string>
    <key>signingStyle</key>
    <string>automatic</string>
    <key>teamID</key>
    <string>ABCDE12345</string>
</dict>
</plist>

El significado de cada clave es este.

  • method = app-store — significa que esta compilación se exporta para el canal de la Mac App Store. Contrasta con el developer-id del canal de distribución directa.
  • destination = uploadxcodebuild -exportArchive sube directamente a App Store Connect el resultado exportado. Ya no hace falta pasar por Transporter ni por una herramienta de subida aparte como antes.
  • signingStyle = automatic — Xcode empareja automáticamente el perfil de aprovisionamiento de la Mac App Store y el certificado de Apple Distribution.
  • teamID — tu Apple Developer Team ID.

Una vez creado este archivo, lo reutilizas en todas las releases de MAS. Deja tal cual el ExportOptions.plist de distribución directa y coloca este archivo junto a él.

Paso 2 — Registrar el registro de la app en App Store Connect

Para enviar de verdad la app a revisión, debe existir un registro (record) de la app en App Store Connect. El registro es el recipiente que contiene toda la información que se mostrará en la tienda: el nombre de la app, su descripción, las capturas de pantalla, el precio, etc.

La creación del registro puedes hacerla justo antes del primer envío real. En la fase de configuración inicial basta con saber de antemano “qué elementos hay que decidir y cómo”. En particular, el Primary Language de más abajo es difícil de revertir una vez decidido, así que decídelo con cuidado por adelantado.

En App Store Connect → My Apps+New App introduce lo siguiente.

  • Platform — selecciona macOS
  • Primary Language (idioma principal) — ⚠️ el elemento que hay que decidir con más cuidado. Una vez decidido, es muy difícil cambiarlo mediante autoservicio. Si planeas publicar la app en varios países, es habitual dejar el inglés (English, U.S.) como idioma principal. El motivo es que el idioma principal es “el idioma de referencia que se mostrará cuando no exista una traducción para un país concreto”.
  • App Name (nombre de la app) — el nombre según el idioma principal (por ejemplo, FocusTimer). Los nombres para otros idiomas se añaden aparte más tarde mediante la localización por idioma (localization). Por ejemplo, puedes hacer que a los usuarios en coreano se les muestre un nombre en coreano y a los usuarios en japonés, un nombre en japonés.
  • Bundle ID — en el menú desplegable, selecciona com.example.FocusTimer.mas. Es el ID que registraste en la Parte 1. No lo confundas con el Bundle ID de distribución directa (com.example.FocusTimer): tiene que ser sin falta el que lleva .mas.
  • SKU — una cadena de identificación interna que solo usas tú. No se muestra en la tienda, así que puedes decidirla libremente (por ejemplo, focustimer-mas-001).

La categoría de la app debe coincidir con el valor que pusiste en LSApplicationCategoryType del Info.plist en la Parte 2. Si en el plist pusiste public.app-category.productivity (Productividad), en App Store Connect también debes elegir la categoría “Productividad” para que en la fase de revisión no aparezca una advertencia de discrepancia.

Paso 3 — Verificar las compilaciones de los dos canales

Ahora un mismo código base tiene dos targets de compilación. Eso conlleva un coste de mantenimiento. Si normalmente solo compilas el canal de distribución directa, puede que el target MAS se haya roto sin que te des cuenta. Por ejemplo, añades código nuevo pero olvidas la bifurcación #if canImport(Sparkle), y solo la compilación de MAS falla al compilar.

La forma más fiable de evitarlo es archivar también el target MAS cada vez que creas una release de distribución directa. Si la compilación tiene éxito, significa que la bifurcación de ambos canales está intacta.

xcodebuild -project FocusTimer.xcodeproj -scheme "FocusTimer MAS" \
  -configuration Release \
  -destination 'platform=macOS' \
  -archivePath build/FocusTimer-MAS.xcarchive \
  archive

Si al final de la salida ves esto, la bifurcación de MAS está correcta.

** ARCHIVE SUCCEEDED **

Te recomendamos insertar este comando como último paso del script de automatización de releases, para que se ejecute automáticamente en cada release. Aunque sea un momento en el que no vas a subir realmente la compilación de MAS a la App Store, el simple hecho de comprobar que el archivo (archive) tiene éxito garantiza que la bifurcación de ambos canales no se ha roto.

Resumen de la serie — configuración inicial para publicar en MAS completada

La configuración inicial para publicar en la Mac App Store, a lo largo de 3 partes, ha terminado por completo. Ahora tienes lo siguiente.

  • (Parte 1) Un Bundle ID exclusivo para MAS + el target de compilación FocusTimer MAS duplicado
  • (Parte 2) Unos entitlements e Info.plist exclusivos para MAS + los ajustes de compilación + la bifurcación de código #if canImport(Sparkle)
  • (Parte 3) Un ExportOptions-MAS.plist para la subida + cómo registrar el registro en App Store Connect + la verificación de las compilaciones de ambos canales

Con esto, una misma app de macOS ha llegado a contar con los dos canales: distribución directa (Developer ID) y Mac App Store. Si volvemos a resumir la estructura clave, es esta.

  • Comparte el mismo código base, pero divídelo en dos targets de compilación.
  • El target de distribución directa incluye Sparkle y el target MAS excluye Sparkle.
  • La diferencia entre ambos se expresa con unos entitlements, Info.plist y ExportOptions aparte y con la bifurcación de código #if canImport(Sparkle).

La primera configuración da bastante trabajo, pero también esta es una estructura que, una vez montada, se reutiliza continuamente. A partir de ahí, basta con archivar también la compilación de MAS al sacar una release de distribución directa y comprobar que la bifurcación sigue viva. El envío real a la App Store (capturas de pantalla, descripción, gestión de la revisión) es un trabajo aparte que se lleva a cabo sobre esta configuración inicial, y es un tema que abordaremos en otro artículo.

Recursos de referencia