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.
Related
We have a Filters framework that contains many image processing filters (written in Swift and Metal) and the resources they require (like ML models and static images). But not every app we have uses all the filters in Filters. Rather we want to only build and bundle the required filters and resources that are needed by the app.
The only way we can think of to achieve that is to create different framework targets in Xcode, one for each app. But that would require that the Filters framework project “knows” all of its consumers (apps) and we would rather like to avoid that. Especially since the filters are in a separate repository.
Is there a way to, for instance, pass some kind of configuration file to the framework that is used at build time to decide which files to build and bundle?
You can use Target Membership to assign files into specific targets. See image below.
Make sure you are on the File Inspector tab on the right side of Xcode. Select the files you want to limit to a target and in the Target Membership area, you can select which target the selected file belongs to or don't belong to. For public resources, make sure to select public for the visibility scope.
For files that don't require compilation, e.g. image files, once you've selected the target membership, the file will be automatically added to the Build Phases' Copy Bundle Resources area.
Alternative One
Alternatively, you can use add a Copy Files Phase in the Build Phases. With the Copy Files Phase, you can copy files to subdirectories instead of the root of the framework bundle.
Alternative Two
Yet another way is to add a Run Script Phase in the Build Phases. The script can be in any language but usually shell script. You can do whatever you need in the script including compiling code manually but you need to know where the files goes by using environment variables and placed the files in the correct location. I think this will be the most manual and most hassle to use for selecting files based on targets.
Alternative Three
If you really want to go fancy, you can even break down all the components into targets and use Aggregate target to tie the different components into the target you are building for. I would not recommend this usually and reserve this for very special needs that other methods could not achieve.
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
I have my own framework which I've made. I use this framework in another project I made. That is, after building my framework, Dragged the Product, .framework to Embedded Binaries of project.
However, I've to continuously make changes to the framework. So the process of dragging and dropping again and again is a lot of work. How to conquer this ?
Can someone tell the exact steps even if it means including the project as well ?
Copy the framework Project to your project folder.
Open your Project in xcode.
Right click on the Project File on left side of xcode and click on option "Add file to Project Name" and then select the framework project here.
Delete the Product .framework available in the embedded libraries and add the framework product properly.
So your goal is to 'deploy' changes made to .framework to all the projects you've already embedded it in previously. Here is one approach to it.
Create [myFramework]Targets.txt file where you'll be putting all the locations (directories) of your framework in different projects, line by line. It will have something like this:
~/Path/to/project/A/Frameworks
~/Path/to/project/B/Frameworks
~/Path/to/project/C/Frameworks
Create deploy_framework.sh file with script that will replace your framework everywhere you need. I'm definitely not the one you can call a Bash expert, by here is what it probably looks like:
for destination in $(<[myFramework]Targets.txt); do /bin/cp -rf /Path/to/updated/[myFramework].framework "$destination"; done
Now, whenever you're done with your framework changes, just run deploy_framework.sh from Terminal. Assuming your Xcode projects have existing reference to .framework and you didn't change its name, it should work.
NOTE: You might still need to do Clean+Build for your projects to compile with updated framework. I believe you can also tweak project settings to 'cache' builds less aggressively.
Let me know if it works for you, we might need to adjust script a bit, since I never tested it.
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?
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.