Импорт CommonCrypto в рамках Swift


как импортировать CommonCrypto в рамках Swift для iOS?

Я понимаю, как использовать CommonCrypto в быстром приложении: вы добавляете #import <CommonCrypto/CommonCrypto.h> к заголовку моста.

однако фреймворки Swift не поддерживают мостовые заголовки. Элемент документация говорит:

вы можете импортировать внешние фреймворки, которые имеют чистую кодовую базу Objective-C, чистую кодовую базу Swift или кодовую базу на смешанном языке. Этот процесс импорта внешнего рамки одинаковы ли фреймворк написан на одном языке или содержит файлы из обоих языки. При импорте внешней среды убедитесь, что Определяет настройку сборки модуля для импортируемой платформы да.

вы можете импортировать фреймворк в любой Swift файл в пределах другого цель с помощью следующего синтаксиса:

import FrameworkName

к сожалению, импорт CommonCrypto не работает. Как и добавление #import <CommonCrypto/CommonCrypto.h> в заголовок зонтик.

14 163

14 ответов:

что-то немного более простое и надежное-это создать агрегатную цель под названием "CommonCryptoModuleMap" с фазой запуска скрипта для автоматического создания карты модуля и с правильным путем Xcode/SDK:

enter image description here enter image description here

этап запуска скрипта должен содержать этот 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

С помощью кода оболочки и ${SDKROOT} означает, что вам не нужно жестко кодировать Xcode.путь приложения, который может меняться система-система, особенно если вы используете xcode-select для перехода на бета-версию, или строятся на сервере CI, где несколько версий установлены в нестандартных местах. Вам также не нужно жестко кодировать SDK, поэтому это должно работать для iOS, macOS и т. д. Вам также не нужно, чтобы что-то сидело в исходном каталоге вашего проекта.

после создания этой цели, сделайте вашу библиотеку / фреймворк зависят от него с целевыми зависимостями пункт:

enter image description here

это гарантирует, что карта модуля будет сгенерирована до того, как ваш фреймворк будет построен.

в macOS Примечание: если вы поддерживаете macOS а также, вам нужно будет добавить macosx до Supported Platforms настройка сборки на новую цель aggregate, которую вы только что создали, иначе она не поместит карту модуля в правильное Debug папка производных данных с остальной частью фреймворка товары.

enter image description here

затем добавьте родительский каталог карты модуля,${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap, к настройке сборки "импорт путей" в разделе Swift (SWIFT_INCLUDE_PATHS):

enter image description here

не забудьте добавить $(inherited) строка, если у вас есть пути поиска, определенные на уровне проекта или xcconfig.

вот и все, теперь вы должны быть в состоянии import CommonCrypto

обновление для Xcode 10

Xcode 10 теперь поставляется с картой модуля CommonCrypto, что делает этот обходной путь ненужным. Если вы хотите поддерживать как Xcode 9, так и 10, вы можете выполнить проверку на этапе запуска скрипта, чтобы узнать, существует ли карта модуля или нет, например

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

вы можете фактически построить решение, которое "просто работает" (нет необходимости копировать .modulemap и SWIFT_INCLUDE_PATHS настройки для вашего проекта, как того требуют другие решения здесь), но он требует, чтобы вы создали фиктивный фреймворк/модуль, который вы импортируете в свой фреймворк. Мы также можем обеспечить его работу независимо от платформы (iphoneos,iphonesimulator или macosx).

  1. добавьте новую цель фреймворка в свой проект и назовите ее после системная библиотека,например, "CommonCrypto". (Вы можете удалить заголовок зонтика,CommonCrypto.h.)

  2. Добавить новый Настройки имя, например, "CommonCrypto.xcconfig". (Не проверяйте ни одну из ваших целей для включения.) Заполните его следующим образом:

    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. создайте три указанных выше файла карт модулей и заполните их следующим образом следующее:

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

    (Заменить " Xcode.приложение " с " Xcode-бета.приложение" если вы используете бета-версию. Заменить 10.11 С вашим текущим OS SDK, если не работает El Capitan.)

  4. на элемент Info вкладка настроек вашего проекта, в разделе конфигурации, выберите Debug и релиз конфигурации CommonCrypto до CommonCrypto (ссылка CommonCrypto.xcconfig).

  5. на вашей целевой платформе Собрать Фаз tab, добавьте CommonCrypto рамки Целевой Зависимостей. Дополнительно добавить libcommonCrypto.dylib нужна до Связать Двоичный Файл С Библиотеками построить этапа.

  6. выберите CommonCrypto.рамки на продукты и убедитесь, что его Целевые Членские для вашей обертки установлено значение дополнительно.

теперь вы должны быть в состоянии построить, запустить и import CommonCrypto в рамках фантик.

для примера см. как SQLite.Свифт использует фиктивную sqlite3.рамки.

я нашел проект GitHub, который успешно использует CommonCrypto в рамках Swift:SHA256-Swift. Кроме того, эта статья о та же проблема с sqlite3 была полезной.

на основании вышеизложенного, шаги:

1) Создать CommonCrypto каталог внутри каталога проекта. Внутри, создать . Карта модуля позволит нам использовать библиотеку CommonCrypto в качестве модуля в Swift. Его содержание являются:

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) в настройках сборки, в пределах Swift Компилятор - Поиск Путей добавить

