Flutter: disable screenshot capture for app - dart

I am making a Flutter app and I need to make sure the user is not able to capture screenshot of the app (any screen). Is there any way to achieve this in Flutter or do I need to write native code for both Android and IOS?

Android
Method 1 (all app screens):
Locate your MainActivity (.java or .kt) class inside the embedded android project dir in your Flutter Project,
Add the following import to your main activity class:
import android.view.WindowManager.LayoutParams;
Add the following line to your MainActivity's onCreate method:
getWindow().addFlags(LayoutParams.FLAG_SECURE);
Method 2 (for specific screens):
Use FlutterWindowManagerPlugin:
https://pub.dev/packages/flutter_windowmanager
Thanks, #Kamlesh!

It's only in iOS,just modify in AppDelegate.
And no more plugins
import UIKit
import Flutter
import Firebase
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.window.makeSecure() //Add this line
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
//And this extension
extension UIWindow {
func makeSecure() {
let field = UITextField()
field.isSecureTextEntry = true
self.addSubview(field)
field.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
field.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
self.layer.superlayer?.addSublayer(field.layer)
field.layer.sublayers?.first?.addSublayer(self.layer)
}
}
See image here

For Flutter2 project
Method 1 : using package flutter_windowmanager
Method 2 :
in Android with kotlin
Step 1 Open the file "mainActivity.kt" using the path
android\app\src\main\kotlin\com\example\auth_email\MainActivity.kt
Step 2 Import Library
import android.view.WindowManager.LayoutParams
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
Step 3 In main activity class
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
window.addFlags(LayoutParams.FLAG_SECURE)
super.configureFlutterEngine(flutterEngine)
}
}
In iOS Swift : AppDelegate.swift file
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// <Add>
override func applicationWillResignActive(
_ application: UIApplication
) {
self.window.isHidden = true;
}
override func applicationDidBecomeActive(
_ application: UIApplication
) {
self.window.isHidden = false;
}
}

The simplest way to do this is to use a flutter package called flutter_windowmanager
Works only for Android, not for IOS!
First import its latest version in pubspec.yaml file of your Flutter project and run pub get. Then add the below code inside the widget's initState() method for which you want to disable screenshot and screen recording.
Future<void> secureScreen() async {
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
}
#override
void initState() {
secureScreen();
super.initState();
}
#override
void dispose(){
super.dispose();
await FlutterWindowManager.clearFlags(FlutterWindowManager.FLAG_SECURE);
}
If you want to make your whole app screenshot disable just call securescreen() method (defined above) inside your main() function in main.dart file.

What worked for me was writing the below code in MainActivity.java file.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
}
and importing these packages!
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.os.Bundle; // required for onCreate parameter

On iOS I have disabled taking of screenshots with the help of extension https://stackoverflow.com/a/67054892/4899849. Follow next steps:
Add property in AppDelegate:
var field = UITextField()
in didFinishLaunchingWithOptions call next method: addSecuredView()
private func addSecuredView() {
if (!window.subviews.contains(field)) {
window.addSubview(field)
field.centerYAnchor.constraint(equalTo: window.centerYAnchor).isActive = true
field.centerXAnchor.constraint(equalTo: window.centerXAnchor).isActive = true
window.layer.superlayer?.addSublayer(field.layer)
field.layer.sublayers?.first?.addSublayer(window.layer)
}
}
override delegate methods:
override func applicationWillResignActive(_ application: UIApplication) {
field.isSecureTextEntry = false
}
override func applicationDidBecomeActive(_ application: UIApplication) {
field.isSecureTextEntry = true
}
Now, when you make a screenshot in the app or record a screen video you will see a black image or video. Hope, it will help cuz I spent 2 days trying to make it work)

