I am trying to create a swift module (Cocoa Touch Framework) with reusable code inside the environment set up by cocoa pods which includes third party libraries written in Objective-C (namely here Restkit).
Unfortunately I am not able to use Restkit in the module I create.
Here's what I did to create the module:
File -> New target: Cocoa Touch Framework, Language: Swift, Project: MyProject, Embed in Application: MyProject
In the "Info" tab of the project settings in the "Configurations" section I define the Pods.debug and Pods.release xcconfig file for my newly created target.
In the header file, which Xcode automatically created for me, networkModule.h, I add the following line:
#import <RestKit/RestKit.h>
Result: When trying to compile I get the error "include of non-modular header inside framework module 'networkModule'"
I have set the flag for "Allow Non-modular Includes in Framework Modules" to YES in the build settings for the Project Target and the Module/Framework target.
I went to the Cocoa pod project and have tried setting the visibility of the RestKit.h Header file to "Public" in the target membership (which of course is not a good solution to mess with the cocoa pods environment)
I am not able to compile. I still get the same error.
Is it possible in the first place to create a Cocoa Touch Framework with dependencies to a cocoa pod managed framework?
Btw. My first idea of creating a private cocoa pod didn't work out as well, as it doesn't seem to be supported, although I am using the prerelease of cocoa pods 0.36 with support for swift.
You should be able to make your won private Pod. You just need to make a podspec for it. Here is an example of one.
Pod::Spec.new do |s|
s.name = "Commons"
s.version = "1.0.0"
s.summary = "Common code for my iOS projects."
s.license = {:type => 'Commercial', :text => "Copyright (c) Dan Leonard(Or Your Name?). All rights reserved." }
s.source = { :git => "https://github.com/PATHTOPOD", :tag =>
s.version.to_s }
s.homepage = "https://github.com/PATHTOPOD"
s.requires_arc = true
s.ios.deployment_target = '9.0'
s.subspec 'Core' do |ss|
ss.source_files = '*.swift'
end
s.subspec 'Menu' do |ss|
ss.source_files = 'Menu/*.swift'
ss.resources = ['Menu/*.storyboard', 'Menu/*.xcassets']
ss.dependency 'Alamofire'
end
end
Then Inside your project you just have to do pod init open your podfile that was just created and add this
source 'https://github.com/CocoaPods/Specs.git'
xcodeproj 'YOURPROJECT.xcodeproj'
platform :ios, '9.0'
use_frameworks!
pod 'Commons', git: 'https://github.com/PATHTOPODPROJECT'
#pod 'Commons', :path => '/Users/YourUser/Path/To/Project/commons'
pod 'KeychainSwift'
pod 'SQLite.swift', git: 'https://github.com/stephencelis/SQLite.swift.git'
Now in this example Podfile Commons is stated twice the second is commented out. If you uncomment it and comment out the first then do pod install in your projects folder from the terminal. This will make a DevelopmentPod which is a pod that is local. This way you can make changes to the pod locally within Xcode. No switching and pod installing every time you make a change.
You will import the pod just like any other by putting
import Commons not #import <Commons/Commons.h> That is how you do it in Objective C not Swift
Once you have a working version commit it to git hub and point your project to the the github version.
Hope this helps.
Related
We are developing a framework that is dependent on some firebase dependencies like login, analytics, etc. Once our framework is developed we will distribute it to our customers.
Things to be taken care of are
Code should not be visible(Best suggestion is to create XCFramework)
If possible create a dynamic framework instead of a static framework
Can be distributed via Swift package manager or cocoapods
What we have tried
We have tried to create a dynamic framework using pods and then create a XCFramework. But while importing into client app, pods module are not found
We created static library and add firebase manually(In project directly) instead of pods, in that case XCFramework is not imported
We have tried to create XCFrame Work as mentioned here (for dynamic framework)
XCFramework with Pods Dependencies
To hide code umbrella framework and universal library can be used,but with firebase, this approach is to typical and also not suggested on the internet at many places
Is there any other/alternative way where we can fulfill our requirements?
We have the exact same setup right now, and it works quite well. Hope that'll also be of help for you.
Things that are taken care of:
It's an XCFramework distribution.
It's been distributed by CocoaPods (albeit in a private Podspec repository)
It's a dynamic framework.
Prerequisites:
CocoaPods version >= 1.10.1
Xcode version >= 11.6 (could be lower though, not sure)
After creating your .xcframework, you need to have a .podspec for your framework, which should look like:
Pod::Spec.new do |s|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
s.name = "MyAwesomeSDK"
s.version = "1.0.0"
s.summary = "Best framework ever: MyAwesomeSDK"
s.description = <<-DESC
"Best framework ever: MyAwesomeSDK"
DESC
s.homepage = "http://github.com"
s.license = "MIT"
s.author = { "ItIsI" => "me#myself.com" }
# ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
s.platform = :ios
s.ios.deployment_target = '11.3'
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
s.source = { :http => '<MyAwesomeSDK.zip> (We're storing our zipped .xcframework in a hosted page)' }
s.vendored_frameworks = 'MyAwesomeSDK.xcframework'
s.swift_version = "5.0"
# ――― Dependencies ―――――――――――――――――――――――――――---――――――――――――――――――――――――――――――― #
s.dependency 'SwiftProtobuf', '1.12.0'
s.dependency 'lottie-ios', '3.1.8'
# Any other dependency you might need.
end
Then, we are consuming it in another project via Podfile, that will look like:
platform :ios, '13.0'
# If you're going to have a private Podspec repo, add the source URL here.
# Don't forget to add the original source if you're going to specify another source.
# source 'https://cdn.cocoapods.org/'
target 'Test' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# If you are publishing the SDK publicly or in a private Podspec repository, this is it:
pod 'MyAwesomeSDK'
# If not, you should provide the .podspec to your customers, and:
pod 'MyAwesomeSDK', :podspec => '<path/to/MyAwesomeSDK.podspec>'
target 'TestTests' do
inherit! :search_paths
# Pods for testing
end
target 'TestUITests' do
# Pods for testing
end
end
Then, that's it! When running pod install, you should see:
Analyzing dependencies
Downloading dependencies
Installing MyAwesomeSDK (1.0.0)
# These are our own:
# ---
Installing SwiftProtobuf (1.12.0)
Installing lottie-ios (3.1.8)
# ---
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 3 total pods installed.
P.S: We also had to add a post_install setup in our Podfile, otherwise it'll not properly link the dependency frameworks:
if ["SwiftProtobuf", "lottie-ios"].include? target.name
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
I'm trying to create a custom Cocoapod to handle all of my networking calls for my iOS application. The issue that I am having is that some of my files that should be part of my new Cocoapod/framework are not found when I try to reference them in code.
I followed this tutorial https://www.raywenderlich.com/5823-how-to-create-a-cocoapod-in-swift and I successfully created the Cocoapod .xcworkspace project (named: ios-oauth2-rest-template) and added it to bitbucket and created a private PodSpec repo on bitbucket as well (named: KPodSpec) (two separate repos).
I was able to make it through the tutorial but I got stuck on the part 'Using Your New CocoaPod.' I was able to run the following commands to add the Cocoapod to my PodSpec repo:
pod repo add KPodSpecs [Your RWPodSpecs Git URL]
pod repo push KPodSpecs ios-oauth2-rest-template.podspec
When I try to use my new pod in an existing project (named: KApp) some of the files that are in my Cocoapod are able to be referenced while others will not autocomplete even after I import ios_oauth2_rest_template.
I'm not sure if I'm just missing the framework for ios-oauth2-rest-template inside my KApp project. Any help would be much appreciated.
KApp Podfile:
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'
source 'https://github.com/CocoaPods/Specs.git'
source 'https://bitbucket.org/kpodspecs.git'
target 'KApp' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for KApp
target 'KAppTests' do
inherit! :search_paths
# Pods for testing
end
target 'KAppUITests' do
inherit! :search_paths
# Pods for testing
end
pod 'LBTAComponents'
pod 'SwiftyJSON', '~> 4.0'
pod 'TRON', '~>4.0'
pod 'ios-oauth2-rest-template', '~> 0.0.1'
end
ios-oauth2-rest-template podspec:
Pod::Spec.new do |s|
# 1
s.platform = :ios
s.ios.deployment_target = '12.0'
s.name = "ios-oauth2-rest-template"
s.summary = "My summary here"
s.requires_arc = true
# 2
s.version = "0.0.1"
# 3
s.license = { :type => "Proprietary", :file => "LICENSE" }
# 4 - Replace with your name and e-mail address
s.author = { "My Name" => "myemail#email.com" }
# 5 - Replace this URL with your own GitHub page's URL (from the address bar)
s.homepage = "https://bitbucket.org/myStuff"
# 6 - Replace this URL with your own Git URL from "Quick Setup"
s.source = { :git => "https://bitbucket.org/myStuff.git",
:tag => "#{s.version}" }
# 7
s.framework = "UIKit"
s.dependency 'Heimdallr', '~> 3.6.1'
# 8
s.source_files = "ios-oauth2-rest-template/**/*.{swift}"
# 9
#s.resources = "RWPickFlavor/**/*.{png,jpeg,jpg,storyboard,xib,xcassets}"
# 10
# s.swift_version = "4.0"
end
ios-oauth2-rest-template Podfile:
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'
target 'ios-oauth2-rest-template' do
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
use_frameworks!
# Pods for ios-oauth2-rest-template
pod 'Heimdallr', '~> 3.6.1'
target 'ios-oauth2-rest-templateTests' do
inherit! :search_paths
# Pods for testing
end
end
Thanks in advance. I have scoured the internet to no avail as to why this could be happening and I am stumped since I don't have that much experience with CocoaPods in the first place.
UPDATE
Here are some screenshots
The Pods section of the KApp, to show some of my classes. When I try to use ApplicationUtils it works just fine and autocompletes, but when I try to use BaseClass it cannot seem to find it.
Build phases under settings to show that all 30 files are under compile sources. The 30 files match the 30 files from the ios-oauth2-rest-template Xcode project. The 31st file is ios-oauth2-rest-template-dummy.m.
Image showing the folder structure of ios-oauth2-rest-template Cocoapod project.
Thanks to #balazs630, I was able to solve the problem. I had to make sure my access control was set to public or open in order to access them. Looking back at my code, ApplicationUtils was a public class and BaseClass had no designation, so it was by default internal, which according to the docs:
Internal access enables entities to be used within any source file
from their defining module, but not in any source file outside of that
module.
For anyone with a similar problem, check to make sure your access control is set appropriately. Here are some sources to familiarize yourself with access control in Swift:
https://medium.com/#abhimuralidharan/swift-3-0-1-access-control-9e71d641a56c
https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html
I've set up a workspace with two Swift projects in it: one a framework I'm developing, the other a demo app for the framework.
Podfile looks like this:
platform :ios, '9.0'
workspace 'foo.xcworkspace'
target 'framework' do
project 'framework.xcodeproj'
end
target :'demo' do
project 'demo/demo.xcodeproj'
pod 'framework', :path => 'framework.podspec'
end
the .podspec file looks like this:
Pod::Spec.new do |s|
s.name = 'framework'
s.authors = { "foo author" }
s.version = '0.1.0'
s.summary = 'foo summary.'
s.homepage = 'foo homepage'
s.platform = :ios, '9.0'
s.license = {
:type => "Proprietary",
:file => "LICENSE"
}
s.source = {
:git => 'https://url.to/foo.git',
:tag => s.version.to_s
}
s.source_files = 'framework/framework/**/*.{swift,h,m}'
s.requires_arc = true
s.weak_framework = "XCTest"
s.pod_target_xcconfig = {
'FRAMEWORK_SEARCH_PATHS' => '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"',
}
end
After running pod install, Xcode/AppCode can still not see the classes from the framework project. So if I add a manual import to a class in the demo app and try to compile, it fails with:
Error:(13, 21) use of undeclared type 'FooClass'
What do I have to do to properly have the demo app project see the classes from the framework project generated pod?
Try using inherit! :search_paths on the demo target
This means they don't get their own copies of the pods but can see they exist via the header files.
platform :ios, '9.0'
workspace 'foo.xcworkspace'
target :framework do
project 'framework.xcodeproj'
end
target :demo do
inherit! :search_paths
project 'demo/demo.xcodeproj'
pod 'framework', :path => 'framework.podspec'
end
untested but perhaps worth a shot
If you install a Cocoapod don't use the file with .xcodeproj to open your project anymore, but the newly created .workspace in the same folder.
I finally resolved this issue:
Make sure the min. required iOS is defined in Podfile, e.g.:
platform :ios, '10.0'
Add any third-party pods also to the podspec file, e.g.:
spec.dependency 'Alamofire', '~> 4.5'
spec.dependency 'Serpent', '~> 1.0'
If doing pod install without the use_frameworks! it will mess up some things (see this answer: ld: framework not found Pods). So in between I got these invalid Pod xconfigs that I had to delete and then do a clean and pod install.
Make sure to build the framework project at least once and then the demo source should find the import to the framework pod name!
Make sure that all classes are correctly added to their target, especially classes in the test target should not have been added to the app target accidentally.
After all is said and done, having worked with a multitude of IDEs and development technologies, Xcode and Cocoapods can only be summed up as one giant clusterf*** of an accident!
How do I include Alamofire (a web request pod like AFNetworking) in my cocoapod source files? I have a service in my cocoapod that needs to make web requests using Alamofire, my cocoapod doesn't seem to have a podfile that I can see, so I don't know how to add the dependency to my cocoapod.
I am creating a cocoapod using pod lib create The build fails whenever I go to import Alamofire in any of my files. In a normal project, I'd just add Alamofire to my podfile, but this is a cocoapod, so I can't figure out where to add the dependency, or how to get it to build successfully.
I followed the guide here but it doesn't say anything about importing another pod into my cocoapod's files.
My directory structure looks like this:
MyLib.podspec
Example/
MyLib example project
Pod/
Source files for my cocoapod
If your pod depends on other pods you can define that in your pod's .podspec file. You can add dependencies there.
Have a look at RealmSwift's podspec file as an example. The RealmSwift pod has a dependency to the Realm pod. This is defined in RealmSwift.podspec:
Pod::Spec.new do |s|
s.name = 'RealmSwift'
s.version = `sh build.sh get-version`
s.summary = 'Realm is a modern data framework & database for iOS & OS X.'
s.description = <<-DESC
The Realm database, for Swift. (If you want to use Realm from Objective-C, see the “Realm” pod.)
Realm is a mobile database: a replacement for Core Data & SQLite. You can use it on iOS & OS X. Realm is not an ORM on top SQLite: instead it uses its own persistence engine, built for simplicity (& speed). Learn more and get help at https://realm.io
DESC
s.homepage = "https://realm.io"
s.source = { :git => 'https://github.com/realm/realm-cocoa.git', :tag => "v#{s.version}" }
s.author = { 'Realm' => 'help#realm.io' }
s.requires_arc = true
s.social_media_url = 'https://twitter.com/realm'
s.documentation_url = "https://realm.io/docs/swift/#{s.version}"
s.license = { :type => 'Apache 2.0', :file => 'LICENSE' }
# ↓↓↓ THIS IS WHERE YOU DEFINE THE DEPENDENCY TO ANOTHER POD ↓↓↓
s.dependency 'Realm', "= #{s.version}"
# ↑↑↑ THIS IS WHERE YOU DEFINE THE DEPENDENCY TO ANOTHER POD ↑↑↑
s.source_files = 'RealmSwift/*.swift'
s.prepare_command = 'sh build.sh cocoapods-setup without-core'
s.preserve_paths = %w(build.sh)
s.pod_target_xcconfig = { 'SWIFT_WHOLE_MODULE_OPTIMIZATION' => 'YES',
'APPLICATION_EXTENSION_API_ONLY' => 'YES' }
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.9'
s.watchos.deployment_target = '2.0' if s.respond_to?(:watchos)
end
You should check out the AlamofireImage project. It uses Carthage to add the Alamofire submodule to the project. The Alamofire project is then added as a dependency to the AlamofireImage project.
The AlamofireImage.podspec also demonstrates how to add Alamofire as a dependency for CocoaPods. If you follow the AlamofireImage project structure exactly, you'll be up and running in no time. Here are some useful commands to get you going:
Cartfile
github "Alamofire/Alamofire" ~> 3.0
Checkout through Carthage
brew update
brew doctor
brew install carthage
// or
brew upgrade carthage
carthage update --no-build --use-submodules
Hopefully that helps!
If you have created a pod and in your .podspec file you are trying to add a dependency (like Alamofire, RealmSwift..) after that you should go to the Example/.. folder and do a pod install to make the dependencies required from the .podspec of your custom pod visible to the .swift files in your custom pod/framework.
A typical example of a pod project folder hierarchy would be:
- MyLib/
- _Pods.xcodeproj
- Example/ // <-- do a pod install under this folder in order to get the dependencies declared in your .podspec
- Podfile
- MyLib.xcodeproj
- MyLib.xcworkspace
- MyLib/
- Classes/ // <-- folder with pod specific logic that also uses Alamofire
- Assets/
- MyLib.podspec // <-- your podspec with dependencies (Alamofire..)
What is the purpose of each target in a Cocoapods workspace?
When I created a new CocoaPods library via "pod lib create Foo", I expected only two targets: One to build my library, and one to build my example.
But the resulting xcworkspace has a total of four targets:
Project Foo
Target Foo_Tests
Project Pods
Target Pods-Foo_Tests
Target Pods-Foo_Tests-Foo
Target Pods-Foo_Tests-Foo-Foo
What's the meaning of these targets?
(I chose no demo application, view-based testing, or testing frameworks.)
There are 2 project in your workspace one is yours and the other is cocoapods, and cocoapods adds new target for each pod which you add in your Podfile. For example, let's say this is your Podfile :
platform :ios, '7.0'
pod 'AFNetworking', '~> 2.5.4'
pod 'BPXLUUIDHandler'
you should see in your pod project's target list something like this :
but what is that mean?
Targets where cocoapods manage everything for each pod. For example if you choose AFNwtworking target in pod project, you must see something like this :
but for example how cocoapods know to add "Link binary with libraries" frameworks like above? Well, please check AFNetworking's podspec file for this :
s.public_header_files = 'AFNetworking/*.h'
s.source_files = 'AFNetworking/AFNetworking.h'
s.subspec 'Serialization' do |ss|
ss.source_files = 'AFNetworking/AFURL{Request,Response}Serialization.{h,m}'
ss.ios.frameworks = 'MobileCoreServices', 'CoreGraphics'
ss.osx.frameworks = 'CoreServices'
end
s.subspec 'Security' do |ss|
ss.source_files = 'AFNetworking/AFSecurityPolicy.{h,m}'
ss.frameworks = 'Security'
end
s.subspec 'Reachability' do |ss|
ss.source_files = 'AFNetworking/AFNetworkReachabilityManager.{h,m}'
ss.frameworks = 'SystemConfiguration'
end
as you can see above this lines "ss.ios.frameworks" are describe what is going on there.
Hope everything is clear now.