в этом ответе обсуждается, как заставить его работать внутри структуры, а также с Cocoapods и Carthage

модульный подход

я использую modulemap в моей обертке вокруг CommonCrypto https://github.com/onmyway133/arcane, https://github.com/onmyway133/Reindeer

для тех, кто получает header not found, пожалуйста, взгляните https://github.com/onmyway133/Arcane/issues/4 или бежать xcode-select --install

  • сделать папку CCommonCrypto содержащих module.modulemap

      module CCommonCrypto {
        header "/usr/include/CommonCrypto/CommonCrypto.h"
        export *
      }
    
  • перейти к встроенным настройкам - > пути импорта

      ${SRCROOT}/Sources/CCommonCrypto
    

Cocoapods с модульным подходом

подход к публичному заголовку

  • Ji является оболочкой вокруг libxml2, и он использует открытый подход заголовка

  • он имеет файл заголовкаhttps://github.com/honghaoz/Ji/blob/master/Source/Ji.h с Target Membership значение Public

  • он имеет список заголовочных файлов для libxml2 https://github.com/honghaoz/Ji/tree/master/Source/Ji-libxml

  • он имеет настройки сборки - > пути поиска заголовка

      $(SDKROOT)/usr/include/libxml2
    
  • он имеет настройки сборки- > другие флаги компоновщика

      -lxml2
    

Cocoapods с публичным подходом заголовка

интересные сообщения по теме

хорошая новость! Swift 4.2 (Xcode 10) наконец-то предоставляет CommonCrypto!

внимание: iTunesConnect может отклонение приложения, которые используют этот метод.


новый член моей команды случайно сломал решение, данное одним из лучших ответов, поэтому я решил объединить его в небольшой проект-оболочку под названием CommonCryptoModule. Вы можете установить его вручную или через Cocoapods:

pod 'CommonCryptoModule', '~> 1.0.2'

тогда все, что вам нужно сделать, это импортировать модуль, где вам нужно CommonCrypto, как Итак:

import CommonCryptoModule

надеюсь, что кто-то еще находит это полезным.

Я думаю, что у меня есть улучшение к отличной работе Майка Веллера.

добавьте этап запуска скрипта перед Compile Sources фаза, содержащая этот 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"

этот скрипт создает каркас голых костей с модулем.карта в правильном месте, а затем полагается на автоматический поиск Xcode BUILT_PRODUCTS_DIR для рамок.

я связал исходную папку CommonCrypto include в качестве папки заголовков фреймворка, поэтому результат также должен функционировать для Objective C проекты.

@mogstad был достаточно любезен, чтобы обернуть решение @stephencelis в Cocoapod:

pod 'libCommonCrypto'

другие доступные стручки не работали для меня.

