22
votes

In my Xcode project, I have 4 different schemes (prod, dev, staging, staging2) which changes the bundle identifier of the app that gets installed to the phone. That way I can have all 4 versions installed side by side, similar to this technique.

Now I'm building a Today Extension for iOS 8. It's a new Target requiring its own bundle identifier.

The Extension's Bundle Identifier must be prefixed with the Parent App's Bundle Identifier, or a warning is thrown:

error: Embedded binary's bundle identifier is not prefixed with the parent app's bundle identifier.

    Embedded Binary Bundle Identifier:  com.company.app.TodayExtension
    Parent App Bundle Identifier:       com.company.app.staging

In this case, the Embedded Binary Bundle Identifier must be com.company.app.staging.TodayExtension.

Is there a way I can configure my Today Extension target to set its bundle identifier by first looking at the Parent target's bundle identifier? Perhaps through a custom Run Script Build Phase?

3
Can you explain in more detail how you solved this problem? In Jafar's answer below, were you somehow able to set PARENT_APP_BUNDLE_IDENTIFIER just by switching schemes, and if so how? Or otherwise what did you specify for the bundle ids and PARENT_APP_BUNDLE_IDENTIFIER in each target (including the extension target)? Thanks! - qix
In Project Settings | Build Settings | User Defined, create a new entry called PARENT_APP_BUNDLE_ID. I have 4 configurations, I add a value for each one (com.company.app.staging, com.company.app.development, etc.). In you Main App Target's Info.plist, set Bundle Identifier to $(PARENT_APP_BUNDLE_ID). In your Extension Target's Info.plist, set it's Bundle Identifier to $(PARENT_APP_BUNDLE_ID).NameOfYourExtension. - djibouti33
Aha, completely missed the fact that you were doing this through additional custom build configurations (Project | Info | Configurations) and setting a different value of PARENT_APP_BUNDLE_ID for each config at the Project level, instead thinking you somehow did it by overriding individual target settings. So you're still able to switch schemes to build w/ different bundle ids, since each scheme uses a different set of build configs. Cool, works for me, and helps me clean up duplicate targets and plist files! - qix
when you add PARENT_APP_BUNDLE_ID to your build settings at the Project level, you should see all your configs underneath by clicking the triangle to the left. In my app, I have 4 configs (dev, prod, staging, staging2). After creating that user defined build setting, I see all 4 configs, and can assign each one a different value. - djibouti33
what if my extension embedded to multiple targets? - Neil Galiaskarov

3 Answers

30
votes

The build settings of the targets are not available for the other targets. However the build settings of the PROJECT are available.

You can thus add a user-defined build setting in your project and call it PARENT_APP_BUNDLE_IDENTIFIER and set the correct bundle id for all your schemes.

Then in the info tab of the app extension target set the bundle id to

$(PARENT_APP_BUNDLE_IDENTIFIER).$(PRODUCT_NAME:rfc1034identifier)

It worked perfectly fine for me.

3
votes

In my project I need to build different versions of apps (differ in details, e.g. each application is branded with a different logo).

Let's say there is about 10 "app" targets, I can't imagine adding Notification Content and Notification Service extensions per each main target (in this case I would maintaining 30 targets in total - madness).

I run a script (https://gist.github.com/damian-rzeszot/0b23ad87e5ab5d52aa15c095cbf43c59) after "Embed App Extensions" phase. It overrides bundle id in app extension plists and re-signs the bundle.

3
votes

I have Siri extension and multiple targets, so to avoid duplicating extension for every target I added pre-action to every scheme that changes the BundleId of the extension's plist before build:

  1. Select 'Edit scheme'
  2. Click triangle near 'Build'
  3. Choose 'Pre-actions'
  4. Click '+', choose 'New Run Script Action'
  5. Choose target to provide build settings from
  6. In script field paste following with your BundleId and extension folder
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier 
YourDesiredBundleId" "$PROJECT_DIR/YourExtensionFolder/Info.plist"

And it works like a charm! You need to configure it for every scheme.