Creating Pod which depends on static library - ios

I'm trying to create Pod which depends on static library (.a file + headers whose structure should be preserved for my pod compilation) and I don't want to link my static library to Application that will be using my pod, it's only internal dependency, no headers or lib itself should be exposed outside of Pod.
How do I create podspec for this situation?

I ended up with wrapping my static library with headers into framework folder and adding this framework to vendored_frameworks podspec field and adding header search path
s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(FRAMEWORK_SEARCH_PATHS)/FrameworkName.framework/Headers" }
Alongside with CocoaPods I'm able to link my binary and headers separately to Xcode framework target and distribute my library using Carthage

Looks like this will get a bit messy... One way would be to recompile the static lib to a dylib, and then load the symbols on demand. By doing so you won't have to touch the .podspec file. I assume you are using Swift 3 and want to load C functions from the library.
If you do not have the source or otherwise can't recompile the static lib, you could convert it to a dylib by using this guide.
I will add an example on how to dynamically load the CCHmac function from libcommonCrypto.dylib
/// - Returns: A function pointer to CCHmac from libcommonCrypto
private static func loadHMACfromCommonCrypto() -> CCHmac
{
let libcc = dlopen("/usr/lib/system/libcommonCrypto.dylib", RTLD_NOW)
return unsafeBitCast(dlsym(libcc, "CCHmac"), to: CCHmac.self)
}
In case that you can't/won't load the symbols from the header file, you will have to define them yourself.
private typealias CCHmac = #convention(c) (
_ algorithm: CUnsignedInt,
_ key: UnsafePointer<CUnsignedChar>,
_ keyLength: CUnsignedLong,
_ data: UnsafePointer<CUnsignedChar>,
_ dataLength: CUnsignedLong,
_ macOut: UnsafeMutablePointer<CUnsignedChar>
) -> Void

Related

Declare Podspec with a dependency to an objc library

I am developing a Swift framework (MyFramework) that has a dependency to a third party static library written in Objc (NewRelic)
I am using CocoaPods 1.4.0 and I have declared my podspec like this:
...
s.source_files = 'MyFrame/Classes/**/*'
s.static_framework = true
s.dependency 'NewRelicAgent', '6.1.1' # Obj-c
s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(PODS_ROOT)/NewRelicAgent/NewRelicAgent/NewRelicAgent.framework/Headers', 'SWIFT_INCLUDE_PATHS' => '$(PODS_TARGET_SRCROOT)/MyFrameFramework' }
s.preserve_paths = 'MyFrameFramework/MyFrame.modulemap'
From what I read in different posts, what I think I am doing here is:
first declare a static_framework to be able to use a static library, NewRelic.
Set the NewRelic dependency.
Set the header paths to find the NewRelic headers and locate the modulemap as explained here
This is my MyFrame.modulemap:
framework module LGResources {
umbrella header "MyFrameFramework.h"
export *
module * { export * }
}
And this MyFrameFramework.h:
//! Project version number for LGResources.
FOUNDATION_EXPORT double MyFrameVersionNumber;
//! Project version string for LGResources.
FOUNDATION_EXPORT const unsigned char MyFrameVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Amplitude/PublicHeader.h>
#import <NewRelicAgent/NewRelic.h>
Inside my framework classes I am trying to use NewRelic but it does not work
I am starting to give up since I find confusing to have so many references in the CocoaPod specs: module_map, frameworks, vendored_frameworks, dependency, preserve_paths, ...
Can someone please point me into the right direction? How can I declare a static dependency and use it inside my framework?
Many thanks in advance!
PS: I don't really know where should I put the MyFrameFramework.h file to be managed by CocoaPods, by I have tried different manual approaches with no luck.
There may be additional issues, but one problem is that NewRelicAgent.framework is missing a module map.
Static frameworks can have other static frameworks or static vendored_frameworks as dependencies. A static library is not sufficient. A module map bundled into a framework is necessary to tell the build system how to access its public methods from Swift or Objective C modules.
The NewRelicAgent podspec is specifying a vendored_framework, but the zip is missing a module map.
It might be possible to come up with a workaround, but the best solution would be to convince the NewRelicAgent pod maintainers to update the pod.

native zlib inflate/deflate for swift3 on iOS

