Info.plist and its variables like ${APPNAME} - ios

I am preparing Info.plist for my iOS application. I want to carefully set each option. However, there are some weird variables like ${REGION}, ${APPNAME}, ${EXTRA_ICONS}, etc. I guess they are set via Xcode?
I don't want Xcode to mess with the values. Can I simply set them? For example, for ${REGION} insert "en". For CFBundleDisplayName – nothing, because the docs says:
If you do not intend to localize your bundle, do not include this key
in your Info.plist file. Inclusion of this key does not affect the
display of the bundle name but does incur a performance penalty to
search for localized versions of this key.
And so on. Can I simply do this? What to insert for "CFBundleExecutable"? I guess I have to know what Xcode generates?
This is horrible design, as there are two sources of values: the plist itself, and some stupid meta-plist inside Xcode.

Your Info.plist file is processed by Xcode thanks to the "Expand Build Settings in Info.plist Files" (INFOPLIST_EXPAND_BUILD_SETTINGS) Build Setting of your Project.
That's usually a great feature, as it avoids to have a different Info.plist depending on your build settings and configuration, and avoids you to modify the settings in multiple places. But if you really don't want it, simply turn this settings off in the Build Settings of your project or target.
I suggest you keep this setting on anyway, so that the values chosen in your build settings will be reported in your Info.plist, and if you need to change stuffs like the application name for example, change it in the Build Settings directly. This way you will keep consistency between your build settings and your Info.plist file, instead of risking to have an inconsistent configuration.
A great example is the one you wrote yourself in your own question : the CFBundleExecutable entry of the Info.plist file. This entry typically have to contain the name of the executable in your bundle (so that iOS knows which executable to launch inside your .ipa bundle).
This value typically depends on your Build Settings, typically the EXECUTABLE_NAME build setting. If you ever change the name of the generated executable (in the Build Settings of your project or target) and you did put some constant string for this value in the Info.plist, you obviously need to change this CFBundleExecutable key to the new name of the executable generated by Xcode. If you use ${EXECUTABLE_NAME} as the value for this key (and kept the processing of your Info.plist turned on in the project settings), Xcode will replace it for you, ensuring that the Info.plist is consistent with your Build Settings and with the name of the executable it has generated.
I don't see any advantage of disabling this processing phase of the Info.plist file by Xcode ; you should take advantage of it and keep using the ${xxx} build variables so they are replaced by their real values Xcode dynamically at compile time thus ensuring consistency and avoiding errors.

Related

Xcode: How to add key into generated Info.plist file (or merge generated and existing Info.plist)?