Flutter
Method 1: Using this package screen_protector
Method 2:
In Whole your Application
Open AppDelegate file and add UITextField variable.
private var textField = UITextField()
Create a function in AppDelegate file.
// Screenshot Prevent Functions
private func makeSecureYourScreen() {
if (!self.window.subviews.contains(textField)) {
self.window.addSubview(textField)
textField.centerYAnchor.constraint(equalTo: self.window.centerYAnchor).isActive = true
textField.centerXAnchor.constraint(equalTo: self.window.centerXAnchor).isActive = true
self.window.layer.superlayer?.addSublayer(textField.layer)
textField.layer.sublayers?.first?.addSublayer(self.window.layer)
}
}
Call this method into the didFinishLaunchingWithOptions function.
makeSecureYourScreen()
Code Screenshot
In Specific Screen - Using Method Channel
Open AppDelegate file and add UITextField variable.
private var textField = UITextField()
Create a function in AppDelegate file.
// Screenshot Prevent Functions
private func makeSecureYourScreen() {
if (!self.window.subviews.contains(textField)) {
self.window.addSubview(textField)
textField.centerYAnchor.constraint(equalTo: self.window.centerYAnchor).isActive = true
textField.centerXAnchor.constraint(equalTo: self.window.centerXAnchor).isActive = true
self.window.layer.superlayer?.addSublayer(textField.layer)
textField.layer.sublayers?.first?.addSublayer(self.window.layer)
}
}
Call this method into the didFinishLaunchingWithOptions function.
makeSecureYourScreen()
Also, add your method channel code in the didFinishLaunchingWithOptions function.
let controller : FlutterViewController = self.window?.rootViewController as! FlutterViewController
let securityChannel = FlutterMethodChannel(name: "secureScreenshotChannel", binaryMessenger: controller.binaryMessenger)
securityChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
if call.method == "secureiOS" {
self.textField.isSecureTextEntry = true
} else if call.method == "unSecureiOS" {
self.textField.isSecureTextEntry = false
}
})
Add your code below code to your flutter files to disable the screenshot on a specific screen.
// Declare your method channel varibale here
var iosSecureScreenShotChannel = const MethodChannel('secureScreenshotChannel');
Now add code to initState to prevent screenshot
#override
void initState() {
// this method to user can't take screenshots of your application
iosSecureScreenShotChannel.invokeMethod("secureiOS");
// TODO: implement initState
super.initState();
}
For add code to dispose to allow screenshots on another screen.
#override
void dispose() {
// this method to the user can take screenshots of your application
iosSecureScreenShotChannel.invokeMethod("unSecureiOS");
// TODO: implement dispose
super.dispose();
}
Code Screenshot in Xcode
Code Screenshot in Flutter
You can disable screenshots and video captures like the Netflix app and Disney Hotstar app.
I have tried it in my application and it works fine. 😊

Screenshots can be prevented very easily by following below two steps.
I am using VS code.
Step 1 Open the file "mainActivity.kt" using the path android\app\src\main\kotlin\com\example\auth_email\MainActivity.kt
Step 2 Add the two lines
(a) import android.view.WindowManager.LayoutParams;
(b) getWindow().addFlags(LayoutParams.FLAG_SECURE); in MainActivity: FlutterActivity() section
Restart the app
enter image description here

This works for iOS. In your Runner > AppDelegate.m:
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)applicationWillResignActive:(UIApplication *)application{
self.window.hidden = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
self.window.hidden = NO;
}
#end

If you are using kotlin
open MainActivity.kt
Add below code at end of imports
import android.view.WindowManager.LayoutParams
Add below code at end of super.onCreate(savedInstanceState)
window.addFlags(LayoutParams.FLAG_SECURE)
Its done.

try to use
for android edit MainActivity.kt
package com.package.app_name
import android.view.WindowManager.LayoutParams
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
window.addFlags(LayoutParams.FLAG_SECURE)
super.configureFlutterEngine(flutterEngine)
}
}

define this package inside pubspec.yaml file
flutter_windowmanager: ^0.0.1+1
get dependencies
flutter pub get
You need to call a method of FlutterWindowManager using await and async.
You have to add a few lines of code in your StatefulWidget.
Future<void> secureScreen() async {
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
}
#override
void initState() {
secureScreen();
super.initState();
}

https://pub.dev/packages/screen_protector
use this one. works for Android, iOS both.
In iOS, screenshot will be captured but output will be black screen.

You can use the flutter_windowmanager: ^0.2.0 package to disable screenshot capture in a Flutter app. To do this, add the following code in your main.dart file:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
runApp(MyApp());
}
This will add the FLAG_SECURE flag to your app, which will prevent
screenshots from being captured. Note that this will only work on
Android devices.

You could maybe listen for the screenshot keys on iOS and when the combination is being pressed blacken the screen.

Related

Flutter IOS Workmanager Background Fetch Never Called in Production

