How do you import CommonCrypto
in a Swift framework for iOS?
I understand how to use CommonCrypto
in a Swift app:
You add #import <CommonCrypto/CommonCrypto.h>
to the bridging header.
However, Swift frameworks don't support bridging headers. The documentation says:
You can import external frameworks that have a pure Objective-C codebase, a pure Swift codebase, or a mixed-language codebase. The process for importing an external framework is the same whether the framework is written in a single language or contains files from both languages. When you import an external framework, make sure the Defines Module build setting for the framework you’re importing is set to Yes.
You can import a framework into any Swift file within a different target using the following syntax:
import FrameworkName
Unfortunately, import CommonCrypto
doesn't work. Neither does adding #import <CommonCrypto/CommonCrypto.h>
to the umbrella header.
I found a GitHub project that successfully uses CommonCrypto in a Swift framework: SHA256-Swift. Also, this article about the same problem with sqlite3 was useful.
Based on the above, the steps are:
1) Create a CommonCrypto
directory inside the project directory. Within, create a module.map
file. The module map will allow us to use the CommonCrypto library as a module within Swift. Its contents are:
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) In Build Settings, within Swift Compiler - Search Paths, add the CommonCrypto
directory to Import Paths (SWIFT_INCLUDE_PATHS
).
3) Finally, import CommonCrypto inside your Swift files as any other modules. For example:
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 ""
}
}
Using the custom framework in another project fails at compile time with the error missing required module 'CommonCrypto'
. This is because the CommonCrypto module does not appear to be included with the custom framework. A workaround is to repeat step 2 (setting Import Paths
) in the project that uses the framework.
The module map is not platform independent (it currently points to a specific platform, the iOS 8 Simulator). I don't know how to make the header path relative to the current platform.
Updates for iOS 8 <= We should remove the line link "CommonCrypto", to get the successful compilation.
UPDATE / EDIT
I kept getting the following build error:
ld: library not found for -lCommonCrypto for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
Unless I removed the line link "CommonCrypto"
from the module.map
file I created. Once I removed this line it built ok.