Copy file to root of Xcode project when building - ios

I am trying to implement Google Analytics (GA) in my iOS apps. I have two different targets that have different tracking-ids for GA. GA requires a GoogleService-Info.plist (cannot be renamed) file to be placed in the root of the app folder structure. This file contains the tracking-id. However, since I have two different targets I need to have two different tracking-ids.
I cannot have two file named to files with the same name with different targets.
So, is there a way to either copy another file into the root in the build process. Have tried this and similar but does not seem to work:
Any suggestions?

The script:
PLIST_FILE="CustomGoogleService-Info.plist"
PLIST_PATH="${PROJECT_DIR}/path/To/Plist/Here/${PLIST_FILE}"
cp "${PLIST_PATH}" "${CONFIGURATION_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/GoogleService-Info.plist"
Instructions:
Add this script to the end of your Build Phases
Change name CustomGoogleService-Info.plist to your own
Change pathToPlistHere to the correct path where CustomGoogleService-Info.plist is located (starting from your project directory)
You should not have GoogleService-Info.plist file in your project - the script will create it for you.
Grab a coffee while it is running
You may be interested in reading Apple's Xcode Build Setting Reference
Alternatively:
You could have 2 files with the name GoogleService-Info.plist, but keep each in separate directory. Then you could add each to the corresponding target. Without any script.

I did correctly all along, however Destination should be set to Wrapper and subpath empty. No need to have them in the target either.
This one explained the Destination options: xcode copy files build phase - what do the destination options mean exactly?

Related

Whats the best way to add a dataset of 50 Folders to an iOS App?

In my case I have 50 Folders where each of it has subfolders and images. I could drag them into the apps main bundle but there are many duplicate filenames and it would be more practical to access them in the structured way.
Your wording "it would be more practical to access them in the structured way" seems to suggest that you think the Resources folder cannot contain a folder tree of files, it can. However if you let Xcode itself copy your resource files into the bundle it will flatten the tree without any option to preserve it (for reasons unknown). To address this you can copy the files into the bundle using a build script.
In outline, you need to fill in the gaps with some reading:
First add your files and folders into your project. Use one group per folder, in Xcode 9 creating a group creates a corresponding folder in the project directory but in prior versions you must create the group and then associate it with a folder – check the documentation of whatever Xcode version you are using.
Mark all the folders and files added in this way as not part of your build target. This prevents Xcode copying the files automatically into the bundle, and flattening your folder tree in the process.
Now in the target settings go to the "Build Phases" tab and add a new build script phase. Add a shell script which uses something like ditto to copy the folder tree into the bundle. Various environment variables are set which reference the project and the bundle, check your Xcode documentation or just run a dummy script and dump them out (it is an option, or use printenv). You can use these environment variables to determine the source and destination for your copy.
In your app itself you can locate the root folder of your tree using standard bundle methods. From there you can use whatever method you choose to traverse it/reference items with in it, in exactly the same way you would if the folder tree was not inside the bundle.
HTH

Have two GoogleService-Info.plist (or more) in one target (GCM)

