Using cocoapods in a framework - ios

I created an iOS framework that uses a library (RestKit) via CocoaPods.
In the application project that uses my framework I also use CocoaPods to include other libraries. I had to include the library from the framework as the project didn't compile otherwise.
Everything works fine, but as expected when I launch the application I get:
Class X is implemented in both /private/var/mobile/Containers/Bundle/Application/[...]/Application.app/Frameworks/Framework.framework/Framework and /private/var/mobile/Containers/Bundle/Application/[...]/Application.app/Application. One of the two will be used. Which one is undefined." in several classes from the libraries.
Is there any way in CocoaPods or in the build process to prevent having duplicate libraries when they're already being used?
Some more context to my question. Here's what I did:
Created a framework project as a Cocoa Touch Framework. Initially I added just a Podfile with a dependency for RestKit as following:
pod 'RestKit', '~>0.23'Then I removed the Podfile and just added a podspec as in the comment by #Paula Chavarría.
Created the app project. Added a Podfile with other dependencies and also the dependency to the framework as #Paula Chavarría also mentioned.
When I build the app project the framework fails building because it can't find the right headers.
I changed the header search path for the framework but it doesn't seem to be enough for the build to be successful.
Do I need to have also a Podfile in the framework? As I said in my original question, I did that at first and I ended up having duplicate libraries and that's what I'm trying to avoid in the first place.
Is there any way to tweak the Podfile or the configurations generated by it and use the headers in the app and link with the libraries in the app?
What am I missing here?... Thanks in advance! :)

If you are using Cocoapods on the application project you can create a private pod for the iOS framework. To do so you have to create a .podspec file in order to add the conflicting dependency. For Restkit the .podspec file would be like this:
Pod::Spec.new do |s|
s.name = "MyFramework"
...
s.dependency 'RestKit', '~> 0.23'
end
You can read more about these files here: http://guides.cocoapods.org/making/specs-and-specs-repo.html
After that you just have to add a dependency of your framework on the application project Podfile. You can do so through a local path or through a version control system.
pod 'MyFramework', :path => './../my-framework'
pod 'MyFramework', :git => 'https://url/to/my-framework.git', :tag => '0.0.1'

Related

How to integrate iOS Framework into Cocoapod

My company has an iOS SDK/framework that I've been asked to implement a Cocoapod for to help the install process.
I'm a C#/.Net developer by trade, so this is more of a task than it probably should be!
I successfully followed a guide over at https://code.tutsplus.com/tutorials/creating-your-first-cocoapod--cms-24332 which walks through setting up a cocoapod, but doesn't include any Framework integration.
Our framework appears to be a combination of objective-C and swift files.
I then tried setting up another cocoapod project and adding my framework file under Pods>Frameworks>iOS>myFramework.framework.
Once I did this, I tried pod install on the example project which looked like it installed my pod, but I see no reference to the framework.
I also tried adding my framework via the podspec metadata file in s.ios.vendored_frameworks, to no avail...
Why on earth is something that's supposed to make our lives easier so complicated to setup!?
Help most appreciated.
Dave
podfile
use_frameworks!
target 'iOS_sdk_Example' do
pod 'iOS_sdk', :path => '../'
target 'iOS_sdk_Tests' do
inherit! :search_paths
end
end

Using a CocoaPod dependency while developing a CocoaPod

