iOS Xcode: Warn about methods not in minimum target SDK - ios

Is there a way to have Xcode tell me when I'm calling a method that isn't available in the SDK of the minimum supported target?
For example, the method [NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. This method is available on iOS5 and up. But my application's minimum target is iOS4.
If I use that method (sendAsync), I'd like Xcode to tell me that that method isn't available for the minimum target I'm trying to support.
I've tried putting __IPHONE_OS_VERSION_MAX_ALLOWED=40000 in the preprocessor settings, but that just triggers a bunch of Apple SDK errors that aren't helpful. (Probably because my active SDK is iOS5.1)
Is the only solution to get ahold of old SDKs and install them in Xcode?
Are there any easier solutions?

There is unfortunately no standard way of doing this. By setting the target OS to a lower number than the base SDK, Xcode will weakly link the libraries and frameworks. When doing that Xcode will not warn you for using methods that may not be available on the target OS.
You could temporarily set the base SDK lower, but that might not always work. Since you want to ignore most of the errors and warnings produced (because they are only called conditionally in your code path), and many warnings and errors are dependant on other error that you may need to resolve before the compiler will give any meaningful output.
I do not think there exist any static analysis tools for this, neither from Apple nor third party.

After doing some research, reading the Apple Doc about it, and trying a number of things. The solution is downloading an old Xcode DMG from Apple, grab the .pkg file for the same SDK as your deployment target and install it in your version of Xcode. Here's how:
Download older Xcode.dmg from Apple
Open the DMG
In Terminal, go into packages: "cd /Volumes/[DMG]/Packages; open ."
Find the SDK you want, something like iPhoneSDK_4.0.pkg
Install that package, but change the install directory to /Applications/Xcode/Contents/Developer
Restart Xcode if it was open.
Now that you have the same SDK as your deployment target, set your BaseSDK to the same. When you build you'll get warnings about missing methods. Your project may or may not successfully build with an older BaseSDK in a new version of Xcode, but that doesn't matter - you've just found the method calls you need to wrap in a feature check with respondsToSelector:.

As of Xcode 7.3, the compiler can now generate these warnings for you. All you need to do is set the -Wpartial-availability warning flag in the Build Settings, as described in this answer.

Related

Why does Xcode want me to add "#available" checks when the Deployment Target is already at a higher version?

My SwiftUI project has its Deployment Target version set to 15.0. However, when I try to use the new Logger API, I'm still getting warnings about the SDK is only available for iOS 14 or above.
Could it be that an extension to UIImage requires something special? I have a few other files that I used the Logger and the compiler isn't complaining.
As suggested by Kiril, the problem happens because the Test Project was targeting 13.2.
Grep showed that project.pbxproj file has a 13.2 specified. After changing the xml file directly, the problem disappeared.
(I didn't notice this because the test Target doesn't have a place showing the "Deployment Info".

AVFAudio Framework not present on macOS causes warning for iOS app (app should also be available on AS Macs)

My iOS app uses the AVFAudio framework to provide spoken feedback to the user while running. I would like this app to also run on Apple Silicon Macs (where the spoken feedback is not really necessary).
However, just importing the framework results in the following warning email after I upload to App Store Connect:
We identified one or more issues with a recent delivery for your app,
"App Name" 7.0 (24). Your delivery was successful, but you may wish to
correct the following issues in your next delivery:
ITMS-90863: Apple silicon Macs support issue - The app links with
libraries that are not present on Mac:
/System/Library/Frameworks/AVFAudio.framework/AVFAudio
I guess that this means the app will not be able to run on Macs.
How should I get this app to use the AVFAudio framework for iOS and still be available to run on macOS (AS Macs) with or without the framework on macOS?
Relevant code is:
import AVFoundation
class Speaker {
var speechSynth: AVSpeechSynthesizer
class func establishAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, options: [.interruptSpokenAudioAndMixWithOthers, .duckOthers])
try AVAudioSession.sharedInstance().setMode(.voicePrompt)
try AVAudioSession.sharedInstance().setActive(true, options: [])
UPDATE / CLARIFICATION:
Note that my project does not include multiple targets. With multiple targets, this would be fairly straightforward. I am wondering if there is a way to achieve this by taking advantage of the newer AS Macs’ ability to run apps built for iOS without a separate target.
Is this possible when using this framework?
UPDATE 2:
I have submitted a support request to Apple for this now and their first suggestion was replacing
import AVFoundation
with
import AVFAudio
and then re-uploaded to App Store Connect, but after trying this, I get the same warning email back again. Will post an update (or hopefully an answer) when I hear back from them again.
I suppose your project has multiple targets defines (i.e. one for iOS and one for macOS). In the "General" tag of your target settings you can select which frameworks should be included under "Frameworks, Libraries and Embedded Content". Add your library for iOS, remove it for macOS.
If you share the same code you between apps you can also conditionally exclude some of it for macOS.
#if os(iOS)
// iOS only code
#endif
However, just importing the framework results in the following warning email after I upload to App Store Connect:
The problem probably isn't importing, but (as the message you got indicates), linking to AVFAudio, that's the problem. So solve that, you should select your app target in the Xcode project and go to the Build Phases tab. Look at the Link Binary with Libraries line and hit the disclosure button at the beginning of the line to reveal all the libraries that are linked into your app. Find AVFAudio and change the setting (there's a popup on the right side of the line) from Required to Optional. That'll let your app link to the framework if it's there, but still run if it's not.
But wait, you're not done yet... What do you think will happen if your app tries to actually use a framework that's not linked in (because it doesn't exist on the machine)? You'll get a crash, of course. To avoid that unhappy fate, you'll need to check for the existence of the framework before you use it. For example, you could do something like:
if NSClassFromString("AVAudioPlayer") != nil {
// do your AVFAudio stuff here
}
Further follow up from Apple support suggested the following:
Change back to import AVFoundation
Reduce the deployment targets from the latest and greatest back down to something less recent.
So I did both of these, changing the deployment targets from iOS 14.5 and macOS 11.3 to iOS 14.1 and macOS 11.0.
This has resolved (or worked around!) the issue.
I do want to deploy to the latest and greatest target for this particular app, so I don't consider it to be a complete solution as yet, but it will do as a work around for now. (I actually want to deploy to 15.0 when it's available to make use of the promised improvements to OSLogStore.)
So this sounds like a bug to me, and I have queried Apple for some further information on the issue, in particular, the ability to target more recent OS versions.

Changing symbol names and embedding bitcode

tl;dr: I get this error message:
ld: -alias_list and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES)
cannot be used together
How do I fix it?
I am trying to create my own version of a third-party library. I want to make sure that none of my calls are going to the system version of this library, so I use --alias-list to put a prefix on all the symbols, and generate a header file which renames all the symbols from foo to MJB_foo. My build system then includes this header file with the --include option whenever I want to use this library.
This works great on Android and Linux (and I'm pretty sure it will eventually work on Windows too). However I get the above error when I try to link the shared library. How do I achieve the same effect?
In Build Settings of project you need to set Enable Bitcode to No. For iOS Apps bitcode is default but optional so you can send the app to AppStore without bitcode.
Bitcode re-optimize your app binary in the future without the need to submit a new version of your app to the App Store.
From Apple Doc:
For iOS apps, bitcode is the default, but optional. For watchOS and tvOS apps, bitcode is required. If you provide bitcode, all apps and frameworks in the app bundle (all targets in the project) need to include bitcode.
https://help.apple.com/xcode/mac/current/#/devbbdc5ce4f
What I have ended up doing is forcing the inclusion of the header full of #defines when building the library, as well as when using it. This allows me to drop --alias-list from the linker command line, so it is happy.
Sadly, this is not the complete solution. The library (it is OpenSSL) has a number of assembler modules, so those have to be patched with sed by the build script first.
It also has some macros which turn
FOO(SHA1)
into
void SHA1_Init(struct SHA1_CTX *ctx)
the problem is that SHA1 is one of the functions I am renaming, so it becomes instead:
void MJB_SHA1_Init(struct MJB_SHA1_CTX *ctx)
renaming the function is harmless (because it turns out it gets renamed uniformly), but I am not renaming the structs. The solution is to create another small file which renames MJB_SHA1_CTX et al back to SHA1_CTX.
*When bitcode is enabled for a target, all the objects, static libraries and user frameworks used when linking that target must contain bitcode.
Otherwise, an error or a warning will be issued by the linker. (Note: missing bitcode is currently a warning for iOS, but it will become an error in an upcoming release of Xcode .)
ENABLE_BITCODE should be consistently turned on for all the targets. If you use a library or framework provided by a third party, please contact the vendor for an updated version which contains bitcode."

Xcode compile error with Firebase

I just installed the Firebase framework to Xcode (not using CocoaPods due to other unsolvable issues with that). I followed the Firebase Alternative Setup instructions from here (manually dragging the FireBase 2.5 Framework to my project).
Problem is, when I compile my app I get 27 errors:
screenshot
I'm just using the sample code from the Getting Started page.
In fact, all I'm using so far is the first line, but it won't even instantiate that. (var ref = Firebase(url:"my firebase URL here")
I'm on Xcode 7.2 and Swift 2.1. My target is iOS 9.2 using the Simulator.
Please help!
Thanks.
PS.
I should also add that libicucore.dylib and libc++.dylib no longer appear to be available as linkable libraries that you mention to include from firebase.com/docs/ios/alternate-setup.html So maybe this is related? Someone mentioned libz.tbd is the one to use now? (which I'm using)
If you are targeting 9.2 then the frameworks changed to the following:
libicucore.dylib to libicucore.tbd
libc++.dylib to libc++.tbd
They are exactly the same so use them instead, you have to use them in order to get it working.
A comment by apple:
For those who are curious, the .tbd files are new "text-based stub
libraries", that provide a much more compact version of the stub
libraries for use in the SDK, and help to significantly reduce its
download size.

XE4 Deployment error

Good afternoon all. Apologies if SO isn't the place to ask, I wasn't sure there was an 'errors stack exchange' or such, and whether or not any XE4 users would be visitors there.
I'm currently trying out the XE4 trial, and I'm wanting to see just whether the iOS implementation is as easy as they made it look.
I've got my remote profile all setup and working, and I've made a small application that only contains a progress bar. Now, when I deploy that application to the simulator, it runs on the iOS simulator as expected.
However, when I try to deploy to a device, I get the following error;
[DCC Error] E2597 ld: warning: directory not found for option '-FC:\Users\Scott\Documents\RAD Studio\SDKs\iPhoneOS5.0.sdk\System\Library\PrivateFrameworks'
I've tried Debug, Ad-hoc, and App Store profiles, but they all return the same error. The folder 'PrivateFrameworks' doesn't even exist. There's one called 'Frameworks' in the 'Library' folder, but nothing else. I considered that maybe it's an incorrect SDK library path, but the only one with such a path is 'UIFoundation'. Changing the path to 'frameworks' like the others are returns this;
[DCC Error] E2597 ld: warning: can't parse __DATA/__objc_imageinfo section in C:\Users\Scott\Documents\RAD Studio\SDKs\iPhoneOS5.0.sdk/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation
That file DOES exist (99KB) but the error remains (and so I assume that changing the SDK lib path wasn't the right thing to do). It's like it's not even attempting to deploy over to the mac for compilation due to a file or folder issue.
Any ideas?
You could look at the checklist in the Troubleshooting: Cannot Deploy to the iOS Device help topic.
If you have not run your iOS app on the iOS Simulator, make sure you satisfy the requirements here:
Troubleshooting: Cannot Deploy to the iOS Simulator
Make sure your iOS device is connected to your Mac by USB cable.
Specify the iOS Device as the target platform in the Project Manager.
Complete the Provisioning page. (Your developer certificate is required for code signing)
Set the required Project Options for your iOS app:
Specify your application icons - Application Options.
Specify info.plist keys such as UIDeviceFamily - Version Info.
Install the Xcode command-line tools on your Mac. (Required for code signing your iOS app)
There are links in the documentation above with details about some of the steps involved.
I had extactly the same issue. It happened when trtying to deploy to the iOS 5.0 simulator (not even an iOS device).
It appears that UIFoundations (PrivateFrameworks) gets pulled across and cached when you setup the SDK for iOS 6.1 on XE4.
Make sure the sumulators are installed on Xcode in preferences. Restart Xcode (make sure the PA server is running). Setup a connection profile with the 6.1 SDK in options on XE4 and it works.
Hope this makes sense but it solved my issue.
Add the missing framework into your SDK. Tools->Options->SDK Manager, go to Frameworks and click the yellow button. Also remember to press "Update Local File Cache" after you're done. You will find that you will need to fetch more Frameworks and Libraries in the future.

Resources