Dynamically change Bundle Loader of Unit Test - ios

I have an Xcode project with multiple targets, but I want the same Unit Test to run across all of them.
I have created the Unit Test and attached it to each target in my project (using the Edit Scheme>Test menu). Xcode still uses the "Bundle Loader" project setting to determine which app to run when performing a Test though.
So I created an .xcconfig file which the Unit Test uses. This is what it looks like:
SO_BUILDING_PRODUCT_NAME = None
BUNDLE_LOADER = $BUILT_PRODUCTS_DIR/$(SO_BUILDING_PRODUCT_NAME).app/$SO_BUILDING_PRODUCT_NAME
As you can see, it's pretty straightforward. I then wrote a bash script which will change "None" to the actual name of the Xcode target that is being built. I then added this script to each target's Pre-Actions Build phase.
I can see as soon as I tell Xcode to Test, the .xcconfig file updates instantly and I can even see Xcode's UI for the Unit Test update automatically. Unfortunately though each time I change my target, I have to build twice for the change to take effect. It seems like I'm making my change too late for Xcode to notice or care.
Does anyone have some suggestions about how to force Xcode to take notice of the change I make at the start of the Build process?

As far as I have seen (although I haven't explored this since Xcode 5 was released), as soon as you hit Build, it's impossible to change any build settings via .xcconfig files, Xcode seems to take a snapshot before you get the chance to run any scripts or anything like that.
Unless those limitations of dynamic .xcconfig configuration have changed, you will need to try a different approach. I'm not familiar with BUNDLE_LOADER, but if you can change that variable via a script, rather than changing the .xcconfig file itself, you may have more luck.

Related

iOS - Exclude Test files from Release build

While developing an iOS application, I am required to run unit & ui tests on a preloaded database. So, I planned to include the DB file preloaded in the App only for DEBUG build as UI/Unit tests will run only with DEBUG build. How can i exclude the DB file from Release build?
Currently I can detect if the host app is running for testing or not using following way,
https://stackoverflow.com/a/33466038/1084174,
but how can exclude and include database.db using this technique?
A little guidance will really be appreciated.
Finally i solve the problem.
Open your project file. At the bottom of the screen click Add Build Setting -> Add User Defined Setting and name it EXCLUDED_SOURCE_FILE_NAMES.
Click the arrow to the left of EXCLUDED_SOURCE_FILE_NAMES to expand it. In the Release configuration for this variable, add libTestFlight.a and any other files you’d like to exclude (separated by spaces).
The standard way to do this would be to create a new Target in Xcode to use for debug. You can then use the target selector on files
Here you can see I have a source file that is included in my main target, but not in my messages extension. This appears in the Utilities pane on the right hand side of the screen. You can achieve the same by including a file in your debug target, but not release (or vice versa).

Apple Watch pre-build action to change storyboard customModule references

I currently have a project with 3 different versions of the same app (different branding and such), which is working just fine. I've since then added 3 new Apple Watch targets (1 for each app "version"), where which 2 of them reference the files in the "master" Apple Watch target.
Everything works fine as long as i remember to change the module reference for each storyboard view, so that it maps to the correct interface controller in the corresponding watchkit extension target.
However, remembering to switch this every time i need to run/build a app version/target is a pain and not really a long term solution.
I've created the following command which I want to be run at the correct time, such that it changes the storyboard references before it is compiled.
perl -pi.bak -e 's/customModule=\"(.*?)\">/customModule=\"watchMyTarget_Extension\">/g' ${SRCROOT}/watch/Base.lproj/Interface.storyboard
I also concluded that I would probably want to reset the change after the app was compiled, since I don't want to have a file change for git to complain about. Which is why the aforementioned script creates a .bak file. So after the compilation is done and packed/run on device or whatever, I want to run
mv ${SRCROOT}/watch/Base.lproj/Interface.storyboard.bak ${SRCROOT}/watch/Base.lproj/Interface.storyboard
I've tried placing the scripts in the target's (watchTarget, not appTarget) build scheme, Build->Pre/Post Actions which didn't seem to have any effect. And I tried putting it in Run->Pre/Post Actions which worked to some degree, but it seemed like the post action kicked in before the app was pushed to the simulator and thus crashing the application ("could not run see device logs" or something like that).
So where on earth do I need to put these scripts to have them run at the correct time in the build process?
you should use add New Run Script Phase in your target's Build Phases, place it before the Compile Sources
Steps: (from Apple)
In the project editor, select the target to which you want to add a
run script build phase.
Click Build Phases at the top of the project editor.
Choose Editor > Add Build Phase > Add Run Script Build Phase.
Disclose the Run Script section in the project editor.
Configure the script in the Run Script template.
My solution is to go the Build settings of each watch extension target, setting the Product module name to the same value, for example, xxx_watch_extension. Then we should be able to choose this module for custom classes on the storyboard.
It works fine for me.

how to config and run objective C test cases in Xcode--XCTest

I was reading the document of XCTest(and personally i think the documentation for this part is not that enough) and I thought I should give it a try for a new project(a MAC command-line project, not and iOS project). and then I faced complaints about linking issues--the test case building failed because the conresponsding class .o(if I am not wrong) files are not found. (the error mes here was not recorded by me, sorry)
Then I wanted to delete the test project and in the end I did not even manage to remove the test project. So seriously, how to remove an exsiting project from the solution if the notion in VS applies here?
After failing at that, I removed the auto-generated test file and created my own test case file and strangely, although Xcode detects the existence of the new test case and test method, the build failed and it failed with no issues--no linking issue, no syntax or whatever issue but it just failed. Now I do not know how to move on now as I do not even get a complaint or an error.
I don't know enough about the state of your project to be certain what the problem is, but here is something to consider: If Xcode added a new build target for your tests, be sure that the .m files that contain the classes you are testing are included in the new build target. You can do this by clicking on the relevant .m file in the Project Navigator and looking at the "Target Membership" in the File Inspector pane. Make sure the box is checked next to the test target.

Resource files not updating with Xcode 5

I have some binary files with a proprietary extension that don't get updated in a build when I compile. In previous versions of Xcode with this same project, it would detect the file was changed, and rarely would I have to perform a 'Clean' as I have to do with this version. Of course this is consuming a lot more time -- I would appreciate it if someone could let me know what's changed with Xcode 5 and/or what I could do about this.
I didn't include any project specifics because it's really just a proprietary binary file with a custom extension in a resource folder, which, used to update automatically upon it being changed since last compile. If you need any specific project settings I would be glad to offer it.
It's using the sort of 'blue' resource folder that is a reference to the folder it's in, and isn't just copied into the project directory. I apologize since I forget what this particular resource folder type is called (I'm guessing Reference).
Version: Xcode 5 (5A1413)
UPDATE:
This only happens when I'm referencing a file that I modify programmatically with fopen,fwrite,etc, and upon using a file editor in OSX to resave the file (without really changing it) Xcode will then see it as changed.
I'm now looking into FSEvents to see if this underlying API is something I need to use, although I'm not exactly sure how to set flags with this just yet.
UPDATE:
Well, just as a simple test, I take the same file and resave it via:
NSData* data = [[NSData alloc] initWithContentsOfFile: #"/location/file.dat"];
[data writeToFile:#"/location/file.dat" atomically:YES];
Sure enough, after I call that and then run the app that uses the resource, it is updated via Xcode during the build. So it would seem that Xcode 5 relies on some special flags not set by the standard io functions. At this point I can either patch what I've got with that 2 line thing or figure out what the flagging mechanism is, and how to write to it. (FSEvents? I don't see a writing mechanism there..)
I had the same problem. I set up an Xcode build-phase script to touch the root resource folder, and it works now. I found the instructions here and they are as follows (see link for more detail):
1) Add your single resource directory (named anything but ‘Resources’) to your project in the Resources section as a blue ‘Folder Reference’
2) Right click on your app target, select Add->New Build Phase->New Run Script Build Phase
3) In the resulting ‘Info’ window, change the shell to /bin/tcsh and copy and past the script below into the ‘Script’ text view.
Script:
touch -cm ${SRCROOT}/../../YourResourceFolder
(Also, you may need to know how to find "Build Phases" in Xcode 5)
I was also running into problems. Everything was fine before Xcode 5, and my referenced resources folder would copy pretty dependably. However, after updating, no matter what I did to an individual file (touch it, delete and re-copy it, etc.), nothing triggered Xcode to scoop it up again.
However, I now modify the last write time on the referenced folder during my build step, and now it's contents seem to be copying correctly again. I Hope that helps you too.
I am using custom tools, but I'm sure a build script can do the same. My guess is that Xcode tries to optimize the dependency step, and checks the folder's last access/write times before diving into it.
well a simpler way would be to just touch the folder from your shell or term.
e.g. on your terminal just run
touch -cm PATH_TO_FOLDER_UNDER_RESOURCES
PATH_TO_FOLDER_UNDER_RESOURCES is actual path to the folder under resource folders which contains the files.
Since changing your files do not necessarily change the timestamp of the folder and Xcode looks into the timestamp of the containing folder.
I had the same issue with xcode5, I need to update javascript frequently. I had to clean and then build, it took long time because my project had many source files. Later I tried to delete the app (choose "move to trash" rather than "delete reference") and then build, it was quite fast, but I had to restart xcode so that app can appear in the project again.

Xcode : One test target for multiple app targets

I am wondering if you can link one Unit Testing bundle to multiple targets. So one can test all the application targets with one Testing bundle.
I have some shared code between all app targets but also some specific calculations based upon which app target is running.
Currently I have to set the Bundle Loader option in the Build Settings to the used application target's .app file if I want to test a different application target.
My question to you all is : can this be done without creating multiple test bundle targets for every app target, and without always changing the Bundle Loader option?
You need to:
Select the target you want to test
Go to Test navigation tab
Right-click on test target you want to enable
Click on Enable [name_of_your_target]
No, at this point you can't. It's like the extensions, you have to create a new one for each project's targets you have.
It's not pretty usefull but if the code differes from one to another target, the tests can fail because of missing code, not failing code.
It's why it's not allowed.
Sorry for the negative answer.

Resources