I'm seemingly unable to get background fetch working with Flutter workmanager on IOS.
I can confirm that it is working when called within xcode through debug. Just never when deployed to the device.
I've got my workmanager initialised and callback setup in main.dart
...
Workmanager().initialize(
callbackDispatcher,
isInDebugMode: true
);
}
void callbackDispatcher()
{
Workmanager().executeTask((task, inputData) async
{
function()
return Future.value(true);
});
}
I've added fetch background mode to info.plist
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
I've added system capabilities to project.pbxproj
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};
I've added the plugin to appdelegate.swift
import UIKit
import Flutter
import workmanager
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*15))
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Be much appreciated if anyone has a working setup.
Ok. For future people reading this with the same issue, this does 'eventually' work.
After having the app open in the background for ~48hrs, I finally got a background task to run. This is by no means a complete success as it is not really at the frequency desired, but this implementation does 'work' none the less.
Just run in debug mode to confirm and be very patient.

How to Callback from Swift Framework to Flutter project? [duplicate]

This question already has answers here:
How do I use a Flutter MethodChannel to invoke a method in dart code from the native swift code?
(3 answers)
Closed 29 days ago.
I have the framework written in Swift 5 language and now i need to integrate that framework into the new flutter project and there is more number of callbacks to notify from Swift Framework to Flutter project. In that I don't know how to do that, what is the way to callback/delegate to the flutter project from Swift Framework.
Try to use Method channels. You can call Flutter methods from Swift code and vise versa.
iOS:
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
private var flutterMethodChannel: FlutterMethodChannel?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
flutterMethodChannel = FlutterMethodChannel(
name: "packageOfYourApp",
binaryMessenger: controller.binaryMessenger
)
flutterMethodChannel?.invokeMethod(
"methodName",
arguments: nil
)
}
}
Flutter:
_someMethodChannel.setMethodCallHandler((handler) async {
if (handler.method == 'methodName') {
// Do your logic here.
} else {
print('Unknown method from MethodChannel: ${handler.method}');
}
});

Delegate methods not being called in swift class

I'm integrating an SDK that tracks location points.
The SDK demo app has the SDK framework loaded, and then a UIViewController that extends the SDK delegate. The SDK calls certain delegate functions as the user moves around - these all work fine in the demo app from the SDK provider. All the delegate callback functions, like processStart are inside the TripsViewController: UIViewController, TheSDKSwiftDelegate
Example:
import TheSDKSwift
final class TripsViewController: UIViewController, TheSDKSwiftDelegate {
...
TheSDKSwift.setup(with: configuration, delegate: self, completionHandler: {success, error in
if success {
successBlock()
} else {
failureBlock(error)
}
})
...
// TheSDK Delegate callbacks
func processStart(ofDrive startInfo: DriveStartInfo) {
self.driveStatusLabel.text = "Driving"
if self.isAccidentEnabled() {
self.mockAccidentButton.isEnabled = true
}
let dateString = DateFormatter.shortStyleFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(startInfo.startTimestamp/1000 )))
NotificationManager.displayNotification(message: "Trip Started: \(dateString)")
}
}
So during the normal running of the SDK, it then calls back to the processStart method to provide info on what's happening.
Now, in my own app, I can't have these functions/delegates in UIViewController. I need to have them in a separate Swift file and call the functions from another controller. When I do that, my SDK initializes, but the delegate methods don't get called by the SDK while it's running, whereas the delegate methods DO get called when everything is in on UIViewController extending the delegate. Just not when I put it in my own swift file.
Here's a short snippet of what I'm doing:
import Foundation
import Capacitor
#objc(TheSDKPlugin)
public class TheSDKPlugin: CAPPlugin {
#objc func SetupSDK(_ call: CAPPluginCall) {
TheSDKPluginWrapper().StartSDK()
}
So TheSDKPluginiWrapper().StartSDK() gets called.
import Foundation
import TheSDKSwift
import Capacitor
class TheSDKPluginWrapper: NSObject, TheSDKSwiftDelegate {
...
TheSDKSwift.setup(with: configuration, delegate: self, completionHandler: {success, error in
if success {
successBlock()
} else {
failureBlock(error)
}
})
...
// TheSDK Delegate callbacks
func processStart(ofDrive startInfo: DriveStartInfo) {
self.driveStatusLabel.text = "Driving"
if self.isAccidentEnabled() {
self.mockAccidentButton.isEnabled = true
}
let dateString = DateFormatter.shortStyleFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(startInfo.startTimestamp/1000 )))
NotificationManager.displayNotification(message: "Trip Started: \(dateString)")
}
}
Again, SDK initializes successfully. But now, SDK never calls the delegate method in TheSDKPluginiWrapper().
How do I retain the delegate throughout, so that SDK delegate methods get called in my swift file, same way it gets called when everything is in UIViewController?
If you want the delegate methods in a separate file, you can just define them as an extension to the class:
extension TripsViewController: TheSDKSwiftDelegate {
// TheSDK Delegate callbacks
func processStart(ofDrive startInfo: DriveStartInfo) {
}
...
}

