¿Cómo se codifican paquetes de marcos para Mac App Store?

81

Después de un envío reciente, he recibido el siguiente error:

Firma no válida: el paquete de aplicaciones anidado (FooBar.app/Contents/Frameworks/GData.framework) no está firmado, la firma no es válida o no está firmada con un certificado de envío de Apple. Consulte la Guía de creación de código y espacio aislado de aplicaciones para obtener más información.

Firma no válida: el paquete de aplicaciones anidado (FooBar.app/Contents/Frameworks/Growl.framework) no está firmado, la firma no es válida o no está firmada con un certificado de envío de Apple. Consulte la Guía de creación de código y espacio aislado de aplicaciones para obtener más información.

Firma no válida: el paquete de aplicaciones anidado libcurl (FooBar.app/Contents/Frameworks/libcurl.framework) no está firmado, la firma no es válida o no está firmada con un certificado de envío de Apple. Consulte la Guía de firma de código y espacio aislado de aplicaciones para obtener más información.

Así que firmé todos los paquetes de marcos según Technote 2206 :

codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libcurl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libssh2.1.dylib
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A/Growl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A/GData

Nota técnica 2206 dice:

Marcos de firma

Dado que los marcos son paquetes, parece lógico concluir que puede firmar un marco directamente. Sin embargo, éste no es el caso. Para evitar problemas al firmar marcos, asegúrese de firmar una versión específica en lugar de todo el marco:

# Esta es la forma incorrecta:

codeign -s mi-firma-identidad ../FooBarBaz.framework

# Esta es la manera correcta:

codeign -s mi-firma-identidad ../FooBarBaz.framework/Versions/A

Y cuando trato de verificar los resultados, me parece bien:

% codesign -vvv FooBar.app/Contents/Frameworks/libcurl.framework
FooBar.app/Contents/Frameworks/libcurl.framework: valid on disk
FooBar.app/Contents/Frameworks/libcurl.framework: satisfies its Designated Requirement
% codesign -vvv FooBar.app/Contents/Frameworks/Growl.framework
FooBar.app/Contents/Frameworks/Growl.framework: valid on disk
FooBar.app/Contents/Frameworks/Growl.framework: satisfies its Designated Requirement

Por diversión, intenté firmar el paquete de marco directamente y aún así fue rechazado. Pero eso es exactamente lo que la documentación dice que no debe hacer.

¿Alguna suposición de por qué eso se consideraría inválido? Estoy usando el mismo certificado que uso para firmar el código de mi aplicación, el que ha funcionado en el pasado.

Mi única suposición sería algo que ver con los plists existentes (¿necesito poseer los identificadores en los Info.plists del marco?) O derechos, ¿alguna sugerencia?

csexton
fuente
También descubrí esto antes cuando envié mi aplicación. Afortunadamente, Apple no lo rechazó, pero señaló que tendremos que firmar marcos más adelante. Creo que es mejor publicar en la página de problemas de código de Google Growl y muy pronto la gente se encontrará con el mismo problema.
koo
2
También encontré este problema al enviar una aplicación con el marco Growl. Supongo que tendrás que cambiar el identificador del paquete growl.framework por uno que te pertenezca y luego firmarlo con código.
Andrew
Esto es extraño: publiqué una aplicación, que incluye dos marcos (CorePlot y MacRuby), ambos sin firmar. Solo ejecuto el comando de signo de código en el paquete de la aplicación una vez, y la aplicación ha sido aceptada sin ningún comentario sobre el marco. Ahora, si miras en el paquete de aplicaciones ( bit.ly/charterapp ), ambos marcos parecen estar firmados. ¿Intentaste simplemente firmar toda la aplicación?
p4010
@ p4010, lo hice, antes no estaban firmados. Growl, por ejemplo, fue solo el paquete recto que distribuyen. Ahora, he tenido esta aplicación en la tienda por un tiempo, así que supongo que esto tiene que ver con las nuevas cosas de sandboxing. ¿Cuándo envió su aplicación?
csexton
@Andrew, ¿te funcionó cambiar el identificador del paquete?
csexton

