Using preprocessor definitions in iOS App info.plist - objective-c

I have an iOS app that uses SSO with Facebook as part of getting your app to work with Facebook's SSO you have to specify the FacebookAppId and callback url in the info.plist. I have 2 different Facebook groups one for testing and one for production. I want to be able to have the values of the two keys specified above set based on preprocessor directives.
In my MessageBomb-Prefix.pch i have the following, which works fine:
#ifdef TEST
//Development environments
#define PARSE_APP_ID "dev parse app id"
#define PARSE_CLIENT_ID "dev parse client id"
#define FB_APP_ID "dev facebook id"
#else
//Production environments
#define PARSE_APP_ID "prod parse app id"
#define PARSE_CLIENT_ID "prod parse client id"
#define FB_APP_ID "prod facebook id"
#endif
However in my info.plist i have done the below, but it doesn't seem to work:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fb${FB_APP_ID}</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>${FB_APP_ID}</string>
Is it even possible to do what i'm trying to do. I've set the project to preprocess the info.plist.
Thanks
Peter

If you go into Build Settings you can set Preprocess Info.plist File to YES and then set Info.plist Preprocessor Prefix File to a .h file you've placed in your project with #define directives.
So for example if I add a key to my Info.plist file: testKey with the value TEST_VALUE. Then I place test.h in my project with:
#define TEST_VALUE hello_world
And then I set Preprocess Info.plist File to YES and Info.plist Preprocessor Prefix File to test.h
The value of that key, when retrieved is now "hello_world". If you change the value of the macro a lot you may find you need to do Product/Clean to see changes because XCode seems to cache the compiled value.

To access in plist:
Create a new variable
Define it
Use it in your info plist

The Info.plist preprocessor will let you use build settings in your Info.plist, not #defines. So you can define FB_APP_ID as a custom user build setting in your target (and give it overrides for different schemes), and this value will then be available to Info.plist. However, user build settings don't get exposed to your code. That is, unless you muck with your Preprocessor Definitions build setting and add an entry that looks like
FB_APP_ID=#\"$(FB_APP_ID)\"
(the backslashes are required to get the double-quotes past the shell invocation)
If your app ID may contain spaces, then you'll need to add quotes to get past the shell invocation:
FB_APP_ID="#\"$(FB_APP_ID)\""
In the end, you'll have build settings that looks something like this:

Related

Is there a way to apply ITSAppUsesNonExemptEncryption in a Swift Playground?

