Facebook SDK iOS on multiple targets - ios

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

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.

iOS How to create config file per target

Hi I have been working on my first iOS app. I have completed all of its requirements. Now its time to distribute. But before distribution I want to manage things well.
I searched for it and got "Target" as what I wanted. now just suppose the following requirement:
I have Client 1 and Client 2, and they both have different web addresses and Images and App Master password.
Now the 1 thing is to change them manually before making the build. But I wanted more proper way. So I thought of creating a Config file per target per client. but I am not getting it done.
Because after adding "Config" file for client 1 I am unable to create the 2nd "Config" file for Target 2 which indicates the client 2.
Please help me I am confused. Thanks in advance
Once you have different targets, you also have different property list attached to it. This allows you to customise some elements of your configuration for a specific target.
In this example, I duplicated my target and have now two targets, two schemes and two .plist files. I can customise one .plist without affecting the other target.
Another way to solve this problem is to create two configuration files in Swift. For instance, you can create a AppConfig struct foreach app configuration and attach it to one target at a time. It could be under AppConfig.swift and AppConfigDemo.swift, both with following code but different url in it.
struct AppConfig {
let urlString = "https://myclienturl.com"
}
The key is to include each file into the right target. Here, this AppConfig.swift is available with Test target. It won't be accessible in TestDemo target. You can do the same foreach one of your client.
Make sure they have different names, Info.plist and Client2-Info.plist (for example).
and you can set targets config file in its build settings. just search for Info.plist and set the relative path to the configuration you need.

Set build variable in scheme instead of target

I am currently working on an iOS project in XCode that uses configurations to specify the different API environments my app can connect to. Additionally, I use targets to override one of my project configuration's user-defined values to specify a particular configuration file to use in the app. However, this is the only value that changes in the target. I work with multiple different configuration files (maybe 10 to 20 at a time) and creating a new target for each file to update one value seems clunky.
My question: Is there a way to pass this one value in from the scheme instead of setting it in the target?
I have seen that there is a pre-build script that can be run but I have not yet had any success exporting environment variables.
CONFIG_FILE="My Config File"
export CONFIG_FILE
I have also seen that some people have had success using PlistBuddy to write the values into the info.plist file during the pre-build phase of the scheme. This may be an option as well although it would require I redo a lot of my build process. I wanted to see if there was any other options before heading down this path.
Thanks for the help.
I was able to do this by using a .xcconfig file that is updated during my pre-build action in my scheme.
I used this tutorial to learn how to set up the project: http://www.jontolof.com/cocoa/using-xcconfig-files-for-you-xcode-project/

Environment variables in different schemes for use in code Xcode Swift

My project, with one target, has three configurations:
Debug, UAT, Release
I have four shared schemes that use these configurations for build/run/test/profile/analyse/archive.
In my app I have different bundle IDs for each scheme. This was easy to change, I did so within Product Bundle Identifier for each configuration.
However, I want each scheme to connect to a different REST API. (dev.example.com/api etc)
What is the best way of setting a variable for each environment and then using it within my app?
I have looked at:
1) Swift Compiler>Custom Flags (Mine are currently $(inherited) "-D" "COCOAPODS")
2) NSProcessInfo.processInfo().environment
3) Adding a Configuration.plist file for each environment
Basically, it's not clear to me which is the best way of doing this.
Thank you for your help.
I usually prefer this :
I define constants in different .xcconfig files, then I use them for keys in one single plist file.
Let's say you'd have this in your debug.xcconfig :
<pre>
BASEURL = api.dev.com/api/"
</pre>
Then, in your plist, you'd add a key baseUrl = http://${BASEURL}
Then, in code, you'd access it with
NSBundle.mainBundle().infoDictionary?["baseUrl"]
This is a great article if you want to know more about xcconfig : http://www.jontolof.com/cocoa/using-xcconfig-files-for-you-xcode-project/
Personally I use different .plist files for each scheme. I tried the custom flags approach at first, but as the app grew i needed more and more scheme-based configurations and things got messy.
Different .plist files worked wonders for my project at least.

Info.plist and its variables like ${APPNAME}

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.

Resources