I'm creating a CocoaPod, say MyPod, which depends on another Cocoapod, say RxSwift.
So I have this in MyPod.podspec:
s.dependency "RxSwift", "~> 3.0.1"
However, while developing MyPod, how can I actually use the dependency?
import RxSwift
// ^
// No such module 'RxSwift'
public class MyClass { //...
Is there a step I'm missing, or some common convention? It looks like some other projects like Moya are using Carthage to build dependencies while developing. Should I be doing that, or maybe adding a Podfile?
I know that this shouldn't be a problem for an Example App located within the repo, which would have its own Podfile. However, I'd like to still have tests located at top level, outside of the Example App, and to be able to actually build the framework while working on it, again, outside of an Example App.
I can't speak to whether or not to use CocoaPods or Carthage. Both have their strong points and weak points. Plus the decision should be made considering many factors, some of which you might not be able to control (like a client that insists you use CocoaPods!) So I'll skip that part.
However, to your question, indeed a pod you are developing can depend on another pod. You already have the correct s.dependency line. That's necessary.
However, I suspect that the reason why you were not able to reference the dependent pod could be because you did not have a Podfile in your 'tester/example' project and/or you did not do a pod install after adding the dependency in your Podspec.
The reason for this is requirement I suspect is that since the Podspec is not actually processed at all by Xcode, you're not actually downloading (or compiling) the dependency.
Instead, when you do the pod install (via command line of course), CocoaPods will create a Pods project with your development pod, the pods you depend on (in Podspec) as well as any other pods in your Podfile.
To test this theory, I:
Created a new pod (using CocoaPod's own 'pod lib create' (https://guides.cocoapods.org/making/using-pod-lib-create.html).
Opened the workspace that CocoaPod created for me and edited the Podspec to add the dependency s.dependency 'RxSwift', '~> 3.0.1'.
Added another pod in my Example App's Podfile (to demonstrate the difference between Podfile dependencies and Podspec dependencies.)
Performed pod install in the Example App's folder.
Edited my Pod's class to do something useful AND to add the import RxSwift line.
Added a label to my Example App ("Hello World" of course).
Used PureLayout to do all the auto layout constraints for the label (and to demonstrate how the Example project has access to both pods - the development pod as well as the referenced pod PureLayout.)
You can check out the demo I created on my public GitHub:
https://github.com/ericwastaken/CocoaPod-Dependency-Demo
Honestly, I've created several pods using the pod lib create and it does indeed create a nice structure that has always worked for me. For this reason, I would recommend always using it to create your pod's skeleton.
Xcode 8 comment: pod lib create still seems to create a Swift 1.x project. So, right after you use this tool, when you open Xcode, you'll be offered to "convert" to a newer version of Swift. I would let that conversion happen right then and there (the first time) so that you can be in Swift 2.x or 3.x syntax (you choose).
I ended up using Carthage to build the framework dependencies. I imagine I could have used CocoaPods to do it as well. However, that would have required that I start using a workspace, and I didn't want to have to do that so as to keep changes as minimal as possible.
Also, with Carthage, it didn't require that I add a new Podfile/Podfile.lock, since Carthage will use the existing Cartfile/Cartfile.resolved that's already there. That's because Carthage uses the Cartfile.resolved when using the framework in another project and when building the framework on its own. Whereas, with CocoaPods, *.podspec is used when using the framework in another project but Podfile.lock (if you've added a Podfile) is required to install dependent pods in the framework itself.
This was a very challenging problem to solve, and required a combination of a few solutions pieced together. #EricWasTaken's solution helped, as well as adding:
source 'https://github.com/CocoaPods/Specs.git'
to the top of my Podfile. Then navigating to the Example app and run
pod repo update
pod install
Now the framework I am creating can find the cocoapods my framework requires.

Can I use CocoaPods when creating a Cocoa Touch Framework?

I'm creating a new Cocoa Touch Framework (MyFramework.framework), which will have a dependency on Alamofire. This framework will be written in Swift. As a test I started a new Cocoa Touch Framework project:
File > New > Project > Framework & Library > Cocoa Touch Framework
Then, in the terminal I performed:
pod init
under this projects directory. In the newly created Podfile I added the following:
source 'https://github.com/CocoaPods/Specs.git'
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!
pod 'Alamofire', '~> 3.0'
Once again, in the Terminal I performed:
pod install
and started coding away.
Everything seemed well and good till I used the MyFramework.framework Product in a Single View Project. When I attempt to run the project I get the following issue:
dyld: Library not loaded: #rpath/Alamofire.framework/Alamofire
Referenced from: /Users/me/Library/Developer/CoreSimulator/Devices/87DA70B6-49BF-441E-BD81-F4A80B0792CF/data/Containers/Bundle/Application/2E414EA8-7E54-4D71-9295-566D4FAAADE2/test.app/Frameworks/MyFramework.framework/MyFramework
Reason: image not found
I thought that Cocoa Touch Framework projects were inherently Dynamic, and therefore would include all dependencies.
Can anyone tell me why this is happening and how I may be able to fix it?
Is this an issue with CocoaPods or am I missing something?
I'm a noob to Stack Overflow so please let me know if you need more information from me.
Thanks!
Unfortunately CocoaPods doesn't support use with Cocoa Touch Framework target. I found a few references to this while digging through their issues on GitHub:
We don't really support integrating Pods into framework targets...
-neonichu on Nov 4, 2015
and
...in order for this to "just work", CP would need to do a recursive analysis of dependencies in your Xcode project and also somehow ensure that you would never use the build product in another context.
-neonichu on Jul 7, 2015
So far I've found two ways to deal with the issue:
The right way is to create a new pod spec for your framework and bring it in to your main project via CocoaPods. This resolves all of the problems CococaPods has with the dependency graph and is the recommended solution from the CocoaPods developers.
The easy way is to include the pods from your framework in your main project. This seems to work, but frankly I don't know why. This is the Podfile from my test project:
platform :ios, '9.0'
use_frameworks!
def myfirstframework_pods
pod 'Alamofire', '~> 3.0'
end
target 'MyApp' do
pod 'SwiftKeychainWrapper', '~>1.0'
myfirstframework_pods
end
target 'MyFirstFramework' do
myfirstframework_pods
end
Try adding the dependency on Alamofire in the framework's podspec as below
Pod::Spec.new do |s|
# Other setup
# Dependencies
s.dependency "Alamofire"
# Other dependencies if any

Creating a pod that relies on another pod

Trying to build a Cocoapod library which is dependant of other published Cocoapod library I own, got the project in XCode to build OK, but running pod lib lint command for checking pod validity fails with
error: include of non-modular header inside framework module on the header files of the library (pod) I'm depending on. All source is Obj-C not Swift.
I did try the following, according to the recommendations found here
Setting the header files of the dependant library as public instead of project
Setting CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES =
YES for each target
verifying that the relevant headers in build phases are under public.
but problem persists, I cannot publish the pod nor test it.
Update
when I comment out the
s.dependency 'OldPodIDependOn'
line in my podspec file of my new pod then error disappears but the dependent headers are not found. if I do not include the pod I depend on in the Podfile under the ./Example folder, like so:
target 'NewPod', :exclusive => true do
pod "NewPod", :path => "../"
pod "OldPodIDependOn", :path => "../../OldPodIDependOn/"
end
then project will just not build in XCode since the OldPodIDependOn files are not part of the project. Got a bit of a chicken-or-the-egg problem.
Update 2
Also tried removing the :path => "../../OldPodIDependOn/" component to reference the pod that has been published instead of a local one - doesn't help.
Worth mentioning that this pod will include a UI hence a storyboard will be included and referenced, I added s.resources = 'Pod/Classes/UI/NewPod.storyboard' line to the podspec file, and removed the storyboard from the pod target compile sources (otherwise xcode won't build). I don't think that this has something to do with the problem but worth mentioning, maybe I'm doing something wrong in there.
What am I doing wrong?
Any help will be greatly appreciated!
To finally solve this issue I had to discard the workspace that pob lib create created - there was no way around it, I tried all possible combinations / recommendations / code modifications to get rid of the "non-modular header inside framework" errors but nothing seemed to work. pod lib lint ALWAYS failed.
I created my own static library xcode project from scratch, then run pod update on it after adding the dependent pod to the Podfile, then created a .podspec file for this lib and added the dependant pod header files to the "Copy files" build phase of the static lib target + libPods.a file to the "Link Binary with libs" build phase. Poof! no more "non modular header" errors from pod lib lint, even though I am practically doing the exact same thing. Lesson learnt is that pod lib create is not recommended for ALL cocoapod cases.
I had the same issue, and I used
pod lib lint MyPod.podspec --allow-warnings --use-libraries
When adding the --use-libraries option, it worked.
In general error: include of non-modular header inside framework module implies that one of the header files inside the resulting framework ( CocoaPods lints for both frameworks and libraries now ) is not stored inside the framework, or classed as a public header.
This can usually be worked around moving external imports into the implementation files, see this Modified to support using framework #353.

Making a private cocoapod with dependencies on other cocoapods

I've read all the tutorials (some less deeply than others), and discovered that there is a huge focus on using the pod lib create command and how to get your new cocoapod into the the podspec repo and available to other developers, but they are all missing the middle part involving actually setting up and developing your pod, Xcode example project, etc..
I'm trying to make a cocoapod for internal use that has dependencies on other pods. I told pod lib create that I wanted an example project and now I need to be able to build and run it using the pods it depends on. I'm not clear on how I actually get those pods to download. I understand that there is a podspec syntax for specifying dependencies:
spec.dependency 'SOMEPOD', '~> VER.0', but that doesn't do much for my example project.
Am I supposed to make a Podfile in the folder with my example project? Does that conflict with the podspec somehow? Do I need to include the pod I'm making in that podfile? Should I not be using an example project and just be developing my pod in conjunction with a test project that pulls my pod in like any other cocoapod?
Also, when all my testing is said and done, does the example project get distributed with the pod and set up as a weird sub-target in whatever project uses the pod? Or do I eventually have to make a different repo that just has the pod (without the example project)?

Resources