I'd like to be able to inflate/deflate Swift3 Data structs. I found GzipSwift, but it's not clear how I make that available to my iOS app. The naive things I've tried include:
Copying the Data+Gzip.swift file into my own project. This then complains about the import zlib at the top of said file. I think that has something to do the with the modulemap files in the zlib directory of the same sources. But I'm not sure what or how to recreate those in my own project.
Cloned the repository from github, opened XCode and built in (pressed the run button basically). Then tried to add that as a linked library or framework to my own project. I'm pretty sure just selecting the top level directory of the repository is not what I want to do, but I didn't know what else to try.
I've found some other code out there, but it seems dated and relative to Swift2.
Swift 5 implementation using Compression.
Took me a few days to realise I had to drop the first 2 bytes of the compressed data.
Hope it can help somebody else.
import Foundation
import Compression
func decompress(_ data: Data) -> String {
let size = 8_000_000
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
let result = data.subdata(in: 2 ..< data.count).withUnsafeBytes ({
let read = compression_decode_buffer(buffer, size, $0.baseAddress!.bindMemory(to: UInt8.self, capacity: 1),
data.count - 2, nil, COMPRESSION_ZLIB)
return String(decoding: Data(bytes: buffer, count:read), as: UTF8.self)
}) as String
buffer.deallocate()
return result
}
I just recently had to add that exact library and file to my project, and after a lot of troubleshooting finally got it working, so let me walk you through the steps!
Okay
1) Go to the top level directory of your project in finder, and create a new folder called Swiftzlib or whatever you want the name of the module that you will be importing to be. (What we will do is add the zlib library as a module, so think of it as importing Foundation or some such other module). To clarify, this Swiftzlib directory will end up as a child directory of the same directory that contains your *.xcodeproj and *.xcworkspace files.
2) Inside the folder you created, make two files.
include.h
module.modulemap
3) In your include.h file, enter the following:
#include<zlib.h>
4) In your module.modulemap file, enter the following:
module Swiftzlib [system] {
header "include.h"
export *
}
Where Swiftzlib is the same as the name of the folder that you created.
5) Open your Xcode project, and select your target
5a) In Build Phases -> Link Binary with Libraries, add libz.tbd
5b) In Build Settings -> Swift Compiler - Search Paths, add $(PROJECT_DIR)/Swiftzlib non-recursively to the import paths
5c) In Build Settings -> Other Linker Flags, add -lz as a flag
6) Select your project in Xcode (may not be necessary, but I've done it in my project and it works)
6a) In Build Settings -> Swift Compiler - Search Paths, add $(PROJECT_DIR)/Swiftzlib non-recursively to the import paths
7) In Data+Gzip.swfit, add import Swiftzlib to the top of the file
8) Clean, Build, and Run!
I maintain a small Swift 3+ wrapper around Apples native libcompression framework at:
https://github.com/mw99/DataCompression
Usage example for gzip:
let data: Data! = "https://www.ietf.org/rfc/rfc1952.txt".data(using: .utf8)
let gzipped: Data! = data.zip()
let gunzipped: Data? = gzipped.unzip()
assert(data == gunzipped)
But if you are only interested in classic inflate and deflate you may use the .inflate() and .deflate() methods instead. That will save 18 bytes because the gzip header won't be added.
I made a small spm extension inspired by #vauxhall 's answer
https://github.com/mezhevikin/Zlib
import Zlib
// Decompressed data
print(data.decompressed)
// Decompressed string
print(data.decompressedString)

How to link my cocoapod with library?

My cocoapod library need to be linked with some lib, let's say "libFoo.a". How can i add headers to search path (Libs/foo/include) and library path to link (Libs/foo/lib)?
I've used:
s.ios.library = "Foo"
s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "$(PODS_ROOT)/Libs/foo/include" }
but when linting i'm getting an error:
ld: library not found for -lFoo
Let's say here is my cocoapod structure:
L---Classes
| L---myClass.m
| L---... (other files)
L---Libs
L---foo
L---include
| L---libFoo.h
L---lib
L---libFoo.a
You might need to ensure the folder structure is retained, check out preserve_paths and also look at podspecs from other pods to see what they do.

