Expose ability to update tweaks programmatically
johntmcintosh opened this issue · 2 comments
I have a use-case where it would be very helpful for me to be able to update the value of a tweak programmatically. I found a discussion of this from awhile back in #66 that was specifically related to unit tests. I'll be happy to put up a PR with the change, but first wanted to see if it was a change you'd be open to accepting.
In my situation, I'm building out SwiftTweak controllable simulations of various services that the app connects to. For example, rather the having the app talk directly to CLLocationManager for location services, I'm putting CLLocationManager behind a protocol and allowing a Tweak in debug builds to swap out whether the app is talking to the real location manager or my simulated one. In the case of the simulated one, I allow a Tweak to modify whether the simulated location manager thinks that the user has enabled location services.
By doing this, I can easily test through the screens in the app that are related to requesting permission from the user. We have some custom UI that we show before presenting the system dialog, and it's difficult to test those flows without the ability to mock location services. In this mock state, we also simulate the system permissions dialog, so I would like to be able to programmatically update the Tweak with the user's selection.
Would you be open to a PR exposing the ability to do this?
Hey John!
(Thank you for checking before writing up a PR!)
One of the benefits of using a tool like SwiftTweaks (or Facebook’s Tweaks) is that we can guarantee there’s no way to ship a non-default Tweak value. If the TweakStore
is initialized with enabled: false
, then all of the tweaks are locked-down to their default value, and there’s no way for a developer to muck it up, because there’s no API for editing Tweaks!
I hear ya that it’d be nice to programmatically force certain feature-flags on-or-off, or to store user information in a few places.
In Khan Academy’s app, we use SwiftTweaks to “sometimes override” our A/B tests or feature flags. We use the StringOption
tweak to return one of three values: noOverride | alwaysOn | alwaysOff
, etc. This allows us to sometimes have our A/B test decide, and sometimes have SwiftTweaks decide a value - but we do that work outside of SwiftTweaks, so that we can build in the special features that we need to do the right thing there.
I’d prefer that we keep SwiftTweaks a purely “debug-only, no programmatic API for setting values” tool. It provides a promise to adopters that they can trust SwiftTweaks in their production code.
As for the issue you’re describing - I imagine that a simple class (let’s call it MockLocationManager
) that hides a few flags in UserDefaults
could perform many of those issues - just have a Tweak<Bool>
as a feature flag for whether-or-not to fake a user’s location permissions, and then read/write whatever you want into UserDefaults
in this MockLocationManager
class!
(Putting it all behind a protocol that MockLocationManager
and CLLocationManager
can conform to is a great choice! We’ve used that before to deprecate older Objective-C classes or for testing purposes. Nice!)
Always open to more discussion here!
We actually find similar needs. We have a tweak to control debug viewer. Instead of going to tweak menu to turn it off, we want user clicks on X button, and then programmatically change this tweak to false. This is doable in objective -c using https://github.com/facebook/Tweaks