Error: `call FirebaseApp.configure() before using Firestore`

Background Info
I have started developing a backend for an simple App, and I have set up a database class (named DBDelegate) that all the files will communicate with.
In my AppDelegate.swift I have this:
static public var dbDelegate:DBDelegate = DBDelegate()
private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
Its a static public so I can access the dbDelegate from other files.
In my other files, I have the following to help readability: (because it is a class it will pass by reference)
let dbDelegate = AppDelegate.dbDelegate
In my DBDelegate class:
var db = Firestore.firestore()
init() {
FirebaseApp.configure()
}
Building and Running
When I build my code, it builds fine.
On run, the app promptly crashes with SIGABRT.
The error message is:
Terminating app due to uncaught exception 'FIRAppNotConfiguredException', reason: 'Failed to get FirebaseApp instance. Please call FirebaseApp.configure() before using Firestore'
What I have tried
I have tried putting a breakpoint on the init function in the DBDelegate class. It does not reach the breakpoint.
I have tried making the all the dbDelegate variables lazy:
I got a compile error for the one in AppDelegate: lazy must not be used on an already-lazy global
Runtime errors for others: please call FirebaseApp.configure() before using Firestore.
I have tried the following (assigning dbDelegate in didFinishLaunchingWithOptions):
static public var dbDelegate:DBDelegate!
private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
dbDelegate = DBDelegate()
return true
}
I get Compile error: Static member 'dbDelegate' cannot be used on instance of type 'AppDelegate'
Any help would be great!
Edit: I found a janky solution, see below.
Firstly, I would like to thank #DionzB for suggesting using singletons (which I did). I will reference his/her post in this answer.
Ok, so after some research and playing with breakpoints, I found that my custom class actually executes before the AppDelegate. Knowing such, I created a variable before the following line:
static let shared = FirebaseService()
the name does not matter, because I/you will not call it, and assign it to FirebaseApp.configure()
The FirebaseService class becomes:
class FirebaseService: NSObject {
let constantToNeverTouch = FirebaseApp.configure()
static let shared = FirebaseService()
init() {
}
}
Next, you must make sure that FirebaseApp.configure() is no where else in your code. It should not be in the AppDelegate either. Having multiple FirebaseApp.configure()'s crashes the app.
You can override the AppDelegate init method with FirebaseApp.configure() and make sure it loads before any windows are created.
override init() {
FirebaseApp.configure()
}
It would be better to create a new singleton for Firebase.
class FirebaseService: NSObject {
static let shared = FirebaseService()
init() {
FirebaseApp.configure()
}
}
Then you can access everything via shared like:
FirebaseService.shared.methodName
For configuring in app delegate you would need to call it like:
_ = FirebaseService.shared
Chances are your code are in the wrong order. Make sure your window code are put AFTER the firebaseApp.configure and not before. I was getting the same crash until I simply placed my window creation codes: (window = UIWindow(frame: UIScreen.main.bounds), etc) after the firebaseApp.configure connection .Just swapped their placement:
FirebaseApp.configure()
let db = Firestore.firestore()
let settings = db.settings
settings.areTimestampsInSnapshotsEnabled = true
db.settings = settings
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = HomeController()
window?.makeKeyAndVisible()
I got the same issue because my pod version it old. So the solution is
Check your pods by using command pod --version
If pod the version is old or not the same, CocoaPods needs to update. Use comment sudo gem install CocoaPods
After it has completed you need to check your pods again use command pod --version make sure your pod version is upgraded
cd to your project directory then use command pod deintegrate
After the command completed then use pod install
Open your project workspace, build & run

