Localise App display name that have append suffix - ios

I have a issue with getting app display name to include the appending suffix when adding localisation to InfoStrings.plist.
I have add different scheme and User-Defined attribute. So in my info.plist, i have App Name $(BUNDLE_DISPLAY_NAME_SUFFIX) in my CFBundleDisplayName. It will append a -S to my app name when running on development scheme and normal app name on release scheme that i created. Everything is working well.
However, when I try to translate the app name, it does not work anymore. So in my infoPlist.strings, I tried the following:
"CFBundleDisplayName" = "App Name ";
"CFBundleDisplayName" = "App Name $(BUNDLE_DISPLAY_NAME_SUFFIX)";
Both does not append the -S anymore when I run on development scheme. Does anyone know how I could still do that? Like maybe how to get the $(Bundle_DISPLAY_NAME_SUFFIX) to be read in the infoPlist.strings.
More specifically, how do I include a preprocessor in InfoPlist.strings?

I found the answer to your question in another thread, here, but it says you need a scrip for this.
How you create different suffixes (not what was asked for)
Here is how you set up different display name of your app based on the your scheme. You can do this by setting up different configurations. Go to the project settings -> select the project (not the target) -> Info tab -> then create as many configurations you would like. Maybe one for Production, Debug and one for Beta releases.
Then select your Target -> Build settings tab -> Enter display in search. Under User defined you can create your own variable, call it e.g. BUNDLE_DISPLAY_NAME_SUFFIX. Give it different values for Production, Debug and Beta.
Open your Info.plist file, under Bundle display name, your see maybe MyApp, append the string ${BUNDLE_DISPLAY_NAME_SUFFIX} so it makes MyApp${BUNDLE_DISPLAY_NAME_SUFFIX}.
Finally configure your schemes to use the correct configuration. You probably want to use Production for Archive and Debug for Debug.
Here is an image of the User defined variable

Related

Apple/fastlane submit for review action failing with unclear error message about privacy text

I am following fastlane's default configuration conventions for a React Native project. That is to say, my project structure looks like (e.g.):
/ios/fastlane/metadata/en-GB
with the en-GB subdirectory containing the following files:
description.txt
keywords.txt
name.txt
privacy_url.txt
release_notes.txt
support_url.txt
Everything was working perfectly until I tried to internationalise.
Now, when fastlane's upload_to_app_store() (aliased with deliver()) runs in my CI/CD pipeline, it fails and I see the following error:
The provided entity is missing a required attribute - You must provide a value for the attribute 'privacyPolicyText' with this request - /data/attributes/privacyPolicyText
I already have privacy_url.txt in there which was previously sufficient.
The thing that fixed it was adding a apple_tv_privacy_policy.txt (just containing a URL pointing to our privacy policy) file to the en-GB subdirectory.
Weird, given that the Fastfile was working completely fine before without any sort of privacy policy for TV. Very frustrating error message!

Xcode UI tests, development language, fallback translation and CI servers

