I'm currently working on a Swift project where the workspace contains multiple projects (ACM...) due to company decision.
When adding Firebase with Cocoapods, I need it in two of the projects (in 'myapp' and 'ACMLoyalty'). So my .podfile looks like this:
workspace 'myapp.xcworkspace'
platform :ios, '12.0'
use_frameworks!
def shared_pods
source 'https://github.com/CocoaPods/Specs.git'
pod 'Nuke', '9.2.3'
pod 'Alamofire', '~> 4.9.1'
pod 'DeepDiff', '2.3.1'
end
def firebase_pods
pod 'Firebase/Analytics', '7.4.0'
pod 'Firebase/Crashlytics', '7.4.0'
pod 'Firebase', '7.4.0'
end
def appcenter_pods
pod 'AppCenter', '4.1.0'
pod 'AppCenter/Distribute', '4.1.0'
end
project 'myapp.xcodeproj'
project 'ACMCore/ACMCore.xcodeproj'
project 'ACMData/ACMData.xcodeproj'
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
project 'ACMMVVM/ACMMVVM.xcodeproj'
project 'ACMNetwork/ACMNetwork.xcodeproj'
project 'ACMShared/ACMShared.xcodeproj'
target :myapp do
project 'myapp.xcodeproj'
shared_pods
firebase_pods
appcenter_pods
end
target :ACMCore do
project 'ACMCore/ACMCore.xcodeproj'
shared_pods
end
target :ACMData do
project 'ACMData/ACMData.xcodeproj'
shared_pods
end
target :ACMLoyalty do
use_frameworks! :linkage => :dynamic
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
shared_pods
firebase_pods
target 'ACMLoyaltyTests' do
inherit! :search_paths
shared_pods
firebase_pods
end
target 'ACMLoyaltyTestHost' do
inherit! :search_paths
shared_pods
firebase_pods
end
end
target :ACMMVVM do
project 'ACMMVVM/ACMMVVM.xcodeproj'
shared_pods
target 'ACMMVVMTests' do
inherit! :search_paths
shared_pods
end
end
target :ACMNetwork do
project 'ACMNetwork/ACMNetwork.xcodeproj'
shared_pods
target 'ACMNetworkTests' do
inherit! :search_paths
shared_pods
end
end
target :ACMShared do
project 'ACMShared/ACMShared.xcodeproj'
shared_pods
target 'ACMSharedTests' do
inherit! :search_paths
shared_pods
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if Gem::Version.new('9.0') > Gem::Version.new(config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'])
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
end
end
end
end
Problem:
During run-time I get following warnings in the console:
objc[2946]: Class FIRAnalyticsConnector is implemented in both /private/var/containers/Bundle/Application/05B31227-083E-42A7-9E27-DB7924A754B9/myapp.app/Frameworks/ACMLoyalty.framework/ACMLoyalty (0x107c4d1b8) and /private/var/containers/Bundle/Application/05B31227-083E-42A7-9E27-DB7924A754B9/myapp.app/myapp (0x104217298). One of the two will be used. Which one is undefined.
This is just one line as sample, but there are a lot of other Firebase classes listed with the same description.
After some research I know, that the problem is, that Firebase is a static library and will be simply copied to the specific target which causes this issue. With the other libraries (dynamic) this problem doesn't occur.
Does anybody have a solution for my problem?
Edit: Answer #mbi
I already tried a solution with abstract_target.
Please find my .podfile for this attempt:
# Uncomment the next line to define a global platform for your project
workspace 'myapp.xcworkspace'
platform :ios, '12.0'
use_frameworks!
project 'myapp.xcodeproj'
project 'ACMCore/ACMCore.xcodeproj'
project 'ACMData/ACMData.xcodeproj'
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
project 'ACMMVVM/ACMMVVM.xcodeproj'
project 'ACMNetwork/ACMNetwork.xcodeproj'
project 'ACMShared/ACMShared.xcodeproj'
abstract_target 'myapp-app' do
source 'https://github.com/CocoaPods/Specs.git'
pod 'Nuke', '9.2.3'
pod 'Alamofire', '~> 4.9.1'
pod 'DeepDiff', '2.3.1'
pod 'Firebase/Analytics', '7.4.0'
pod 'Firebase/Crashlytics', '7.4.0'
pod 'Firebase', '7.4.0'
def appcenter_pods
pod 'AppCenter', '4.1.0'
pod 'AppCenter/Distribute', '4.1.0'
end
target :myapp do
project 'myapp.xcodeproj'
appcenter_pods
end
target :ACMCore do
project 'ACMCore/ACMCore.xcodeproj'
end
target :ACMData do
project 'ACMData/ACMData.xcodeproj'
end
target :ACMLoyalty do
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
target 'ACMLoyaltyTests' do
end
target 'ACMLoyaltyTestHost' do
end
end
target :ACMMVVM do
project 'ACMMVVM/ACMMVVM.xcodeproj'
target 'ACMMVVMTests' do
end
end
target :ACMNetwork do
project 'ACMNetwork/ACMNetwork.xcodeproj'
target 'ACMNetworkTests' do
end
end
target :ACMShared do
project 'ACMShared/ACMShared.xcodeproj'
target 'ACMSharedTests' do
end
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if Gem::Version.new('9.0') > Gem::Version.new(config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'])
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
end
end
end
end
The problem is, with this solution I have even more warning, because Firebase is built in ALL projects and conflicts.
EDIT2: With the answer of #arturdev I got it working without the ... implemented in both... warning with following podfile:
# Uncomment the next line to define a global platform for your project
workspace 'myapp.xcworkspace'
platform :ios, '12.0'
use_frameworks!
project 'myapp.xcodeproj'
project 'ACMCore/ACMCore.xcodeproj'
project 'ACMData/ACMData.xcodeproj'
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
project 'ACMMVVM/ACMMVVM.xcodeproj'
project 'ACMNetwork/ACMNetwork.xcodeproj'
project 'ACMShared/ACMShared.xcodeproj'
abstract_target 'myapp-app' do
source 'https://github.com/CocoaPods/Specs.git'
pod 'Nuke', '9.2.3'
pod 'Alamofire', '~> 4.9.1'
pod 'DeepDiff', '2.3.1'
def firebase_pods
pod 'Firebase/Analytics', '7.4.0'
pod 'Firebase/Crashlytics', '7.4.0'
pod 'Firebase', '7.4.0'
end
def appcenter_pods
pod 'AppCenter', '4.1.0'
pod 'AppCenter/Distribute', '4.1.0'
end
target :myapp do
project 'myapp.xcodeproj'
firebase_pods
appcenter_pods
target 'myappTests' do
end
end
target :ACMCore do
project 'ACMCore/ACMCore.xcodeproj'
target 'ACMCoreTests' do
firebase_pods
end
end
target :ACMData do
project 'ACMData/ACMData.xcodeproj'
target 'ACMDataTests' do
firebase_pods
end
end
target :ACMLoyalty do
project 'ACMLoyalty/ACMLoyalty.xcodeproj'
firebase_pods
target 'ACMLoyaltyTests' do
end
target 'ACMLoyaltyTestHost' do
end
end
target :ACMMVVM do
project 'ACMMVVM/ACMMVVM.xcodeproj'
target 'ACMMVVMTests' do
end
end
target :ACMNetwork do
project 'ACMNetwork/ACMNetwork.xcodeproj'
target 'ACMNetworkTests' do
end
end
target :ACMShared do
project 'ACMShared/ACMShared.xcodeproj'
target 'ACMSharedTests' do
end
end
end
PROJECT_ROOT_DIR = File.dirname(File.expand_path(__FILE__))
PODS_DIR = File.join(PROJECT_ROOT_DIR, 'Pods')
PODS_TARGET_SUPPORT_FILES_DIR = File.join(PODS_DIR, 'Target Support Files')
post_install do |installer|
## For more information: https://stackoverflow.com/questions/65904011/cocoapods-with-multiple-projects-firebase-causes-class-xxx-is-implemented-in-b
remove_static_framework_duplicate_linkage({
'ACMLoyalty' => ['FBLPromises', 'FIRAnalyticsConnector', 'FirebaseAnalytics', 'FirebaseCore', 'FirebaseCoreDiagnostics', 'FirebaseCrashlytics', 'FirebaseInstallations', 'GoogleAppMeasurement', 'GoogleDataTransport', 'GoogleUtilities']
})
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
#config.build_settings['LD_NO_PIE'] = 'NO'
if Gem::Version.new('9.0') > Gem::Version.new(config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'])
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0'
end
end
end
end
# CocoaPods provides the abstract_target mechanism for sharing dependencies between distinct targets.
# However, due to the complexity of our project and use of shared frameworks, we cannot simply bundle everything under
# a single abstract_target. Using a pod in a shared framework target and an app target will cause CocoaPods to generate
# a build configuration that links the pod's frameworks with both targets. This is not an issue with dynamic frameworks,
# as the linker is smart enough to avoid duplicate linkage at runtime. Yet for static frameworks the linkage happens at
# build time, thus when the shared framework target and app target are combined to form an executable, the static
# framework will reside within multiple distinct address spaces. The end result is duplicated symbols, and global
# variables that are confined to each target's address space, i.e not truly global within the app's address space.
#
# Previously we avoided this by linking the static framework with a single target using an abstract_target, and then
# provided a shim to expose their interfaces to other targets. The new approach implemented here removes the need for
# shim by modifying the build configuration generated by CocoaPods to restrict linkage to a single target.
def remove_static_framework_duplicate_linkage(static_framework_pods)
puts "Removing duplicate linkage of static frameworks"
Dir.glob(File.join(PODS_TARGET_SUPPORT_FILES_DIR, "Pods-*")).each do |path|
pod_target = path.split('-', -1).last
static_framework_pods.each do |target, pods|
next if pod_target == target
frameworks = pods.map { |pod| identify_frameworks(pod) }.flatten
Dir.glob(File.join(path, "*.xcconfig")).each do |xcconfig|
lines = File.readlines(xcconfig)
if other_ldflags_index = lines.find_index { |l| l.start_with?('OTHER_LDFLAGS') }
other_ldflags = lines[other_ldflags_index]
frameworks.each do |framework|
other_ldflags.gsub!("-framework \"#{framework}\"", '')
end
File.open(xcconfig, 'w') do |fd|
fd.write(lines.join)
end
end
end
end
end
end
def identify_frameworks(pod)
frameworks = Dir.glob(File.join(PODS_DIR, pod, "**/*.framework")).map { |path| File.basename(path) }
if frameworks.any?
return frameworks.map { |f| f.split('.framework').first }
end
return pod
end
Some of the pod dependencies are being compiled as a static library and not dynamic (f.e. Firebase and other Google libs).
A static framework can't be linked more than once (f.e. in a framework target and in a main target which also links the framework above), because the linkage of static frameworks happens during build-time, yet for the dynamic frameworks the linkage happens on runtime and the linker is smart enough to avoid duplications.
Therefore you need to write a script in your podfile to remove static library linkages.
A dirty example:
post_install do |installer|
remove_static_framework_duplicate_linkage({
'FrameworkTarget1' => ['Firebase', 'FirebaseAnalytics', 'FirebaseCore', 'FirebaseCoreDiagnostics', 'FirebaseCoreDiagnosticsInterop', 'FirebaseInstanceID', 'FirebaseInstallations', 'GoogleAppMeasurement', 'GoogleDataTransport', 'GoogleDataTransportCCTSupport', 'GoogleUtilities'],
'FrameworkTarget2' => ['GoogleMaps', 'GooglePlaces'],
})
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['LD_NO_PIE'] = 'NO'
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end
end
# CocoaPods provides the abstract_target mechanism for sharing dependencies between distinct targets.
# However, due to the complexity of our project and use of shared frameworks, we cannot simply bundle everything under
# a single abstract_target. Using a pod in a shared framework target and an app target will cause CocoaPods to generate
# a build configuration that links the pod's frameworks with both targets. This is not an issue with dynamic frameworks,
# as the linker is smart enough to avoid duplicate linkage at runtime. Yet for static frameworks the linkage happens at
# build time, thus when the shared framework target and app target are combined to form an executable, the static
# framework will reside within multiple distinct address spaces. The end result is duplicated symbols, and global
# variables that are confined to each target's address space, i.e not truly global within the app's address space.
#
# Previously we avoided this by linking the static framework with a single target using an abstract_target, and then
# provided a shim to expose their interfaces to other targets. The new approach implemented here removes the need for
# shim by modifying the build configuration generated by CocoaPods to restrict linkage to a single target.
def remove_static_framework_duplicate_linkage(static_framework_pods)
puts "Removing duplicate linkage of static frameworks"
Dir.glob(File.join(PODS_TARGET_SUPPORT_FILES_DIR, "Pods-*")).each do |path|
pod_target = path.split('-', -1).last
static_framework_pods.each do |target, pods|
next if pod_target == target
frameworks = pods.map { |pod| identify_frameworks(pod) }.flatten
Dir.glob(File.join(path, "*.xcconfig")).each do |xcconfig|
lines = File.readlines(xcconfig)
if other_ldflags_index = lines.find_index { |l| l.start_with?('OTHER_LDFLAGS') }
other_ldflags = lines[other_ldflags_index]
frameworks.each do |framework|
other_ldflags.gsub!("-framework \"#{framework}\"", '')
end
File.open(xcconfig, 'w') do |fd|
fd.write(lines.join)
end
end
end
end
end
end
def identify_frameworks(pod)
frameworks = Dir.glob(File.join(PODS_DIR, pod, "**/*.framework")).map { |path| File.basename(path) }
if frameworks.any?
return frameworks.map { |f| f.split('.framework').first }
end
return pod
end
The error Class XYZ is implemented in both ... indicates that the same class is beeing compiled and linked into more than one built product. You are making things more complex than they need to be.
I'm really having a hard time to figure out by looking at the given Podfile what your actually trying to achieve. Obviously there a few things that could be improved but that heavily depends on what the requirements are.
For example you should read about and use the concept of abstract_target and nesting targets in a Podfile. This gives you the possibility to describe dependencies just one time and inherit them to the nested targets. See https://guides.cocoapods.org/using/the-podfile.html
Furthermore you have to keep in mind that Cocoapods is applying something called dedublication which basically means no matter how often you specify a dependency in your Podfile it tries to squash them into as least targets as possible in the generated Pods project. So to me the many statements of the very same dependencies such as share_pods in your Podfile seem some kind of wrong.
And in my opinion you are using inheritance in a weird way. For example you limit inheritance to exclude parent's deps just to add them again in the next line. Example:
target :ACMMVVM do
project 'ACMMVVM/ACMMVVM.xcodeproj'
shared_pods # <-- dependency here
target 'ACMMVVMTests' do
inherit! :search_paths # <-- excluded here
shared_pods # <-- added again here
end
end
As of my experience in most cases nested test targets don't need the dependencies so inheriting just search paths as you do is just fine. But only you know whether this particular test target really depends on share_pods or not.
I'm pretty sure once you sort out your actual requirements and rewrite the Podfile to a nested structure of abstract and non-abstract targets there is a very high chance that your problem goes away.
target_names = installer.pod_targets.map { |target| target.name }in post_install can get all dependent pods, but it include sub pod of pod in Podfile.
Thanks!
I had the answer,below code in post_install can do it.
podfile = Pod::Podfile.from_file(Pathname.new('Podfile'))
podfile_pod_items = podfile.dependencies.map do |pod|
pod.name
end
I have a react-native project and I have to link my xCode project with firebase. Even though I used CocoaPod and manual ways I am getting the error
"No such module as firebase.h".
I have followed all the steps correctly.
Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
target 'App' do
# Uncomment the next line if you're using Swift or would like to use
dynamic frameworks
# use_frameworks!
# Pods for App
target 'App-tvOSTests' do
inherit! :search_paths
# Pods for testing
end
target 'AppTests' do
inherit! :search_paths
# Pods for testing
end
pod 'Google-Mobile-Ads-SDK'
pod 'Firebase/Core', '~> 5.6.0'
pod 'GoogleIDFASupport'
end
target 'App-tvOS' do
# Uncomment the next line if you're using Swift or would like to use
dynamic frameworks
# use_frameworks!
# Pods for App-tvOS
end
I also faced this problem. I was using react-native-firebase package. Please try following their official docs . I would rate their documentation 10/10 as they've explained every possible scenario a developer would face during integration.
Just change value with deployment target of your app.
platform :ios, 'value'
inhibit_all_warnings!
def sharedpods
pod 'Google-Mobile-Ads-SDK'
pod 'Firebase/Core', '~> 5.6.0'
pod 'GoogleIDFASupport'
end
target 'AppTests’ do
use_frameworks!
sharedpods
end
target 'App-tvOSTests’ do
use_frameworks!
sharedpods
end
target 'App-tvOS’ do
use_frameworks!
sharedpods
end
#post_install do |installer|
# installer.pods_project.targets.each do |target|
# puts "#{target.name}"
# end
#end
I'm willing to add unit and UI tests to my app.
I first configured unit tests with success, I tried to do the same with UI tests. Here is my Podfile, after adding a new UI Testing Bundle target :
platform :ios, '8.0'
use_frameworks!
inhibit_all_warnings!
def shared_pods
pod 'Bolts'
pod 'Branch'
pod 'FBSDKCoreKit'
pod 'FBSDKLoginKit'
pod 'FBSDKShareKit'
pod 'GoogleAnalytics'
pod 'GooglePlaces'
pod 'Parse'
pod 'Toast-Swift'
end
target 'MyTarget' do
shared_pods
end
target 'MyTargetUITests' do
shared_pods
end
target 'MyTargetUnitTests' do
shared_pods
end
However, when I try to run the automatically created MyProjectUITests test case, which only contains the basic setup and without even a #testable import MyProject:
import XCTest
class MyProjectUITests: XCTestCase {
override func setUp() {
continueAfterFailure = false
XCUIApplication().launch()
}
}
I'm getting this error:
Running tests...
The bundle “MyProjectUITests” couldn’t be loaded because it is damaged or missing necessary resources. Try reinstalling the bundle.
(dlopen_preflight(/var/containers/Bundle/Application/5A1FE39F-E675-4A47-9BF4-FBCDB96F5821/MyProjectUITests-Runner.app/PlugIns/MyProjectUITests.xctest/MyProjectUITests): Library not loaded: #rpath/libswiftSwiftOnoneSupport.dylib
Referenced from: /private/var/containers/Bundle/Application/5A1FE39F-E675-4A47-9BF4-FBCDB96F5821/MyProjectUITests-Runner.app/PlugIns/MyProjectUITests.xctest/Frameworks/Toast_Swift.framework/Toast_Swift
Reason: image not found)
What is wrong? Thanks for your help.
EDIT : for information, it works fine when I remove that Toast_swift pod from my UI test target and let it only in my app and unit test targets.
Check out this issue on the cocoapods github issue tracker.
I'm still a little confused as to why this became a problem but the setting the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to YES using this script fixed the issue for me.
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
# This works around a unit test issue introduced in Xcode 10.
# We only apply it to the Debug configuration to avoid bloating the app size
if config.name == "Debug" && defined?(target.product_type) && target.product_type == "com.apple.product-type.framework"
config.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = "YES"
end
end
end
end
Try adding inherit! :search_paths
and also changing ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES in post_install
use_frameworks!
def shared_pods
pod 'SomePod'
end
target 'App_name' do
shared_pods
end
target 'App_nameTests' do
inherit! :search_paths
shared_pods
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'YES'
end
end
end
I too faced this issue and none of the other suggestions worked.
After a while I found out that specifically using print() anywhere in your code will somehow force libswiftSwiftOnoneSupport.dylib to be loaded and the issue will go away.
I'm using Xcode 10.1, Swift 4.2 and the pod that was giving me this issue was Nimble.
Hope this helps!
I'm new to iOS, i already have Alamofire and MarqueeLabel on my Podfile and now trying to add GoogleMaps, it keeps showing this message,
[!] Unable to find a specification for `GoogleMaps`
My Podfile looks like this
# Uncomment the next line to define a global platform for your project
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
target 'Migapixel' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'GoogleMaps'
pod 'Alamofire',
:git => 'https://github.com/Alamofire/Alamofire.git',
:branch => 'master',
:tag => '4.0.0'
pod 'MarqueeLabel/Swift',
:git => 'https://github.com/cbpowell/MarqueeLabel.git'
# Pods for Migapixel
post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'NO' end end end
target 'MigapixelTests' do
inherit! :search_paths
end
target 'MigapixelUITests' do
inherit! :search_paths
# Pods for testing
end
end
i even tried this
pod 'GoogleMaps',
:git => 'https://github.com/CocoaPods/Specs.git'
What am i doing wrong?
Try removing source 'https://github.com/CocoaPods/Specs.git' and moving use_frameworks! out of the target block. Moreover you don't need to manually set the git path for both Alamofire and MarqueeLabel.
Try this:
platform :ios, '9.0'
use_frameworks!
target 'Migapixel' do
pod 'GoogleMaps'
pod 'Alamofire'
pod 'MarqueeLabel/Swift'
# Pods for Migapixel
end
post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES'] = 'NO' end end end
target 'MigapixelTests' do
inherit! :search_paths
end
target 'MigapixelUITests' do
inherit! :search_paths
# Pods for testing
end
Edit:
It seems that there's something wrong with your local repo.
Try cleaning and reinstalling:
pod repo remove master
pod setup
i resolved the issue like that with these step:
open terminal.
go to your project path.
type:
pod repo update
install pod again.
After trying many things Here is the fix!!
Imp: Make sure that you have these lines in your PodFile
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
target 'YOUR_APPLICATION_TARGET_NAME_HERE' do
pod 'GoogleMaps'
end
If the above is fine then you need to update the pods:
try the following steps:
Open a new terminal and run the following command in a temp directory.
pod try GoogleMaps
keep patience! It will take some time but will update the pod.
Now try to install the pod in ur project again. It should work.Else try to run the following commands in the project dir:
pod repo update
try again.
Comment in the case of any issue!!
Go to your project directory and delete pods folder and .lock file then run
pod repo update
it helps for me.