diff --git a/.gitignore b/.gitignore index 3b5517d..4e395b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp .DS_Store -.dart_tool/ +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +# .vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies .packages +.pub-cache/ .pub/ +/build/ -build/ +# Symbolication related +app.*.symbols -# IntelliJ -*.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/assetWizardSettings.xml -.idea/dictionaries -.idea/libraries -.idea/caches +# Obfuscation related +app.*.map.json +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release #Ignore thumbnails created by Windows Thumbs.db diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 117351f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index dc7311b..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.idea/runConfigurations/example_lib_main_dart.xml b/.idea/runConfigurations/example_lib_main_dart.xml deleted file mode 100644 index 5fd9159..0000000 --- a/.idea/runConfigurations/example_lib_main_dart.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 25de80d..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1628727602623 - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.metadata b/.metadata deleted file mode 100644 index 9fc7ede..0000000 --- a/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 0b8abb4724aa590dd0f429683339b1e045a1594d - channel: stable - -project_type: plugin diff --git a/android/src/main/kotlin/org/jezequel/secure_application/SecureApplicationPlugin.kt b/android/src/main/kotlin/org/jezequel/secure_application/SecureApplicationPlugin.kt index 4f0b3ac..dea620c 100644 --- a/android/src/main/kotlin/org/jezequel/secure_application/SecureApplicationPlugin.kt +++ b/android/src/main/kotlin/org/jezequel/secure_application/SecureApplicationPlugin.kt @@ -50,7 +50,7 @@ public class SecureApplicationPlugin: FlutterPlugin, MethodCallHandler, Activity } - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { instance = SecureApplicationPlugin() val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "secure_application") channel.setMethodCallHandler(instance) @@ -78,18 +78,26 @@ public class SecureApplicationPlugin: FlutterPlugin, MethodCallHandler, Activity } } - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "secure") { - activity?.window?.addFlags(LayoutParams.FLAG_SECURE) - result.success(true) - } else if (call.method == "open") { - activity?.window?.clearFlags(LayoutParams.FLAG_SECURE) - result.success(true) - } else { - result.success(true) + override fun onMethodCall(call: MethodCall, result: Result) { + when (call.method) { + "secure" -> { + activity?.window?.addFlags(LayoutParams.FLAG_SECURE) + result.success(true) + } + "open" -> { + activity?.window?.clearFlags(LayoutParams.FLAG_SECURE) + result.success(true) + } + "opacity" -> { + // Implementation available only on ios + result.success(true) + } + else -> { + result.notImplemented() + } } } - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { } } diff --git a/example/ios/Podfile b/example/ios/Podfile index 1e8c3c9..313ea4a 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1a3f02c..0740c0e 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -2,21 +2,27 @@ PODS: - Flutter (1.0.0) - secure_application (0.0.1): - Flutter + - url_launcher_ios (0.0.1): + - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - secure_application (from `.symlinks/plugins/secure_application/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) EXTERNAL SOURCES: Flutter: :path: Flutter secure_application: :path: ".symlinks/plugins/secure_application/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 secure_application: 27d424e8c2e770f63e38e280b5a51f921aa9b0c8 + url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d -COCOAPODS: 1.10.1 +COCOAPODS: 1.12.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index d605d68..6427efd 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -121,7 +121,6 @@ 502301990184875FCF6A4E97 /* Pods-Runner.release.xcconfig */, 17B764A4A20FF79E31940E05 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -358,7 +357,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = org.jezequel.example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -467,7 +469,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -480,10 +483,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DZA2GZYF9B; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = org.jezequel.example; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = example.secure.application.kuama; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -501,7 +508,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = org.jezequel.example; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/example/lib/main.dart b/example/lib/main.dart index 2c8ce77..d3e4fa6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:secure_application/secure_application.dart'; +import 'package:url_launcher/url_launcher.dart'; void main() => runApp(MaterialApp(home: MyApp())); @@ -88,6 +89,13 @@ class _MyAppState extends State { child: Scaffold( appBar: AppBar( title: const Text('Secure Window Example'), + actions: [ + IconButton( + onPressed: () => + launchUrl(Uri.parse('https://example.com')), + icon: const Icon(Icons.share), + ), + ], ), body: Center( child: Builder(builder: (context) { @@ -125,19 +133,19 @@ class _MyAppState extends State { child: Text('Secure app'), ), ), - if (failedAuth == null) + if (failedAuth) Text( 'Lock the app then switch to another app and come back'), - if (failedAuth != null) - failedAuth - ? Text( - 'Auth failed we cleaned sensitive data', - style: TextStyle(color: Colors.red), - ) - : Text( - 'Auth success', - style: TextStyle(color: Colors.green), - ), + if (failedAuth) + Text( + 'Auth failed we cleaned sensitive data', + style: TextStyle(color: Colors.red), + ) + else + Text( + 'Auth success', + style: TextStyle(color: Colors.green), + ), FlutterLogo( size: width, ), diff --git a/example/pubspec.lock b/example/pubspec.lock index b5e1268..0fed498 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,58 +5,58 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.17.0" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + sha256: a937da4c006989739ceb4d10e3bd6cce64ca85d0fe287fc5b2b9f6ee757dcee6 + url: "https://pub.dev" source: hosted version: "0.1.3" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -66,7 +66,8 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "0ba8a1854c2098ddbd043e47eb28451a13f4cab7db9b2696f13a39fd8853421d" + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_test: @@ -83,37 +84,58 @@ packages: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.6.5" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" + source: hosted + version: "0.12.13" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.8.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.8.2" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" source: hosted - version: "0.26.0" + version: "0.27.7" secure_application: dependency: "direct dev" description: @@ -130,58 +152,122 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.3" - typed_data: + version: "0.4.16" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" + url: "https://pub.dev" + source: hosted + version: "6.1.10" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "40612cd31902fe46b5158693faa65781b1ca7adfb883d77fa6f0d6dcf0317d85" + url: "https://pub.dev" + source: hosted + version: "6.0.30" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_macos: dependency: transitive description: - name: typed_data - url: "https://pub.dartlang.org" + name: url_launcher_macos + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "3.0.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" + url: "https://pub.dev" + source: hosted + version: "2.0.16" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" + url: "https://pub.dev" + source: hosted + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.20.0" + dart: ">=2.18.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cccb0c3..d4d5dda 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -13,6 +13,8 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 + url_launcher: ^6.1.10 + dev_dependencies: flutter_test: sdk: flutter diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 68a06fa..0000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,13 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:secure_application_example/main.dart'; - -void main() {} diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index b359ee1..d0dcaa2 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -2,11 +2,16 @@ // Generated file. Do not edit. // +// clang-format off + #include "generated_plugin_registrant.h" #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { SecureApplicationPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("SecureApplicationPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/example/windows/flutter/generated_plugin_registrant.h b/example/windows/flutter/generated_plugin_registrant.h index 9846246..dc139d8 100644 --- a/example/windows/flutter/generated_plugin_registrant.h +++ b/example/windows/flutter/generated_plugin_registrant.h @@ -2,6 +2,8 @@ // Generated file. Do not edit. // +// clang-format off + #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index 6a5fe7f..8dd4cd0 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -4,6 +4,10 @@ list(APPEND FLUTTER_PLUGIN_LIST secure_application + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) @@ -14,3 +18,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/ios/Classes/SwiftSecureApplicationPlugin.swift b/ios/Classes/SwiftSecureApplicationPlugin.swift index 2fab50e..c4435cc 100644 --- a/ios/Classes/SwiftSecureApplicationPlugin.swift +++ b/ios/Classes/SwiftSecureApplicationPlugin.swift @@ -3,10 +3,9 @@ import UIKit public class SwiftSecureApplicationPlugin: NSObject, FlutterPlugin { var secured = false; + var secureView = UIVisualEffectView() var opacity: CGFloat = 0.2; - var backgroundTask: UIBackgroundTaskIdentifier! - internal let registrar: FlutterPluginRegistrar init(registrar: FlutterPluginRegistrar) { @@ -20,82 +19,63 @@ public class SwiftSecureApplicationPlugin: NSObject, FlutterPlugin { let instance = SwiftSecureApplicationPlugin(registrar: registrar) registrar.addMethodCallDelegate(instance, channel: channel) } - - public func applicationWillResignActive(_ application: UIApplication) { - if ( secured ) { - self.registerBackgroundTask() - UIApplication.shared.ignoreSnapshotOnNextApplicationLaunch() - if let window = UIApplication.shared.windows.filter({ (w) -> Bool in - return w.isHidden == false - }).first { - if let existingView = window.viewWithTag(99699), let existingBlurrView = window.viewWithTag(99698) { - window.bringSubviewToFront(existingView) - window.bringSubviewToFront(existingBlurrView) - return - } else { - let colorView = UIView(frame: window.bounds); - colorView.tag = 99699 - colorView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - colorView.backgroundColor = UIColor(white: 1, alpha: opacity) - window.addSubview(colorView) - window.bringSubviewToFront(colorView) - - let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.extraLight) - let blurEffectView = UIVisualEffectView(effect: blurEffect) - blurEffectView.frame = window.bounds - blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - - blurEffectView.tag = 99698 - - window.addSubview(blurEffectView) - window.bringSubviewToFront(blurEffectView) - window.snapshotView(afterScreenUpdates: true) - RunLoop.current.run(until: Date(timeIntervalSinceNow:0.5)) - } - } - self.endBackgroundTask() - } - } - func registerBackgroundTask() { - self.backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in - self?.endBackgroundTask() - } - assert(self.backgroundTask != UIBackgroundTaskIdentifier.invalid) + + public func applicationWillEnterForeground(_ application: UIApplication) { + self.unlockApp() } - func endBackgroundTask() { - print("Background task ended.") - UIApplication.shared.endBackgroundTask(backgroundTask) - backgroundTask = UIBackgroundTaskIdentifier.invalid + public func applicationWillResignActive(_ application: UIApplication) { + if !secured { return } + self.lockApp() } - + + public func applicationDidBecomeActive(_ application: UIApplication) { + self.unlockApp() + } + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - if (call.method == "secure") { + switch (call.method) { + case "secure": secured = true; + result(nil) + case "open": + secured = false; + self.unlockApp() + result(nil) + case "opacity": if let args = call.arguments as? Dictionary, - let opacity = args["opacity"] as? NSNumber { + let opacity = args["opacity"] as? NSNumber { self.opacity = opacity as! CGFloat } - } else if (call.method == "open") { - secured = false; - } else if (call.method == "opacity") { - if let args = call.arguments as? Dictionary, - let opacity = args["opacity"] as? NSNumber { - self.opacity = opacity as! CGFloat - } - } else if (call.method == "unlock") { - if let window = UIApplication.shared.windows.filter({ (w) -> Bool in - return w.isHidden == false - }).first, let view = window.viewWithTag(99699), let blurrView = window.viewWithTag(99698) { - UIView.animate(withDuration: 0.5, animations: { - view.alpha = 0.0 - blurrView.alpha = 0.0 - }, completion: { finished in - view.removeFromSuperview() - blurrView.removeFromSuperview() - - }) - } + result(nil) + default: + result(FlutterMethodNotImplemented) } } + + private func unlockApp() { + UIView.animate(withDuration: 0.3, animations: { [weak self] in + guard let self else { return } + self.secureView.backgroundColor = UIColor(white: 1, alpha: 0.0) + self.secureView.effect = nil + }, completion: { [weak self] (_) in + guard let self else { return } + self.secureView.removeFromSuperview() + }) + } + + private func lockApp() { + let window = UIApplication.shared.windows.first + + if let window, !self.secureView.isDescendant(of: window) { + self.secureView.frame = window.bounds + UIView.animate(withDuration: 0.3) { [weak self] in + guard let self else { return } + self.secureView.backgroundColor = UIColor(white: 1, alpha: self.opacity) + self.secureView.effect = UIBlurEffect(style: .light) + } + window.addSubview(self.secureView) + window.snapshotView(afterScreenUpdates: true) + } + } } diff --git a/lib/secure_application.dart b/lib/secure_application.dart index 70acb6d..446ff62 100644 --- a/lib/secure_application.dart +++ b/lib/secure_application.dart @@ -1,16 +1,16 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; +import 'package:secure_application/secure_application_controller.dart'; import 'package:secure_application/secure_application_native.dart'; import 'package:secure_application/secure_application_provider.dart'; import 'package:secure_application/secure_application_state.dart'; -import 'package:secure_application/secure_application_controller.dart'; export './secure_application.dart'; -export './secure_gate.dart'; +export './secure_application_controller.dart'; export './secure_application_provider.dart'; export './secure_application_state.dart'; -export './secure_application_controller.dart'; +export './secure_gate.dart'; /// Widget that will manage Secure Gates and visibility protection for your app content /// @@ -22,6 +22,8 @@ class SecureApplication extends StatefulWidget { /// This will remove IOs glass effect from native automatically. To set to true (default) if you don't want to manage it /// you can play with the [nativeRemoveDelay] to avoid iOS unsecure flicker + @Deprecated( + 'It is handled internally on ios getting the same behavior as on android. This flag will no longer have any effect') final bool autoUnlockNative; /// Method will be called when the user switch back to your application @@ -83,7 +85,6 @@ class _SecureApplicationState extends State return _secureApplicationController!; } - bool _removeNativeOnNextFrame = false; @override void initState() { _authStreamSubscription = @@ -116,17 +117,12 @@ class _SecureApplicationState extends State void didChangeAppLifecycleState(AppLifecycleState state) async { switch (state) { case AppLifecycleState.resumed: - if (mounted) { - setState(() => _removeNativeOnNextFrame = true); - } else { - _removeNativeOnNextFrame = true; - } if (!secureApplicationController.paused) { if (secureApplicationController.secured && secureApplicationController.value.locked) { if (widget.onNeedUnlock != null) { secureApplicationController.pause(); - var authStatus = + final authStatus = await widget.onNeedUnlock!(secureApplicationController); if (authStatus != null) secureApplicationController.sendAuthenticationEvent(authStatus); @@ -138,7 +134,6 @@ class _SecureApplicationState extends State } secureApplicationController.resumed(); } - super.didChangeAppLifecycleState(state); break; case AppLifecycleState.paused: if (!secureApplicationController.paused) { @@ -146,22 +141,15 @@ class _SecureApplicationState extends State secureApplicationController.lock(); } } - super.didChangeAppLifecycleState(state); break; default: - super.didChangeAppLifecycleState(state); break; } + super.didChangeAppLifecycleState(state); } @override Widget build(BuildContext context) { - if (_removeNativeOnNextFrame && widget.autoUnlockNative) { - Future.delayed(Duration(milliseconds: widget.nativeRemoveDelay)) - .then((_) => SecureApplicationNative.unlock()); - - _removeNativeOnNextFrame = false; - } return SecureApplicationProvider( secureData: secureApplicationController, child: widget.child, diff --git a/lib/secure_application_controller.dart b/lib/secure_application_controller.dart index 648ece8..f5baaa0 100644 --- a/lib/secure_application_controller.dart +++ b/lib/secure_application_controller.dart @@ -94,7 +94,6 @@ class SecureApplicationController /// content under [SecureGate] will not be visible void lock() { - SecureApplicationNative.lock(); if (!value.locked) { value = value.copyWith(locked: true); notifyListeners(); @@ -108,8 +107,6 @@ class SecureApplicationController /// Use when you want your user to see content under [SecureGate] void unlock() { - SecureApplicationNative - .unlock(); //lock from native is removed when resumed but why not! if (value.locked) { value = value.copyWith(locked: false); notifyListeners(); @@ -119,7 +116,6 @@ class SecureApplicationController /// temporary prevent the app from locking if use leave and come back to the app void pause() { - SecureApplicationNative.lock(); if (!value.paused) { value = value.copyWith(paused: true); notifyListeners(); @@ -142,7 +138,7 @@ class SecureApplicationController /// App will be secured and content will not be visible if user switch app /// - /// on Android this will also prevent scrensshot/screen recording + /// on Android this will also prevent screenshot/screen recording void secure() { SecureApplicationNative.secure(); if (!value.secured) { diff --git a/lib/secure_application_native.dart b/lib/secure_application_native.dart index 6f710c0..2448f67 100644 --- a/lib/secure_application_native.dart +++ b/lib/secure_application_native.dart @@ -1,19 +1,22 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; class SecureApplicationNative { static const MethodChannel _channel = const MethodChannel('secure_application'); + /// Implemented only in windows static void registerForEvents(VoidCallback lock, VoidCallback unlock) { _channel.setMethodCallHandler( (call) => secureApplicationHandler(call, lock, unlock)); } - static Future secureApplicationHandler( - MethodCall methodCall, lock, unlock) async { + static Future secureApplicationHandler( + MethodCall methodCall, + VoidCallback lock, + VoidCallback unlock, + ) async { switch (methodCall.method) { case 'lock': lock(); @@ -26,23 +29,28 @@ class SecureApplicationNative { } } - static Future secure() { + /// App will be secured and content will not be visible if user switch app + /// + /// on Android this will also prevent screenshot/screen recording + static Future secure() { return _channel.invokeMethod('secure'); } - static Future open() { + /// App will no longer be secured and content will be visible if user switch app + static Future open() { return _channel.invokeMethod('open'); } - static Future lock() { - return _channel.invokeMethod('lock'); - } + /// Temporary prevent the app from locking if use leave and come back to the app + @Deprecated('It never did anything') + static Future lock() async {} - static Future unlock() { - return _channel.invokeMethod('unlock'); - } + /// Use when you want your user to see content + @Deprecated('It never did anything') + static Future unlock() async {} - static Future opacity(double opacity) { - return _channel.invokeMethod('opacity', {"opacity": opacity}); + /// Only work on ios + static Future opacity(double opacity) { + return _channel.invokeMethod('opacity', {'opacity': opacity}); } } diff --git a/lib/secure_application_state.dart b/lib/secure_application_state.dart index ee66078..6987504 100644 --- a/lib/secure_application_state.dart +++ b/lib/secure_application_state.dart @@ -7,6 +7,7 @@ class SecureApplicationState { final bool secured; final bool paused; final bool authenticated; + SecureApplicationState({ this.locked = false, this.secured = false, diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 0de7638..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,173 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: "direct main" - description: - name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - rxdart: - dependency: "direct main" - description: - name: rxdart - url: "https://pub.dartlang.org" - source: hosted - version: "0.26.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.20.0"