Following scenario:
I'm having an iOS project that automatically gets unit and UI tested on every git push on a CI server (CircleCI). The tests are executed with fastlane which is also used to create screenshots for the App Store automatically.
Now, my project gets translated into several languages. I want fastlane to work on all languages (to be able to take the screenshots), so I changed the UI tests from something like this:
app.navigationBars.buttons["Confirm"].tap()
to
let buttonTitle = NSLocalizedString("navbar.confirm", comment: "")
app.navigationBars.buttons[buttonTitle].tap()
I thought this will do the trick, but it doesn't. I don't know how the simulator is configured in CircleCI, but the UI tests now fail with
[00:46:34]: ▸ testDashboard, No matches found for Find: Elements matching predicate '"navbar.confirm" IN identifiers' from input {(
So for some reason the fallback language set with CFBundleDevelopmentRegion is not respected, probably because the language is not in the preferredLanguages list of the bundle. This is an issue in itself as I do not want keys to be displayed for end users in any case. I'd like to make sure this never ever happens.
So I tried to fix that in turn by writing a wrapper for NSLocalizedString that checks whether NSLocalizedString(..) returns the key and if so loads the default (en) bundle and gets the string localized that way.
However it seems you can't load another bundle in the UI tests. The test will crash and fail. So I can't use this workaround.
Am I just overlooking some obvious solution? I can't be the only one having this issue, right? Any hints?
When you use NSLocalizedString("navbar.confirm", comment: "") the system tries to retrieve a value for that key from the strings file in the main bundle.
The main bundle does not work when running UITests because it gives you the bundle of the UITest Runner App instead of the UITest bundle.
To be able to use NSLocalizedString in a UITest you have to do 2 things:
1. Add your Localizable.strings file to your UITest target
2. Access the file via the UITest bundle (You can use a little helper method for that):
func localized(_ key: String) -> String {
let uiTestBundle = Bundle(for: AClassFromYourUITests.self)
return NSLocalizedString(key, bundle: uiTestBundle, comment: "")
}
You can use any class from your UITests to access the UITest bundle.
Now you can use NSLocalizedString in your UITest like this:
app.navigationBars.buttons[localized("navbar.confirm")].tap()
I wrote a little blog post about this a while ago, if you are interested in more details.
Set accessibility identifiers on your UI elements and query using those in your tests instead of using the localized string values. This will make your tests language-agnostic and there will be no need to fiddle with access to different bundles.
See this answer for an example of how to set and use accessibility identifiers.

Xcode building different environments for the same app

I have an app that talks to a server. I have 2 versions of this server: a production one and a testing one. This means I'd need to have a production iOS app and a testing iOS app. The logic is essentially the same for both versions of the app, except it would need to use certain configurations depending on which server it connects to. Right now, my solution is to use a plist file that contains informations that the 2 versions need. The plist would contain a bunch of key-value pairs like:
url: test-server.domain.com
username: test-subject
password: test-password
I have 2 git branches: a production branch and a testing branch for each of the iOS app version. The content of the said plist file would be different on each branch.
Question is: is there a more elegant way to solve this? Preferably I'd like to only have 1 branch. I've looked into using Xcode's environment variables, but those don't stick when I archive/build my apps.
There sure is! You can do this with environment variables, as described in this blogpost: Flavors for iOS. You can even switch app icon and app name based on the variables when building, therefore, you can check in code in the following way: if #APP_DEV // call dev API ELSIF // call prod API.
Steps
1: On the project settings level, duplicate the debug configuration and rename it to staging. (Optional)
2: Open the project build settings and add some user-defined settings: APP_ENV with values dev => dev, staging => stage, production => prod.
3: You need multiple bundle IDs to load apps side by side (for instance a beta or production app). Therefor, create another user-defined settings APP_BUNDLE_SUFFIX with the value .$(APP_ENV:lower). This turns Dev into .dev. Leave production empty if you like to have no extra suffix when submitting the app.
4: Append the APP_BUNDLE_SUFFIX to your product bundle ID (com.testapp.YourCoolApp.$(APP_BUNDLE_SUFFIX)).
5: In Swift projects, you can add the added variables to the "Active Compilation Conditions" on the same screen. Do this by adding ENV_$(APP_ENV) to the environments listed. In Objective-C projects, this can be done by adding the environments to the "Preprocessor macro's", but pay attention, you'll need to suffix =1 to the value in order to activate the variables.
Making the env vars stick
You might need to create separate schemes to achieve this. You can duplicate schemes, or option+click on the scheme at the top and switch the build config.
I usually use Preprocessor Macros for this.
Define variable like DEBUG for Debug and nothing in Release.
And then use this like
enum AppConfig {
case debug
case testFlight
case appStore
var host: String {
switch self {
case .debug: return "test host"
default: return "production host"
}
}
static var current: AppConfiguration {
#if DEBUG
return .debug
#else
if Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" {
return .testFlight
} else {
return .appStore
}
#endif
}
}
Wherever you want to use host, you can use AppConfig.current.host. The only thing you need to do is create scheme for debug and release.

What is customURLScheme in Firebase Dynamic Links?

In the documentation it says to add the following lines to my AppDelegate.swift:
// Set deepLinkURLScheme to the custom URL scheme you defined in your
// Xcode project.
FIROptions.default().deepLinkURLScheme = self.customURLScheme
From what I understand this should be the same link you put in your info.plist. However, I'm confused why in the quickstart-ios repo they decided to make this equal to "dlscheme".
Can anybody help me understand what exactly this scheme is?
This is not clear in the Dynamic Links integration instructions — I ran into the same issue even though I work with these things all day at Branch.io (full disclosure: we're an alternative/improvement to Dynamic Links).
When configuring a custom URI scheme, you need to supply both an Identifier and a URL Scheme. Apple recommends using a reverse domain value for the Identifier, but since your bundle ID is also typically reverse domain format, these two often end up being identical.
By default, Firebase expects you to use your bundle identifier as your custom URI scheme. When you do this, their default configuration takes over and you don't need to specify the FIROptions.default().deepLinkURLScheme = self.customURLScheme line at all. The URI scheme config ends up looking like this, which is a bit counter-intuitive:
However, if you decide to use a value that is not your bundle ID for the URL Scheme (very common), then you DO need the FIROptions.default().deepLinkURLScheme = self.customURLScheme line. But you also need this one before it: let customURLScheme = "somethingelse". You can see this here in the quickstart, and also where the URI scheme is defined in the info.plist file here.
Basically, the Firebase team tried to simplify things by assuming the bundle ID as the custom URI scheme value. This is not a bad option, but it can be confusing and as you can see, even their own quickstart project uses a more advanced config.

How do I assign a device level hotkey to my Blackberry App?

Blackberry devices have shortcuts to open applications. For example, if you hit the 'T' button, the tasks app will open.
(BTW, you have to have "Call from Home Screen" disabled in the Phone App Settings for this to work)
How can I assign a shortcut key to open my own application?
For clarity and in case the link dies, I'll post the instructions here:
Complete the following steps:
In your Project Properties in the Integration Development Environment (IDE), click the Resources tab.
Under the Title ID option, specify the Resource variable name (App_Title) which corresponds to the actual text to be displayed (myApp) on the ribbon.
If you want the A in myApp to be a hotkey, insert the unicode underscore character (\u0332) after the A. Therefore, in your resource package, instead of specifying myApp as the value for the variable App_Title, specify the following:
myA\u0332pp
See this knowledge base article. Of course you have to avoid collisions with other applications.

Resources