Respuestas:

45

Basado en la respuesta de baptr, he desarrollado este script de shell que codifica todos mis frameworks y otros recursos binarios / ejecutables auxiliares (tipos actualmente admitidos: dylib, bundle y elementos de inicio de sesión):

#!/bin/sh

# WARNING: You may have to run Clean in Xcode after changing CODE_SIGN_IDENTITY! 

# Verify that $CODE_SIGN_IDENTITY is set
if [ -z "${CODE_SIGN_IDENTITY}" ] ; then
    echo "CODE_SIGN_IDENTITY needs to be set for framework code-signing!"

    if [ "${CONFIGURATION}" = "Release" ] ; then
        exit 1
    else
        # Code-signing is optional for non-release builds.
        exit 0
    fi
fi

if [ -z "${CODE_SIGN_ENTITLEMENTS}" ] ; then
    echo "CODE_SIGN_ENTITLEMENTS needs to be set for framework code-signing!"

    if [ "${CONFIGURATION}" = "Release" ] ; then
        exit 1
    else
        # Code-signing is optional for non-release builds.
        exit 0
    fi
fi

ITEMS=""

FRAMEWORKS_DIR="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -d "$FRAMEWORKS_DIR" ] ; then
    FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -name "*.dylib" -or -name "*.bundle" | sed -e "s/\(.*framework\)/\1\/Versions\/A\//")
    RESULT=$?
    if [[ $RESULT != 0 ]] ; then
        exit 1
    fi

    ITEMS="${FRAMEWORKS}"
fi

LOGINITEMS_DIR="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/"
if [ -d "$LOGINITEMS_DIR" ] ; then
    LOGINITEMS=$(find "${LOGINITEMS_DIR}" -depth -type d -name "*.app")
    RESULT=$?
    if [[ $RESULT != 0 ]] ; then
        exit 1
    fi

    ITEMS="${ITEMS}"$'\n'"${LOGINITEMS}"
fi

# Prefer the expanded name, if available.
CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then
    # Fall back to old behavior.
    CODE_SIGN_IDENTITY_FOR_ITEMS="${CODE_SIGN_IDENTITY}"
fi

echo "Identity:"
echo "${CODE_SIGN_IDENTITY_FOR_ITEMS}"

echo "Entitlements:"
echo "${CODE_SIGN_ENTITLEMENTS}"

echo "Found:"
echo "${ITEMS}"

# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below.
SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")

# Loop through all items.
for ITEM in $ITEMS;
do
    echo "Signing '${ITEM}'"
    codesign --force --verbose --sign "${CODE_SIGN_IDENTITY_FOR_ITEMS}" --entitlements "${CODE_SIGN_ENTITLEMENTS}" "${ITEM}"
    RESULT=$?
    if [[ $RESULT != 0 ]] ; then
        echo "Failed to sign '${ITEM}'."
        IFS=$SAVED_IFS
        exit 1
    fi
done

# Restore $IFS.
IFS=$SAVED_IFS
  1. Guárdelo en un archivo de su proyecto. Guardo mi copia en un Scriptssubdirectorio en la raíz de mi proyecto.
    • El mío se llama codesign-frameworks.sh.
  2. Agregue una fase de compilación "Ejecutar script" justo después de la fase de compilación "Copiar marcos integrados".
    • Puede llamarlo "Codesign Embedded Frameworks".
  3. Pegue ./codesign-frameworks.sh(o lo que sea que haya llamado su secuencia de comandos anteriormente) en el campo de texto del editor de secuencias de comandos. Úselo ./Scripts/codesign-frameworks.shsi almacena el script en un subdirectorio.
  4. Crea tu aplicación. Todos los marcos incluidos estarán codificados.

¿Aún debería obtener un " error de Identidad : ambigua (coincide con: ...", comente a continuación. Esto no debería suceder más.

Actualizado el 14-11-2012: Adición de soporte para marcos con caracteres especiales en su nombre (esto no incluye comillas simples) a “codesign-frameworks.sh”.