I have been using Info.plist in my projects, but recently I noticed that freshly generated new projects don't contain them anymore, and Info.plist is instead generated by Xcode at build time, from Info.plist Values section in target's Build settings.
I like this, as it would allow me to ship two projects (beta and non-beta one) from a same folder, without special build steps modifying the Info.plist for each project.
However, I noticed that:
Many Info.plist keys are missing in Build settings (eg. ITSAppUsesNonExemptEncryption, or NSLocationAlwaysUsageDescription/NSLocationUsageDescription/NSLocationWhenInUseUsageDescription), so I cannot set them from there. There also doesn't appear to be any + sign when hovering, which would let me add another key into that section.
And the way of adding INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; into a .pbxproj file, which I have found documented somewhere, no longer works.
Is there a way of adding additional keys into generated Info.plist? Or, is there a way of having both both Info.plist file in a filesystem, and Info.plist Values section in build settings, and make Xcode merge them during build?
Here is how the section looks like:
So, this was helpful (thank you Andrew!), but the core insight I got from experimenting is:
Xcode doesn't want to let you enter invalid keys in places they don't belong.
Build Settings only have basic properties, anything else belongs into the 'Info' section. Editing it will create a new Info.plist file with only the changed properties, which will then be merged with info.plist keys from build settings (I couldn't find a documentation for build order).
Some settings, like ITSAppUsesNonExemptEncryption for standalone watch-only apps have no place to go.
Apple mostly abandoned standalone watchapps, there is a ton of bugs around them and they don't care.

Access one targets Plist from Another target

I am currently trying to unify my targets inside of my application.
I have one codebase I build multiple versions of the app, all tailored to a different client using targets.
That said, I want to unify the build number and versions so when I write code and archive, all the apps are built with the same version/build numbers.
Can I have all the target plist files reference the main target plist for these numbers, so I do not have to go into each target and increment them?
Or should I have my appDelegate update its own target when archiving?
From what I understand you have multiple targets under the same project, and you want all the app's that the targets build to have the same version (that you set in one place). It is not so easy to read them from one info.plist, but it is easy to have one build setting variable that all the info.plist use.
Simply go to the info.plist for each of the targets and replace the value of the version with a variable value e.g. ${APP_VERSION}:
The go to the project's build settings and add a user defined value with that name:
and give it the value of the version you want:
Now the info.plist will have the version you set in one place(the APP_VERSION build setting), you can do the same for the other info.plist files so that all read the same value.

Multiple Target App with single Info.plist file fails to export for translation

Strange issue:
I have a project with tens of targets and a single Info.plist file because it uses variables for it's data. This makes it easier to maintain if I need new ones added.
I need to translate this app by using XLIFF files. The problem is that the export dialog gives a "Duplicate info.plist export for localization" error and stops. This happens because all targets use the same Info.plist
If I remove the entry from all targets and leave it to just one, it works fine but it's a lot of work to do each time.
Now, a good solution would be to add the plist file to the project's entry which it seems would make it work for all targets, but it doesn't. Xcode complaints on build that the Info.plist file has not been found.
Any suggestions?

$(AppIdentifierPrefix) is not resolved during build time

$(AppIdentifierPrefix) in .entitlements file is not getting replaced with the actual AppIdentifierPrefix. Can someone please shine some light onto this issue?
So here is my understanding of the YourApp.entitlements file that gets added to your project when you add capabilities like iCloud or Game Centre to your application.
(I'd love to see some pointers to official documentation ... if any exists.)
What are these entitlements files used for?
So first of all, the .entitlements is only in your project for the build process. It should not end up in the final .app product. If it does, select the .entitlements file and in the File Inspector, clear it's Target Membership. (This is how Xcode generated these files actually, without any target membership)
So what is the .entitlements file used for then? It is part of the build process where it is taken and processed and put in your final application bundle in two forms:
First: the contents of the .entitlements file is embedded in the embedded.mobileprovision file. This is a signed property list with a binary signature on top but if you open it up in a text editor you can see there is a <key>Entitlements</key> section that should have the processed entitlements in there.
Second: there is also a copy of the .entitlements file called archived-expanded-entitlements.xcent. This is essentially the same file as the original .entitlements file except that it has been processed.
What preprocessor values can be used in the .entitlements file
I don't think the processing of the .entitlements file is documented anywhere. There most certainly is a pre-processor running over it, so that things like $(AppIdentifierPrefix) are replaced with the actual value. However, this seems to be not the same as the one that is used for the Info.plist file.
The $(AppIdentifierPrefix) is the same as the Team Identifier that you may have configured in your Xcode project. You can find the configured Team under your target's General settings in the Identity section. If team is set to None then there is a good change that $(AppIdentifierPrefix) won't be set.
So to finally answer your question: if you look at those two files that I mentioned above, and you still see the $(AppIdentifierPrefix) is not correctly substituted, make sure your project has a Team Identifier configured.
How does Xcode know what entitlements file to use for your target?
In your build settings you can look at the Code Signing Entitlements settings to find out what file Xcode uses for each build configuration. Usually Debug and Release use the same entitlements file but you can change that.
(For example, for Firefox for iOS we have build configurations for Nightly, Aurora, Beta and Release builds. These all have different entitlements files. The reason we have different entitlements files is because we could not make the .entitlements pre-processor recognize settings like $(PRODUCT_NAME:rfc1034identifier) - i'd love to hear if there is a way to do that because that will make our build simpler.)
What tool processes the .entitlements files?
Not entirely sure. But if you look in the build logs, you will see some reference to a builtin-productPackagingUtility tool. This seems to be an internal Xcode command, not something actually present as a command line tool. So that is not very useful.
Now you know pretty much everything that I know about .entitlements files :-)
(I'd love comments and turn this answer into the definitive guide to entitlements files - i think there is a lot of confusion around them)

Facebook SDK iOS on multiple targets

I am trying to create an app with multiple targets so I can use the code for different apps with small changes. I managed to work with many variables needed by setting custom keys in plist file and making user-defined-settings entries for referencing them. The problem is that with Facebook SDK I cannot do that. I have set a custom key in plist like ${FACEBOOK_APP_ID} and a user defined setting on my target like FACEBOOK_APP_ID with my app's id in it. When I compile and run, I get app_id is required error (of course if I hardcode it on plist works fine). Does anyone know of a solution not requiring to use different plist files for each target?
After struggling for days with that without a good solution, I found that if I set preprocess info.plist to Yes, I can add user-defined settings to build-settings as usual and they are available at runtime. Now, I only have to enter the three variables to the target configuration and there is no need for a preprocess file or preprocess macros.
Update:
I have added FACEBOOK_DISPLAY_NAME, FACEBOOK_APP_ID and FACEBOOK_URL_SCHEMES to user defined settings (from Editor->Add Build Setting menu in Xcode) with the proper details for each target. Then In Info.plist (I use one globally for all targets) I added the options Facebook SDK guide states but instead of static values I added ${FACEBOOK_APP_ID}, ${FACEBOOK_URL_SCHEMES}, and ${FACEBOOK_DISPLAY_NAME}. Then on build settings I chose YES to preprocess plist file. Now I can change the info in my user-defined settings for each target and works ok (without the need of an extra preprocess file and the need for defining macros)
You can try use the macro in your difference target, in the code you just define the value by the macro. exampe:
#if project1
//the app id const
#endif

Resources