ios - Importando o CommonCrypto em um framework Swift




(10)

Como você importa o CommonCrypto em um framework Swift para iOS?

Entendo como usar o CommonCrypto em um aplicativo Swift: você adiciona #import <CommonCrypto/CommonCrypto.h> ao cabeçalho de ponte. No entanto, as estruturas do Swift não suportam cabeçalhos de ponte. A documentation diz:

Você pode importar estruturas externas que tenham uma base de código Objective-C pura, uma base de código Swift pura ou uma base de código de idioma misto. O processo de importação de uma estrutura externa é o mesmo, quer a estrutura esteja escrita em um único idioma ou contenha arquivos de ambas as linguagens. Quando você importa uma estrutura externa, certifique-se de que a configuração de construção do módulo de definição para a estrutura que você está importando esteja definida como Sim.

Você pode importar uma estrutura para qualquer arquivo do Swift em um destino diferente usando a seguinte sintaxe:

import FrameworkName

Infelizmente, importar o CommonCrypto não funciona. Nem adicionar #import <CommonCrypto/CommonCrypto.h> ao cabeçalho do guarda-chuva.


É muito simples. Adicionar

#import <CommonCrypto/CommonCrypto.h>

para um arquivo .h (o arquivo de cabeçalho de bridging do seu projeto). Como convenção, você pode chamá-lo de YourProjectName-Bridging-Header.h.

Então vá para o seu projeto Build Settings e procure pelo Swift Compiler - Code Generation. Abaixo, adicione o nome do seu cabeçalho de bridging à entrada "Objetive-C Bridging Header".

Você está feito. Nenhuma importação necessária no seu código Swift. Todos os cabeçalhos públicos do Objective-C listados neste arquivo de cabeçalho de ponte serão visíveis para o Swift.


Algo um pouco mais simples e robusto é criar um alvo Aggregate chamado "CommonCryptoModuleMap" com uma fase Run Script para gerar o mapa do módulo automaticamente e com o caminho correto do Xcode / SDK:

A fase Run Script deve conter 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

Usar código shell e ${SDKROOT} significa que você não precisa codificar o caminho Xcode.app que pode variar de sistema para sistema, especialmente se você usa xcode-select para mudar para uma versão beta, ou está construindo um Servidor de CI em que várias versões são instaladas em locais não padrão. Você também não precisa codificar o SDK para que isso funcione para iOS, macOS, etc. Você também não precisa ter nada no diretório de origem do seu projeto.

Depois de criar esse destino, faça com que sua biblioteca / estrutura dependa dele com um item Target Dependencies:

Isso garantirá que o mapa do módulo seja gerado antes que o framework seja construído.

macOS note : Se você também está dando suporte ao macOS , precisará adicionar macosx à configuração de compilação Supported Platforms no novo alvo agregado que acabou de criar, caso contrário, ele não colocará o mapa do módulo na pasta de dados derivados correta. com o resto dos produtos de framework.

Em seguida, adicione o diretório-pai do mapa do módulo, ${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap , à configuração de construção "Import Paths" na seção Swift ( SWIFT_INCLUDE_PATHS ):

Lembre-se de adicionar uma linha $(inherited) se você tiver caminhos de pesquisa definidos no nível do projeto ou do xcconfig.

É isso aí, agora você deve poder import CommonCrypto

Atualização para o Xcode 10

O Xcode 10 agora é fornecido com um mapa do módulo CommonCrypto, tornando desnecessária essa solução alternativa. Se você gostaria de apoiar ambos os Xcode 9 e 10 você pode fazer uma verificação na fase Run Script para ver se o mapa do módulo existe ou não, por exemplo

COMMON_CRYPTO_DIR="${SDKROOT}/usr/include/CommonCrypto"
if [ -f "${COMMON_CRYPTO_DIR}/module.modulemap" ]
then
   echo "CommonCrypto already exists, skipping"
else
    # generate the module map, using the original code above
fi

Boas notícias! O Swift 4.2 (Xcode 10) finalmente fornece o CommonCrypto!

Basta adicionar import CommonCrypto no seu arquivo rápido.


Caso você tenha o problema abaixo:

ld: biblioteca não encontrada para -lapple_crypto clang: erro: o comando linker falhou com o código de saída 1 (use -v para ver invocação)

No Xcode 10, Swift 4.0. CommonCrypto é uma parte do framework.

Adicionar

  • importar CommonCrypto

Remover

  • Arquivo commonCrpto lib do link binário com bibliotecas das fases de construção
  • importar CommonCrypto do cabeçalho Bridging

Isso funcionou para mim!


Eu acho que tenho uma melhoria para o excelente trabalho de Mike Weller.

Adicione uma fase Run Script antes da fase Compile Sources contendo 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"

Esse script constrói uma estrutura bare-bone com o module.map no lugar correto e depois confia na busca automática do Xcode de BUILT_PRODUCTS_DIR para frameworks.

Eu vinculei o CommonCrypto original a incluir a pasta como a pasta Headers da estrutura, para que o resultado também funcionasse para os projetos do Objective C.


Eu adicionei algumas mágicas de cocoapods à resposta do jjrscott caso você precise usar o CommonCrypto na sua biblioteca de cocoapods.

1) Adicione esta linha ao seu podspec:

