代码之家  ›  专栏  ›  技术社区  ›  hpique

在Swift框架中导入CommonCrypto

  •  189
  • hpique  · 技术社区  · 11 年前

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

    我知道如何使用 通用密码 在Swift应用程序中: 您添加了 #import <CommonCrypto/CommonCrypto.h> 到桥接头。 然而,Swift框架不支持桥接头。这个 documentation 说:

    您可以导入具有纯Objective-C代码库、纯Swift代码库或混合语言代码库的外部框架。这个 导入外部框架的过程是相同的,无论 框架是用一种语言编写的,或者包含两种语言的文件 语言。导入外部框架时,请确保 定义要导入的框架的模块构建设置 更改为“是”。

    您可以将框架导入到另一个 目标,使用以下语法:

    import FrameworkName
    

    不幸的是,导入 通用密码 不起作用。也不能添加 #导入<CommonCrypto/CommonCrypto.h> 至伞头。

    16 回复  |  直到 7 年前
        1
  •  141
  •   Mike Weller    7 年前

    更简单、更健壮的方法是创建一个名为“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
    

    使用shell代码和 ${SDKROOT} 意味着你不必硬编码Xcode.app路径,因为它可能会因系统而异,特别是如果你使用 xcode-select 或者正在CI服务器上构建,其中多个版本安装在非标准位置。您也不需要对SDK进行硬编码,因此这应该适用于iOS、macOS等。您也不必在项目的源目录中有任何内容。

    创建此目标后,使用目标依赖项使库/框架依赖于它:

    enter image description here

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

    macOS注释 :如果您支持 macOS 此外,您还需要添加 macosx Supported Platforms 在刚刚创建的新聚合目标上构建设置,否则它不会将模块映射放在正确的 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
    
        2
  •  95
  •   stephencelis    10 年前

    实际上,您可以构建一个“只起作用”的解决方案(无需复制 模块.模块映射 SWIFT_INCLUDE_PATHS 根据其他解决方案的要求,设置到项目中),但它确实需要您创建一个虚拟框架/模块,然后将其导入到框架中。我们还可以确保无论平台如何,它都能正常工作( iphoneos , iphonesimulator macosx ).

    1. 将新的框架目标添加到项目中,并以系统库的名称命名, 例如 ,“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 *
        }
        
      • iphone模拟器模块图

        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.app”替换为“Xcode-beta.app”。替换 10.11 如果不运行El Capitan,则使用当前的OS SDK。)

    4. 信息 项目设置的选项卡,位于 配置 ,设置 调试 释放 的配置 通用密码 通用密码 (参考 CommonCrypto.xc配置 ).

    5. 在您的框架目标上 构建阶段 选项卡,添加 通用密码 框架 目标相关性 。另外添加 libcommonCrypto.dylib 将二进制文件与库链接 构建阶段。

    6. 选择 CommonCrypto.framework 在里面 产品 并确保 目标成员资格 您的包装设置为 可选择的 .

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

    例如,请参见 SQLite.swift 使用虚拟对象 sqlite3.框架 .

        3
  •  84
  •   mxcl    8 年前

    我发现了一个在Swift框架中成功使用CommonCrypto的GitHub项目: SHA256-Swift 。此外,本文关于 the same problem with sqlite3 是有用的。

    基于上述内容,步骤如下:

    1) 创建 CommonCrypto 项目目录中的目录。在中,创建 module.map 文件模块映射将允许我们在Swift中使用CommonCrypto库作为模块。其内容包括:

    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编译器-搜索路径 ,添加 通用密码 目录到 导入路径 ( SWIFT_INCLUDE_PATHS ).

    Build Settings

    3) 最后,将CommonCrypto作为其他模块导入Swift文件中。例如:

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

    局限性

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

    模块映射不是独立于平台的(它当前指向一个特定的平台,即iOS 8模拟器)。我不知道如何使标头路径相对于当前平台。

    iOS 8更新<=我们应该把这条线去掉 链接“CommonCrypto” ,以获得成功的编译。

    更新/编辑

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

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

    除非我拔掉了电话线 link "CommonCrypto" 来自 模块.map 我创建的文件。一旦我删除了这条线,它就正常了。

        4
  •  52
  •   Community Mohan Dere    8 年前

    这个答案讨论了如何使其在框架内工作,以及如何与Cocoapods和迦太基合作

    模块映射法

    我使用 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

    公共标头方法

    带有公共标头方法的椰子

    有趣的相关帖子

        5
  •  46
  •   Marián Černý    7 年前

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

    只需添加 import CommonCrypto 在您的swift文件中。

        6
  •  7
  •   Nikita Kukushkin    8 年前

    警告:iTunesConnect可能 reject 使用此方法的应用程序。


    我团队中的新成员意外地打破了一个顶级答案给出的解决方案,因此我决定将其整合到一个名为 CommonCryptoModule 。您可以手动或通过Cocoapods安装:

    pod 'CommonCryptoModule', '~> 1.0.2'
    

    然后,您所要做的就是在需要的地方导入模块 CommonCrypto ,类似于:

    import CommonCryptoModule
    

    希望其他人觉得这很有用。

        7
  •  5
  •   jjrscott    8 年前

    我认为我对迈克·韦勒的出色工作有所改进。

    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"
    

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

    我将最初的CommonCryptoinclude文件夹链接为框架的Headers文件夹,因此结果也应适用于Objective C项目。

        8
  •  5
  •   kubrick G    7 年前

    对于任何使用 雨燕4.2 具有 X代码10 :

    CommonCrypto模块现在由系统提供,因此您可以像任何其他系统框架一样直接导入它。

    import CommonCrypto
    
    
        9
  •  4
  •   Jacob Jennings    9 年前

    @莫格斯塔德非常友善地将@斯蒂芬塞利斯的解决方案包装成可可酱:

    pod'libCommonCrypto'

    其他可用的吊舱对我不起作用。

        10
  •  4
  •   iwasrobbed    8 年前

    modulemap解决方案可能很好,并且对SDK的更改很健壮,但我发现它们在实践中很难使用,而且在向其他人分发东西时不如我希望的那样可靠。为了使这一切更加简单,我采取了不同的方式:

    只需复制标题。

    我知道,脆弱。但苹果几乎从未对CommonCrypto进行过重大更改,我一直梦想着,如果不最终将CommonCrypto成为模块化标头,他们将不会以任何重大方式对其进行更改。

    所谓“复制头”,我的意思是“像预处理器一样,将您需要的所有头剪切并粘贴到项目中的一个大型头中。” RNCryptor.h .

    请注意,所有这些文件都是根据APSL 2.0许可的,这种方法有意维护版权和许可声明。我的连接步骤在麻省理工学院许可,这只适用于下一个许可通知)。

    我并不是说这是一个漂亮的解决方案,但到目前为止,它似乎是一个对实现和支持都非常简单的解决方案。

        11
  •  2
  •   Terence    9 年前

    我知道这是个老问题。但我找到了在Swift项目中使用库的另一种方法,这可能对那些不想导入这些答案中介绍的框架的人有所帮助。

    在Swift项目中,创建Objective-C桥接头,在Objective-C中创建NSData类别(或使用库的自定义类)。唯一的缺点是必须用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
    }
    }
    

    它按预期工作。

        12
  •  2
  •   David    7 年前

    我在jjrcott的答案中添加了一些cocapods魔法,以防您需要在cocapods库中使用CommonCrypto。


    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"
    

    像符咒一样工作:)

        13
  •  0
  •   Dylan Nicholson    7 年前

    我不确定Xcode 9.2是否有所改变,但现在实现这一点要简单得多。我唯一需要做的就是在我的框架项目目录中创建一个名为“CommonCrypto”的文件夹,并在其中创建两个文件,其中一个文件名为“cc.h”,如下所示:

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

    另一个名为module.modulemap:

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

    (我不知道为什么不能在modulemap文件中直接引用来自SDKROOT区域的头文件,但我无法使其工作)

    第三件事是找到“导入路径”设置并设置为$(SRCROOT)。 事实上,如果您不希望CommonCrypto文件夹位于根级别,您可以将其设置为任何您想要的文件夹。

    在此之后,您应该能够使用

    import CommonCrypto
    

    在任何swift文件和所有类型/功能等中。可用。

    不过需要提醒的是,如果你的应用程序使用libCommonCrypto(或libcoreCrypto),那么一个不太老练的黑客非常容易将调试器连接到你的应用,并找出传递给这些函数的密钥。

        14
  •  0
  •   Ravi B    6 年前

    如果您遇到以下问题:

    ld:找不到-lapple_crypto的库 clang:error:链接器命令失败,退出代码为1(使用-v查看调用)

    在Xcode 10中,Swift 4.0。CommonCrypto是框架的一部分。

    添加

     import CommonCrypto
    

    去除

    • 链接二进制文件中的CommonCrpto-lib文件与Build中的库 相位
    • import CommonCrypto 来自桥接集管

    这对我有用!

        15
  •  -1
  •   Joey    6 年前

    更新Xcode后,我也遇到了同样的情况。 我尝试了我能做的一切,比如重新安装cocapods和清理项目,但都没有成功。 现在它已经解决了 重新启动 系统。

        16
  •  -14
  •   Juanjo Conti    11 年前

    这很简单。添加

    #import <CommonCrypto/CommonCrypto.h>
    

    到.h文件(项目的桥接头文件)。按照惯例,您可以将其称为YourProjectName Bridging Header.h。

    然后转到项目Build Settings,查找Swift编译器-代码生成。在它下面,将桥接标头的名称添加到条目“Objetive-C桥接标头”。

    你完了。您的Swift代码中不需要导入。这个桥接头文件中列出的任何公共Objective-C头对Swift都是可见的。