iphone - precio - Cree una gran biblioteca estática(dispositivo+simulador) utilizando Xcode y SDK 4+
licencia de desarrollo ios (9)
Parece que podemos, teóricamente, construir una única biblioteca estática que incluya tanto el simulador como el iPhone y el iPad.
Sin embargo, Apple no tiene documentación sobre esto que pueda encontrar, y las plantillas predeterminadas de Xcode NO están configuradas para hacer esto.
Estoy buscando una técnica simple, portátil y reutilizable que se pueda hacer dentro de Xcode.
Algo de historia:
- En 2008, solíamos poder hacer librerías estáticas únicas que incluían tanto el simulador como el dispositivo. Apple deshabilitó eso.
- A lo largo de 2009, creamos pares de librerías estáticas: una para sim, otra para dispositivo. Apple ahora también ha desactivado eso.
Referencias:
Esta es una gran idea, es un excelente enfoque, pero no funciona: http://www.drobnik.com/touch/2010/04/universal-static-libraries/
- Hay algunos errores en su script que significa que solo funciona en su máquina (debería usar BUILT_PRODUCTS_DIR y / o BUILD_DIR en lugar de "guesstimating")
- El último Xcode de Apple le impide hacer lo que hizo, simplemente no funcionará, debido al cambio (documentado) en la forma en que Xcode procesa los objetivos.
Otro interrogador de SO preguntó cómo hacerlo SIN xcode, y con respuestas que se centraron en la parte arm6 vs arm7, pero ignoró la parte i386: ¿Cómo compilo una biblioteca estática (fat) para armv6, armv7 y i386?
- Desde los últimos cambios de Apple, la parte del simulador ya no es lo mismo que la diferencia arm6 / arm7 (es un problema diferente, ver más arriba)
¡Gran trabajo! Hacké algo similar, pero tuve que ejecutarlo por separado. Tenerlo solo como parte del proceso de construcción lo hace mucho más simple.
Un elemento de la nota. Noté que no copia ninguno de los archivos de inclusión que marca como públicos. He adaptado lo que tenía en mi guión al tuyo y funciona bastante bien. Pegue lo siguiente al final de su script.
if [ -d "${CURRENTCONFIG_DEVICE_DIR}/usr/local/include" ]
then
mkdir -p "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
cp "${CURRENTCONFIG_DEVICE_DIR}"/usr/local/include/* "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
fi
ALTERNATIVAS:
Copie / pegue fácilmente la última versión (pero las instrucciones de instalación pueden cambiar, consulte más abajo)
La biblioteca de Karl requiere mucho más esfuerzo para la instalación, pero una solución a largo plazo mucho más agradable (convierte su biblioteca en un Marco).
Use esto, luego ajústelo para agregar soporte para las compilaciones de archivo - vea el comentario de Frederik a continuación sobre los cambios que está usando para hacer que esto funcione bien con el modo de archivo.
CAMBIOS RECIENTES: 1. Se agregó soporte para iOS 10.x (mientras se mantiene el soporte para plataformas más antiguas)
Información sobre cómo usar esta secuencia de comandos con un proyecto incrustado en otro proyecto (aunque recomiendo NO hacer eso nunca, Apple tiene un par de errores de show stopper en Xcode si integras proyectos uno dentro de otro, desde Xcode 3.x hasta Xcode 4.6.x)
Script de bonificación para permitirle incluir paquetes automáticamente (es decir, incluir archivos PNG, archivos PLIST, etc. de su biblioteca) - vea más abajo (desplácese hacia abajo)
ahora es compatible con iPhone5 (usando la solución de Apple para los errores en lipo). NOTA: las instrucciones de instalación han cambiado (probablemente pueda simplificar esto cambiando la secuencia de comandos en el futuro, pero no quiero arriesgarme ahora)
La sección "copiar encabezados" ahora respeta la configuración de compilación para la ubicación de los encabezados públicos (cortesía de Frederik Wallner)
Se agregó la configuración explícita de SYMROOT (¿quizás necesite OBJROOT para establecer también?), Gracias a Doug Dickinson
SCRIPT (esto es lo que tienes que copiar / pegar)
Para instrucciones de uso / instalación, vea a continuación
##########################################
#
# c.f. https://.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4
#
# Version 2.82
#
# Latest Change:
# - MORE tweaks to get the iOS 10+ and 9- working
# - Support iOS 10+
# - Corrected typo for iOS 1-10+ (thanks @stuikomma)
#
# Purpose:
# Automatically create a Universal static library for iPhone + iPad + iPhone Simulator from within XCode
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil''s script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#
set -e
set -o pipefail
#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"
if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi
#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
# (incidental: searching for substrings in sh is a nightmare! Sob)
SDK_VERSION=$(echo ${SDK_NAME} | grep -o ''/d/{1,2/}/./d/{1,2/}$'')
# Next, work out if we''re in SIM or DEVICE
if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi
echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################
#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I''m NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"
echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration /"${CONFIGURATION}/" -project /"${PROJECT_NAME}.xcodeproj/" -target /"${TARGET_NAME}/" -sdk /"${OTHER_SDK_TO_BUILD}/" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO" BUILD_DIR=/"${BUILD_DIR}/" BUILD_ROOT=/"${BUILD_ROOT}/" SYMROOT=/"${SYMROOT}/"
xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"
ACTION="build"
#Merge all platform binaries as a fat binary for each configurations.
# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator
echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"
CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"
# ... remove the products of previous runs of this script
# NB: this directory is ONLY created by this script - it should be safe to delete!
rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"
#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
xcrun -sdk iphoneos lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"
#########
#
# Added: suggestion to also copy "include" files
# (untested, but should work OK)
#
echo "Fetching headers from ${PUBLIC_HEADERS_FOLDER_PATH}"
echo " (if you embed your library project in another project, you will need to add"
echo " a "User Search Headers" build setting of: (NB INCLUDE THE DOUBLE QUOTES BELOW!)"
echo '' "$(TARGET_BUILD_DIR)/usr/local/include/"''
if [ -d "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
# * needs to be outside the double quotes?
cp -r "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"* "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
fi
fi
Instale instrucciones
- Crear un proyecto lib lib
- Seleccione el objetivo
- En la pestaña "Configuraciones de compilación", configure "Construir solo arquitectura activa" en "NO" (para todos los elementos)
- En la pestaña "Fases de compilación", seleccione "Agregar ... Nueva fase de compilación ... Nueva fase de compilación del script de ejecución"
- Copia / pega el script (arriba) en el cuadro
... BONUS OPCIONAL de uso:
- OPCIONAL: si tiene encabezados en su biblioteca, agréguelos a la fase "Copiar encabezados"
- OPCIONAL: ... y arrástrelos / suéltelos desde la sección "Proyecto" a la sección "Público"
- OPCIONAL: ... y se exportarán AUTOMÁTICAMENTE cada vez que cree la aplicación, en un subdirectorio del directorio "debug-universal" (estarán en usr / local / include)
- OPCIONAL: NOTA: si también intenta arrastrar / soltar su proyecto en otro proyecto de Xcode, esto expone un error en Xcode 4, donde no puede crear un archivo .IPA si tiene Encabezados Públicos en su proyecto de arrastrar / soltar. La solución: no incrustar proyectos xcode (¡demasiados errores en el código de Apple!)
Si no puede encontrar el archivo de salida, aquí hay una solución:
Agregue el siguiente código al final del script (cortesía de Frederik Wallner): abra "$ {CREATING_UNIVERSAL_DIR}"
Apple borra toda la salida después de 200 líneas. Seleccione su destino y, en la fase de ejecución del guión, DEBE desmarcar: "Mostrar variables de entorno en el registro de compilación"
Si está utilizando un directorio de "salida de compilación" personalizado para XCode4, entonces XCode coloca todos sus archivos "inesperados" en el lugar equivocado.
- Construir el proyecto
- Haga clic en el último icono a la derecha, en el área superior izquierda de Xcode4.
- Seleccione el elemento superior (esta es su "compilación más reciente". Apple debería seleccionarlo automáticamente, pero no se les ocurrió)
- en la ventana principal, desplácese hacia abajo. La última línea debe leer: lipo: para la configuración actual (Depuración) creando el archivo de salida: /Users/blah/Library/Developer/Xcode/DerivedData/AppName-ashwnbutvodmoleijzlncudsekyf/Build/Products/Debug-universal/libTargetName.a
... esa es la ubicación de tu Universal Build.
Cómo incluir archivos "sin código fuente" en su proyecto (PNG, PLIST, XML, etc.)
- Haz todo lo de arriba, verifica que funcione.
- Cree una nueva fase de ejecución de script que se realice DESPUÉS DE LA PRIMERA (copie / pegue el código a continuación)
- Crear un nuevo destino en Xcode, de tipo "paquete"
- En su PROYECTO PRINCIPAL, en "Fases de creación", agregue el nuevo paquete como algo de lo que "depende" (sección superior, presione el botón más, desplácese hasta la parte inferior, busque el archivo ".bundle" en sus Productos)
- En su NEW BUNDLE TARGET, en "Build Phases", agregue una sección "Copy Bundle Resources", y arrastre / suelte todos los archivos PNG, etc.
Guión para copiar automáticamente los paquetes integrados en la misma carpeta que su biblioteca estática FAT:
echo "RunScript2:"
echo "Autocopying any bundles into the ''universal'' output folder created by RunScript1"
CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
cp -r "${BUILT_PRODUCTS_DIR}/"*.bundle "${CREATING_UNIVERSAL_DIR}"
De hecho, acabo de escribir mi propio guión para este propósito. No utiliza Xcode. (Se basa en un script similar en el proyecto Gambit Scheme).
Básicamente, ejecuta ./configure y make tres veces (para i386, armv7 y armv7s), y combina cada una de las bibliotecas resultantes en un lib lib.
Existe una utilidad de línea de comandos xcodebuild
y puede ejecutar el comando de shell dentro de xcode. Por lo tanto, si no te importa usar un script personalizado, este script puede ayudarte.
#Configurations.
#This script designed for Mac OS X command-line, so does not use Xcode build variables.
#But you can use it freely if you want.
TARGET=sns
ACTION="clean build"
FILE_NAME=libsns.a
DEVICE=iphoneos3.2
SIMULATOR=iphonesimulator3.2
#Build for all platforms/configurations.
xcodebuild -configuration Debug -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Debug -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
#Merge all platform binaries as a fat binary for each configurations.
DEBUG_DEVICE_DIR=${SYMROOT}/Debug-iphoneos
DEBUG_SIMULATOR_DIR=${SYMROOT}/Debug-iphonesimulator
DEBUG_UNIVERSAL_DIR=${SYMROOT}/Debug-universal
RELEASE_DEVICE_DIR=${SYMROOT}/Release-iphoneos
RELEASE_SIMULATOR_DIR=${SYMROOT}/Release-iphonesimulator
RELEASE_UNIVERSAL_DIR=${SYMROOT}/Release-universal
rm -rf "${DEBUG_UNIVERSAL_DIR}"
rm -rf "${RELEASE_UNIVERSAL_DIR}"
mkdir "${DEBUG_UNIVERSAL_DIR}"
mkdir "${RELEASE_UNIVERSAL_DIR}"
lipo -create -output "${DEBUG_UNIVERSAL_DIR}/${FILE_NAME}" "${DEBUG_DEVICE_DIR}/${FILE_NAME}" "${DEBUG_SIMULATOR_DIR}/${FILE_NAME}"
lipo -create -output "${RELEASE_UNIVERSAL_DIR}/${FILE_NAME}" "${RELEASE_DEVICE_DIR}/${FILE_NAME}" "${RELEASE_SIMULATOR_DIR}/${FILE_NAME}"
Tal vez parece ineficiente (no soy bueno en shell script), pero es fácil de entender. Configuré un nuevo objetivo ejecutando solo este script. El script está diseñado para la línea de comandos pero no se prueba en :)
El concepto central es xcodebuild
y lipo
.
Probé muchas configuraciones dentro de Xcode UI, pero nada funcionó. Debido a que este es un tipo de procesamiento por lotes, el diseño de la línea de comando es más adecuado, por lo que Apple eliminó gradualmente la función de construcción por lotes de Xcode. Así que no espero que ofrezcan una función de creación de lotes basada en UI en el futuro.
He creado una plantilla de proyecto XCode 4 que te permite crear un marco universal tan fácilmente como hacer una biblioteca normal.
He hecho esto en una plantilla de Xcode 4 , en la misma línea que la plantilla de marco estático de Karl.
Descubrí que la creación de marcos estáticos (en lugar de las bibliotecas estáticas simples) causaba bloqueos aleatorios con LLVM, debido a un error aparente del vinculador, por lo que supongo que las bibliotecas estáticas siguen siendo útiles
He pasado muchas horas tratando de construir una biblioteca estática que funcione en armv7, armv7s y el simulador. Finalmente encontré una solución .
Lo esencial es construir las dos bibliotecas (una para el dispositivo y luego la otra para el simulador), renombrarlas para distinguirlas entre sí y luego crear una lipo para crearlas.
lipo -create libPhone.a libSimulator.a -output libUniversal.a
¡Lo probé y funciona!
Necesitaba un lib lib estático para JsonKit, así que creé un proyecto de lib estático en Xcode y luego ejecuté este script bash en el directorio del proyecto. Siempre que haya configurado el proyecto xcode con "Crear solo configuración activa" desactivado, debe obtener todas las arquitecturas en una lib.
#!/bin/bash
xcodebuild -sdk iphoneos
xcodebuild -sdk iphonesimulator
lipo -create -output libJsonKit.a build/Release-iphoneos/libJsonKit.a build/Release-iphonesimulator/libJsonKit.a
Actualización de IOS 10:
Tuve un problema con la creación de fatlib con iphoneos10.0 porque la expresión regular en el script solo espera 9.xy menor y devuelve 0.0 para ios 10.0
para solucionar este problema simplemente reemplazar
SDK_VERSION=$(echo ${SDK_NAME} | grep -o ''./{3/}$'')
con
SDK_VERSION=$(echo ${SDK_NAME} | grep -o ''[//.0-9]/{3,4/}$'')