JustTweak est un framework de signalisation de fonctionnalité pour les applications iOS. Il fournit une interface de façade simple interagissant avec plusieurs fournisseurs de tweak qui sont interrogés concernant une priorité donnée. Les ajustements représentent les drapeaux utilisés pour générer des décisions dans le code client.
Avec JustTweak, vous pouvez réaliser ce qui suit:
JustTweak est disponible via Cocoapods. Pour l'installer, ajoutez simplement la ligne suivante à votre podfile:
pod "JustTweak"
JustTweak est également disponible via SPM. Copiez l'URL pour ce dépôt et ajoutez le package dans les paramètres de votre projet.
LocalTweakProvider
y compris vos fonctionnalités. Reportez-vous à LocalTweaks_example.json
pour un point de départ.Pour configurer la pile, vous avez deux options:
static let tweakManager : TweakManager = {
var tweakProviders : [ TweakProvider ] = [ ]
// Mutable TweakProvider (to override tweaks from other TweakProviders)
let userDefaultsTweakProvider = UserDefaultsTweakProvider ( userDefaults : UserDefaults . standard )
tweakProviders . append ( userDefaultsTweakProvider )
// Optimizely (remote TweakProvider)
let optimizelyTweakProvider = OptimizelyTweakProvider ( )
optimizelyTweakProvider . userId = UUID ( ) . uuidString
tweakProviders . append ( optimizelyTweakProvider )
// Firebase Remote Config (remote TweakProvider)
let firebaseTweakProvider = FirebaseTweakProvider ( )
tweakProviders . append ( firebaseTweakProvider )
// Local JSON-based TweakProvider (default TweakProvider)
let jsonFileURL = Bundle . main . url ( forResource : " LocalTweaks_example " , withExtension : " json " ) !
let localTweakProvider = LocalTweakProvider ( jsonURL : jsonFileURL )
tweakProviders . append ( localTweakProvider )
return TweakManager ( tweakProviders : tweakProviders )
} ( )
LocalTweakProvider
. Reportez-vous à TweakAccessor.swift
pour un point de départ. config.json
dans le format suivant: {
"accessorName" : " GeneratedTweakAccessor "
}
La seule valeur actuellement prise en charge est accessorName
qui définit le nom de la classe générée.
Podfile
script_phase :name = > ' TweakAccessorGenerator ' ,
:script = > ' $SRCROOT/../TweakAccessorGenerator
-l $SRCROOT/<path_to_the_local_tweaks_json_file>
-o $SRCROOT/<path_to_the_output_folder_for_the_generated_code>
-c $SRCROOT/<path_to_the_folder_containing_config.json> ' ,
:execution_position = > :before_compile
Chaque fois que la cible est construite, l'outil de générateur de code régénérera le code de la pile. Il comprendra toutes les propriétés qui soutiennent les fonctionnalités définies dans le LocalTweakProvider
.
Si vous avez utilisé l'outil de générateur de code, la pile générée comprend tous les indicateurs de fonctionnalité. Allouez simplement l'objet Accessor (le nom que vous avez défini dans la configuration .json
et utilisez-le pour accéder aux indicateurs de fonctionnalité.
let accessor = GeneratedTweakAccessor ( with : < #tweak_manager_instance# > )
if accessor . meaningOfLife == 42 {
...
}
Voir GeneratedTweakAccessor.swift
et GeneratedTweakAccessor+Constants.swift
pour un exemple de code généré.
Si vous avez décidé d'implémenter le code de pile vous-même, vous devrez implémenter le code pour accéder aux fonctionnalités via le TweakManager
.
Les trois principales caractéristiques de JustTweak sont accessibles à partir de l'instance TweakManager
pour piloter des décisions de chemin de code.
// check for a feature to be enabled
let enabled = tweakManager . isFeatureEnabled ( " some_feature " )
if enabled {
// enable the feature
} else {
// default behaviour
}
TweakManager
renvoie la valeur du fournisseur de tweak avec la priorité la plus élevée et se rend automatiquement en arrière aux autres si aucune valeur définie n'est trouvée. Il lance l'exécution lorsqu'un ajustement nul est trouvé qui peut être attrapé et manipulé selon les besoins. Utilisez soit tweakWith(feature:variable:)
ou les wrappers de propriété fournis.
// check for a tweak value
let tweak = try ? tweakManager . tweakWith ( feature : " some_feature " , variable : " some_flag " )
if let tweak = tweak {
// tweak was found in some tweak provider, use tweak.value
} else {
// tweak was not found in any tweak provider
}
Ou avec une prise de main
// check for a tweak value
do {
let tweak = try tweakManager . tweakWith ( feature : " some_feature " , variable : " some_flag " )
// tweak was found in some tweak provider, use tweak.value
return tweak
} catch let error as TweakError {
switch error {
case . notFound : ( ) // "Feature or variable is not found"
case . notSupported : ( ) // "Variable type is not supported"
case . decryptionClosureNotProvided : ( ) // "Value is encrypted but there's no decryption closure provided"
}
} catch let error { // add a default catch to satisfy the compiler
print ( error . localizedDescription )
}
@TweakProperty
, @OptionalTweakProperty
et @FallbackTweakProperty
Property Wrappers sont disponibles pour marquer les propriétés représentant les drapeaux de fonctionnalité. Pensez que pour utiliser ces emballages de propriété, une instance statique de TweakManager
est nécessaire.
@ TweakProperty ( feature : < #feature_key# > ,
variable : < # var iable_key# > ,
tweakManager : < #TweakManager# > )
var labelText : String
@ OptionalTweakProperty ( fallbackValue : < #nillable_fallback_value# > ,
feature : < #feature_key# > ,
variable : < # var iable_key# > ,
tweakManager : < #TweakManager# > )
var meaningOfLife : Int ?
@ FallbackTweakProperty ( fallbackValue : < #nillable_fallback_value# > ,
feature : < #feature_key# > ,
variable : < # var iable_key# > ,
tweakManager : < #TweakManager# > )
var shouldShowFeatureX : Bool
L'ordre des objets dans le tableau tweakProviders
définit la priorité des fournisseurs de tweak.
Le MutableTweakProvider
avec la priorité la plus élevée, tel que UserDefaultsTweakProvider
dans l'exemple ci-dessus, sera utilisé pour refléter les modifications apportées dans l'interface utilisateur ( TweakViewController
). Le LocalTweakProvider
doit avoir la priorité la plus faible car elle fournit les valeurs par défaut d'un fournisseur de tweak local et c'est celui utilisé par le TweakViewController
pour remplir l'interface utilisateur.
Afin de migrer du manuel vers l'implémentation générée par le code, il est nécessaire de mettre à jour vers le nouveau format .json
. Pour aider à ce processus, nous avons ajouté la propriété GeneratedPropertyName
à l'objet Tweak. Définissez cette valeur pour aligner avec vos noms de propriétés actuels dans le code, afin que les propriétés accessoires générées correspondent à votre implémentation existante.
Le TweakManager
offre la possibilité de mettre en cache les valeurs de tweak afin d'améliorer les performances. La mise en cache est désactivée par défaut mais peut être activée via la propriété useCache
. Lorsqu'il est activé, il existe deux façons de réinitialiser le cache:
resetCache
sur le TweakManager
TweakProviderDidChangeNotification
JustTweak est livré avec un ViewController qui permet à l'utilisateur de modifier le MutableTweakProvider
avec la plus haute priorité.
func presentTweakViewController ( ) {
let tweakViewController = TweakViewController ( style : . grouped , tweakManager : < #TweakManager# > )
// either present it modally
let tweaksNavigationController = UINavigationController ( rootViewController : tweakViewController )
tweaksNavigationController . navigationBar . prefersLargeTitles = true
present ( tweaksNavigationController , animated : true , completion : nil )
// or push it on an existing UINavigationController
navigationController ? . pushViewController ( tweakViewController , animated : true )
}
Lorsqu'une valeur est modifiée dans tout MutableTweakProvider
, une notification est renvoyée pour donner aux clients la possibilité de réagir et de refléter des changements dans l'interface utilisateur.
override func viewDidLoad ( ) {
super . viewDidLoad ( )
NotificationCenter . defaultCenter ( ) . addObserver ( self ,
selector : #selector ( updateUI ) ,
name : TweakProviderDidChangeNotification ,
object : nil )
}
@ objc func updateUI ( ) {
// update the UI accordingly
}
JustTweak est livré avec trois fournisseurs de tweak à l'extérieur de la boîte:
UserDefaultsTweakProvider
qui est mutable et utilise UserDefaults
comme magasin de clé / valeurLocalTweakProvider
qui est en lecture seule et utilise un fichier JSON qui est destiné à contenir la configuration de la fonctionnalité par défautEphemeralTweakProvider
qui est simplement une instance de NSMutableDictionary
De plus, JustTweak définit les protocoles TweakProvider
et MutableTweakProvider
que vous pouvez implémenter pour créer votre propre fournisseur de tweak pour répondre à vos besoins. Dans l'exemple du projet, vous pouvez trouver quelques exemples que vous pouvez utiliser comme point de départ.
JustTweak offre la possibilité d'ajouter un decryptionClosure
à un TweakProvider
. Cette fermeture prend le Tweak
en entrée et renvoie un TweakValue
en tant que sortie. La fermeture vous permet de faire du prétraitement sur votre ajustement qui peut être utilisé par exemple pour décrypter les valeurs. Cela peut être utilisé si vous avez une valeur cryptée dans votre fichier JSON Tweaks comme on peut le voir ci-dessous:
"encrypted_answer_to_the_universe" : {
"Title" : " Encrypted definitive answer " ,
"Description" : " Encrypted answer to the Ultimate Question of Life, the Universe, and Everything " ,
"Group" : " General " ,
"Value" : " 24 ton yletinifeD " ,
"GeneratedPropertyName" : " definitiveAnswerEncrypted " ,
"Encrypted" : true
}
Notez que vous devez spécifier si la valeur est chiffrée dans votre fichier JSON (avec la propriété Encrypted
) pour la fermeture de décryptage pour traiter la valeur. La fermeture de décryptage pour le JSON ci-dessus peut être spécifiée comme suit:
tweakProvider . decryptionClosure = { tweak in
// decrypt `tweak.value` with your cypher of choice and return the decrypted value
}
De cette façon, le tweak récupéré du fournisseur de tweak aura la valeur décryptée.
JustTweak est disponible sous la licence Apache 2.0. Voir le fichier de licence pour plus d'informations.