I have an iOS app project, written by Swift 3.0
the workspace contains a dynamic framework build by our team, for sharing reusable codes and resources all across the Project.
We use Activate Compilation Conditions for switching production server url and beta server url, like this:
#if DEBUG
let url = "http://my-beta-server-url"
#else
let url = "http://my-production-server-url"
So that when app is Archived, the url will switch to production server url.
And when debugging, we can use the beta server for development.
We have an unit test target for testing this framework.
Recently we'd want to add a simple sanity test for checking whether the url is correct in Release mode.
If we want to test for this behavior, we'll have to set the Build configuartion flag to Release for the Test target.
When setting it to Release, Xcode compiles for error:
Module XXXXFramework was not compiled for testing
To solve this problem, we can just simply set Enable Testability for Release to Yes for our framework.
However, the issue is that Apple does not recommend setting Enable Testability to Yes for Release mode according to this note
Testability: Tests of Swift 2.0 frameworks and apps are written
without having to make internal routines public. Use #testable import
{ModuleName} in your test source code to make all public and internal
routines usable. The app or framework target needs to be compiled with
the Enable Testability build setting set to Yes. The Enable
Testability build setting should be used only in your Debug
configuration, because it prohibits optimizations that depend on not
exporting internal symbols from the app or framework. (17732115)
Does anyone have suggestions for solving my problem, or, any alternative solutions to achieve my goal?
For testing a framework using Release mode
I created a sample project for you. Your setup might be different, but this sample project will demonstrate how to test the release url and debug url, go through the edit scheme settings. Here is the link https://github.com/borg666/ios-multi-scheme-config-example
Basically the trick is to have another scheme in which debug flag is disabled and it runs a separate test file where you can test the release url, By doing this you are free to enable testability on this scheme.
You might consider having user defined variable for the url, with my example you can achieve more complex configurations.
Related
In ios apps the default behaviour appears to be to fail for Test Compilation.
Why would I want that to be default? Surely, at worst, I would want Debug to have it enabled? What changes does Enabling Testability actually make?
I happened upon this while tracking down another issue. But perhaps I can give provide a scenario. Why would you ever not want to enable testability?
-fvisibility=hidden.
If you want to use the GCC_SYMBOLS_PRIVATE_EXTERN (aka Symbols Hidden By Default), enable testability has higher precedence and will override this.
In my case, I have a configuration which is copied from Debug and hence has Enable Testability == YES. I have an external static library which was built with -fvisibility=hidden which is used to build one of my own static libs (built with Xcode). However when building my debug builds, I get errors such as (I redacted the function names and paths)
Showing All Messages : Direct access in function ... means the weak
symbol cannot be overridden at runtime. This was likely caused by
different translation units being compiled with different visibility
settings.
From the Apple doc here:
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/04-writing_tests.html
When you set the Enable Testability build setting to Yes, which is
true by default for test builds in new projects, Xcode includes the
-enable-testing flag during compilation. This makes the Swift entities declared in the compiled module eligible for a higher level of access.
It would seem that it is also there for Swift accessibility. So if you are not using Xcode's testing and Swift, it would also seem like you could do without this.
I've just developed my own (universal) framework with Xcode. When I import it into a test project (which definitely needs the classes of my framework), all runs well - both with the simulator as well as a real device (iPhone).
I've built a debug and a release version.
Under "edit schemes", I've also disabled "view debugging" within the release version.
However, when I set a break point into my source code of my test project (which - as mentioned - fetches some info from the release version of my framework), I can still step into the classes (.m files) without any problems.
As I want to deliver this framework to paying customers, I want to prevent anybody from seeing my source code while debugging. Experimenting with several flags in "build settings" had no effect ...
Any ideas?
nobody could help me, so I rookie had to help myself :-)
The solution could no bet easier:
just goto Targets -> Build Settings and then make a search for "Generate Debug Symbols" - arrived there, simply change form YES to NO
... and that's it!
Happy Frameworking :-)
I'm developing an iOS app with Swift 2 and, like most developers, I have a staging and a production environment, with different servers, URL and settings.
I'm looking for a way to quickly switch between the two configurations as I'm developing the app.
On Android I could use build types and flavors to solve this problem.
I've read a lot of guides around the web but all of them were in Obj-C and relied on the macro preprocessor and the #ifdef that was available in Obj-C but isn't in Swift.
There are no clear guides on how to do this in swift and, being a total beginner, I'm not even sure where to start looking.
To recap: what I'm looking for it's a way to switch between two configurations (ex 2 property list files) and to reference the settings contained in those configurations from my code, based on the build I've selected.
You can add a user defined setting in Target's settings with different values for each scheme (Debug, Release, Ad-Hoc, AppStore etc) and use the user defined variable in info.plist file (or as you call it configurations).
Check answer to this question. Although the question is specific to Facebook App Id setup, the answer applies to any generic setting.
Once you have correct data in info.plist you can directly use it in code.
I am creating a iOS Static Library in Xcode. I will be distributing two separate binaries, one for running in simulators(x86 architecture) & other for devices(ARM architecture).
I am aware of aggregate target, but I want to know whether it is possible to write a script to check whether the code is running in Debug or Release mode, i.e in Simulator(debug) or Device(Release) in ideal scenario.
Depending on this, I can put some check in my respective binary to compile or not.
Devices do not run in debug or release. The user chooses to build their target in debug or release. You can supply a debug version of your library, if you'd like, though. That is something I have seen other vendors do, and is greatly appreciated by developers.
I wish to use Xcode's schemes to determine what server to run my app against. I have an app that fetches its information from a server. Like most people I have a development server, a staging server and a production server.
I wish to create a scheme for each of these where Xcode will inject the correct URL. Do I duplicate the run scheme and add environmental variables? Is this the best way to do things, I don't particularly wish to have #ifdef's in my server class and setting it in code each time I change server. Can anyone point me in the right direction please?
FYI: I'm using Xcode 5.0.2 iOS7 SDK.
[EDIT] Everyone gave some great suggestions but I feel #redent84 answer best suits my needs. Though I found it interesting that none actually suggested using different schemes. [/EDIT]
I recommend you to create different XCode Targets for each environment. I recommend you to change the App Identifier of the Apps, for example, the production app would be com.mycompany.App and the DEVEL version would be com.mycompany.App-DEVEL. This way you can track the Apps separately in HockeyApp or TestFlight, and you can have both applications in the same device at the same time.
Then, add Preprocessor Macros that define the environment for every target. DEVEL for development, for example.
If the URL is hardcoded, simply add a #ifdef instruction to choose the URL:
#ifdef DEVEL
#define ENDPOINT_URL #"http://develserver:8080/EndPoint"
#elif defined(STAGING)
#define ENDPOINT_URL #"http://stagingserver:8080/EndPoint"
#else
#define ENDPOINT_URL #"http://app.mycompany.com/EndPoint"
#endif
This way is less error-prone to distribute a development version, easier to maintain and allows you to add custom code to different versions. For example, you may want to include the version number in the login screen or show alert dialogs for development, but not for distribution version.
Use a key in the plist (for each schema, eg: URL_TO_USE), use define to create a 'shortcut' to get the value.
#define MyURL [[NSBundle mainBundle] objectForInfoDictionaryKey:#"URL_TO_USE"]
EDIT
You must have multiple targets. Each target should point to a different .plist file. See:
How to configure independent sets of runtime settings in XCode
I handle this by setting custom pre-processor defines for each scheme.