In Swift Playgrounds 4 you can upload apps to App Store Connect. Like in Xcode, by default App Store Connect will complain every build is missing compliance when you upload it and cannot be tested until you provide the information.
If you are building an application in Xcode that doesn't use non-exempt encryption you can set the key ITSAppUsesNonExemptEncryption in your Info.plist and App Store Connect will skip the compliance step for each build.
Swift Playgrounds don't have an info.plist, so is there a way to provide this value inside Swift Playgrounds or is this just a minor oversight?
If you open the .swiftpm file package, and look at the Package.swift file, you will see the .iOSApplication product. It takes an optional value, additionalInfoPlistContentFilePath. Give that a relative path to an Info.plist file you create, and values from that file will be merged into the app's final Info.plist when you build.
(I know the Package.swift file has a comment saying you shouldn't edit it because it is generated, but Apple employees on Twitter have said they try to be good about not overwriting valid changes made. I can confirm the plist one is working for me.)
Details here.

Consume FFmpeg XCFramework from Objective-C, headers not found

I built FFmpeg for Apple's platforms as an XCFramework. I used the script in https://github.com/kewlbear/FFmpeg-iOS-build-script/pull/147 to do so.
I'm trying to now consume that framework inside a traditional iOS/macOS framework (named VideoEditing), that then is used inside my iOS app (soon to try and be Catalyst).
In VideoEditing I have linked to FFmpeg.xcframework and then in the app that uses VideoEditing I have linked & embedded FFmpeg.xcframework. Previously I was building FFmpeg as a standard static library, and using that from inside VideoEditing in a Objective-C++ wrapper so I can use it all from Swift.
In that Objective-C++ file I would import FFmpeg headers like #import <libswscale/swscale.h> To make that work, I had to set header search paths. How are you supposed to do it once you convert to the XCFramework? I've tried #import FFmpeg, #import <FFmpeg/libswscale/swscale.h>, #import <FFmpeg/swscale.h> as well as #import <libswscale/swscale.h>. In every case I just get a file not found error on the import line.
All of Apple's examples are showing it just in Swift with the framework vending a module. If I was to try and still set a header search path, you now have different headers per architecture.
Try #import FFmpeg and also set Enable Modules (C and Objective C) to YES from build settings. Make sure that Link Frameworks Automatically is set to YES
You need to put header files parallel to xcframework and set header search path to that header file. xcframework is just like a single .a file, Xcode will not search headers inside xcframework.

App Launched from Safari Displays: Do you want to allow this page to open "(null)"?

I am writing a Mac OS app in Go/Objective-C. Suffice it to say, I am not using Xcode and have assembled the application bundle by hand. Here is what it's filesystem hierarchy looks like
${APPNAME}.app
Contents
MacOS
${APPNAME} (binary)
Resources
Base.lproj
InfoPlist.strings (text)
Info.plist (text)
The bundle launches fine. Application works as expected. I have a CFBundleURLTypes dictionary in my Plist file which defines a URL scheme for my application.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>${APPNAME}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>zzz</string>
</array>
</dict>
</array>
(Note: ${APPNAME} is something like "MyApp." It is not a Java-style, reverse DNS name string.)
When I click on a link in Safari that uses the zzz:// scheme, I get a message that says:
Do you want to allow this page to open "(null)"?
Why is that? I have defined my application name in both the Info.plist file and in the InfoPlist.strings file.
The InfoPlist.strings file simply contains this:
CFBundleName = "My Wonderful Application"
There apparently was some sort of caching mechanism happening. When deployed to another Mac system we managed to procure, which never had the software in question installed on it, this problem did not occur.
Note: The previous system which behaved erroneously had, at the beginning of each test, the software completely removed from it. Finder, Safari or some other Apple software must have secretly cached the app name as "(null)".
Answer: Install it on a new Mac machine, or completely restore (with no backup) the machine you are testing with.

WatchKit2 error on Archive - WatchKit App doesn't contain any WatchKit Extensions

I have this error after Archive of watchkit app.
error: WatchKit App doesn't contain any WatchKit Extensions. Verify that the value of NSExtensionPointIdentifier in your WatchKit Extension's Info.plist is set to com.apple.watchkit.
My Info.plist is like this:
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>com.company.nomeapp.watchkit</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.watchkit</string>
</dict>
Build and run on device and simulator works correctly.
I ran into this issue recently (though it didn't build correctly), the problem for me ended up being Mach-O Type was set to static
Go to build settings of watchkit app/extension and make sure:
Mach-O Type = Executable

Encountering One-off Issue Integrating Dropbox SDK?

I have downloaded the Dropbox API for Objective-C/iOS devices, and I am able to successfully build and run the DBRoulette application.
When I follow the README directions for including the API in my project, I have an enormous number of build errors, all appearing to be related to missing the Foundation header. (Eg. Can't find the interface declaration for NSObject, NSString, etc.)
Many of their header files don't include any other headers at all. Don't all .h files need to import Foundation.h if they extend NSObject? This doesn't seem to be the case, as the example project (DBRoulette) builds and runs fine without the Foundation header declarations, but my own application fails miserably.
I must be missing some sort of project setting, but I can't determine what it is.
Screenshot of One Failing Class
In their example app, they have
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#endif
in their prefix header file (DBRoulette_Prefix.pch). This file is automatically prefixed to all source files in the project, so the appropriate headers are found. You can either put the #import directives in the source files themselves, or do what they did and edit the .pch file for your project.