Actualizado 2013-01-30: Adición de soporte para caracteres especiales en todas las rutas (esto debe incluir comillas simples) a "codesign-frameworks.sh".

Actualizado 2013-10-29: Adición de compatibilidad con dylib experimental.

Actualizado el 28 de noviembre de 2013: Adición de compatibilidad con derechos. Mejora del soporte experimental de dylib.

Actualizado el 13 de junio de 2014: solución de problemas de codificación con marcos que contienen marcos (anidados). Esto se hizo agregando la -depthopción a find, lo que hace findque se realice un recorrido en profundidad primero. Esto se ha vuelto necesario debido al problema que se describe aquí . En resumen: un paquete contenedor solo se puede firmar si sus paquetes anidados ya están firmados.

Actualizado 2014-06-28: Adición de compatibilidad con paquetes experimentales.

Actualizado 2014-08-22: Mejora del código y prevención de fallas al restaurar IFS.

Actualizado 2014-09-26: Adición de soporte para elementos de inicio de sesión.

Actualizado 2014-10-26: Cotización de comprobaciones de directorio. Esto corrige los errores de "línea 31/42: demasiados argumentos" y el error resultante "el objeto de código no está firmado en absoluto" para las rutas que incluyen caracteres especiales.

Actualizado 2014-11-07: Resolviendo el error de identidad ambigua (como "Desarrollador de Mac: ambiguo ...") cuando se usa la resolución de identidad automática en Xcode. ¡Ya no tiene que establecer explícitamente la identidad y puede usar "Mac Developer"!

Actualizado 2015-08-07: Mejora de la semántica.

¡Bienvenidas las mejoras!

JanX2
fuente
Gracias por esto, solo una nota, no funciona si su objetivo tiene un espacio en su nombre. Intenté arreglarlo pero no pude hacerlo funcionar, así que cambié el objetivo.
Craig
Debería funcionar ahora cuando FRAMEWORK_DIR tiene espacios / caracteres especiales en su nombre.
EneX2
Sin embargo, también necesitaba deshabilitar la opción de marca de tiempo agregando "- marca de tiempo" al final del comando codeign.
Elmer Cat
Interesante. ¿Eres @Elmer Cat, por casualidad, haciendo esto en una versión inédita de OS X? La página de manual describe esta opción de tener un "comportamiento predeterminado específico del sistema".
EneX2
1
Elmer Cat: no sé qué versión de Xcode está ejecutando, pero estoy en 5.0.1 y definitivamente NO está firmando mis marcos automáticamente. Me estaba arrancando el pelo hasta que encontré este guión.
Bryan
11

Su comentario muestra que firmó los objetos dentro del directorio de versiones del paquete. La nota técnica muestra para firmar el directorio en sí.

Lo siguiente coincide mejor con la nota técnica:

codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A
baptr
fuente
4

Así es como lo arreglé;

  • Ingrese a la configuración de construcción de su objetivo
  • Busque la línea "Otros indicadores de firma de código"
  • Enter --deep valor para el parámetro de lanzamiento
  • Cerrar XCode
  • Ingrese a la carpeta de datos derivados en su Mac y elimine los datos derivados antiguos (la ruta predeterminada es: / Users / YOUR_USER_NAME / Library / Developer / Xcode / DerivedData)
  • Abra Xcode y compile

Después del archivo de compilación y envíe la aplicación nuevamente ...

emreoktem
fuente
3
En un mundo de sueños, "--deep" funcionaría como se esperaba, pero no estamos viviendo en un mundo de sueños ...
Mike
0

Una cosa que no veo que se mencione aquí es que necesita tener su Info.plist dentro de / Resources dentro del directorio del marco versionado. De lo contrario, obtendrá el error "formato de paquete no reconocido, no válido o inadecuado" cuando intente firmar el directorio con versión.

Proporcioné una respuesta más extendida aquí: Cómo codificar Growl.framework para la aplicación Mac Sandboxed

Ross Bencina
fuente