How to clear NSUserDefaults programmatically in XCUITest using Simulator

I've read several answers related to this and they suggest doing one of the following, but these options are not working for me. I have an XCUITest and I'm trying to clear the standard user defaults before before running the rest of my XCUITest. Currently my test app has a button that calls this code. I've also tried calling this code directly from within the XCUITest (I'm not sure if this is expected to work or if it needs to be run from within the app).
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
I've also tried removing each individually:
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"MyKey1"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"MyKey2"];
I also tried each of the above methods followed by a synchronize call:
[[NSUserDefaults standardUserDefaults] synchronize];
The next time I read #"MyKey1" from the NSUserDefaults its still has the old value and has not been deleted.
Is there any way to remove an object from the NSUserDefaults programmatically when running an XCUITest in the simulator? These are automated tests, so I can't always manually click on "Reset Contents and Settings" in xcode.
Thanks!
There are couple of ways to solve your issues by setting the UserDefaults values before your tests run the app (not after).
Solution #1
Mock UserDefaults values for certain keys using launchArguments:
func testExample() {
let app = XCUIApplication()
app.launchArguments += ["-keepScreenOnKey", "YES"]
app.launch()
}
Note the minus sign before the keepScreenOnKey key. The minus sign indicates that it should take the next launch argument value as a value for that UserDefaults key.
Solution #2 (if solution #1 doesn’t work)
The previous solution might not work if you’re using the SwiftyUserDefaults library. In this case, there is one elegant solution: if the application is running under UI tests, erase all UserDefaults data from the app. How does the app know if it is being run under UI tests? By passing the launch arguments message, like this:
override func setUp() {
super.setUp()
app.launchArguments += ["UI-Testing"]
}
Then, in AppDelegate.swift check if the app is running under UI-Testing and remove all UserDefaults data (like you do):
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
setStateForUITesting()
return true
}
static var isUITestingEnabled: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("UI-Testing")
}
}
private func setStateForUITesting() {
if AppDelegate.isUITestingEnabled {
UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
}
}
}
Solution #3 (if solution #2 is not enough)
But what if the UI test expects states other than the default state set by solution #2? Bools default to false, Integers to 0 and Strings to "", but what if you need true for the Bool key?
Do something like this:
func testExample() {
app.launchEnvironment["UI-TestingKey_keepScreenOn"] = "YES"
app.launch()
}
And then in AppDelegate.swift file:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
static let uiTestingKeyPrefix = "UI-TestingKey_"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if AppDelegate.isUITestingEnabled {
setUserDefaults()
}
return true
}
static var isUITestingEnabled: Bool {
get {
return ProcessInfo.processInfo.arguments.contains("UI-Testing")
}
}
private func setUserDefaults() {
for (key, value)
in ProcessInfo.processInfo.environment
where key.hasPrefix(AppDelegate.uiTestingKeyPrefix) {
// Truncate "UI-TestingKey_" part
let userDefaultsKey = key.truncateUITestingKey()
switch value {
case "YES":
UserDefaults.standard.set(true, forKey: userDefaultsKey)
case "NO":
UserDefaults.standard.set(false, forKey: userDefaultsKey)
default:
UserDefaults.standard.set(value, forKey: userDefaultsKey)
}
}
}
}
extension String {
func truncateUITestingKey() -> String {
if let range = self.range(of: AppDelegate.uiTestingKeyPrefix) {
let userDefaultsKey = self[range.upperBound...]
return String(userDefaultsKey)
}
return self
}
}
Please note that this example only works for Bool and String keys. If you need more scalability, the switch command should be modified to somehow check if the value is Integer or Double or Any other value, but the general idea is here.
EDIT: It looks like the reason for using solutions #2 and #3 is not valid anymore as of SwiftyUserDefaults version 4.0.0-beta.1 as they've added support for setting values through launch arguments. But, I have to admit that I have not tested SwiftyUserDefaults library from this version onward, so I'll keep both solutions here.
With UI tests, the app runs as a separate process. You would need to call the methods to clear NSUserDefaults from within the app itself.
We have our UI Test pass a resetNSUserDefaults flag to the app when it launches the app. The app then clears the NSUserDefaults early in the launch process.

Resources