14

After the app uploading I receive the following email

We identified one or more issues with a recent delivery for your app, XXX. Please correct the following issues, then upload again.

ITMS-90806: CFBundleIdentifier collision - Each bundle must have a unique bundle identifier. The bundle identifier 'org.cocoapods.CocoaLumberjack' is used in the bundles '[CocoaLumberjack.framework, CocoaLumberjack.framework]'

CocoaLumberjack is a third party library that I've already used in the past a lot of times without any problem, I am pretty confused.

It is not related to the framework's .plist keyword CFBundlePackageType as it is specified in this question/answer Framework CFBundleIdentifier Collision. The CocoaLumberjack bundle package type is "Framework" (CFBundlePackageType = FMWK). CocoaLumberjack is a wide used third party library added to my project using cocoapods.

The issue is probably related to the watchOS target in my app bundle. The CocoaLumberjack library is used in both iOS app and watchOS app and it is causing the issue about the bundle identifier duplication.

CFBundleIdentifier collision is detected by Apple Connect server if sharing framework between iOS target and Watch Extension.

target 'App' do
 platform :ios, '9.0'
 # Pods for App
 ...
 pod 'CocoaLumberjack/Swift', '~> 3.5.3'
 ...
end

target 'AppWatch Extension' do
 platform :watchos, '5.0'
 # Pods for Watch Extension
 ...
 pod 'CocoaLumberjack/Swift', '~> 3.5.3'
 ...
end

The iOS app is using the library and the watchOS extension is using the same library. They are using different libraries but CocoaLumberjack is the only one present in both.

I have already published my app a lot of times in the past without any issues with the same libraries configuration. I guess that the Apple has changed some constraints about bundle identifier in the last few days.

The same issue is present also using Carthage.

cristallo
  • 1,951
  • 2
  • 25
  • 42

6 Answers6

9

As a temporary workaround I have manually renamed the bundle identifier in the watchOS extension then the app publishing is working fine but it does not look like a nice solution, especially if you are running the build on a CI system.

A better option is to add a specific post install operation in pod file:

post_install do |installer|
 installer.pods_project.targets.each do |target|
  if target.name == 'CocoaLumberjack-watchOS'
   target.build_configurations.each do |config|       
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}-$(PLATFORM_NAME)'
   end
  end
 end
end

or if you have to handle multiple libraries:

post_install do |installer|
 watchosLibs = ['Lib1-watchOS', 'Lib2-watchOS', 'Lib3-watchOS']
 installer.pods_project.targets.each do |target|
  if watchosLibs.include? target.name
   target.build_configurations.each do |config|
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}.${PLATFORM_NAME}"
   end
  end
 end
end

Pay attention to rename pods bundle identifier because some libraries don't behave correctly otherwise.

I suggest to rename only the libraries rejected by Apple in order to minimize the possible issues.

Currently there are some different open threads about this issue:

A similar issue is present also using Carthage instead of Cocoapods

If Apple will not change this new policy about bundle identifier then a more clean solution will probably come from cocoapods team.

cristallo
  • 1,951
  • 2
  • 25
  • 42
  • I see that the whole discussion thread on Apple forum was rejected by a moderator. So it is not available anymore. Fortunately we can continue to talk about it here :-) – cristallo Sep 05 '19 at 11:36
8

Apparently Apple changed the validation process. It looks like they don't allow to platform specific frameworks within an app to have the same identifier.

There's a post on the forum about this as well: https://forums.developer.apple.com/thread/122048

If you're running into this issue because you're using Cocoapods you could patch your Podfile to append the Platform Name to the bundle identifier so that they'll be always unique (source):

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}-$(PLATFORM_NAME)'
    end
  end
end

If you have multiple targets in your app you can change the watchOS targets in your scheme in XCode and append .watchos to the identifier as well.

Tieme
  • 62,602
  • 20
  • 102
  • 156
  • 1
    I opened the thread on Apple forum: I am still trying to understand which is the best solution for this issue, in the meantime the workaround about changing the name of the bundle looks good – cristallo Aug 30 '19 at 13:11
  • 2
    Pay attention to rename all pods bundle identifier because some pods don't behave correctly otherwise. i.e.: some people have been experiencing issues with Firebase and the problem was that the script had renamed its bundle. I suggest to rename only the ones rejected by Apple. – cristallo Sep 03 '19 at 07:39
  • 1
    Apple just approved our app update that was using the technique described in my answer. – Tieme Sep 03 '19 at 08:27
  • I am not saying that it is wrong, since it is right the way for handling this issue :-) ... just pay attention that it could not work properly for every library. – cristallo Sep 03 '19 at 08:35
  • When I try to archive a build after implementing this approach I am getting the following error: "Invalid code signature identifier. The identifier in your code signature must match its bundle identifier." – Zachary Bell Sep 05 '19 at 15:49
1

You don't need to change every target, its cleaner to write something like this:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.platform_name == :watchos
      target.build_configurations.each do |config|
        config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'org.cocoapods.${PRODUCT_NAME:rfc1034identifier}-$(PLATFORM_NAME)'
      end
    end
  end
end
Alexandra
  • 23
  • 4
0

Here is how I've worked around the problem for Carthage.

1) create a Carthage build script that separates out the different Carthage build phases

2) when you do the actual framework builds; first build the problem frameworks for iOS (I only had one), then modify your project files to change the bundle identifier, then build those frameworks for watchOS, then build the rest of your frameworks

carthage bootstrap --no-checkout
carthage checkout
#undo previous CFBundleIdentifier changes
sed -i '' 's/com.someco.MyFramework.watchOS;/com.someco.MyFramework;/g' Carthage/Checkouts/MyFramework/MyFramework.xcodeproj/project.pbxproj
carthage build --cache-builds --platform iOS
#set a unique CFBundleIdentifier
sed -i '' 's/com.someco.MyFramework;/com.someco.MyFramework.watchOS;/g' Carthage/Checkouts/MyFramework/MyFramework.xcodeproj/project.pbxproj
carthage build --no-use-binaries --platform watchOS --configuration $CONF $VERBOSE MyFramework

Daniel
  • 132
  • 1
  • 12
0

One option is - you can add ".watchos"(abc.asd.alomofire.watchos) to the watch bundle identifier manually.

Saurabh Bisht
  • 389
  • 1
  • 13
-5

Just remove the embed frameworks build phase from your extension.

Click on extension in target section -> Build phases -> remove the embed pods frameworks

See attached picture:enter image description here

Sagar Dhake
  • 1
  • 1
  • 2
  • 1
    If I remove the embed frameworks operation then the extension app does not work anymore because it is no more able to find the libraries – cristallo Aug 30 '19 at 09:44