Импорт CommonCrypto в рамках Swift
как импортировать CommonCrypto в рамках Swift для iOS?
Я понимаю, как использовать CommonCrypto в быстром приложении: вы добавляете #import <CommonCrypto/CommonCrypto.h>
к заголовку моста.
однако фреймворки Swift не поддерживают мостовые заголовки. Элемент документация говорит:
вы можете импортировать внешние фреймворки, которые имеют чистую кодовую базу Objective-C, чистую кодовую базу Swift или кодовую базу на смешанном языке. Этот процесс импорта внешнего рамки одинаковы ли фреймворк написан на одном языке или содержит файлы из обоих языки. При импорте внешней среды убедитесь, что Определяет настройку сборки модуля для импортируемой платформы да.
вы можете импортировать фреймворк в любой Swift файл в пределах другого цель с помощью следующего синтаксиса:
import FrameworkName
к сожалению, импорт CommonCrypto
не работает. Как и добавление #import <CommonCrypto/CommonCrypto.h>
в заголовок зонтик.
14 ответов:
что-то немного более простое и надежное-это создать агрегатную цель под названием "CommonCryptoModuleMap" с фазой запуска скрипта для автоматического создания карты модуля и с правильным путем Xcode/SDK:
этап запуска скрипта должен содержать этот 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 и т. д. Вам также не нужно, чтобы что-то сидело в исходном каталоге вашего проекта.после создания этой цели, сделайте вашу библиотеку / фреймворк зависят от него с целевыми зависимостями пункт:
это гарантирует, что карта модуля будет сгенерирована до того, как ваш фреймворк будет построен.
в macOS Примечание: если вы поддерживаете
macOS
а также, вам нужно будет добавитьmacosx
доSupported Platforms
настройка сборки на новую цель aggregate, которую вы только что создали, иначе она не поместит карту модуля в правильноеDebug
папка производных данных с остальной частью фреймворка товары.затем добавьте родительский каталог карты модуля,
${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap
, к настройке сборки "импорт путей" в разделе Swift (SWIFT_INCLUDE_PATHS
):не забудьте добавить
$(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
).
добавьте новую цель фреймворка в свой проект и назовите ее после системная библиотека,например, "CommonCrypto". (Вы можете удалить заголовок зонтика,CommonCrypto.h.)
Добавить новый Настройки имя, например, "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
создайте три указанных выше файла карт модулей и заполните их следующим образом следующее:
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.)на элемент Info вкладка настроек вашего проекта, в разделе конфигурации, выберите Debug и релиз конфигурации CommonCrypto до CommonCrypto (ссылка CommonCrypto.xcconfig).
на вашей целевой платформе Собрать Фаз tab, добавьте CommonCrypto рамки Целевой Зависимостей. Дополнительно добавить libcommonCrypto.dylib нужна до Связать Двоичный Файл С Библиотеками построить этапа.
выберите 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 с модульным подходом
вот подспец https://github.com/onmyway133/Arcane/blob/master/Arcane.podspec
s.source_files = 'Sources/**/*.swift' s.xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/CommonCryptoSwift/Sources/CCommonCrypto' } s.preserve_paths = 'Sources/CCommonCrypto/module.modulemap'
используя
module_map
не работает, смотрите https://github.com/CocoaPods/CocoaPods/issues/5271использование локального модуля разработки с
path
не работает, см. https://github.com/CocoaPods/CocoaPods/issues/809вот почему вы видите, что мой пример Подфайл https://github.com/onmyway133/CommonCrypto.swift/blob/master/Example/CommonCryptoSwiftDemo/Podfile указывает на git РЕПО
target 'CommonCryptoSwiftDemo' do pod 'CommonCryptoSwift', :git => 'https://github.com/onmyway133/CommonCrypto.swift' end
подход к публичному заголовку
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 с публичным подходом заголовка
взгляните на podspec https://github.com/honghaoz/Ji/blob/master/Ji.podspec
s.libraries = "xml2" s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2', 'OTHER_LDFLAGS' => '-lxml2' }
интересные сообщения по теме
внимание: 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.