Comment on page
Encrypted String
Using
ENCRYPTED_STRING
and ENCRYPTED_STRING_IOS_WATCHOS
guarantees that the plaintext of the list item values will not be included in the resulting application binary, only the ciphertext. The ciphertext can only be decrypted by Appfigurate using the correct private key.You can verify that the plain text is not included in the RELEASE application binary using the macOS
strings
tool as follows:Terminal
> cd ~/Library/Developer/Xcode/DerivedData/AppfigurateWorkspace-esajjxyazigjunfteipthjfiobut/Build/Products/Release-iphoneos/AppfigurateExample (iOS).app
> strings AppfigurateExample | grep "https://dev.appfigurate.io/list" // no results
> strings AppfigurateExample | grep "H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==" // prints H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==
It is best practice to use
ENCRYPTED_STRING
and ENCRYPTED_STRING_IOS_WATCHOS
to encrypt sensitive information such as server urls (e.g. internal test environments), rather than expose them as plain text.Using a combination of
BuildConfig.ENCRYPTED
and ProGuard guarantees that the plaintext of the list item values will not be included in the resulting application binary, only the ciphertext. The ciphertext can only be decrypted by Appfigurate using the correct private key.You can verify that the plaintext is not included in the RELEASE build variant APK or AAB using the macOS strings tool as follows:
Terminal
> cd AppfigurateExample/build/outputs/apk/release
> unzip AppfigurateExample-release.apk
> d2j-dex2jar -f classes.dex
> unzip classes-dex2jar.jar
> cd nz/co/electricbolt/appfigurateexample
> strings - ExampleConfiguration.class | grep "https://dev.appfigurate.io/list" // no results
> strings - ExampleConfiguration.class | grep "jm9SM4MEYa4FR...glwMGnpRI4JAQ==" // prints jm9SM4MEYa4FR...glwMGnpRI4JAQ==
The
dex2jar
tool can be installed using brew.The Appfigurate Flutter Plugin defers to the underlying native iOS app's
APLConfiguration
or Android app's nz.co.electricbolt.appfiguratelibrary.Configuration
subclasses to read encrypted strings. Ensure you have read the encryption best practices for iOS and watchOS, and Android sections.The default value of an encrypted
NSString
is nil. You must change the default value of the property by assigning a new plain text value in an overridden reset
method.@property(strong) NSString* propertyName;
ENCRYPTED_STRING_PROPERTY_LIST_EDIT(propertyName, regex, description, restart, ...)
The
NSString
property can be changed in Appfigurate by allowing the user to select from a predefined list of valid choices. The user can customize the list adding by additional values using a text field and a regular expression validating input.Objective-C example
@import AppfigurateLibrary;
@interface Configuration : APLConfiguration
@property(nonatomic, strong) NSString* url;
@end
@implementation Configuration
ENCRYPTED_STRING_PROPERTY_LIST_EDIT(url, @"https://[\\w\\.-]+\\.appfigurate.io/.*", @"url", NO, @{
@"Dev": ENCRYPTED_STRING_IOS_WATCHOS(@"https://dev.appfigurate.io/list",@"H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==",@""JaMa92a122zZs...Mnz23KamnZ0a="),
@"Test": ENCRYPTED_STRING_IOS_WATCHOS(@"https://test.appfigurate.io/list",@"PL+UtWB9WHuO7...aX5BdNqEcbmQE=",@"Na1MSadBCaDD...KKANZias199Km=="),
@"Prod": ENCRYPTED_STRING_IOS_WATCHOS(@"https://m.appfigurate.io/list",@"IxrJFFUarMg6p...E7OWYOC2uJ1AQ==",@"aZSDIMSaasiaM...8SKS1MMahfpIa=")});
...
Appfigurate UI element example

ENCRYPTED_STRING(plaintext, ciphertext)
For an iOS app where the
APLConfiguration
subclass has one public key use the ENCRYPTED_STRING
macro for each list item in the ENCRYPTED_STRING_PROPERTY_LIST_EDIT
.The first parameter of the
ENCRYPTED_STRING
macro is the plain text, and will be used by DEBUG
builds. The second parameter of the ENCRYPTED_STRING
macro is the ciphertext, and will be used by RELEASE
builds. To generate the ciphertext, use the AppfigurateSE app or source editor extension for Xcode.Objective-C example
ENCRYPTED_STRING_PROPERTY_LIST_EDIT(url, @"https://[\\w\\.-]+\\.appfigurate.io/.*", @"url", NO, @{
@"Dev":ENCRYPTED_STRING(@"https://dev.appfigurate.io/list",@"H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ=="),
@"Test":ENCRYPTED_STRING(@"https://test.appfigurate.io/list",@"PL+UtWB9WHuO7...aX5BdNqEcbmQE="),
@"Prod":ENCRYPTED_STRING(@"https://m.appfigurate.io/list",@"IxrJFFUarMg6p...E7OWYOC2uJ1AQ==")});
ENCRYPTED_STRING_IOS_WATCHOS(plaintext, ciphertextIOS, ciphertextWatchOS)
For an iOS and watchOS app where the
APLConfiguration
subclass has two public keys, use the ENCRYPTED_STRING_IOS_WATCHOS
macro for each list item in the ENCRYPTED_STRING_PROPERTY_LIST_EDIT
macro.The first parameter of the
ENCRYPTED_STRING
macro is the plain text, and will be used by DEBUG
builds. The second and third parameters of the ENCRYPTED_STRING
macro are the ciphertext for iOS and watchOS apps, and will be used by RELEASE
builds. To generate the ciphertext, use the AppfigurateSE app or source editor extension for Xcode.Objective-C example
ENCRYPTED_STRING_PROPERTY_LIST_EDIT(url, @"https://[\\w\\.-]+\\.appfigurate.io/.*", @"url", NO, @{
@"Dev": ENCRYPTED_STRING_IOS_WATCHOS(@"https://dev.appfigurate.io/list",@"H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==",@""JaMa92a122zZs...Mnz23KamnZ0a="),
@"Test": ENCRYPTED_STRING_IOS_WATCHOS(@"https://test.appfigurate.io/list",@"PL+UtWB9WHuO7...aX5BdNqEcbmQE=",@"Na1MSadBCaDD...KKANZias199Km=="),
@"Prod": ENCRYPTED_STRING_IOS_WATCHOS(@"https://m.appfigurate.io/list",@"IxrJFFUarMg6p...E7OWYOC2uJ1AQ==",@"aZSDIMSaasiaM...8SKS1MMahfpIa=")});
The default value of an encrypted
String
is nil. You must change the default value of the property by assigning a new plain text value in an overridden reset
method.@EncryptedStringPropertyListEdit(regex, description, encrypted, restart, values)
var propertyName: String
The
String
property can be changed in Appfigurate by allowing the user to select from a predefined list of valid choices. The user can customize the list adding by additional values using a text field and a regular expression validating input.- The
encrypted
parameter ofEncryptedStringPropertyListEdit
must be the result of calling theENCRYPTED()
function. e.g.
... description: "url", encrypted: ENCRYPTED(), restart: ...
Swift example
@EncryptedStringPropertyListEdit(regex: #"https://[\w\.-]+\.appfigurate.io/.*"#, description: "url", encrypted: ENCRYPTED(), restart: false, values: [
"Dev":ENCRYPTED_STRING_IOS_WATCHOS("https://dev.appfigurate.io/list","H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==","JaMa92a122zZs...Mnz23KamnZ0a="),
"Test":ENCRYPTED_STRING_IOS_WATCHOS("https://test.appfigurate.io/list","PL+UtWB9WHuO7...aX5BdNqEcbmQE=","Na1MSadBCaDD...KKANZias199Km=="),
"Prod":ENCRYPTED_STRING_IOS_WATCHOS("https://m.appfigurate.io/list","IxrJFFUarMg6p...E7OWYOC2uJ1AQ==","aZSDIMSaasiaM...8SKS1MMahfpIa=")])
var url: String
...
Appfigurate UI element example

func ENCRYPTED_STRING(_ plaintext: String, _ ciphertext: String) -> String
For an iOS app where the
APLConfiguration
subclass has one public key use the ENCRYPTED_STRING
function for each list item in the @EncryptedStringPropertyListEdit
.The first parameter of the
ENCRYPTED_STRING
function is the plaintext, and will be used by DEBUG
builds. The second parameter of the ENCRYPTED_STRING
macro is the ciphertext, and will be used by RELEASE
builds. To generate the ciphertext, use the AppfigurateSE app or source editor extension for Xcode.Swift example
@EncryptedStringPropertyListEdit(regex: #"https://[\w\.-]+\.appfigurate.io/.*"#, description: "url", encrypted: ENCRYPTED(), restart: false, values: [
"Dev":ENCRYPTED_STRING("https://dev.appfigurate.io/list","H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ=="),
"Test":ENCRYPTED_STRING("https://test.appfigurate.io/list","PL+UtWB9WHuO7...aX5BdNqEcbmQE="),
"Prod":ENCRYPTED_STRING("https://m.appfigurate.io/list","IxrJFFUarMg6p...E7OWYOC2uJ1AQ==")])
var url: String
func ENCRYPTED_STRING_IOS_WATCHOS(_ plaintext: String, _ ciphertextIOS: String, _ ciphertextWatchOS: String) -> String
For an iOS and watchOS app where the
APLConfiguration
subclass has two public keys, use the ENCRYPTED_STRING_IOS_WATCHOS
function for each list item in the @EncryptedStringPropertyListEdit
.The first parameter of the
ENCRYPTED_STRING
function is the plaintext, and will be used by DEBUG
builds. The second and third parameters of the ENCRYPTED_STRING
function are the ciphertext for iOS and watchOS apps, and will be used by RELEASE
builds. To generate the ciphertext, use the AppfigurateSE app or source editor extension for Xcode.Swift example
@EncryptedStringPropertyListEdit(regex: #"https://[\w\.-]+\.appfigurate.io/.*"#, description: "url", encrypted: ENCRYPTED(), restart: false, values: [
"Dev":ENCRYPTED_STRING_IOS_WATCHOS("https://dev.appfigurate.io/list","H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==","JaMa92a122zZs...Mnz23KamnZ0a="),
"Test":ENCRYPTED_STRING_IOS_WATCHOS("https://test.appfigurate.io/list","PL+UtWB9WHuO7...aX5BdNqEcbmQE=","Na1MSadBCaDD...KKANZias199Km=="),
"Prod":ENCRYPTED_STRING_IOS_WATCHOS("https://m.appfigurate.io/list","IxrJFFUarMg6p...E7OWYOC2uJ1AQ==","aZSDIMSaasiaM...8SKS1MMahfpIa=")])
var url: String
...
func ENCRYPTED() -> Bool
Used in conjunction with the
@EncryptedStringPropertyListEdit
property wrapper. The encrypted
parameter of @EncryptedStringPropertyListEdit
must be the result of calling the ENCRYPTED()
function. e.g.... description: "url", encrypted: ENCRYPTED(), restart: ...
The function returns
true
if the calling app has been compiled in RELEASE mode or false
if the calling app has been compiled in DEBUG mode.Warning: This function will behave incorrectly if the apps build settings
Swift compiler - Code generation ‣ Optimization Level
is set to Optimize for Size
(-Osize). The default Swift compiler optimization levels are No Optimization
for DEBUG
builds and Optimize for Speed
-Ospeed for RELEASE
builds. If you must use -Osize, then implement your own isEncrypted()
style function as follows:func isEncrypted() {
#if DEBUG
return false
#else
return true
#end
}
Then call your own
isEncrypted()
function instead of the provided ENCRYPTED()
function e.g.... description: "url", encrypted: isEncrypted(), restart: ...
The default value of an encrypted
String
is null. You must change the default value of the property by assigning a new plaintext value in an overridden reset
method.In your application's
build.gradle
:- Add the following into the
android
‣buildTypes
‣debug
section:buildConfigField("boolean", "ENCRYPTED", "false") - Add the following into the
android
‣buildTypes
‣release
section:buildConfigField("boolean", "ENCRYPTED", "true") - Ensure ProGuard runs on a Release build variant so that
BuildConfig.ENCRYPTED == false
dead code is stripped from the resulting APK or AAB (this will ensure the plaintext values are removed).
e.g.
apply plugin: 'com.android.application'
android {
compileSdkVersion 32
defaultConfig {
...
}
buildTypes {
debug {
debuggable true
minifyEnabled false
zipAlignEnabled false
buildConfigField("boolean", "ENCRYPTED", "false")
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
buildConfigField("boolean", "ENCRYPTED", "true")
}
}
}
...
Once you've modified
build.gradle
and synced the Gradle project, ensure the generated BuildConfig.java
contains the following for a Debug build variant:public static final boolean ENCRYPTED = false;
and the following for a Release build variant:
public static final boolean ENCRYPTED = true;
@EncryptedStringPropertyListEdit(description, regularExpression, encrypted, restart)
String propertyName;
static Map<String, String> _propertyNameValues = new HashMap<>();
static {
_propertyNameValues.put("key1", BuildConfig.ENCRYPTED ? "cipher1" : "plain1");
}
public Map<String, String> propertyNameValues() {
return _propertyNameValues;
}
The
String
property can be changed in Appfigurate by allowing the user to select from a predefined list of valid choices. The user can customize the list adding by additional values using a text field and a regular expression validating input.- The
encrypted
parameter ofEncryptedStringPropertyListEdit
must be the result of callingBuildConfig.ENCRYPTED
. e.g.
... description = "url", encrypted = BuildConfig.ENCRYPTED, restart = ...
- You must implement a method with the same name as the property, but ending with
Values
. e.g. if your property name isurl
, your method must be namedurlValues
. The method must return aMap<String, String>
of the possible property values.
Java example
import nz.co.electricbolt.appfiguratelibrary.Configuration;
import nz.co.electricbolt.appfiguratelibrary.annotations.EncryptedStringPropertyListEdit;
public class AppConfiguration extends Configuration {
@EncryptedStringPropertyListEdit(description: "url", regularExpression = "https://[\w\.-]+\.appfigurate.io/.*", encrypted = BuildConfig.ENCRYPTED, restart = false)
String url;
static Map<String, String> _urlValues = new HashMap<>();
static {
_urlValues("Dev", BuildConfig.ENCRYPTED ? "H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==" : "https://dev.appfigurate.io/list");
_urlValues("Test", BuildConfig.ENCRYPTED ? "PL+UtWB9WHuO7...aX5BdNqEcbmQE=" : "https://test.appfigurate.io/list");
_urlValues("Prod", BuildConfig.ENCRYPTED ? "IxrJFFUarMg6p...E7OWYOC2uJ1AQ==" : "https://m.appfigurate.io/list");
}
public Map<String, String> urlValues() {
return _urlValues;
}
...
Appfigurate UI element example

The default value of an encrypted
String
is null. You must change the default value of the property by assigning a new plaintext value in an overridden reset
method.In your application's
build.gradle
:- Add the following into the
android
‣buildTypes
‣debug
section:buildConfigField("boolean", "ENCRYPTED", "false") - Add the following into the
android
‣buildTypes
‣release
section:buildConfigField("boolean", "ENCRYPTED", "true") - Ensure ProGuard runs on a Release build variant so that
BuildConfig.ENCRYPTED == false
dead code is stripped from the resulting APK or AAB (this will ensure the plaintext values are removed).
e.g.
apply plugin: 'com.android.application'
android {
compileSdkVersion 32
defaultConfig {
...
}
buildTypes {
debug {
debuggable true
minifyEnabled false
zipAlignEnabled false
buildConfigField("boolean", "ENCRYPTED", "false")
}
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
buildConfigField("boolean", "ENCRYPTED", "true")
}
}
}
...
Once you've modified
build.gradle
and synced the Gradle project, ensure the generated BuildConfig.java
contains the following for a Debug build variant:public static final boolean ENCRYPTED = false;
and the following for a Release build variant:
public static final boolean ENCRYPTED = true;
@EncryptedStringPropertyListEdit(description, regularExpression, encrypted, restart)
var propertyName: String? = null
companion object {
var _propertyNameValues: MutableMap<String, String> = HashMap()
init {
_propertyNameValues["key1"] = if (BuildConfig.ENCRYPTED) "cipher1" else "plain1"
}
}
fun propertyNameValues(): Map<String, String> {
return _propertyNameValues;
}
The
String
property can be changed in Appfigurate by allowing the user to select from a predefined list of valid choices. The user can customize the list adding by additional values using a text field and a regular expression validating input.- The
encrypted
parameter ofEncryptedStringPropertyListEdit
must be the result of callingBuildConfig.ENCRYPTED
. e.g.
... description = "url", encrypted = BuildConfig.ENCRYPTED, restart = ...
- You must implement a method with the same name as the property, but ending with
Values
. e.g. if your property name isurl
, your method must be namedurlValues
. The method must return aMap<String, String>
of the possible property values.
Kotlin example
import nz.co.electricbolt.appfiguratelibrary.Configuration
import nz.co.electricbolt.appfiguratelibrary.annotations.EncryptedStringPropertyListEdit
class AppConfiguration : Configuration() {
@EncryptedStringPropertyListEdit(description = "url", regularExpression = "https://[\w\.-]+\.appfigurate.io/.*", encrypted = BuildConfig.ENCRYPTED, restart = false)
var url: String? = null
companion object {
var _urlValues: MutableMap<String, String> _urlValues = HashMap()
init {
_urlValues["Dev"] = if (BuildConfig.ENCRYPTED) "H7o9Lgqd4RgMJ...rtJQGh8DiiSAQ==" else "https://dev.appfigurate.io/list"
_urlValues["Test"] = if (BuildConfig.ENCRYPTED) "PL+UtWB9WHuO7...aX5BdNqEcbmQE=" else "https://test.appfigurate.io/list"
_urlValues["Prod"] = if (BuildConfig.ENCRYPTED) "IxrJFFUarMg6p...E7OWYOC2uJ1AQ==" else "https://m.appfigurate.io/list"
}
}
fun urlValues(): Map<String, String> {
return _urlValues
}
...
Appfigurate UI element example

The flutter
APLNativeConfiguration
class defers to the underlying platform APLConfiguration
(iOS) or nz.co.electricbolt.appfiguratelibrary.Configuration
(Android) subclass to read property values.String get propertyName => nativeString('propertyName');
Dart example
import 'package:appfigurateflutter/appfigurateflutter.dart';
public class Configuration extends APLNativeConfiguration {
String get foregroundColorHex => nativeString('foregroundColorHex');
...
Last modified 1mo ago