s.script_phase = { :name => 'CommonCrypto', :script => 'sh $PROJECT_DIR/../../install_common_crypto.sh', :execution_position => :before_compile }

2) Salve isso na pasta da sua biblioteca ou onde quiser (no entanto, não esqueça de alterar a script_phase de acordo ...)

# 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"
echo "module CommonCrypto [system] {
    header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}" >> "${FRAMEWORK_DIR}/Modules/module.modulemap"

ln -sf "${SDKROOT}/usr/include/CommonCrypto" "${FRAMEWORK_DIR}/Headers"

Funciona como um encanto :)


Eu sei que esta é uma questão antiga. Mas eu descubro uma maneira alternativa de usar a biblioteca no projeto Swift, o que pode ser útil para aqueles que não querem importar o framework introduzido nessas respostas.

No projeto Swift, crie um cabeçalho de ponte Objective-C, crie a categoria NSData (ou classe personalizada que use a biblioteca) em Objective-C. A única desvantagem seria que você tem que escrever todo o código de implementação no Objective-C. Por exemplo:

#import "NSData+NSDataEncryptionExtension.h"
#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (NSDataEncryptionExtension)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
    //do something
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
//do something
}

E, em seguida, no cabeçalho de ponte object-c, adicione isto

#import "NSData+NSDataEncryptionExtension.h"

E então na classe Swift faz coisa semelhante:

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 esperado.


Não tenho certeza se algo mudou com o Xcode 9.2, mas agora é muito mais simples conseguir isso. As únicas coisas que eu tive que fazer é criar uma pasta chamada "CommonCrypto" no meu diretório de projeto do framework e criar dois arquivos dentro dele, um chamado "cc.h" como segue:

#include <CommonCrypto/CommonCrypto.h>
#include <CommonCrypto/CommonRandom.h>

E outro chamado module.modulemap:

module CommonCrypto {
    export *
    header "cc.h"
}

(Eu não sei porque você não pode referenciar arquivos de cabeçalho da área do SDKROOT diretamente em um arquivo de modulemap, mas eu não consegui fazê-lo funcionar)

A terceira coisa é encontrar a configuração "Import Paths" e definir como $ (SRCROOT). Na verdade, você pode configurá-lo para qualquer pasta na qual deseja que a pasta CommonCrypto esteja, se você não quiser no nível raiz.

Depois disso você deve ser capaz de usar

import CommonCrypto

Em qualquer arquivo rápido e todos os tipos / funções / etc. Estão disponíveis.

Uma palavra de aviso - se seu aplicativo usa libCommonCrypto (ou libcoreCrypto) é excepcionalmente fácil para um hacker não muito sofisticado anexar um depurador ao seu aplicativo e descobrir quais chaves estão sendo passadas para essas funções.


Para quem usa o swift 4.2 com o Xcode 10 :

O módulo CommonCrypto é agora fornecido pelo sistema, para que você possa importá-lo diretamente como qualquer outra estrutura do sistema.

import CommonCrypto

Você pode realmente criar uma solução que "simplesmente funcione" (não é necessário copiar as configurações de SWIFT_INCLUDE_PATHS e SWIFT_INCLUDE_PATHS para o seu projeto, conforme exigido por outras soluções aqui), mas requer que você crie um framework / módulo fictício Vou importar em sua estrutura adequada. Também podemos garantir que ele funcione independentemente da plataforma ( iphoneos , iphonesimulator ou macosx ).

  1. Adicione um novo alvo de framework ao seu projeto e nomeie-o após a biblioteca do sistema, por exemplo , "CommonCrypto". (Você pode excluir o cabeçalho do guarda-chuva, CommonCrypto.h .)

  2. Adicione um novo arquivo de definições de configuração e nomeie-o, por exemplo , "CommonCrypto.xcconfig". (Não marque nenhum dos seus alvos para inclusão.) Preencha com o seguinte:

    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. Crie os três arquivos de mapeamento de módulo referenciados acima e preencha-os com o seguinte:

    • 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 *
      }

    (Substitua "Xcode.app" por "Xcode-beta.app" se você estiver executando uma versão beta. Substitua 10.11 pelo seu atual SDK do SO, se não estiver executando o El Capitan.)

  4. Na guia Informações das configurações do projeto, em Configurações , defina as configurações Depurar e Liberar do CommonCrypto para CommonCrypto (referenciando CommonCrypto.xcconfig ).

  5. Na guia Fases de Construção do seu alvo de estrutura, inclua a estrutura CommonCrypto em Dependências de Destino . Adicione também libcommonCrypto.dylib à fase de compilação Link Binary With Libraries .

  6. Selecione CommonCrypto.framework em Produtos e certifique-se de que sua Associação de Destino para seu wrapper esteja configurada como Opcional .

Agora você deve ser capaz de criar, executar e import CommonCrypto em sua estrutura de wrapper.

Por exemplo, veja como o SQLite.swift usa um fictício sqlite3.framework .





commoncrypto