ios swift commoncrypto

ios - Importación de CommonCrypto en un marco de Swift



(11)

@mogstad ha tenido la amabilidad de envolver la solución @stephencelis en un Cocoapod:

pod ''libCommonCrypto''

Los otros pods disponibles no funcionaron para mí.

¿Cómo se importa CommonCrypto en Swift framework para iOS?

Entiendo cómo usar CommonCrypto en una aplicación Swift: agrega #import <CommonCrypto/CommonCrypto.h> al encabezado de puente.

Sin embargo, los marcos Swift no son compatibles con los encabezados puente. La documentation dice:

Puede importar marcos externos que tengan una base de código Objective-C pura, una base de código Swift pura o una base de código de idioma mixto. El proceso para importar un marco externo es el mismo ya sea que el marco esté escrito en un solo idioma o contenga archivos de ambos idiomas. Cuando importe un marco de trabajo externo, asegúrese de que la configuración de creación de Definir módulo para el marco que está importando esté configurado en Sí.

Puede importar un marco en cualquier archivo Swift dentro de un destino diferente usando la siguiente sintaxis:

import FrameworkName

Desafortunadamente, importar CommonCrypto no funciona. Tampoco agrega #import <CommonCrypto/CommonCrypto.h> al encabezado del paraguas.


Algo un poco más simple y más robusto es crear un objetivo Agregado llamado "CommonCryptoModuleMap" con una fase Run Script para generar el mapa del módulo automáticamente y con la ruta correcta de Xcode / SDK:

La fase Run Script debe contener este bash:

# This if-statement means we''ll only run the main script if the CommonCryptoModuleMap directory doesn''t exist # Because otherwise the rest of the script causes a full recompile for anything where CommonCrypto is a dependency # Do a "Clean Build Folder" to remove this directory and trigger the rest of the script to run if [ -d "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap" ]; then echo "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap directory already exists, so skipping the rest of the script." exit 0 fi mkdir -p "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap" cat <<EOF > "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap/module.modulemap" module CommonCrypto [system] { header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h" export * } EOF

El uso del código del shell y ${SDKROOT} significa que no es necesario codificar la ruta Xcode.app, que puede variar de sistema a sistema, especialmente si usa xcode-select para cambiar a una versión beta, o si se basa en una Servidor CI donde se instalan múltiples versiones en ubicaciones no estándar. Tampoco necesita codificar el SDK de forma rígida, por lo que debería funcionar para iOS, macOS, etc. Tampoco necesita tener nada en el directorio de origen de su proyecto.

Después de crear este objetivo, haga que su biblioteca / marco dependa de él con un elemento Dependencias de destino:

Esto asegurará que el mapa del módulo se genere antes de que se cree su marco.

Nota de macOS : si también es compatible con macOS , deberá agregar macosx a la configuración de compilación Supported Platforms en el nuevo objetivo agregado que acaba de crear; de lo contrario, no colocará el mapa del módulo en la carpeta de datos derivados de Debug correcta. con el resto de los productos de framework.

