Add static library to podspec - ios

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'

Related

Cocoapods - Swift framework with internal static library dependency

I'm implementing an iOS framework written on Swift. This framework has an internal dependency on a C based static library. To make it work and based on some tutorials I've made a module map similar to this:
framework module Module {
umbrella header "Module.h"
explicit module ModuleDep {
private header "header1.h"
}
export *
}
Based on that I can include C code in Swift like this:
import Module.ModuleDep
When export framework manually everything seems to work just fine. It is a sure thing, I want to have Cocoapods support for my framework with code visibility (easier to debug). The podspec, that make it work was this (some parts are omitted):
Pod::Spec.new do |s|
s.platform = :ios
s.ios.deployment_target = '12.0'
s.module_map = "Module.modulemap"
s.source_files = "Module/*.{h,swift}", "ModuleDep/*.h"
s.vendored_libraries = "ModuleDep/*.a"
s.swift_version = "5.1"
end
From my understanding, vendored_libraries is used when this is the artifact you are providing to your users and that is why I don't like this solution.
I've also tried this spec variant:
Pod::Spec.new do |s|
s.platform = :ios
s.ios.deployment_target = '12.0'
s.module_map = "Module.modulemap"
s.source_files = "Module/*.{h,swift}", "ModuleDep/*.h", "ModuleDep/*.a"
s.swift_version = "5.1"
end
but it doesn't compile.
So what is the correct way to do this? Or what have I done wrong?
Since you are using a static library as a dependency then you must specify it as a library in your podspec file. Which is why your second approach is not working because it's a library not a source file.
As mentioned in the docs vendored_libraries are for libraries that come shipped with the Pod. Also in your case that C based static library is a dependency which must be shipped with the Pod. Thus using vendored_libraries should be ok in your case.

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.

How to distribute compiled framework using Cocoapods?

I'm building a framework using cocoapods. Now, I have it in a private repository with a private spec repo. I want to distribute this framework not as open source, but closed source. Basically, I want to distribute only the .framework file, already compiled. This way, I will avoid to expose my source code to externals.
I don't know how to tell cocoapods to distribute the compiled file.
After compiling your framework, you'll want to create a separate, public repository to use for distribution. That is where you will place your compiled framework, podspec, license, readme files, etc.
The podspec is a bit different for distributing frameworks rather than source code. See example:
Pod::Spec.new do |s|
s.name = 'YourFrameworkName'
s.version = '1.7.0'
s.summary = 'The YourFrameworkName iOS SDK enables you to embed state-of-the-art real-time goodness into your iOS app.'
s.homepage = 'http://example.com'
s.author = { 'Name' => 'info#example.com' }
s.license = { :type => 'Custom', :file => 'LICENSE' }
s.platform = :ios
s.source = { :http => 'https://github.com/example/YourFrameworkName/releases/download/1.7.0/YourFrameworkName.zip' }
s.ios.deployment_target = '9.0'
s.ios.vendored_frameworks = 'YourFrameworkName.framework'
s.dependency 'SwiftyJSON', '3.1.4'
end
Once all that is set up, you can publish the pod spec the normal way.
Keep in mind, and this is an important consideration, that your compiled framework written in Swift will only be usable in projects that use the exact same Swift version. You will quickly run into this limitation as people start using your framework in different projects with various Swift versions.
First, you create a sample project and install the pods(the library which you want to release as SDK.framework) for the project.
Then see the below-attached image to get the .framework extension file to distribute to the public.
You can do this by pointing s.source of the podspec file to a zip file of your framework and its source. No need to expose your source in a public repository.
ex.
spec.source = { :http => 'https://bitbucket.org/publicRepo/yourframework.zip' }

Trying to wrap vendor framework in cocoapod but the compiler can't find headers

Hoping somebody has already solved this; I'm trying to wrap a third-party library (Airwatch) in a cocoapod for better management across our apps. I'm having a hell of a time trying to get this to work, though. I've created a pod around a static library, but this one is a dynamic framework, and I'm having a hell of a time getting it to compile. The headers from the framework just aren't accessible in the containing app....
Here's what I have tried already:
When I set vendored_libraries in podspec i can't seem to access headers with either quotes or <>. Xcode just complains as 'Not Found'
Next, I tried adding the path of the headers in the framework as source_files like so
s.source_files = 'Pod/Classes/**/*','Pod/Framework/AWSDK.framework/Versions/A/Headers/*.h'
This allows xcode to find the header for an import like:
import "AWSDKCore.h" //Documented as the framework's main header
But this throws an error for the existing imports within the original framework:
I figured this was a bad idea, but I thought I'd try naming my cocoapod the same name as the Framework (which should keep the import path). So, this throws a bunch of errors saying some enums either aren't declared or are declared twice.
If anybody has thoughts, I'd be eternally greatful...
Just for reference here's my podspec:
Pod::Spec.new do |s|
s.name = "AirwatchSDK"
s.version = "0.1.0"
s.summary = "A short description of AirwatchSDK."
s.homepage = "https://github.com/<GITHUB_USERNAME>/AirwatchSDK"
s.license = 'MIT'
s.author = { "xxxxx" => "xxxx" }
s.source = { :git => "https://github.com/<GITHUB_USERNAME>/AirwatchSDK.git", :tag => s.version.to_s }
s.platform = :ios, '8.0'
s.requires_arc = true
#s.module_name = 'AWSDK'
s.source_files = 'Pod/Classes/**/*','Pod/Framework/AWSDK.framework/Versions/A/Headers/*.h'
s.vendored_frameworks = 'Pod/Framework/AWSDK.framework'
s.frameworks = 'CFNetwork','CoreData','CoreFoundation','CoreGraphics','CoreLocation','CoreTelephony','CoreText'
s.libraries = 'stdc++','z','sqlite3','c++'
end
Since I figured out my own answer, I thought I'd post it here for the next guy...
The key, it turns out, was to not have 'source_files' (or to comment it out). I'm not sure if that is a bug or not, but my final podspec had vendored_framework set and source_files not set like so:
#can't have source files if you want to access vendor framework
#s.source_files = 'Pod/Classes/**/*'
# airwatch framework.
s.vendored_frameworks = 'AWSDK.framework'

Cocoapods with custom framework

I want to generate an podspec-file which has an custom framework, one class and a third party framework as dependency.
The single class refers to the custom framework by including one header of that framework. If I run
pod lib lint
this error appears :
- ERROR | [xcodebuild] /Users/xyz/Documents/iOS/Apps/Sample/Core/Sample.h:10:9: fatal error: 'CustomFramework/Bar.h' file not found
The related part of my podspec file looks like this:
s.source_files = 'Core/*' , 'Core/CustomFramework.framework/Headers/*.h'
s.preserve_paths = 'Core/CustomFramework.framework/**/*'
s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"${PODS_ROOT}/Headers"' }
s.frameworks = 'CustomFramework'
s.xcconfig = { 'OTHER_LDFLAGS' => '-ObjC' , 'LIBRARY_SEARCH_PATHS' => '"${PODS_ROOT}/CustomFramework/Headers"'}
s.dependency 'MapBox', '1.1.0'
The single class inherits from class of the MapBox framework.
I feel like I miss something but can not figure out what. Any suggestions or hints?
Try using vendored_framework like explained here: Podspec Link Binary Library
spec.ios.vendored_frameworks = 'Frameworks/MyFramework.framework'

Resources