在Swift框架中导入CommonCrypto

hpi*_*que 181 ios commoncrypto swift

如何CommonCrypto在iOS的Swift框架中导入?

我理解如何CommonCrypto在Swift应用程序中使用:您添加#import <CommonCrypto/CommonCrypto.h>到桥接标头.但是,Swift框架不支持桥接头.该文件说:

您可以导入具有纯Objective-C代码库,纯Swift代码库或混合语言代码库的外部框架.无论框架是用单一语言编写还是包含来自两种语言的文件,导入外部框架的过程都是相同的.导入外部框架时,请确保将要导入的框架的"定义模块"构建设置设置为"是".

您可以使用以下语法将框架导入到不同目标中的任何Swift文件中:

import FrameworkName
Run Code Online (Sandbox Code Playgroud)

不幸的是,导入CommonCrypto不起作用.也没有添加#import <CommonCrypto/CommonCrypto.h>到伞头.

Mik*_*ler 133

更简单,更健壮的东西是使用Run Script阶段创建一个名为"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
Run Code Online (Sandbox Code Playgroud)

使用shell代码并且${SDKROOT}意味着您不必对Xcode.app路径进行硬编码,这可能会改变系统到系统,特别是如果您使用xcode-select切换到测试版,或者是在安装了多个版本的CI服务器上构建在非标准的位置.您也不需要对SDK进行硬编码,因此这适用于iOS,macOS等.您也不需要在项目的源目录中放置任何内容.

创建此目标后,使用Target Dependencies项使您的库/框架依赖它:

在此输入图像描述

这将确保在构建框架之前生成模块映射.

MACOS注:如果你支持macOS的话,你会需要添加macosxSupported Platforms构建你刚刚创建的新的总目标设定,否则将不把模块映射在正确的Debug导出数据文件夹的其余部分框架产品.

在此输入图像描述

接下来,将模块映射的父目录添加到${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMapSwift部分(SWIFT_INCLUDE_PATHS)下的"Import Paths"构建设置:

在此输入图像描述

$(inherited)如果在项目或xcconfig级别定义了搜索路径,请记住添加一行.

就是这样,你现在应该可以 import CommonCrypto

更新Xcode 10

Xcode 10现在附带了一个CommonCrypto模块映射,因此不需要这种解决方法.如果您想同时支持Xcode 9和10,您可以在Run Script阶段检查模块映射是否存在,例如

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
Run Code Online (Sandbox Code Playgroud)

  • 这个答案应该是最重要的.简单而优雅 (8认同)
  • @IanDundas我更新了上面的代码,修复了重新编译问题以及在macOS上使用它的修复 (2认同)

ste*_*lis 90

您实际上可以构建一个"正常工作"的解决方案(无需将module.modulemapSWIFT_INCLUDE_PATHS设置复制到您的项目中,这是其他解决方案所要求的),但它确实需要您创建一个虚拟框架/模块,您可以将ll导入到您的框架中.我们也可以保证它工作平台无论是(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
    
    Run Code Online (Sandbox Code Playgroud)
  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 *
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • iphonesimulator.modulemap

      module CommonCrypto [system] {
          header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h"
          export *
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 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 *
      }
      
      Run Code Online (Sandbox Code Playgroud)

    (如果您正在运行测试版,请将"Xcode.app"替换为"Xcode-beta.app".10.11如果没有运行El Capitan,请替换为您当前的OS SDK.)

  4. 在项目设置的" 信息"选项卡上的" 配置"下,将CommonCrypto的" 调试"和" 发布"配置设置为" CommonCrypto"(引用CommonCrypto.xcconfig).

  5. 在框架目标的Build Phases选项卡上,将CommonCrypto框架添加到Target Dependencies.另外,将libcommonCrypto.dylib添加到Link Binary With Libraries构建阶段.

  6. Products中选择CommonCrypto.framework并确保其包装器的Target Membership设置为Optional.

您现在应该能够import CommonCrypto在您的包装器框架中构建,运行和运行.

有关示例,请参阅SQLite.swift如何使用虚拟sqlite3.framework.

  • 人们如何或在哪里找到这样的东西? (30认同)
  • 这太可怕了.我有一个Xcodes的动物园,每个都以不同的方式打破,并且在整个地方都有通向标题的绝对路径.在库比蒂诺,或者至少与负责这个模块图混乱的人有什么不妥 (7认同)
  • 只需注意清楚,您需要在步骤1中选择Objective-C作为语言.这很容易被忽略.另外,也许是因为我没有.dylib,我需要在步骤5中添加.framework. (5认同)
  • 没有步骤(5),对我有用.有了它,我得到一个构建错误:`ld:无法直接链接到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.2.sdk/usr/lib/system/libcommonCrypto. dylib.链接反对伞框架'System.framework'.对于架构x86_64` (4认同)
  • 优秀!用它来制作https://github.com/soffes/Crypto虽然我没有链接`System.framework`.值得注意的是,如果您的框架是跨平台的,您必须为Mac和iOS制作单独的包装框架. (4认同)
  • 7.2.1在2月2日发布并发布说明"Swift编译器现在更加严格地包含非模块化头文件.调试Swift目标需要框架正确模块化,这意味着所有公开导入的头文件都要考虑到在框架的伞头中,从另一个模块化框架导入,或在自定义module.modulemap文件中显式列出(仅限高级用户)." 这是IMNSHO不适合高级用户,这是一个面向真正的masochists的功能 (3认同)
  • 得到"没有这样的模块CommonCrypto"总是......在步骤5中也没有.dylib .XCode 7.2 (2认同)
  • 更新:我昨天问过一些苹果的工程师,他们说modulemap是要走的路. (2认同)

hpi*_*que 82

我找到了一个在Swift框架中成功使用CommonCrypto的GitHub项目:SHA256-Swift.此外,这篇关于sqlite3同样问题的文章很有用.

基于以上所述,步骤如下:

1)CommonCrypto在项目目录中创建一个目录.在其中,创建一个module.map文件.模块映射将允许我们将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 *
}
Run Code Online (Sandbox Code Playgroud)

