objective c - Xcode 6 y Embedded Frameworks solo son compatibles con iOS8
objective-c dylib (14)
Cuando uso un marco incrustado (dyld) en Xcode 6.0.1 con un objetivo de implementación menor que iOS 8, obtengo:
- La construcción es exitosa
- Error de carga de la biblioteca en tiempo de ejecución
Error:
dyld: Library not loaded: @rpath/ObjectiveLyricsTouch2.framework/ObjectiveLyricsTouch2
Referenced from: /private/var/mobile/Containers/Bundle/Application/DC65ACA9-98E5-46CD-95F8-829D3416F6C0/musiXmatch.app/musiXmatch
Reason: image not found
(lldb)
A partir de ahora no hay forma de usar un marco incrustado para compartir código entre una aplicación y un widget y ejecutarlo en iOS 8, iOS 7 y versiones anteriores.
Aquí hay más lecturas sobre eso http://atomicbird.com/blog/ios-app-extension-tips
Frameworks vs. iOS 7
Si está compartiendo código entre una aplicación y una extensión, una buena manera de hacerlo es crear su propio marco incrustado para guardar el código. En iOS 8 se cargará dinámicamente para ambos casos, por lo que está configurado.
Si aún admite iOS 7 (o anterior), no es tan claro. Los marcos integrados no funcionan allí. La Guía de programación de la extensión de la aplicación señala que puede usar dlopen para lidiar con esto. Con ese enfoque, escribe código para cargar el marco dinámicamente en tiempo de ejecución en lugar de confiar en que iOS lo cargue por usted, si ha verificado que el código se ejecuta en una versión de iOS que admite hacerlo.
Pero, ¿cómo usas ese código en iOS 7? Usted no Si su código compartido está en un marco incrustado, no hay forma de ejecutarlo en iOS 7. Simplemente no está disponible.
El enfoque dlopen puede ser útil si solo necesita el código compartido en iOS 8. Si lo necesita en iOS 7, deberá incluirlo en el destino de la aplicación. Y una vez que haces eso, no necesitas el marco. Todavía podría usar un marco para la extensión de la aplicación, pero hacerlo no es realmente útil. Estaría haciendo el trabajo de crear el marco pero no obtendría ningún beneficio de él. Solo incluya el código compartido en ambos objetivos.
Y de la guía de extensión de Apple https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensibilityPG.pdf
Si vincula a un marco incrustado desde la aplicación que lo contiene, aún puede implementarlo en versiones de iOS anteriores a 8.0, aunque los marcos incrustados no estén disponibles en esas versiones.
Configuré el tipo Mach-O en EJECUTABLE y funcionó para mí. Establecerlo en Estático, Dinámico o Bundle creó otros errores cuando lo ejecuté.
Target> "Su aplicación"> Configuración de compilación> Vinculación> Tipo de Mach-O> Ejecutable
Cuando utiliza la biblioteca dinámica en ios, debe codificar y firmar la biblioteca. En el Xcode 6, debe seleccionar la "Copia de inicio de sesión de código". Y con el Xcode5, debe firmar la biblioteca usted mismo con el script de ejecución. me gusta :
LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="iPhone Developer: xxxxx"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/BeeFramework.framework/BeeFramework"
Durante algún tiempo pensé que este también era mi problema, pero para las aplicaciones normales ( sin extensión iOS-8 ) solo necesita cambiar una configuración de compilación en su objetivo informal Xcode 6 iOS Universal Framework ( establezca el tipo Mach-O a la biblioteca estática ):
No debería haber ningún problema con iTunes Connect e iOS 7 después de eso :)
Eliminar los marcos de uso! desde su PodFile si desea que Framework funcione en iOS 7.0. es decir, ejecute el comando pod deintegrate, modifique su PodFile y luego vuelva a ejecutar el comando pod install
También después de esto, tuve que agregar todos los archivos .h del Framework en el archivo Bridging, que solucionó el problema. También elimine la importación TestLibrary de los archivos rápidos
Entonces, después de investigar, salí con la solución
Se supone que tiene el suyo MyEmbeddedFramework.framework para agregar a la aplicación, haga esto
- Elimine MyEmbeddedFramework.framework en la pestaña General> Binarios incrustados
- Elimine las fases de compilación> "Frameworks" de la fase de copia si tiene MyEmbeddedFramework.framework allí.
- Carpeta de compilación limpia
- Mueva MyEmbeddedFramework.framework en la sección anular Embedded Frameworks.
- Verá ahora que XCode6 crea una nueva Fase de compilación> Marcos incrustados (no usted, se hace automáticamente)
- Ahora si tienes 5, debería ejecutarse sin errores.
Para resumir, para que funcione, debería ver MyEmbeddedFramework.framework en
A) General> Binarios incrustados
B) Fase de construcción> Marcos incrustados
Funcionó bien en iPhone5 / iOS8 no en iPhone4S / iOS7 donde obtengo:
dyld: Biblioteca no cargada: @ rpath / ObjectiveLyricsTouch2.framework / ObjectiveLyricsTouch2 Referenciada desde: /var/mobile/Applications/739D9C44-3B91-4D4F-805B-83BE66C9CBCA/musiXmatch.app/musiXmatch Motivo: no se encontró una imagen adecuada. Encontré: /private/var/mobile/Applications/739D9C44-3B91-4D4F-805B-83BE66C9CBCA/musiXmatch.app/Frameworks/ObjectiveLyricsTouch2.framework/ObjectiveLyricsTouch2: incompatible cpu-subtype: 0x0000000 / mobile / private / aplicaciones / mobile / var / / / / 739D9C44-3B91-4D4F-805B-83BE66C9CBCA / musiXmatch.app / Frameworks / ObjectiveLyricsTouch2.framework / ObjectiveLyricsTouch2
El problema estaba en el EmbeddedFramework. Tuve que
1) Establecer la arquitectura por defecto 2) Establecer arquitecturas válidas en: armv7, armv7s y armv64 (como Apple sugiere que armv64 es necesario para que funcione Embedded Frameworks).
Luego pude ejecutar la aplicación con un marco incrustado en
- iPhone5S / iPhone5C iOS8
- iPhone5S / iPhone5C iOS7
- iPod 5th gen / iOS7
- iPhone4S / iOS7
- iPhone4 / iOS7
De todos modos, al enviar a iTunesConnect, recibo algunos errores para la versión mínima requerida:
- La versión mínima del framework "..." no es válida. El valor mínimo es iOS 8.0;
- Arquitectura no válida: las aplicaciones que incluyen una extensión de aplicación y un marco deben admitir arm64;
Entonces, temporalmente, le dije que no a la biblioteca dinámica, mientras que muchos dispositivos en iOS 7. Cómo resolví mi problema. Necesitaba lib para transferir el modelo entre la aplicación y la extensión. Entonces, puse mi modelo en una cadena JSON en un contenedor compartido. Y funciona como un encanto.
Intentamos ejecutar el último código en las siguientes configuraciones:
iOS 8+ - iPhone 5s iOS 7.1.2 - iPhone 4 iOS 6.1.3 - iPad 4
La aplicación funciona bien en los tres dispositivos, pero la advertencia está presente en el Xcode durante la compilación. "Los dylibs / frameworks integrados solo se ejecutan en iOS 8 o posterior"
También intenté archivar la aplicación para enviarla a la tienda de aplicaciones, funcionó bien.
Además, descubrí un enlace en el que un desarrollador de Apple declaró que se trataba de un error https://devforums.apple.com/message/999579#999579
Me encontraba con un problema en el que necesitaba incluir algunas bibliotecas como marcos incrustados; de lo contrario, recibí el error anterior y, cuando hice eso, recibí errores al enviarlo a la tienda de aplicaciones.
Mi solución fue usar Pods y asegurarme de que descomentaras "use_frameworks". línea.
Profundizando en la documentación de Apple , descubrí el comando dlopen , que se utiliza para vincular las bibliotecas en algunas condiciones, dependiendo de las versiones del sistema y las bibliotecas compatibles.
Ejemplo de uso de dlopen: ¿Es la función ''dlopen ()'' API privada?
Así que echemos un vistazo a la solución proporcionada por Apple Docs:
Implementación de una aplicación que contiene versiones anteriores de iOS
Si vincula a un marco incrustado desde la aplicación que lo contiene, aún puede implementarlo en versiones de iOS anteriores a 8.0, aunque los marcos incrustados no estén disponibles en esas versiones.
El mecanismo que le permite hacer esto es el comando dlopen , que utiliza para vincular y cargar condicionalmente un paquete de framework. Emplea este comando como alternativa al enlace de tiempo de compilación que puede especificar en el editor de destino Xcode General o Build Phases . La idea principal es vincular los marcos incrustados en la aplicación que lo contiene solo cuando se ejecuta en iOS 8.0 o posterior .
Debe usar Objective-C, no Swift , en sus declaraciones de código que cargan condicionalmente un paquete de framework. El resto de su aplicación se puede escribir en cualquier idioma, y el marco incrustado en sí también se puede escribir en cualquier idioma.
Después de llamar a dlopen , acceda a las clases de framework incrustadas utilizando el siguiente tipo de declaración:
MyLoadedClass *loadedClass = [[NSClassFromString (@"MyClass") alloc] init];
IMPORTANTE
Si su objetivo de aplicación contiene enlaces a un marco incrustado, debe incluir la arquitectura arm64 o será rechazado por la App Store.
Para configurar un proyecto Xcode de extensión de aplicación para aprovechar la vinculación condicional
- Para cada una de sus extensiones de aplicación contenidas, establezca el objetivo de implementación en iOS 8.0 o posterior, como de costumbre. Haga esto en la sección "Información de implementación" de la pestaña General en el editor de destino de Xcode.
- Para su aplicación que contiene, configure el objetivo de implementación para que sea la versión más antigua de iOS que desea admitir.
- En su aplicación que contiene, condicionalice las llamadas al comando dlopen dentro de una verificación de tiempo de ejecución para la versión de iOS utilizando el método systemVersion. Llame al comando dlopen solo si la aplicación que lo contiene se ejecuta en iOS 8.0 o posterior. Asegúrese de usar Objective-C, no Swift, al hacer esta llamada.
Ciertas API de iOS usan marcos integrados a través del comando dlopen. Debe condicionalizar el uso de estas API tal como lo hace al llamar a dlopen directamente. Estas API son del tipo opaco CFBundleRef :
CFBundleGetFunctionPointerForName
CFBundleGetFunctionPointersforNames
Y de la clase NSBundle:
carga
loadAndReturnError:
classNamed:
En una aplicación que contenga que está implementando en versiones de iOS anteriores a 8.0, llame a estas API solo dentro de una verificación de tiempo de ejecución que garantice que se esté ejecutando en iOS 8.0 o posterior, y llame a estas API utilizando Objective-C.
Resuelvo este problema de la siguiente manera: use el mismo objetivo de implementación en el objetivo "Embedded Framework" y en el objetivo "principal de la aplicación".
Se corrigió el error en xcode 6.1.1
usando vim o vi abra el archivo project.pbxproj.
Al final del archivo (busque 8.1), habría una sección Begin XCBuildConfiguration
Busca tu marco.
En nuestro caso, aunque el objetivo de implementación se estableció en 7.1 a través de Xcode -> general en la configuración de destino, la entrada en el archivo tenía 8.1 para depuración y liberación
Aquí se ve la sección del archivo anterior:
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = ENFramework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
La nueva sección se ve así:
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = ENFramework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Ahora no recibimos el error solo una advertencia (pero funciona en el dispositivo iOS 7.1): ld: advertencia: los dylibs / frameworks integrados solo se ejecutan en iOS 8 o posterior
Esto parece un error de xcode que establece incorrectamente diferentes objetivos de ios y luego causa un error.
Solo para que conste ... Tuve este problema al cambiar un proyecto de iOS8 a iOS7.
La aplicación utilizaba cocoapods y no tenía marcos incrustados personalizados.
Tuve que cambiar el proyecto principal dos objetivos
Solicitud
Prueba de aplicación
Cambiar el tipo de Mach-O a estático (de la respuesta anterior).
Luego en el proyecto cocoapods. Debajo de cada proyecto de subpoder, cambiar el tipo de Mach-O a estático, dejando en blanco la configuración del Proyecto de vaina principal de Mach-O.