Building a custom pod for a private framework, in my main project i use custom OTHER_SWIFT_FLAGS.
In theory it should be possible to override the settings of the pod during the install based on the main project but there is no documentation on how to do so.
So far my attempts failed, any hint?
Looks like project(https://guides.cocoapods.org/syntax/podfile.html#project) should be the way to go but again, no documentation.
So basically it looks like this.
Accessing the xcode project, then accessing the pod and looping through each config to set the proper value.
post_install do |installer|
require 'xcodeproj'
project_path = 'pathTo/myProj.xcodeproj' # path to your xcode project
project = Xcodeproj::Project.open(project_path)
project.targets.each do |target|
if target.name == 'myTarget' # name of the target in your main project containing the custom flag
installer.pods_project.targets.each do |podTarget|
if podTarget.name == 'myPod' #name of your pod
target.build_configurations.each do |targetConfig|
podTarget.build_configurations.each do |podConfig|
podConfig.build_settings["OTHER_SWIFT_FLAGS"] = targetConfig.build_settings["OTHER_SWIFT_FLAGS"]
end
end
end
end
end
end
Related
I'm making an app in my spare time and I wanted to ask you a question, my workspace has 3 subprojects: presentation, domain and data, each one is a static framework and has its own pods, and all very cool, but now I have a problem that I don't know how to solve it. I have several firebase dependencies that some of them must be in Presentation and others in Data, the problem comes when executing because it gives me an error :
Class PodsDummy_FirebaseUI is implemented in both
/Users/.../Debug-iphonesimulator/PresentationCleanExample.framework/PresentationCleanExample
(0x104ffada0) and
/Users/.../data/Containers/Bundle/Application/A15FF8B8-7B67-4512-8DFD-04F008175660/CleanExample.app/CleanExample
(0x100c6e288). One of the two will be used. Which one is undefined.
So what I've see in the podspec of FirebaseUI/Storage is the following:
https://github.com/firebase/FirebaseUI-iOS/blob/master/FirebaseStorageUI.podspec
s.dependency 'Firebase/Storage'
s.dependency 'GTMSessionFetcher/Core', '~> 1.5.0'
s.dependency 'SDWebImage', '~> 5.6'
This makes me think that cocoapods is not resolving the dependency Firebase/Storage properly.
And the problem is that this is only one of the thousands of duplicate classes that I have from Firebase for following the diagram above.
I suppose there is a way to inject the Firebase dependency only once and thus avoid class duplication, but I don't know how.
My Podfile:
platform :ios, '13.6'
workspace 'CleanExample'
use_frameworks!
def firebase_pods
pod 'Firebase/Core', '7.11.0'
pod 'Firebase/Auth', '7.11.0'
pod 'Firebase/Firestore', '7.11.0'
pod 'Firebase/Storage', '7.11.0'
pod 'FirebaseFirestoreSwift', '7.11.0-beta'
end
target 'CleanExample' do
project 'CleanExample'
firebase_pods
pod 'FirebaseUI/Storage'
end
target 'PresentationCleanExample' do
project 'PresentationCleanExample/PresentationCleanExample.xcodeproj'
# firebase_pods
pod 'FirebaseUI/Storage'
end
target 'DomainCleanExample' do
project 'DomainCleanExample/DomainCleanExample.xcodeproj'
end
target 'DataCleanExample' do
project 'DataCleanExample/DataCleanExample.xcodeproj'
firebase_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"
end
end
end
Github
I've uploaded the code https://github.com/rchampa/CleanExample
Questions
Is there something wrong with the FirebaseStorageUI.podspec file or
is a limitation of cocoapods?
Is my Podfile wrong?
Finally I solved my problem inspired by this post https://medium.com/#GalvinLi/tinysolution-fix-cocoapods-duplicate-implement-warning-5a2e1a505ea8 because it let me understand the problem.
If i understand correctly OTHER_LDFLAGS is adding the frameworks by duplicate.
Then to avoid the original message problem Class *** is implemented in both I install all the pods in the target 'CleanExample' and remove the OTHER_LDFLAGS line from the following files.
Pods-DataCleanExample.debug.xcconfig
Pods-DataCleanExample.release.xcconfig
Pods-PresentationCleanExample.debug.xcconfig
Pods-PresentationCleanExample.release.xcconfig
Podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
# Inspired by https://medium.com/#GalvinLi/tinysolution-fix-cocoapods-duplicate-implement-warning-5a2e1a505ea8
platform :ios, '13.6'
workspace 'CleanExample'
use_frameworks!
def data_pods
pod 'Firebase/Core', '7.11.0'
pod 'Firebase/Auth', '7.11.0'
pod 'Firebase/Firestore', '7.11.0'
pod 'Firebase/Storage', '7.11.0'
pod 'FirebaseFirestoreSwift', '7.11.0-beta'
end
def presentation_pods
pod 'FirebaseUI/Storage', '10.0.2'
pod 'Firebase/Storage', '7.11.0'
pod 'lottie-ios'
end
target 'CleanExample' do
project 'CleanExample'
presentation_pods
data_pods
end
target 'PresentationCleanExample' do
project 'PresentationCleanExample/PresentationCleanExample.xcodeproj'
presentation_pods
end
target 'DomainCleanExample' do
project 'DomainCleanExample/DomainCleanExample.xcodeproj'
end
target 'DataCleanExample' do
project 'DataCleanExample/DataCleanExample.xcodeproj'
data_pods
end
post_install do |installer|
removeOTHERLDFLAGS(['PresentationCleanExample', 'DataCleanExample'], installer)
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"
end
end
end
def removeOTHERLDFLAGS(target_names, installer)
pods_targets_names = target_names.map{ |str| 'Pods-' + str }
handle_app_targets(pods_targets_names, installer)
end
def find_line_with_start(str, start)
str.each_line do |line|
if line.start_with?(start)
return line
end
end
return nil
end
def remove_words(str, words)
new_str = str
words.each do |word|
new_str = new_str.sub(word, '')
end
return new_str
end
def handle_app_targets(names, installer)
puts "handle_app_targets"
puts "names: #{names}"
installer.pods_project.targets.each do |target|
if names.index(target.name) == nil
next
end
puts "Updating #{target.name} OTHER_LDFLAGS"
target.build_configurations.each do |config|
xcconfig_path = config.base_configuration_reference.real_path
xcconfig = File.read(xcconfig_path)
old_line = find_line_with_start(xcconfig, "OTHER_LDFLAGS")
if old_line == nil
next
end
new_line = ""
new_xcconfig = xcconfig.sub(old_line, new_line)
File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
end
end
end
Github
I've uploaded the code https://github.com/rchampa/CleanExample
everything's fine in build and run for Iphone simulator and apple watch simulator
and below some of screenshots for project setting and configuration:
build for arm64:
build for a real Iphone with ios 14 :
Project Configurations :
development Config file :
WatchAppDev Config file :
watchExtentionDev Config file :
Scheme Details:
output error details:
and my podfile:
platform :ios, '10.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
def watch_pods
pod 'Alamofire', '~> 4.8.2'
pod 'AlamofireObjectMapper', '~> 5.2.1'
pod 'SwiftyJSON', '~> 5.0.0'
pod 'EMTLoadingIndicator', '~> 4.0.0'
end
target 'MNO Watch' do
platform :watchos, '3.0'
use_frameworks!
use_modular_headers!
watch_pods
end
target 'MNO Watch Extension' do
platform :watchos, '3.0'
use_frameworks!
use_modular_headers!
watch_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'YES'
end
end
end
the problem has came from Flutter engine
To resolve this issue just change your Flutter Channel To Beta ,
for more information about it : Flutter Issue Link
I will keep my question here , maybe it will save someone his day
I pod Protobuf-C++ in my ios app, but build failed, build error log looks like this
- NOTE | [iOS] xcodebuild: Protobuf-C++/src/google/protobuf/io/zero_copy_stream.cc:35:10: fatal error: 'google/protobuf/io/zero_copy_stream.h' file not found
- NOTE | [iOS] xcodebuild: Protobuf-C++/src/google/protobuf/wrappers.pb.cc:4:10: fatal error: 'google/protobuf/wrappers.pb.h' file not found
anyone knonw how to fix this ? my protobuf version is 3.11.3
problem like this
'google/protobuf/any.h' file not found
'google/protobuf/arena_test_util.h' file not found
'google/protobuf/util/delimited_message_util.h' file not found
maybe other file not found.
the way to fix it:
way to fix
1. select 'Pods'
2. select 'Protobuf-C++'
3. select 'Build Settings'
4. search 'search path'
5. select 'Header Search Paths'
6. add '$(SRCROOT)/Protobuf-C++/src'
It works for meļ¼thanks a lot! #Rome
i also checked podspec file of Protofbuf, it has missed this config but others does "xcconfig":
{
"HEADER_SEARCH_PATHS": "$(PODS_ROOT)/SQLCipher",
......
}
which looks like same to your solution
#Rome's solution is quite helpful, but after a pod install, I have to do the same thing again manually. So I try to improve it and with this solution, no extra work is needed.
Put the following code in your Podfile:
post_install do |installer|
installer.pods_project.targets.each do |target|
# print "target=", target, "\n"
if target.name == "Protobuf-C++"
target.build_configurations.each do |config|
config.build_settings['HEADER_SEARCH_PATHS'] = '$(SRCROOT)/Protobuf-C++/src'
end
end
end
end
In addition, if you have some C++ code that uses protobuf (i.e. includes it), you may also need to do the following in your xxx.podspec:
s.pod_target_xcconfig = {
'HEADER_SEARCH_PATHS' => '$(SRCROOT)/Protobuf-C++/src',
}
I am trying to find out how to set up unit testing for my private cocoapod library.
Here is the expecting result:
I added a unit testing target 'MyPodTests' to the 'Pods' Project, then I changed target to my 'MyPodTests' scheme. Then I created test classes for my unit tests. I can now select my 'MyPodLib' scheme and press CMD+U and the testing target executes the tests. This is the behavior I am looking for.
This approach, however, has some drawbacks. If I do 'pod update' or 'pod install' on my example app, the test target is gone. if I call pod update on my Example application, the tests are gone too. I'm certain there is a correct way to do this. Also, I would like to prevent the test classes from being loaded into any consumers using the library, therefore I added an exclusion to my podspec:
s.exclude_files = 'Pod/Classes/**/Test/*'
When I select MyPodLib and press CMD+U nothing is happening, and if I select MyPodTests and press CMD+U it throws "No such module 'MyPodLib'" error.
You'll probably want to have the tests running independently of your example app. If that's the case add a test subspec in your pod spec and set its source files.
For example, say you have an Xcode project with a framework target MyFramework and a test target MyFrameworkTests. Your pod spec will look like this:
Pod::Spec.new do |s|
s.name = "MyFramework"
s.version = "1.0.0"
s.summary = "Summary of what MyFramework does"
s.homepage = "https://www.website.com"
s.license = { :type => "MIT", :file => "LICENCE.txt" }
s.author = "Ramesh Boosa"
s.platform = :ios, "11.0"
s.swift_versions = ["5.0", "5.1"]
s.source = { :git => "https://github.com/MyName/MyFramework.git", :tag => "v#{s.version}" }
s.source_files = "MyFramework/*.swift"
s.test_spec do|test|
test.source_files = "MyFrameworkTests/*.swift"
end
end
To lint your pod spec and to run your unit tests execute pod spec lint MyFramework.podspec.
If your example app is included with your pod you can add an app host to your podspec. The CocoaPods documentation has more details.
I am struggling with resources. I want to be able to put a nib in my pod. One of the classes uses this nib.
Here is the podspec:
Pod::Spec.new do |s|
s.name = "MyCBD_BSManagedDocument"
s.requires_arc = true
s.osx.platform = :osx, '10.7'
s.subspec 'MyCBD_BSManagedDocument' do |ss|
ss.source_files = 'Classes/MyCBD_BSManagedDocument/**/*.{h,m}'
end
s.subspec 'Auxiliary classes' do |ss|
ss.subspec 'MyCBDLockManager' do |sss|
sss.source_files = 'Classes/Auxiliary classes/MyCBDLockManager/**/*.{h,m}'
sss.resource_bundle = {'MyCBDLockManager' => 'Classes/Auxiliary classes/MyCBDLockManager/MyCBDLockManager.xib'}
end
ss.subspec 'MyCBDSafeguardManager' do |sss|
sss.source_files = 'Classes/Auxiliary classes/MyCBDSafeguardManager/**/*.{h,m}'
end
end
end
Very strangely, in my toy-project to test the pod, it works (I can check the nib is in the mainBundle), but in my real project, the nib is not in the mainBundle, and I have the error
-[MyCBDLockManager loadWindow]: failed to load window nib file 'MyCBDLockManager'.
Any advice on how to include resources with cocoa pods?
For some reason, one phase in the build phases was missing. I don't know why, though.
So, I had to add this phase again with pod install.
If that phase is missing you should try to run pod install again and make sure you're opening the xcworkspace that is generated. Also you want just resources not resource_bundles for a single xib like that.