Cocoapods with custom framework - ios

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'

Related

App using xcframework CocoaPod logs classes implemented in both app and framework

We have created a CocoaPod which is an XCFramework that has dependencies on other CocoaPods. When we run the demo example app or install the pod in a new app, it works, however this is logged to the console on launch (repeated for many classes):
objc[38875]: Class OTSubscriber is implemented in both
/Users/MyUser/Library/Developer/CoreSimulator/Devices/8DD81910-DD40-4BD7-9355-8A0C78EFD32E/data/Containers/Bundle/Application/60E8C18A-37DC-4C2B-AEB3-E88C3A7C4D96/MyCocoaPod_Example.app/Frameworks/MyFramework.framework/MyFramework
(0x10e3fd660) and
/Users/MyUser/Library/Developer/CoreSimulator/Devices/8DD81910-DD40-4BD7-9355-8A0C78EFD32E/data/Containers/Bundle/Application/60E8C18A-37DC-4C2B-AEB3-E88C3A7C4D96/MyCocoaPod_Example.app/MyCocoaPod_Example
(0x10c8abd80). One of the two will be used. Which one is undefined.
This class is from OpenTok, which is a dependency specified for the pod used in the framework. The message seems to reveal CocoaPods is installing the dependencies on the app in addition to the framework, causing this issue. The app itself shouldn't have any dependencies except this framework.
Perhaps something was done incorrectly in the pod creation process? These are the steps we took:
Create an Xcode framework project, add a Podfile listing its dependencies, build out the framework's functionality
Create an XCFramework from the framework's xcworkspace
Create the pod using pod lib create MyCocoaPod choosing iOS, Swift, include demo, none and no for testing
Update the Podspec:
Pod::Spec.new do |s|
s.name = 'MyCocoaPod'
s.version = '1.0.0'
s.summary = 'Summary'
s.description = <<-DESC
'Description'
DESC
s.homepage = 'https://myhomepage.com'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Author' => 'auther#somedomain.com' }
s.ios.deployment_target = '12.0'
s.source = { :git => 'https://github.com/user/git-repo.git', :tag => s.version.to_s }
s.vendored_frameworks = 'MyFramework.xcframework'
s.swift_version = '5.5.2'
s.dependency 'OpenTok', '2.21.3'
# Needed to pass lint validation
s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
end
Drag and drop MyFramework.xcframework into Pods/Development Pods/MyCocoPod
Update the example's Podfile to specify BUILD_LIBRARY_FOR_DISTRIBUTION = YES:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
Run pod install in Example directory - note this will cause the framework to be moved to the root level in Finder and under a Frameworks group in Xcode
Update the example app's code to import and use MyFramework
Commit, tag, and push the changes to the repo
Push the Podspec to the specs repo
Not sure if this is your case but maybe you are falling in a scenario which happened to me,
meaning a dynamic framework that depends on a static framework. In such scenario, your dynamic framework would end up embedding the static one in his resulting binary. Then, in order to import your dynamic framework in the project, you will import with the setting “Embed and sign” for example, as that’s indeed a dynamic one, along with the other static framework which your dynamic one depends on. This causes the duplicated implementation ( your app including the static dependency + the dynamic one embedding inside the same dependency.
What you could do if this is your case, is to make sure that the dynamic framework configuration is changed to be static (static xcframework to be precise) , maybe outside cocoa pod as first step if that simplifies. Code wise would be the same, but it will “link” to the dependency (OpenTok for example) rather than embedding it. As result, once imported in the app, it should be imported only once, as your custom framework links to it and does not embeds it, finally avoiding the duplicated implementation. (static frameworks are imported with “Do not embed” which means that they will be merged in compile time to the app executable)

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.

XCode says 'Use of undeclared type' when trying to use a protocol defined inside a private Pod (Swift)

I and my team are stuck in a strange situation involving a base project + private pods with some protocols inside.
Our problem is we can't access some of the (protocol) identifiers (defined in a private pod) from our base app code.
Apparently our problem seems to be exactly the same as the one described in these 2 stack overflow threads, but their solutions haven't worked with us.
Thread 1: Source files not found in Swift
Thread 2: CocoaPod installed but doesn't see Swift code
The skeleton we're using is this one:
Our Commons pod (with the protocol we can't see from our base app) is defined with this .podspec file:
Pod::Spec.new do |s|
s.name = "Commons"
s.version = "0.1.10"
s.summary = "Commons framework"
s.description = <<-DESC "Commons framework"
DESC
s.homepage = "http://EXAMPLE/Commons"
s.license = { :type => "Commercial" }
s.author = { "Author" => "author#mail.mail" }
s.source = { :git => "GITLAB_PRIVATE_URL/commons-iOS-Pod.git", :tag => s.version }
s.source_files = "Commons", "Commons/**/*.{h,m,swift}"
s.exclude_files = "Commons/Exclude"
end
From our base app, we have the following Podfile (to get our Commons pod onto our main xcworkspace).
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
target 'ios-appbase' do
# Comment this line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'Alamofire'
pod 'ViewDeck'
pod 'JLRoutes'
pod 'Commons', :git => 'GITLAB_PRIVATE_URL/commons-iOS-Pod.git', :tag => '0.1.4', :branch => 'develop'
pod 'RestManager', :git => 'GITLAB_PRIVATE_URL/RestManager-iOS-Pod.git', :tag => '0.1.3'
pod 'BaseClasses', :git => 'GITLAB_PRIVATE_URL/BaseClasses-iOS-Pod.git', :tag => '0.1.3'
pod 'DesignManager', :git => 'GITLAB_PRIVATE_URL/DesignManager-iOS-Pod.git', :tag => '0.1.2'
end
We've defined our protocol as public (as it's expected to be done, because it's living inside the 'Pods' project).
What else should be looking into?
PS: Not only our custom protocol is "invisible" from our main app, but also protocols defined inside Alamofire, which is another Pod included in our main app. We try to use them and XCode complains at compile time.
Thanks in advance.
Greetings.
EDIT1: Narrowing our problems, we think it's something happening in compilation time. Why? Because XCode is able to solve the faulty symbols pressing CMD+Click (two protocols defined on our Pods file structure), but the compiler can't do it and it's the one complaining with the "Use of undeclared type" error.
Whops, success (!?)
The protocol we were defining was living inside a Framework Pod, so: What were we doing wrong?
Apparently we needed to import the name of the Framework (not the class name of the protocol (!) ). Kind of a newbie error (?).
Once we typed "import Commons" on the top part of our swift file, all "undefined xxxxxx" errors disappeared.
Not sure though if we needed this specific import part because the imported Pod was a Framework project, or we just hit the nail by chance.
I have the impression some other Classes and stuff imported from some other Pods we're using, don't need an import part, and you can directly use them from the start. So our missunderstanding might have been caused by this (?).
Anyway, and as I said before, these are newbie problems using "custom pods + swift + Frameworks + somehow complex escalable .app architectures".
Let's hope this problem and its (alleged solution) sheds some light onto future developers being in a similar situation.
Greetings.

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'

No visible #interface in Cocoapods

I am trying to modulize my app by splitting it in different sub projects.
Inspired by this idea. So I splited my project to static libraries followed by that tutorial. I created a first library with some costume UIHelpers/Views. It has some dependencies which I defined in PodSpec file followed by AFNetworking example. (one of the dependencies is Choosy). I stored this library in bitBucket. Everything is working fine for that library(I can build it in Xcode). The problem start when I create a Model Library. I specify Git path of UIHelpers in the Model PodFile. Every time I get an error of No visible #interface for a category in Choosy (the error come from CocoaPod NOT in my project, the category is imported in the .mfile). I tried to play with link flags -ObjC,$(inhereted),-force_load included all of them.Objective-C categories in static library I cleaned the derived data.
I read the CocoaPodTroubleShoutes.
Can somebody suggest what can be tried. There is a lot of question in stuck regarding that compile error but none of them helped me.
I believe the problem somewhere in my PodSpec(cant be sure) pod lib linit I receive :- ERROR | [iOS] Choosy/Choosy/Model/ChoosyAppInfo.m:32:19: error: no visible #interface for 'UIImage' declares the selector 'applyMaskImage:completion:'
My PodSec:
Pod::Spec.new do |s|
#I tried this options:
#s.xcconfig = { 'OTHER_LDFLAGS' => $(inherited) }
#s.compiler_flags = '-ObjC'
#'-all_load'
#$(inherited)
#'-DOS_OBJECT_USE_OBJC=0', '-Wno-format'
#'-force_load'
s.prefix_header_contents = '#import <UIKit/UIKit.h>', '#import <Foundation/Foundation.h>','#import <CoreGraphics/CoreGraphics.h>','#import "ARNStyles.h"'
s.description = <<-DESC
A longer description of ARNUIHelpers in Markdown format.
DESC
s.homepage = "http://EXAMPLE/ARNUIHelpers"
s.platform = :ios, "7.0"
s.ios.deployment_target = "7.0"
s.source_files = 'UIHelpers/**/*.{h,m}'
s.requires_arc = true
s.subspec 'Choosy' do |ss|
ss.requires_arc = true
ss.compiler_flags = '-force_load'
ss.platform = :ios, "7.0"
ss.dependency 'Choosy'
# ss.xcconfig = { "FRAMEWORK_SEARCH_PATHS" => "$(PODS_ROOT)/Headers/Public/Choosy"}
# ss.ios.public_header_files = 'UIImage+ImageEffects.h'
end
s.subspec 'Dependencies' do |ss|
#ss.ios.public_header_files = 'UIImage+ImageEffects.h'
ss.requires_arc = true
ss.dependency 'FormatterKit'
end
end
In the end it was my fault. The previous developer copied those files from Choosy pod and included it manually.We still use Choosy in other places. Unfortunately the error wasn't clear enough to deduce what was wrong.

Resources