Use name with whitespace for qmake TARGET variable - ios

iOS/OS X application names usually contains spaces (like "App Store.app").
But when i'm trying to use such name in my Qt/ios project like this:
ios: TARGET = "My Cool App"
build process failed with strange error in the autogenerated by Qt Bash script.
Am i doing something wrong, or such whitespaces in names just don't supported?
UPD
the problem first time occurs in qmake-generated shell script:
#!/bin/sh
cp -r $BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME /Users/eraxillan/Projects/<PROJECT_DIR>
If $FULL_PRODUCT_NAME contains spaces, then script just fails.
Script generated and executed only in case of custom DESTDIR project variable value - my case.
So, looks like a bug in qmake-generated script to copy project build artefacts to custom output directory.
Workarounds:
Remove spaces from target name (My Cool App --> my-cool-app)
Do not use custom DESTDIR value at all
Hope this will be helpful

This should work:
TARGET = My" "Cool" "App

Related

iOS Sourcery with Flutter build

Im trying to build my flutter app for iOS it has a google maps key that I want to protect and not check in to source control it needs to be buildable from azure, to achieve this I'm storing my maps key as a secret variable in azure and as a system environment variable locally, I'm using Sourcery https://github.com/krzysztofzablocki/Sourcery to generate a class for me that contains this key, it all works but only the second time I build, the first build always fails.
So I'm building using this command
flutter build ios --flavor dev --verbose
Which the first run will give me the error
error: Build input file cannot be found:
'/Users/martin/xxx/xxx/xxx/ios/Runner/Credentials.generated.swift' (in target
'Runner'
Then issuing the same command again
** BUILD SUCCEEDED **
this is my run script its called before compile sources and after the flutter run script
this calls my script which calls another script to export the map api key and runs sourcery command using a .yml file as its config heres the script, (it also does some logging)
#!/bin/bash
echo "Generate Credentials Code"
CREDENTIALS_DIR="$SRCROOT/credentials"
# Set credentials if local script for adding environment variables exist
if [ -f "$CREDENTIALS_DIR/add_credentials_to_env.sh" ]; then
echo "Add credentials to environement"
source "$CREDENTIALS_DIR/add_credentials_to_env.sh"
echo "finished running add_credentials_to_env.sh"
fi
echo "RUN SOURCERY"
$SRCROOT/Pods/Sourcery/bin/sourcery --config "$SRCROOT/config.yml"
echo "FINISHED RUNNING SOURCERY"
for file in "$SRCROOT/Runner"/*; do
echo "$file"
done
and here is my config file
sources:
- .
project:
file: Runner.xcodeproj
target:
name: Runner
module: Runner
templates:
- credentials/Credentials.stencil
output:
path: ./Runner/
link:
project: Runner.xcodeproj
target: Runner
args:
mapsApiKey: ${MAPS_API_KEY_IOS}
this generates my class correctly on the first build and seems to be added correctly to the target (edited out my key) but the app will only compile if I run the build command again.
// Generated using Sourcery 1.4.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
public struct Credentials {
let mapsApiKey: String
}
public let credentials = Credentials(mapsApiKey:
"xxxxxxxxxxMY_KEYxxxxxxxxxxx")
Any ideas?
xcode 12.5 m1 macbook pro, swift 5
Looks like you generate the file too late. I'll suggest move your script to Aggregate and add it as a dependency to your target
Add Aggregate
Move your script to 'Run script' section
Add 'PreBuildScriptsRunner' as a dependency to your application target, make sure 'Dependencies' section on top of all other sections
Manually setting environment variables is an annoying thing developers would have to do on their own machines, and there are nicer/ more common ways of setting up private keys. After a few years of using environment variables/ bash, it still causes issues which are not easily detectable. You may want to automate/ document it, but then you have to consider developers using zsh, fish vs. bash? Also, I try to avoid using Xcode build phases where possible.
Solution? (This is what I have)
Why don't you use your CI (Azure pipeline?, I use Github workflows) to write a Xcode build configuration file (not a Swift file). The sensitive keys could be in a file Secrets.xcconfig, which is added to your Xcode as a build configuration. Then, in your Info.plist of your application, and your code can load them.
Create a file, Secrets.xcconfig:
SECRET_API_KEY = 12312rfiwhvde.wvascafsf.df325
Add it to your Xcode project, and then to the project's build configuration:
Add Secrets.xcconfig to your .gitignore
Make sure to git ignore the file before committing it to the repo. You can also keep an Example.Secrets.xcconfig which users can use. In the readme, tell users to run cp Example.Secrets.xcconfig Secrets.xcconfig and then to update values in it. Now you can clearly see what keys the application is using (its clearly in the directory). As a bonus, you can add this file the Xcode project, so that when the file is missing, it shows up in red (indicating to the user they really should acquire this file somehow):
In Info.plist, reference the variable:
<dict>
<key>SECRET_API_KEY</key>
<string>$(SECRET_API_KEY)</string>
</dict>
In your code, load the variable that was stored in Info.plist:
let key = Environment.infoDictionary["SECRET_API_KEY"] as? String
In your CI/ Azure pipeline:
Run echo "SECRET_API_KEY = $SECRET_API_KEY_SAVED_IN_CONTINUOUS_INTEGRATION" >> Secrets.xcconfig
Then you can just .gitignore the file instead of setting environment variables. When you work with other developers, you just give them this file, and nothing else needs to be done to build locally.
So I have answered your question not by solving your direct problem, but giving you a more common/ canonical way of solving this problem that many developers have faced before.

iOS app test if Localization translations have same keys

In my iOS app I have localization files such as Localizable.strings.
I want to check that they have same keys and there is no missed keys in each localization.
I thought about performing this in Unit Tests.
Is Unit testing the right place for this? Maybe there is much easier tool for it?
How this Unit testing can be done?
I found article on this topic in Obj-C https://www.cocoanetics.com/2013/03/localization-unit-test/ that is 5 years old. Maybe something else can be used?
You can just use this shell script I made up and run it as a Run Script (within Build Phases) of your App Target.
First, create the shell script and save it somewhere in your App Project, I saved it as check_missing_keys_in_translations.sh for example:
#!/bin/sh
# check_missing_keys_in_translations.sh
#
# Overview: Script will be executed from Build Phases > Run Script
#
# Script: Extract sorted localization keys using "$1" as language code
# given as parameter to locate the right Localizable.strings.
#
# Build Phases > Run Script: The result will be compared to see if
# translations have the same keys or if one of them have more or less.
plutil -convert json 'AppProject/Resources/Localization/'"$1"'.lproj/Localizable.strings' -o - | ruby -r json -e 'puts JSON.parse(STDIN.read).keys.sort'
Just change the path AppProject/Resources/Localization/ to the path where your en.lproj, it.lproj... localization folders are located in your app (in this case called AppProject).
Second, go to your App Project, select the App Target and under Build Phases put this script code within Run Script:
# Check missing localization keys in translations
MISSING_KEYS_TRANSLATIONS=$(diff <($SRCROOT/tools/localization/check_missing_keys_in_translations.sh en) <($SRCROOT/tools/localization/check_missing_keys_in_translations.sh it))
if [ "$MISSING_KEYS_TRANSLATIONS" ]; then
echo "warning: $MISSING_KEYS_TRANSLATIONS"
fi
As always, check the path and adapted to where you saved the script created before. I saved it under App Project/tools/localization/... as you can see. You might want to adapt this script to better reflect your situation as I had only 2 localizable I was interested in checking they had the same keys. Is just shell scripting.
Check screenshot below:

Different Application Name For Development/Release Build

I have an iOS application that has "sysadmin" only features when in the development build which are removed for the release build.
What is the easiest way to have two builds on our testing devices in house, one in development mode, and one in release mode that have different names on the iOS home screen?
The current situation is that when we want to test the release build, I have to manually rebuild it for each device. When we want to switch back, I have to once again manually rebuild the application.
As LoVo mentioned - you will need different app-identifiers and bundle display names. Here's how I would approach the problem:
In Project's build settings set the following values:
Preprocess Info.plist File - Yes
Info.plist Preprocessor Prefix File - InfoPlist_proc.h
Add the header generation script to your Xcode project.
The script in ruby should look like this:
#!/usr/bin/env ruby
# build type is going to be passed
build_type = ENV["CONFIGURATION"]
proc_header_path = File.join(ENV["SRCROOT"], "InfoPlist_proc.h")
File.open(proc_header_path, "w+") do |f|
f.write("#define BUNDLE_IDENTIFIER com.company.app.#{ build_type.downcase }\n")
f.write("#define BUNDLE_DISPLAY_NAME \"My App #{ build_type.downcase }\"")
end
Now in the "Build" stage of your scheme (Cmd+Shift+,) create "Run Script" pre-action:
Add execution permissions to previously created script ($ chmod a+x script.rb) and set it to run from your pre-build script run phase:
Finally in your current Info.plist file change the bundle identifier and display name values with preprocessor definitions:
Now each time you build your app, the InfoPlist_proc.h file will be regenerated. This has a drawback though: to change your app's bundle identifier or name you would have to edit the script, not the Info.plist
But it also gives an advantage: you can inject the bundle version and short version string from what your cvs gives you. I usually use git rev-list --count --all for bundle version and git describe --tags --first-parent for short version string.
Hope this helps.
Set different App-Identifiers and Bundle Display Names

Info.plist | Modify Version String

Our OSX Application running on have some modules which are running on other platform too, i.e. most of the part are ported to different platform and some are common across all platform,
When come to version no, to be consistent with the other platform port, we need to maintain a common version say, AppVersion.h which has the version string.
Now to show on the UI , i need to copy the same version string from AppVersion.h file to Info.plist
Are there any workaround for the same, i.e. run some pre-build script which reads the version string and update the info.plist.
Thanks in advance.
Absolutely! This is what I use as a build phase, after the resource copy. I break down the problem a bit because this is part of a much larger script.
#!/bin/sh
export PlistBuddy="/usr/libexec/PlistBuddy"
# TODO: Get OUR_VERSION here.
export appPlist="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/Info.plist"
$PlistBuddy $appPlist -c "set :CFBundleShortVersionString '$OUR_VERSION'"
$PlistBuddy $appPlist -c "set :CFBundleVersion '$OUR_VERSION'"
As to how to get OUR_VERSION? I leave that open to you. In my case, I simply grepped the file in the script. For me, this was an xcconfig but for you it'll be the header. If you've got command line experience, you might have a better way to extract the symbol meaning from the .h file.
Note that this sets CFBundleShortVersionString (the user-visible version) and CFBundleVersion (the internal version) to the same value. That's probably what you want. If not, fix that. :)

Adding a new build rule to parse all rtf files

Xcode includes a flexible build rules system. The documentation is all but non-existant however.
A project I am working on for iOS 5 and iOS 6 includes an rtf help file. For iOS 6, I can convert the rtf file into an archived NSAttributedString object, then load that at runtimeand display it directly to a UITextView. For iOS 5, I can't (without a lot of work in Core Text...) so I want just the text without the style info.
I wrote a command line tool, RTFToData that takes an RTF file as input and generates a .txt file and a .data file (where the .data file contains a version of the styled text that my project knows how to use.)
Here is the syntax of my command line tool:
RTFToData [-o] source_path [destination_path]
-o (optional) overwite existing files
source_path (required) path to source RTF file (must have extension "rtf" or "RTF"
destination_directory (optional.) writes output files to source file directory if no destination specified
destination_directory must exist if specified.
I want to set up my project so that I can add .rtf files as sources (with the "add to target" checkbox NOT checked.) I want Xcode to run my RTFToData command on each file specifying that the output files should be copied into a directory and then added to the target.
Ideally, I'd like the build process to know about the dependencies between my source .rtf files and the processed .data and .txt files. If I touch a .rtf file, I'd like the build process to re-run the rtftodata command.
I am a makefile and unix scripting neophyte. I THINK I can use a run script build rule that will do this, but I am unclear on how. I guess I need to write a script that finds all files of type ".rtf", pipes that list of files into an invocation of my RTFToData.
Can somebody outline the steps I need to take in the Xcode IDE to make my project handle this smoothly?
As a side-note, is there some directory where you can put command line tools so they are available to the current version of Xcode? So far I've been installing the RTFToData command in /Library/usr/bin, but I'd really like the build tool to be included in the project, or at the very least, not have to use sudo to set up every development machine that is used to build this project.
Create a custom build phase
Add the .rtf files to your project and make sure they are added to your target.
Go to your target settings and select the "Build Rules" tab:
Click the "Add Build Rule" button at the bottom.
You want to configure your rule based on something like this:
Enter a standard wildcard glob for the files you want to match (*.rtf).
Inside the script section you can make use of a number of environment variables. Assuming your glob has matched the input file Test.rtf you have access to these vars:
INPUT_FILE_PATH = /path/to/your/project/source/Test.rtf
INPUT_FILE_NAME = Test.rtf
INPUT_FILE_BASE = Test
INPUT_FILE_SUFFIX = .rtf
INPUT_FILE_DIR = /path/to/your/project/source/
You want to process your file and send it to the ${DERIVED_FILES_DIR} directory with whatever new filename or extension you need. In this case we take the base filename from the input and give it a new extension.
Fill out the "Output Files" section with the same output file you used in the script. This will ensure the dependency system works and that the file will be copied to your .app. The script will only be run if the input has changed or the output file is missing from the .app.
Note that the "Output Files" should not have double quotes. The paths will be quoted for you by Xcode.
If your script generates multiple output files, add extra entries for those as well.
Once this is all set up, .rtf files added to your target will be converted to whatever output files your script generates. The original .rtf files will not exist in the final .app.
Where to put scripts/programs
As a side-note, is there some directory where you can put command line
tools so they are available to the current version of Xcode?
Put your tools somewhere below the directory that contains your .xcproject. Then from your build phase/rules use the ${SRCROOT} environment variable, which is the directory containing your project:
Assuming this file system layout:
/path/to/project/project.xcodeproj
/path/to/project/Tools/CommandLineTool
Use this in your build phase/rules:
"${SRCROOT}/Tools/CommandLineTool" "${INPUT_FILE_PATH}" ...
Remember to use double-quotes everywhere you can!

Resources