A continuación, agregue el directorio principal del mapa del módulo, ${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap , a la configuración de compilación "Importar rutas" en la sección Swift ( SWIFT_INCLUDE_PATHS ):

Recuerde agregar una línea $(inherited) si tiene rutas de búsqueda definidas en el proyecto o en el nivel xcconfig.

Eso es todo, ahora debería poder import CommonCrypto


Creo que tengo una mejora en el excelente trabajo de Mike Weller.

Agregue una fase Ejecutar script antes de la fase Compile Sources contiene este bash:

# This if-statement means we''ll only run the main script if the # CommonCrypto.framework directory doesn''t exist because otherwise # the rest of the script causes a full recompile for anything # where CommonCrypto is a dependency # Do a "Clean Build Folder" to remove this directory and trigger # the rest of the script to run FRAMEWORK_DIR="${BUILT_PRODUCTS_DIR}/CommonCrypto.framework" if [ -d "${FRAMEWORK_DIR}" ]; then echo "${FRAMEWORK_DIR} already exists, so skipping the rest of the script." exit 0 fi mkdir -p "${FRAMEWORK_DIR}/Modules" cat <<EOF > "${FRAMEWORK_DIR}/Modules/module.modulemap" module CommonCrypto [system] { header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h" export * } EOF ln -sf "${SDKROOT}/usr/include/CommonCrypto" "${FRAMEWORK_DIR}/Headers"

Este script construye un framework básico con el module.map en el lugar correcto y luego se basa en la búsqueda automática de Xcode de BUILT_PRODUCTS_DIR para frameworks.

Vinculaba la carpeta de inclusión CommonCrypto original como la carpeta de encabezados del marco, por lo que el resultado también debería funcionar para los proyectos de Objective C.


De hecho, puede crear una solución que "simplemente funcione" (no es necesario copiar las configuraciones module.modulemap y SWIFT_INCLUDE_PATHS en su proyecto, tal como lo requieren otras soluciones aquí), pero sí requiere que cree un marco / módulo ficticio que usted Importaremos en tu marco de trabajo. También podemos garantizar que funciona independientemente de la plataforma ( iphoneos , iphonesimulator o macosx ).

  1. Agregue un nuevo objetivo de infraestructura a su proyecto y asígnele un nombre después de la biblioteca del sistema, por ejemplo , "CommonCrypto". (Puede eliminar el encabezado del paraguas, CommonCrypto.h ).

  2. Agregue un nuevo archivo de configuración de configuración y asígnele un nombre, por ejemplo , "CommonCrypto.xcconfig". (No marque ninguno de sus objetivos para su inclusión.) Rellene con lo siguiente:

    MODULEMAP_FILE[sdk=iphoneos*] = / $(SRCROOT)/CommonCrypto/iphoneos.modulemap MODULEMAP_FILE[sdk=iphonesimulator*] = / $(SRCROOT)/CommonCrypto/iphonesimulator.modulemap MODULEMAP_FILE[sdk=macosx*] = / $(SRCROOT)/CommonCrypto/macosx.modulemap

  3. Cree los tres archivos de mapa de módulo referenciados, arriba, y rellenelos con lo siguiente:

    • iphoneos.modulemap

      module CommonCrypto [system] { header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h" export * }

    • iphonesimulator.modulemap

      module CommonCrypto [system] { header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h" export * }

    • macosx.modulemap

      module CommonCrypto [system] { header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/CommonCrypto/CommonCrypto.h" export * }

    (Reemplace "Xcode.app" por "Xcode-beta.app" si está ejecutando una versión beta. Reemplace 10.11 con su SO SDK actual si no está ejecutando El Capitan).

  4. En la pestaña Información de la configuración de su proyecto, en Configuraciones , establezca las configuraciones de depuración y liberación de CommonCrypto en CommonCrypto ( haciendo referencia a CommonCrypto.xcconfig ).

  5. En la pestaña Crear fases de su objetivo de marco, agregue el marco CommonCrypto a Dependencias de destino . Además, agregue libcommonCrypto.dylib a la fase de compilación de Link Binary With Libraries .

  6. Seleccione CommonCrypto.framework en Productos y asegúrese de que su Membresía de destino para su contenedor esté configurada como Opcional .

Ahora debería poder compilar, ejecutar e import CommonCrypto en su marco de trabajo.

Para ver un ejemplo, vea cómo SQLite.swift usa un ficticio sqlite3.framework .


Encontré un proyecto GitHub que usa CommonCrypto con éxito en un marco Swift: SHA256-Swift . Además, este artículo sobre el mismo problema con sqlite3 fue útil.

En base a lo anterior, los pasos son:

1) Cree un directorio CommonCrypto dentro del directorio del proyecto. En el interior, crea un archivo module.map . El mapa del módulo nos permitirá usar la biblioteca CommonCrypto como un módulo dentro de Swift. Sus contenidos son:

module CommonCrypto [system] { header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.0.sdk/usr/include/CommonCrypto/CommonCrypto.h" link "CommonCrypto" export * }

2) En Configuraciones de compilación, dentro del compilador Swift - Rutas de búsqueda , agregue el directorio CommonCrypto a Importar rutas ( SWIFT_INCLUDE_PATHS ).

3) Finalmente, importe CommonCrypto dentro de sus archivos Swift como cualquier otro módulo. Por ejemplo:

import CommonCrypto extension String { func hnk_MD5String() -> String { if let data = self.dataUsingEncoding(NSUTF8StringEncoding) { let result = NSMutableData(length: Int(CC_MD5_DIGEST_LENGTH)) let resultBytes = UnsafeMutablePointer<CUnsignedChar>(result.mutableBytes) CC_MD5(data.bytes, CC_LONG(data.length), resultBytes) let resultEnumerator = UnsafeBufferPointer<CUnsignedChar>(start: resultBytes, length: result.length) let MD5 = NSMutableString() for c in resultEnumerator { MD5.appendFormat("%02x", c) } return MD5 } return "" } }

Limitaciones

El uso del marco personalizado en otro proyecto falla en tiempo de compilación con el missing required module ''CommonCrypto'' error missing required module ''CommonCrypto'' . Esto se debe a que el módulo CommonCrypto no parece estar incluido en el marco personalizado. Una solución consiste en repetir el paso 2 (establecer Import Paths ) en el proyecto que utiliza el marco.

El mapa del módulo no es independiente de la plataforma (actualmente apunta a una plataforma específica, el simulador de iOS 8). No sé cómo hacer la ruta del encabezado en relación con la plataforma actual.

Actualizaciones para iOS 8 <= Debemos eliminar el enlace de línea "CommonCrypto" , para obtener la compilación exitosa.

ACTUALIZAR / EDITAR

Seguí recibiendo el siguiente error de compilación:

ld: biblioteca no encontrada para -lCommonCrypto para la arquitectura x86_64 clang: error: comando del enlazador falló con el código de salida 1 (use -v para ver la invocación)

A menos que haya eliminado el link "CommonCrypto" línea link "CommonCrypto" del archivo module.map que creé. Una vez que eliminé esta línea, creo bien.


Es muy sencillo. Añadir

#import <CommonCrypto/CommonCrypto.h>

a un archivo .h (el archivo de encabezado de puente de su proyecto). Como una convención, puede llamarlo YourProjectName-Bridging-Header.h.

Luego vaya a la configuración de compilación de su proyecto y busque Swift Compiler - Generación de código. Debajo de él, agregue el nombre de su encabezado de puente a la entrada "Cabecera de puente de Objective-C".

Ya terminaste No se requieren importaciones en su código Swift. Todos los encabezados públicos de Objective-C listados en este archivo de encabezado de puente serán visibles para Swift.


Esta respuesta discute cómo hacer que funcione dentro de un marco, y con Cocoapods y Cartago

🐟 enfoque de mapa de módulos

Uso modulemap en mi envoltorio alrededor de CommonCrypto https://github.com/onmyway133/arcane , https://github.com/onmyway133/Reindeer

Para aquellos que header not found , por favor, xcode-select --install un vistazo a https://github.com/onmyway133/Arcane/issues/4 o ejecuten xcode-select --install

  • Crear una carpeta CCommonCrypto contenga module.modulemap

    module CCommonCrypto { header "/usr/include/CommonCrypto/CommonCrypto.h" export * }

  • Ir a Configuraciones Construidas -> Importar Rutas

    ${SRCROOT}/Sources/CCommonCrypto

🌳 Cocoapods con enfoque modulemap

🐘 enfoque de encabezado público

🐏 Cocoapods con enfoque de encabezado público

🐝 Interesantes publicaciones relacionadas


Las soluciones de módulo de módulo pueden ser buenas y robustas frente a los cambios del SDK, pero me resulta difícil usarlas en la práctica, y no tan confiables como me gustaría cuando se lo entrego a otros. Para intentar que todo sea más infalible, fui de otra manera:

Solo copia los encabezados.

Lo sé, frágil. Pero Apple casi nunca hace cambios significativos en CommonCrypto y estoy viviendo el sueño de que no lo cambiarán de ninguna manera significativa sin convertir finalmente CommonCrypto en un encabezado modular.

Al "copiar los encabezados" me refiero a "cortar y pegar todos los encabezados que necesita en un encabezado masivo en su proyecto, tal como lo haría el preprocesador". Como ejemplo de esto que puede copiar o adaptar, vea RNCryptor.h .

Tenga en cuenta que todos estos archivos tienen licencia bajo APSL 2.0, y este enfoque mantiene intencionalmente los avisos de derechos de autor y licencia. Mi paso de concatenación está autorizado bajo MIT, y eso solo se aplica hasta el próximo aviso de licencia).

No estoy diciendo que esta sea una solución hermosa, pero hasta ahora parece haber sido una solución increíblemente simple tanto para la implementación como para el soporte.


Sé que esta es una vieja pregunta. Pero descubro una forma alternativa de usar la biblioteca en el proyecto Swift, que podría ser útil para aquellos que no quieren importar el marco presentado en estas respuestas.

En el proyecto Swift, cree un encabezado puente de Objective-C, cree la categoría NSData (o clase personalizada que para usar la biblioteca) en Objective-C. El único inconveniente sería que debe escribir todo el código de implementación en Objective-C. Por ejemplo:

#import "NSData+NSDataEncryptionExtension.h" #import <CommonCrypto/CommonCryptor.h> @implementation NSData (NSDataEncryptionExtension) - (NSData *)AES256EncryptWithKey:(NSString *)key { //do something } - (NSData *)AES256DecryptWithKey:(NSString *)key { //do something }

Y luego en su encabezado de puente objetivo-c, agregue esto

#import "NSData+NSDataEncryptionExtension.h"

Y luego en la clase Swift hacemos algo similar:

public extension String { func encryp(withKey key:String) -> String? { if let data = self.data(using: .utf8), let encrypedData = NSData(data: data).aes256Encrypt(withKey: key) { return encrypedData.base64EncodedString() } return nil } func decryp(withKey key:String) -> String? { if let data = NSData(base64Encoded: self, options: []), let decrypedData = data.aes256Decrypt(withKey: key) { return decrypedData.UTF8String } return nil } }

Funciona como se esperaba.


Si está aquí para los algoritmos hash, como SHA, MD5, etc., no use la abultada biblioteca CommonCrypto. Encuentre la biblioteca de hashing específica que está buscando en su lugar.

Por ejemplo, para MD5, puede ir con SwiftHash


ADVERTENCIA: iTunesConnect puede reject aplicaciones que utilizan este método.

El nuevo miembro de mi equipo rompió accidentalmente la solución dada por una de las mejores respuestas, así que decidí consolidarlo en un pequeño proyecto de envoltura llamado CommonCryptoModule . Puede instalarlo manualmente o mediante Cocoapods:

pod ''CommonCryptoModule'', ''~> 1.0.2''

Entonces, todo lo que tiene que hacer es importar el módulo donde necesita CommonCrypto , así:

import CommonCryptoModule

Espero que alguien más encuentre esto útil.