Importing CommonCrypto in a Swift framework

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.
Something a little simpler and more robust is to create an Aggregate target called "CommonCryptoModuleMap" with a Run Script phase to generate the module map automatically and with the correct Xcode/SDK path:
The Run Script phase should contain this 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
Using shell code and ${SDKROOT} means you don't have to hard code the Xcode.app path which can vary system-to-system, especially if you use xcode-select to switch to a beta version, or are building on a CI server where multiple versions are installed in non-standard locations. You also don't need to hard code the SDK so this should work for iOS, macOS, etc. You also don't need to have anything sitting in your project's source directory.
After creating this target, make your library/framework depend on it with a Target Dependencies item:
This will ensure the module map is generated before your framework is built.
macOS note: If you're supporting macOS as well, you'll need to add macosx to the Supported Platforms build setting on the new aggregate target you just created, otherwise it won't put the module map in the correct Debug derived data folder with the rest of the framework products.
Next, add the module map's parent directory, ${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap, to the "Import Paths" build setting under the Swift section (SWIFT_INCLUDE_PATHS):
Remember to add a $(inherited) line if you have search paths defined at the project or xcconfig level.
That's it, you should now be able to import CommonCrypto
Update for Xcode 10
Xcode 10 now ships with a CommonCrypto module map making this workaround unnecessary. If you would like to support both Xcode 9 and 10 you can do a check in the Run Script phase to see if the module map exists or not, e.g.
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
You can actually build a solution that "just works" (no need to copy a module.modulemap and SWIFT_INCLUDE_PATHS settings over to your project, as required by other solutions here), but it does require you to create a dummy framework/module that you'll import into your framework proper. We can also ensure it works regardless of platform (iphoneos, iphonesimulator, or macosx).
Add a new framework target to your project and name it after the system library, e.g., "CommonCrypto". (You can delete the umbrella header, CommonCrypto.h.)
Add a new Configuration Settings File and name it, e.g., "CommonCrypto.xcconfig". (Don't check any of your targets for inclusion.) Populate it with the following:
MODULEMAP_FILE[sdk=iphoneos*] = \
$(SRCROOT)/CommonCrypto/iphoneos.modulemap
MODULEMAP_FILE[sdk=iphonesimulator*] = \
$(SRCROOT)/CommonCrypto/iphonesimulator.modulemap
MODULEMAP_FILE[sdk=macosx*] = \
$(SRCROOT)/CommonCrypto/macosx.modulemap
Create the three referenced module map files, above, and populate them with the following:
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 *
}
(Replace "Xcode.app" with "Xcode-beta.app" if you're running a beta version. Replace 10.11 with your current OS SDK if not running El Capitan.)
On the Info tab of your project settings, under Configurations, set the Debug and Release configurations of CommonCrypto to CommonCrypto (referencing CommonCrypto.xcconfig).
On your framework target's Build Phases tab, add the CommonCrypto framework to Target Dependencies. Additionally add libcommonCrypto.dylib to the Link Binary With Libraries build phase.
Select CommonCrypto.framework in Products and make sure its Target Membership for your wrapper is set to Optional.
You should now be able to build, run and import CommonCrypto in your wrapper framework.
For an example, see how SQLite.swift uses a dummy sqlite3.framework.
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 ""
}
}
Limitations
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.
This answer discusses how to make it work inside a framework, and with Cocoapods and Carthage
🐟 modulemap approach
I use modulemap in my wrapper around CommonCrypto https://github.com/onmyway133/arcane, https://github.com/onmyway133/Reindeer
For those getting header not found, please take a look https://github.com/onmyway133/Arcane/issues/4 or run xcode-select --install
Make a folder CCommonCrypto containing module.modulemap
module CCommonCrypto {
header "/usr/include/CommonCrypto/CommonCrypto.h"
export *
}
Go to Built Settings -> Import Paths
${SRCROOT}/Sources/CCommonCrypto
🌳 Cocoapods with modulemap approach
Here is the podspec 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'
Using module_map does not work, see https://github.com/CocoaPods/CocoaPods/issues/5271
Using Local Development Pod with path does not work, see https://github.com/CocoaPods/CocoaPods/issues/809
That's why you see that my Example Podfile https://github.com/onmyway133/CommonCrypto.swift/blob/master/Example/CommonCryptoSwiftDemo/Podfile points to the git repo
target 'CommonCryptoSwiftDemo' do
pod 'CommonCryptoSwift', :git => 'https://github.com/onmyway133/CommonCrypto.swift'
end
🐘 public header approach
Ji is a wrapper around libxml2, and it uses public header approach
It has a header file https://github.com/honghaoz/Ji/blob/master/Source/Ji.h with Target Membership set to Public
It has a list of header files for libxml2 https://github.com/honghaoz/Ji/tree/master/Source/Ji-libxml
It has Build Settings -> Header Search Paths
$(SDKROOT)/usr/include/libxml2
It has Build Settings -> Other Linker Flags
-lxml2
🐏 Cocoapods with public header approach
Take a look at the 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' }
🐝 Interesting related posts
How to call C from Swift?
https://spin.atomicobject.com/2015/02/23/c-libraries-swift/
Good news! Swift 4.2 (Xcode 10) finally provides CommonCrypto!
Just add import CommonCrypto in your swift file.
WARNING: iTunesConnect may reject apps that are using this method.
New member on my team accidentally broke the solution given by one of the top answers, so I decided to consolidate it in a small wrapper project called CommonCryptoModule. You can install it manually or via Cocoapods:
pod 'CommonCryptoModule', '~> 1.0.2'
Then, all you have to do is to import the module where you need CommonCrypto, like so:
import CommonCryptoModule
Hope someone else finds this useful.
I think I have an improvement to Mike Weller's excellent work.
Add a Run Script phase before the Compile Sources phase containing this 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"
This script constructs a bare bones framework with the module.map in the correct place and then relies on Xcode's automatic search of BUILT_PRODUCTS_DIR for frameworks.
I linked the original CommonCrypto include folder as the framework's Headers folder so the result should also function for Objective C projects.
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
#mogstad has been kind enough to wrap #stephencelis solution in a Cocoapod:
pod 'libCommonCrypto'
The other pods available did not work for me.
The modulemap solutions can be good, and are robust against SDK changes, but I've found them awkward to use in practice, and not as reliable as I'd like when handing things out to others. To try to make it all more foolproof, I went a different way:
Just copy the headers.
I know, fragile. But Apple almost never makes significant changes to CommonCrypto and I'm living the dream that they will not change it in any significant way without also finally making CommonCrypto a modular header.
By "copy the headers" I mean "cut and paste all of the headers you need into one massive header in your project just like the preprocessor would do." As an example of this that you can copy or adapt, see RNCryptor.h.
Note that all of these files are licensed under APSL 2.0, and this approach intentionally maintains the copyright and license notices. My concatenation step is licensed under MIT, and that only applies up to the next license notice).
I am not saying this is a beautiful solution, but so far it seems to have been an incredibly simple solution to both implement and support.
I know this is an old question. But I figure out an alternative way to use the library in Swift project, which might be helpful for those who don't want to import framework introduced in these answers.
In Swift project, create a Objective-C bridging header, create NSData category (or custom class that to use the library) in Objective-C. The only drawback would be that you have to write all implementation code in Objective-C.
For example:
#import "NSData+NSDataEncryptionExtension.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (NSDataEncryptionExtension)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
//do something
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
//do something
}
And then in your objective-c bridging header, add this
#import "NSData+NSDataEncryptionExtension.h"
And then in Swift class do similar thing:
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
}
}
It works as expected.
I've added some cocoapods magic to jjrscott's answer in case you need to use CommonCrypto in your cocoapods library.
1) Add this line to your podspec:
s.script_phase = { :name => 'CommonCrypto', :script => 'sh $PROJECT_DIR/../../install_common_crypto.sh', :execution_position => :before_compile }
2) Save this in your library folder or wherever you like (however don't forget to change the script_phase accordingly ...)
# 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"
Works like a charm :)
I'm not sure if something's changed with Xcode 9.2 but it's now much simpler to achieve this. The only things I had to do are create a folder called "CommonCrypto" in my framework project directory and create two files inside it, one called "cc.h" as follows:
#include <CommonCrypto/CommonCrypto.h>
#include <CommonCrypto/CommonRandom.h>
And another called module.modulemap:
module CommonCrypto {
export *
header "cc.h"
}
(I don't know why you can't reference header files from the SDKROOT area directly in a modulemap file but I couldn't get it to work)
The third thing is to find the "Import Paths" setting and set to $(SRCROOT).
In fact you can set it to whatever folder you want the CommonCrypto folder to be under, if you don't want it at the root level.
After this you should be able to use
import CommonCrypto
In any swift file and all the types/functions/etc. are available.
A word of warning though - if your app uses libCommonCrypto (or libcoreCrypto) it's exceptionally easy for a not-too-sophisticated hacker to attach a debugger to your app and find out what keys are being passed to these functions.
In case you have the below issue :
ld: library not found for -lapple_crypto
clang: error: linker command failed with exit code 1 (use -v to see invocation)
In Xcode 10, Swift 4.0. CommonCrypto is a part of the framework.
Add
import CommonCrypto
Remove
CommonCrpto lib file from link binary with libraries from Build
phases
import CommonCrypto from Bridging header
This worked for me!
It happened the same to me after updating Xcode.
I tried everything I can do such as reinstalling cocoapods and cleaning the project, but it didn't work.
Now it's been solved after restart the system.
It's very simple. Add
#import <CommonCrypto/CommonCrypto.h>
to a .h file (the bridging header file of your project). As a convention you can call it YourProjectName-Bridging-Header.h.
Then go to your project Build Settings and look for Swift Compiler - Code Generation. Under it, add the name of your bridging header to the entry "Objetive-C Bridging Header".
You're done. No imports required in your Swift code. Any public Objective-C headers listed in this bridging header file will be visible to Swift.

Add static library to podspec

My podspec requires a static library (OpenSSL). For convenience, I'm shipping the library with the pod.
The static library contains:
Binaries: MyPod/openssl/bin/libcrypto.a and MyPod/openssl/bin/libsll.a
Headers: MyPod/openssl/include/openssl/*.h
Its own license (in addition to my project's license): MyPod/openssl/include/LICENSE
What is the proper way of expressing this in my podspec? I've seen various example that use combinations of the following properties and I'm currently trying different combinations:
source_files
public_header_files
private_header_files
preserve_paths
libraries
xcconfig
vendored_libraries
Or even better, can I define this static library in a subspec?
I managed to add the static library as a subspec. I prefer this approach because it uses the build shipped with my pod by default, and also enables users to provide their own build if they so desire.
As mentioned, the static library is OpenSSL but the following applies to any static library. I'm using the following directory structure:
libraries/openssl-1.0.1e/include/openssl/*.h
libraries/openssl-1.0.1e/LICENSE
libraries/openssl-1.0.1e/lib/*.a
The resulting subspec would be:
s.subspec 'OpenSSL' do |openssl|
openssl.preserve_paths = 'libraries/openssl-1.0.1e/include/openssl/*.h', 'libraries/openssl-1.0.1e/include/LICENSE'
openssl.vendored_libraries = 'libraries/openssl-1.0.1e/lib/libcrypto.a', 'libraries/openssl-1.0.1e/lib/libssl.a'
openssl.libraries = 'ssl', 'crypto'
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/libraries/openssl-1.0.1e/include/**" }
end
Line by line:
openssl.preserve_paths = 'libraries/openssl-1.0.1e/include/openssl/*.h', 'libraries/openssl-1.0.1e/include/LICENSE'
Preserve headers and the license file. We will use the headers below.
openssl.vendored_libraries = 'libraries/openssl-1.0.1e/lib/libcrypto.a', 'libraries/openssl-1.0.1e/lib/libssl.a'
Tell CocoaPods that we are shipping the above static libraries in the pod. This will preserve the files, as well as modifying LIBRARY_SEARCH_PATHS accordingly.
openssl.libraries = 'ssl', 'crypto'
Includes the libraries in "Other Linker Flags".
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/libraries/openssl-1.0.1e/include/**" }
Tells the project where to find the headers. We cannot use public_header_files because this is a subspec.
You can try do it like it's done here https://github.com/krzak/OpenSSL, or just use this Pod with you project if you find it convienence
pod 'OpenSSL', :podspec => 'https://raw.github.com/krzak/OpenSSL/master/OpenSSL.podspec'

Resources