2)在构建设置中,在Swift编译器 - 搜索路径中,将CommonCrypto目录添加到导入路径(SWIFT_INCLUDE_PATHS).

构建设置

3)最后,将Swice文件中的CommonCrypto导入为任何其他模块.例如:

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 ""
    }
}
Run Code Online (Sandbox Code Playgroud)

限制

在另一个项目中使用自定义框架在编译时失败并出现错误missing required module 'CommonCrypto'.这是因为CommonCrypto模块似乎不包含在自定义框架中.解决方法是Import Paths在使用框架的项目中重复步骤2(设置).

模块映射不是平台独立的(它当前指向特定平台,iOS 8模拟器).我不知道如何制作相对于当前平台的标题路径.

iOS 8的更新<=我们应该删除行链接"CommonCrypto",以获得成功的编译.

更新/编辑

我一直收到以下构建错误:

ld:找不到-lCommonCrypto用于体系结构x86_64 clang的库:错误:链接器命令失败,退出代码为1(使用-v查看调用)

除非我link "CommonCrypto"module.map我创建的文件中删除了该行.一旦我删除了这一行,它就构建好了.

  • 哎呀,苹果肯定想让事情变得困难.它会杀死Swifties让我们导入文件/框架而不必通过所有这些BS吗? (28认同)
  • 这是令人愤怒的,因为`$ SDKROOT`变量应该允许你平台不可知路径,但我不知道如何在Swift中实现. (4认同)
  • 对我来说,直到我从module.map文件中删除了"link"CommonCrypto"`之后才行. (2认同)

onm*_*133 50

这个答案讨论了如何使它在框架内工作,以及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

Cocoapods采用模块映射方法

公共标题方法

Cocoapods采用公共标题方法

有趣的相关帖子

  • 我创建了一个pod,我设置了SWIFT_INCLUDE_PATHS和preserve_paths.当我运行`pod lib lint`,但构建失败并出现错误:没有这样的模块'CommonCrypto'.我该怎么处理它. (3认同)
  • 与问题无关,但我喜欢使用表情符号作为项目符号! (2认同)
  • @ onmyway133如果用`$(PODS_TARGET_SRCROOT)/ Sources/CCommonCrypto`替换`$(PODS_ROOT)/ CommonCryptoSwift/Sources/CCommonCrypto`,使用本地开发pod就可以了.为本地pod正确设置了"PODS_TARGET_SRCROOT". (2认同)

mxc*_*xcl 41

好消息!Swift 4.2(Xcode 10)终于提供了CommonCrypto!

只需添加import CommonCrypto您的swift文件即可.


Nik*_*kin 7

警告:iTunesConnect可能会拒绝使用此方法的应用.


我的团队中的新成员不小心打破了其中一个最佳答案给出的解决方案,因此我决定将其整合到一个名为CommonCryptoModule的小包装项目中.您可以手动安装或通过Cocoapods安装:

pod 'CommonCryptoModule', '~> 1.0.2'
Run Code Online (Sandbox Code Playgroud)

然后,您所要做的就是在需要的地方导入模块CommonCrypto,如下所示:

import CommonCryptoModule
Run Code Online (Sandbox Code Playgroud)

希望别人觉得这很有用.

  • 这在Xcode 9.1上非常有效.谢谢! (4认同)

jjr*_*ott 5

我想我对Mike Weller的出色工作有所改进.

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"
Run Code Online (Sandbox Code Playgroud)

这个脚本在正确的位置构建了一个带有module.map的裸骨架,然后依赖于Xcode自动搜索BUILT_PRODUCTS_DIR框架.

我将原始的CommonCrypto include文件夹链接为框架的Headers文件夹,因此结果也应该用于Objective C项目.


kub*_*k G 5

For anyone using swift 4.2 with Xcode 10:

CommonCrypto module is now provided by the system, so you can directly import it like any other system framework.

import CommonCrypto

Run Code Online (Sandbox Code Playgroud)