I am integrating GCM in an app and we happen to have several build configurations for the same target and some of them use different Bundle Ids (we have different accounts, enterprise and appstore) so if we want to enable GCM push notifications in both we need two different GoogleService-Info.plist files (each one for the different BundleID). I cannot find a way to tell the GCM sdk to initialize from a different named file but the default one. Does anyone know if this is possible?
I can think of a two solutions, but I would rather not do them.
- Write to the plist file the bundle id once the app is started (or before)
- Create a different Target each one with a different plist file
Thanks a lot.
Regards,
Javier
I had a similar problem: Use User-Defined build settings in custom .plist file
You can use a Build Phase Script to copy the proper .plist file to your location:
Create a new folder (for example: GoogleServiceInfoPlists).
Copy there all .plist files (for example: GoogleService-Info-Debug.plist, GoogleService-Info-Stage.plist and GoogleService-Info-Prod.plist).
Add new Run Script Phase (Xcode: Target->Build Phases->"+" button)
Use script below to copy (replace) .plist file for given environment to the main directory (it's src in my case):
cp "${SRCROOT}/src/Resources/GoogleServiceInfoPlists/GoogleService-Info-$CONFIGURATION.plist" "${SRCROOT}/src/GoogleService-Info.plist"
Please note that src/GoogleService-Info.plist file must be added to the Xcode project (Build Phases->Copy Bundle Resources) while /src/Resources/GoogleServiceInfoPlists/GoogleService-Info-* files not necessarily.

One different key between multiple Info.plist files per scheme?

My application's Info.plist file has around 20/30 keys inside. An external SDK we're implementing requires its app key to be set in the Info.plist, but requires separate keys for debug, enterprise distribution, and release schemes.
Is there a way I can create conditional additions to the Info.plist without having to maintain three duplicates of the file (and duplicate all of the other keys, which are identical across all targets)?
Basically what I'd like is the base plist exactly as it is now, then additional new -Debug, -Distribution and Release ones, which just contain this new key. What I'm trying to avoid is repetition of all keys, since it will make adding new ones in future a hassle.
Is this possible?
There are a few different things you might try.
Xcode run script executed before app build
This is a script that is automatically executed before you build. Let's say the 3 duplicate plist files are called InfoA.plist, InfoB.plist and InfoC.plist which are all exact duplicate. When you build the project the contents of InfoA.plist are duplicated to InfoB.plist and InfoC.plist. This would require some knowledge of writing a shell script to do that, but the script is fairly simple.
You could duplicate and rename the files in the script. Or you could use command line tools to copy the contents of the main file to the duplicate files. Two command line utilities you can use to modify the contents of plist files are plutil and https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/PlistBuddy.8.html. These links might help: Add files to an Xcode project from a script?,
Modify scheme and add pre-action
Your schemes also allow you to add pre-actions to your build and you can do the same as above, but have it configured as a pre-action instead of a build phase script.
Here are a few links that might help: how to make xcode run a script before dependencies?, https://www.objc.io/issues/6-build-tools/build-process/, Xcode: Running a script before every build that modifies source code directly but you could also google for “xcode run script before build” for more links.

Adding a dependency to a repository with Xcode 6.1

I'm new to programming on iOS and I'm running into a roadblock with adding dependencies to my repository.
When I drag and drop a framework into the project directory and reference everything, I can build the project no problem. The issue is when I commit my project to the repository, the framework files do not get copied over. I can see that they are located in their original directory in some other location. Xcode merely references these files instead of adding them to the project directory.
So my question is, how do you add a framework or dependency to a project directory and commit it alongside your project to your repository?
Note I'm using SVN, however a Version Management System agnostic solution works for me.
In your case, or most cases people just download the framework and add it from there directly though it works in their machines, but will not work in other machine, because of absolute path added to the Header Search Paths settings in Build Settings.
In case of Third Party frameworks are as follows, will work for any case. Add the relative path rather than absolute path, though you don't set it, it is automatically added while you add a framework. So what are the steps? See below
Step 1
Create a folder named framework inside your svn/git folder of your project, and put all the frameworks inside the folder..
Step 2
Now add the framework, from the framework folder as you were doing earlier.
Step 3
Check your Header Search Paths in Build Settings. You will see entry for your framework header path. It should look something like
/Users/username/ProjectFolder/Project/frameworks/myframework/framework.h
Change the above entry by
$(SRCROOT)/frameworks/myframework/framework.h
Doing the above will automatically change this /Users/username/ProjectFolder/Project/ part of your path according to any system you clone the project. And it will work automatically.
Note - Before performing the steps, remove all old Header entries, which has absolute path.
Hope it helps.
Cheers.

Resources in custom iOS frameworks

I have made an empty single-view application in Xcode 6 (FWTest) and added a Cocoa Touch Framework (FWTestKit) as a target and asked it to embed in FWTest. Then I add an image (photo.png) to the framework, that I expect to be in Frameworks/FWTestKit.framework/Versions/A/Resources/photo.png when I build & archive my app. However, I find it in Frameworks/FWTestKit.framework/photo.png
How can I make it at least be in a Resources folder? Preferably a versioned folder so I can ship different versions of my framework?
When I add this framework to another app, do I need to do anything special to make sure the resources are bundled along with it, so that when I reference a resource from within my framework I can be sure it'll be available also when used in another app?
Cheers
Nik
You should add your photo.png into separate folder (let's call it "gica" ). Then drag folder into project, check Copy items if needed and create folder reference. Then (important) in build phases, drag photo.png again in Copy Bundle Resources, keeping Copy items if needed and create folder references. After you compile you should have now desired folder structure [It is keeping gica/photo.png].
I think you need to revise the architecture about versioning. Anyway if you still need to place the image inside the folder. Try creating a run script.
In your build phases instead of adding your images to copy bundle resource phase. You can create a shell script to copy your images to desired folder. Please note build phases are run in the order they placed. My point is you can customise xCode Build process through your own shell scripts.

Resources