JustTweak是iOS應用程序的功能標記框架。它提供了一個簡單的外牆接口,與多個調整的提供商相互作用,這些提供程序尊重給定的優先級。調整代表用於在客戶端代碼中驅動決策的標誌。
使用JustTweak,您可以實現以下各個方面:
JustTweak可以通過Cocoapods獲得。要安裝它,只需將以下行添加到您的podfile:
pod "JustTweak"
JustTweak也可以通過SPM獲得。複製此存儲庫的URL,然後在項目設置中添加包裝。
LocalTweakProvider
JSON文件,包括您的功能。有關起點,請參閱LocalTweaks_example.json
。要配置堆棧,您有兩個選項:
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
支持的功能實現屬性和常數。有關起點,請參閱TweakAccessor.swift
。 config.json
文件中定義堆棧配置: {
"accessorName" : " GeneratedTweakAccessor "
}
當前唯一支持的值是定義生成類的名稱的accessorName
。
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
每次構建目標時,代碼生成器工具都會重新生成堆棧的代碼。它將包含備份LocalTweakProvider
中定義的功能的所有屬性。
如果您使用了代碼生成器工具,則生成的堆棧包括所有功能標誌。只需分配訪問器對象(您在.json
配置中定義的名稱,然後使用它來訪問功能標誌。
let accessor = GeneratedTweakAccessor ( with : < #tweak_manager_instance# > )
if accessor . meaningOfLife == 42 {
...
}
有關生成的代碼的示例,請參見GeneratedTweakAccessor.swift
和GeneratedTweakAccessor+Constants.swift
。
如果您決定自己實現堆棧代碼,則必須實現通過TweakManager
訪問功能的代碼。
可以從TweakManager
實例訪問JustTweak的三個主要功能來驅動代碼路徑決策。
// check for a feature to be enabled
let enabled = tweakManager . isFeatureEnabled ( " some_feature " )
if enabled {
// enable the feature
} else {
// default behaviour
}
TweakManager
將從優先級最高的調整提供商返回該值,如果找不到設定值,則會自動退回給其他值。當發現零調整時,它可以根據需要捕獲和處理。使用tweakWith(feature:variable:)
或提供的屬性包裝器。
// 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
}
或帶有do-catch
// 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
和@FallbackTweakProperty
屬性包裝器可用於標記代表功能標誌的屬性。請注意,為了使用這些屬性包裝器,需要一個TweakManager
的靜態實例。
@ 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
tweakProviders
數組中對象的順序定義了調整提供商的優先級。
具有最高優先級的MutableTweakProvider
,例如上面示例中的UserDefaultsTweakProvider
,將用於反映UI中所做的更改( TweakViewController
)。 LocalTweakProvider
應該具有最低的優先級,因為它提供了本地調整提供商的默認值,並且是TweakViewController
使用的默認值。
為了從手冊遷移到代碼生成的實現,有必要更新為新的.json
格式。為了協助此過程,我們已將GeneratedPropertyName
屬性添加到調整對像中。設置此值以與代碼中的當前屬性名稱保持一致,以使生成的訪問屬性匹配您現有的實現。
TweakManager
提供了緩存調整值以提高性能的選項。默認情況下禁用緩存,但可以通過useCache
屬性啟用。啟用後,有兩種重置緩存的方法:
TweakManager
上調用resetCache
方法TweakProviderDidChangeNotification
通知JustTweak帶有一個ViewController,該視圖允許用戶編輯具有最高優先級的MutableTweakProvider
。
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 )
}
當在任何MutableTweakProvider
中修改值時,發出通知,以使客戶有機會反應並反映UI的變化。
override func viewDidLoad ( ) {
super . viewDidLoad ( )
NotificationCenter . defaultCenter ( ) . addObserver ( self ,
selector : #selector ( updateUI ) ,
name : TweakProviderDidChangeNotification ,
object : nil )
}
@ objc func updateUI ( ) {
// update the UI accordingly
}
JustTweak帶有三個開箱即用的調整提供商:
UserDefaultsTweakProvider
是可變的,並使用UserDefaults
用作密鑰/值存儲LocalTweakProvider
,它是僅讀取的,並使用旨在保存默認功能標記設置的JSON文件EphemeralTweakProvider
,這只是NSMutableDictionary
的實例此外,JustTweak定義了TweakProvider
和MutableTweakProvider
協議,您可以實現以創建自己的調整提供商以滿足您的需求。在示例項目中,您可以找到一些可以用作起點的示例。
JustTweak提供了在TweakProvider
中添加decryptionClosure
的能力。此封閉將Tweak
作為輸入,並返回一個TweakValue
作為輸出。閉合使您可以對調整進行一些預處理,例如可以使用來解密值。如果您在調整JSON文件中具有加密值,則可以使用此方法,如下所示:
"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
}
請注意,您必須指定該值是否在JSON文件(帶有Encrypted
屬性)中加密,以進行解密閉合以處理該值。上述JSON的解密閉合可以指定如下:
tweakProvider . decryptionClosure = { tweak in
// decrypt `tweak.value` with your cypher of choice and return the decrypted value
}
這樣,從調整提供商那裡獲取的調整將具有解密的價值。
JustTweak可在Apache 2.0許可下使用。有關更多信息,請參見許可證文件。