решения modulemap могут быть хорошими и надежными в отношении изменений SDK, но я нашел их неудобными для использования на практике и не такими надежными, как хотелось бы, когда я раздаю вещи другим. Чтобы попытаться сделать все это более надежным, я пошел другим путем:

просто скопируйте заголовки.

Я знаю, хрупкая. Но Apple почти никогда не вносит существенных изменений в CommonCrypto, и я живу мечтой о том, что они не изменят его каким-либо значительным образом без того, чтобы наконец создание CommonCrypto модульный заголовок.

под " копировать заголовки "я имею в виду" вырезать и вставить все заголовки, которые вам нужны в один массивный заголовок в вашем проекте так же, как препроцессор будет делать."В качестве примера того, что вы можете скопировать или адаптировать, см. RNCryptor.h.

обратите внимание, что все эти файлы лицензируются в соответствии с APSL 2.0, и этот подход намеренно поддерживает уведомления об авторских правах и лицензиях. Мой шаг конкатенации лицензируется под MIT, и это только применяется до следующего уведомления о лицензии).

Я не говорю, что это красивое решение, но до сих пор это было невероятно простое решение для реализации и поддержки.

Я знаю, это старый вопрос. Но я выясняю альтернативный способ использования библиотеки в проекте Swift, который может быть полезен для тех, кто не хочет импортировать фреймворк, представленный в этих ответах.

в проекте Swift создайте заголовок моста Objective-C, создайте категорию NSData (или пользовательский класс, который будет использовать библиотеку) в Objective-C. единственным недостатком будет то, что вам нужно будет написать весь код реализации в Objective-C. Для пример:

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

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

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

а затем в заголовке моста objective-c добавьте это

#import "NSData+NSDataEncryptionExtension.h"

а потом в Swift классе делают то же самое:

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

это работает, как ожидалось.

я добавил некоторые cocoapods magic к ответу jjrscott в случае, если вам нужно использовать CommonCrypto в вашей библиотеке cocoapods.


1) добавьте эту строку в свой podspec:

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

2) сохраните это в папке библиотеки или где угодно (однако не забудьте изменить script_phase соответственно ...)

# 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"

работает как шарм :)

Я не уверен, что что-то изменилось с Xcode 9.2, но теперь гораздо проще достичь этого. Единственное, что мне нужно было сделать, это создать папку под названием "CommonCrypto" в моем каталоге проекта framework и создать в ней два файла, один из которых называется "cc.ч" следующим образом:

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

и еще один называется модуль.modulemap:

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

(Я не знаю, почему вы не можете ссылаться на заголовочные файлы из области SDKROOT непосредственно в файле modulemap, но я не мог получить его работа)

третье-найти параметр "пути импорта" и установить значение $(SRCROOT). На самом деле вы можете установить его в любую папку, в которой вы хотите, чтобы папка CommonCrypto находилась, если вы не хотите ее на корневом уровне.

после этого вы должны быть в состоянии использовать

import CommonCrypto

В любом swift файле и всех типах / функциях / etc. имеются в наличии.

слово предупреждения, хотя-если ваше приложение использует libCommonCrypto (или libcoreCrypto) это исключительно легко чтобы не слишком сложный хакер подключил отладчик к вашему приложению и узнал, какие ключи передаются этим функциям.

Если здесь для алгоритмов хэширования, таких как SHA, MD5 и т. д., Не используйте громоздкую библиотеку CommonCrypto. Вместо этого найдите конкретную библиотеку хэширования, которую вы ищете.

например, для MD5, вы можете пойти с SwiftHash

Это очень просто. Добавить

#import <CommonCrypto/CommonCrypto.h>

к a .H-файл (файл заголовка моста вашего проекта). В качестве соглашения вы можете назвать его Yourprojectname-Bridging-Header.з.

затем перейдите к настройкам сборки проекта и найдите генерацию кода компилятора Swift. Под ним добавьте имя вашего заголовка моста в запись "Objective-C Bridging Header".

ты молодец. В вашем Swift-коде не требуется импорт. Любые публичные заголовки Objective-C, перечисленные в этом файл заголовка моста будет виден Swift.