diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index b988dbf4..76fa0393 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -1,18 +1,23 @@ name: code analysis & formatting -on: [push, pull_request] +on: + - push + - pull_request +defaults: + run: + shell: bash +env: + PUB_ENVIRONMENT: bot.github jobs: - analysis: + analysis_and_formatting: + name: Analysis & Formatting runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '11' - # Use the community Action to install Flutter - uses: subosito/flutter-action@v2 + with: + channel: "stable" - name: Version run: flutter doctor -v - name: Install melos @@ -24,24 +29,5 @@ jobs: run: melos bootstrap - name: Linter run: melos analyze - formatting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '11' - # Use the community Action to install Flutter - - uses: subosito/flutter-action@v2 - - name: Version - run: flutter doctor -v - - name: Install melos - run: | - flutter pub global activate melos - echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH - echo "$HOME/AppData/Local/Pub/Cache/bin" >> $GITHUB_PATH - - name: Initialize workspace through melos - run: melos bootstrap - name: Format - run: melos format --output none --set-exit-if-changed \ No newline at end of file + run: melos format --output none --set-exit-if-changed diff --git a/.github/workflows/flutter_drive.yml b/.github/workflows/flutter_drive.yml index 6176b917..c262e8a8 100644 --- a/.github/workflows/flutter_drive.yml +++ b/.github/workflows/flutter_drive.yml @@ -1,40 +1,81 @@ name: integration test -on: [pull_request] + +on: + - pull_request +defaults: + run: + shell: bash +env: + PUB_ENVIRONMENT: bot.github + jobs: drive_android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '17' - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - name: Install melos - run: | - flutter pub global activate melos - echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH - echo "$HOME/AppData/Local/Pub/Cache/bin" >> $GITHUB_PATH - - name: Initialize workspace through melos - run: melos bootstrap - - name: "Run Flutter Driver tests API 21" - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 21 + name: Android + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + matrix: + include: + - api-level: 21 target: default arch: x86 - script: "cd example && flutter drive --target=test_driver/app.dart" - working-directory: ./flutter_secure_storage - - name: "Run Flutter Driver tests API 34" - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 34 + - api-level: 34 target: google_apis arch: x86_64 - script: "cd example && flutter drive --target=test_driver/app.dart" - working-directory: ./flutter_secure_storage + fail-fast: false + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.22.x + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + cache: "gradle" + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Install melos + run: | + flutter pub global activate melos + echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH + echo "$HOME/AppData/Local/Pub/Cache/bin" >> $GITHUB_PATH + - name: Initialize workspace through melos + run: melos bootstrap + - name: Run Flutter Integration tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + target: ${{ matrix.target }} + arch: ${{ matrix.arch }} + script: flutter test integration_test + working-directory: flutter_secure_storage/example + drive_ios: + name: iOS + runs-on: macos-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.22.x + - name: Install melos + run: | + flutter pub global activate melos + echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH + echo "$HOME/AppData/Local/Pub/Cache/bin" >> $GITHUB_PATH + - name: Initialize workspace through melos + run: melos bootstrap + - uses: futureware-tech/simulator-action@v3 + with: + os: iOS + os_version: 17.5 + model: "iPhone 15" + - name: Run Flutter Integration tests + working-directory: flutter_secure_storage/example + run: flutter test integration_test diff --git a/flutter_secure_storage/example/.metadata b/flutter_secure_storage/example/.metadata index 34edbebf..6e13c773 100644 --- a/flutter_secure_storage/example/.metadata +++ b/flutter_secure_storage/example/.metadata @@ -1,11 +1,11 @@ # 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. +# This file should be version controlled and should not be manually edited. version: - revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 - channel: beta + revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 - base_revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 - - platform: ios - create_revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 - base_revision: 8c1149878bbb8f062aecfab4d825e5b87bdb4487 + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: macos + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 # User provided section diff --git a/flutter_secure_storage/example/android/.gitignore b/flutter_secure_storage/example/android/.gitignore index 1658458c..0a741cb4 100644 --- a/flutter_secure_storage/example/android/.gitignore +++ b/flutter_secure_storage/example/android/.gitignore @@ -1,9 +1,11 @@ -*.iml -.gradle +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat /local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store -/build -/captures GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/flutter_secure_storage/example/android/app/build.gradle b/flutter_secure_storage/example/android/app/build.gradle deleted file mode 100644 index f2626235..00000000 --- a/flutter_secure_storage/example/android/app/build.gradle +++ /dev/null @@ -1,56 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdk 34 - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - applicationId "com.it_nomads.fluttersecurestorageexample" - minSdkVersion flutter.minSdkVersion - targetSdkVersion 34 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - namespace 'com.it_nomads.fluttersecurestorageexample' -} - -flutter { - source '../..' -} diff --git a/flutter_secure_storage/example/android/app/build.gradle.kts b/flutter_secure_storage/example/android/app/build.gradle.kts new file mode 100644 index 00000000..97632f0f --- /dev/null +++ b/flutter_secure_storage/example/android/app/build.gradle.kts @@ -0,0 +1,64 @@ +import java.util.Properties +import java.nio.file.Files +import java.nio.file.Path + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("dev.flutter.flutter-gradle-plugin") +} + +val localProperties: Properties = Properties() +val localPropertiesFile: Path = rootProject.file("local.properties").toPath() +if (Files.exists(localPropertiesFile)) { + Files.newBufferedReader(localPropertiesFile).use { reader -> + localProperties.load(reader) + } +} + +val flutterRoot: String = localProperties.getProperty("flutter.sdk") + ?: throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + +val flutterVersionCode: String = localProperties.getProperty("flutter.versionCode") ?: "1" +val flutterVersionName: String = localProperties.getProperty("flutter.versionName") ?: "1.0" + +android { + namespace = "com.it_nomads.fluttersecurestorageexample" + + compileSdk = 34 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + + sourceSets { + named("main") { + java.srcDir("src/main/kotlin") + } + } + + defaultConfig { + applicationId = "com.it_nomads.fluttersecurestorageexample" + minSdk = flutter.minSdkVersion + targetSdk = 34 + versionCode = flutterVersionCode.toInt() + versionName = flutterVersionName + } + + buildTypes { + getByName("release") { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/flutter_secure_storage/example/android/app/src/main/java/com/it_nomads/fluttersecurestorageexample/MainActivity.java b/flutter_secure_storage/example/android/app/src/main/java/com/it_nomads/fluttersecurestorageexample/MainActivity.java deleted file mode 100644 index 2d9d6923..00000000 --- a/flutter_secure_storage/example/android/app/src/main/java/com/it_nomads/fluttersecurestorageexample/MainActivity.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.it_nomads.fluttersecurestorageexample; - -import io.flutter.embedding.android.FlutterActivity; - -public class MainActivity extends FlutterActivity { - -} diff --git a/flutter_secure_storage/example/android/app/src/main/kotlin/com/it_nomads/fluttersecurestorageexample/MainActivity.kt b/flutter_secure_storage/example/android/app/src/main/kotlin/com/it_nomads/fluttersecurestorageexample/MainActivity.kt new file mode 100644 index 00000000..ddf0de4d --- /dev/null +++ b/flutter_secure_storage/example/android/app/src/main/kotlin/com/it_nomads/fluttersecurestorageexample/MainActivity.kt @@ -0,0 +1,5 @@ +package com.it_nomads.fluttersecurestorageexample; + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/flutter_secure_storage/example/android/build.gradle b/flutter_secure_storage/example/android/build.gradle deleted file mode 100644 index e0cdd7e1..00000000 --- a/flutter_secure_storage/example/android/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.1.2' - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/flutter_secure_storage/example/android/build.gradle.kts b/flutter_secure_storage/example/android/build.gradle.kts new file mode 100644 index 00000000..405a1390 --- /dev/null +++ b/flutter_secure_storage/example/android/build.gradle.kts @@ -0,0 +1,20 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.layout.buildDirectory = file("../build") + +subprojects { + project.layout.buildDirectory = + file("${rootProject.layout.buildDirectory.get().asFile}/${project.name}") +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/flutter_secure_storage/example/android/gradle.properties b/flutter_secure_storage/example/android/gradle.properties index 853359ae..73550de2 100644 --- a/flutter_secure_storage/example/android/gradle.properties +++ b/flutter_secure_storage/example/android/gradle.properties @@ -1,6 +1,6 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableJetifier=true +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true -android.defaults.buildfeatures.buildconfig=true +android.enableJetifier=true android.nonTransitiveRClass=false android.nonFinalResIds=false +android.enableR8.fullMode=false diff --git a/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.jar b/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100755 index 13372aef..00000000 Binary files a/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.properties b/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.properties index 81fe34d9..f37db7f2 100644 --- a/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/flutter_secure_storage/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Aug 29 10:45:20 CEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip diff --git a/flutter_secure_storage/example/android/gradlew b/flutter_secure_storage/example/android/gradlew deleted file mode 100755 index 9d82f789..00000000 --- a/flutter_secure_storage/example/android/gradlew +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/flutter_secure_storage/example/android/gradlew.bat b/flutter_secure_storage/example/android/gradlew.bat deleted file mode 100755 index 8a0b282a..00000000 --- a/flutter_secure_storage/example/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/flutter_secure_storage/example/android/settings.gradle b/flutter_secure_storage/example/android/settings.gradle deleted file mode 100644 index 44e62bcf..00000000 --- a/flutter_secure_storage/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/flutter_secure_storage/example/android/settings.gradle.kts b/flutter_secure_storage/example/android/settings.gradle.kts new file mode 100644 index 00000000..a26fdfc0 --- /dev/null +++ b/flutter_secure_storage/example/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.4.1" apply false + id("org.jetbrains.kotlin.android") version "1.9.24" apply false +} + +include(":app") diff --git a/flutter_secure_storage/example/integration_test/app_test.dart b/flutter_secure_storage/example/integration_test/app_test.dart new file mode 100644 index 00000000..a23b2682 --- /dev/null +++ b/flutter_secure_storage/example/integration_test/app_test.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage_example/main.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Secure Storage Example', (WidgetTester tester) async { + await tester.pumpWidget(const MaterialApp(home: ItemsWidget())); + await tester.pumpAndSettle(); + + final HomePageObject pageObject = HomePageObject(tester); + + await pageObject.deleteAll(); + pageObject.hasNoRow(0); + + await pageObject.addRandom(); + pageObject.hasRow(0); + await pageObject.addRandom(); + pageObject.hasRow(1); + + await pageObject.editRow('Row 0', 0); + await pageObject.editRow('Row 1', 1); + + await Future.delayed(const Duration(seconds: 3)); + + pageObject.rowHasTitle('Row 0', 0); + pageObject.rowHasTitle('Row 1', 1); + + await Future.delayed(const Duration(seconds: 3)); + + await pageObject.deleteRow(1); + pageObject.hasNoRow(1); + + await Future.delayed(const Duration(seconds: 3)); + + pageObject.rowHasTitle('Row 0', 0); + await pageObject.deleteRow(0); + pageObject.hasNoRow(0); + + await Future.delayed(const Duration(seconds: 1)); + + await pageObject.isProtectedDataAvailable(); + + await pageObject.deleteAll(); + }); +} + +class HomePageObject { + HomePageObject(this.tester); + + final WidgetTester tester; + final Finder _addRandomButtonFinder = find.byKey(const Key('add_random')); + final Finder _deleteAllButtonFinder = find.byKey(const Key('delete_all')); + final Finder _popUpMenuButtonFinder = find.byKey(const Key('popup_menu')); + final Finder _isProtectedDataAvailableButtonFinder = + find.byKey(const Key('is_protected_data_available')); + + Future deleteAll() async { + expect(_popUpMenuButtonFinder, findsOneWidget); + await tester.tap(_popUpMenuButtonFinder); + await tester.pumpAndSettle(); + + expect(_deleteAllButtonFinder, findsOneWidget); + await tester.tap(_deleteAllButtonFinder); + await tester.pumpAndSettle(); + } + + Future addRandom() async { + expect(_addRandomButtonFinder, findsOneWidget); + await tester.tap(_addRandomButtonFinder); + await tester.pumpAndSettle(); + } + + Future editRow(String title, int index) async { + final Finder popupRow = find.byKey(Key('popup_row_$index')); + expect(popupRow, findsOneWidget); + await tester.tap(popupRow); + await tester.pumpAndSettle(); + + final Finder editRow = find.byKey(Key('edit_row_$index')); + expect(editRow, findsOneWidget); + await tester.tap(editRow); + await tester.pumpAndSettle(); + + final Finder textFieldFinder = find.byKey(const Key('title_field')); + expect(textFieldFinder, findsOneWidget); + await tester.tap(textFieldFinder); + await tester.pumpAndSettle(); + + await tester.enterText(textFieldFinder, title); + await tester.pumpAndSettle(); + + final Finder saveButtonFinder = find.byKey(const Key('save')); + expect(saveButtonFinder, findsOneWidget); + await tester.tap(saveButtonFinder); + await tester.pumpAndSettle(); + } + + void rowHasTitle(String title, int index) { + final Finder titleRow = find.byKey(Key('title_row_$index')); + expect(titleRow, findsOneWidget); + expect((titleRow.evaluate().single.widget as Text).data, equals(title)); + } + + void hasRow(int index) { + expect(find.byKey(Key('title_row_$index')), findsOneWidget); + } + + Future deleteRow(int index) async { + final Finder popupRow = find.byKey(Key('popup_row_$index')); + expect(popupRow, findsOneWidget); + await tester.tap(popupRow); + await tester.pumpAndSettle(); + + final Finder deleteRow = find.byKey(Key('delete_row_$index')); + expect(deleteRow, findsOneWidget); + await tester.tap(deleteRow); + await tester.pumpAndSettle(); + } + + void hasNoRow(int index) { + expect(find.byKey(Key('title_row_$index')), findsNothing); + } + + Future isProtectedDataAvailable() async { + expect(_popUpMenuButtonFinder, findsOneWidget); + await tester.tap(_popUpMenuButtonFinder); + await tester.pumpAndSettle(); + + expect(_isProtectedDataAvailableButtonFinder, findsOneWidget); + await tester.tap(_isProtectedDataAvailableButtonFinder); + await tester.pumpAndSettle(); + } +} diff --git a/flutter_secure_storage/example/ios/Podfile.lock b/flutter_secure_storage/example/ios/Podfile.lock index 4420f03e..6163a546 100644 --- a/flutter_secure_storage/example/ios/Podfile.lock +++ b/flutter_secure_storage/example/ios/Podfile.lock @@ -2,6 +2,8 @@ PODS: - Flutter (1.0.0) - flutter_secure_storage (6.0.0): - Flutter + - integration_test (0.0.1): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -9,6 +11,7 @@ PODS: DEPENDENCIES: - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) EXTERNAL SOURCES: @@ -16,12 +19,15 @@ EXTERNAL SOURCES: :path: Flutter flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" + integration_test: + :path: ".symlinks/plugins/integration_test/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 + integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 diff --git a/flutter_secure_storage/example/lib/main.dart b/flutter_secure_storage/example/lib/main.dart index 3fa03e1e..5fb014b8 100644 --- a/flutter_secure_storage/example/lib/main.dart +++ b/flutter_secure_storage/example/lib/main.dart @@ -1,8 +1,7 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:math'; +import 'dart:io' show Platform; +import 'dart:math' show Random; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -10,41 +9,50 @@ void main() { runApp(const MaterialApp(home: ItemsWidget())); } +enum _Actions { deleteAll, isProtectedDataAvailable } + +enum _ItemActions { delete, edit, containsKey, read } + class ItemsWidget extends StatefulWidget { - const ItemsWidget({Key? key}) : super(key: key); + const ItemsWidget({super.key}); @override ItemsWidgetState createState() => ItemsWidgetState(); } -enum _Actions { deleteAll, isProtectedDataAvailable } - -enum _ItemActions { delete, edit, containsKey, read } - class ItemsWidgetState extends State { - final _storage = const FlutterSecureStorage(); - final _accountNameController = + final FlutterSecureStorage _storage = const FlutterSecureStorage(); + final TextEditingController _accountNameController = TextEditingController(text: 'flutter_secure_storage_service'); - List<_SecItem> _items = []; + final List<_SecItem> _items = []; @override void initState() { super.initState(); - _accountNameController.addListener(() => _readAll()); + _accountNameController.addListener(_readAll); _readAll(); } + @override + void dispose() { + _accountNameController.removeListener(_readAll); + _accountNameController.dispose(); + + super.dispose(); + } + Future _readAll() async { - final all = await _storage.readAll( + final Map all = await _storage.readAll( iOptions: _getIOSOptions(), aOptions: _getAndroidOptions(), ); setState(() { - _items = all.entries - .map((entry) => _SecItem(entry.key, entry.value)) - .toList(growable: false); + _items + ..clear() + ..addAll(all.entries.map((e) => _SecItem(e.key, e.value))) + ..sort((a, b) => int.parse(a.key).compareTo(int.parse(b.key))); }); } @@ -57,8 +65,9 @@ class ItemsWidgetState extends State { } Future _isProtectedDataAvailable() async { - final scaffold = ScaffoldMessenger.of(context); - final result = await _storage.isCupertinoProtectedDataAvailable(); + final ScaffoldMessengerState scaffold = ScaffoldMessenger.of(context); + final bool? result = await _storage.isCupertinoProtectedDataAvailable(); + scaffold.showSnackBar( SnackBar( content: Text('Protected data available: $result'), @@ -68,12 +77,9 @@ class ItemsWidgetState extends State { } Future _addNewItem() async { - final String key = _randomValue(); - final String value = _randomValue(); - await _storage.write( - key: key, - value: value, + key: DateTime.timestamp().microsecondsSinceEpoch.toString(), + value: _randomValue(), iOptions: _getIOSOptions(), aOptions: _getAndroidOptions(), ); @@ -94,107 +100,106 @@ class ItemsWidgetState extends State { _accountNameController.text.isEmpty ? null : _accountNameController.text; @override - Widget build(BuildContext context) => Scaffold( - appBar: AppBar( - title: const Text('Plugin example app'), - actions: [ - IconButton( - key: const Key('add_random'), - onPressed: _addNewItem, - icon: const Icon(Icons.add), - ), - PopupMenuButton<_Actions>( - key: const Key('popup_menu'), - onSelected: (action) { - switch (action) { - case _Actions.deleteAll: - _deleteAll(); - break; - case _Actions.isProtectedDataAvailable: - _isProtectedDataAvailable(); - break; - } - }, - itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( - key: Key('delete_all'), - value: _Actions.deleteAll, - child: Text('Delete all'), - ), - const PopupMenuItem( - key: Key('is_protected_data_available'), - value: _Actions.isProtectedDataAvailable, - child: Text('IsProtectedDataAvailable'), - ), - ], - ), - ], - ), - body: Column( - children: [ - if (!kIsWeb && Platform.isIOS) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: TextFormField( - controller: _accountNameController, - decoration: - const InputDecoration(labelText: 'kSecAttrService'), - ), + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + actions: [ + IconButton( + key: const Key('add_random'), + onPressed: _addNewItem, + icon: const Icon(Icons.add), + ), + PopupMenuButton<_Actions>( + key: const Key('popup_menu'), + onSelected: (action) { + switch (action) { + case _Actions.deleteAll: + _deleteAll(); + case _Actions.isProtectedDataAvailable: + _isProtectedDataAvailable(); + } + }, + itemBuilder: (BuildContext context) => >[ + const PopupMenuItem( + key: Key('delete_all'), + value: _Actions.deleteAll, + child: Text('Delete all'), + ), + const PopupMenuItem( + key: Key('is_protected_data_available'), + value: _Actions.isProtectedDataAvailable, + child: Text('IsProtectedDataAvailable'), + ), + ], + ), + ], + ), + body: Column( + children: [ + if (!kIsWeb && Platform.isIOS) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: TextFormField( + controller: _accountNameController, + decoration: const InputDecoration(labelText: 'kSecAttrService'), ), - Expanded( - child: ListView.builder( - itemCount: _items.length, - itemBuilder: (BuildContext context, int index) => ListTile( - trailing: PopupMenuButton( - key: Key('popup_row_$index'), - onSelected: (_ItemActions action) => - _performAction(action, _items[index], context), - itemBuilder: (BuildContext context) => - >[ - PopupMenuItem( - value: _ItemActions.delete, - child: Text( - 'Delete', - key: Key('delete_row_$index'), - ), + ), + Expanded( + child: ListView.builder( + itemCount: _items.length, + itemBuilder: (BuildContext context, int index) => ListTile( + trailing: PopupMenuButton( + key: Key('popup_row_$index'), + onSelected: (_ItemActions action) => + _performAction(action, _items[index], context), + itemBuilder: (BuildContext context) => + >[ + PopupMenuItem( + value: _ItemActions.delete, + child: Text( + 'Delete', + key: Key('delete_row_$index'), ), - PopupMenuItem( - value: _ItemActions.edit, - child: Text( - 'Edit', - key: Key('edit_row_$index'), - ), + ), + PopupMenuItem( + value: _ItemActions.edit, + child: Text( + 'Edit', + key: Key('edit_row_$index'), ), - PopupMenuItem( - value: _ItemActions.containsKey, - child: Text( - 'Contains Key', - key: Key('contains_row_$index'), - ), + ), + PopupMenuItem( + value: _ItemActions.containsKey, + child: Text( + 'Contains Key', + key: Key('contains_row_$index'), ), - PopupMenuItem( - value: _ItemActions.read, - child: Text( - 'Read', - key: Key('contains_row_$index'), - ), + ), + PopupMenuItem( + value: _ItemActions.read, + child: Text( + 'Read', + key: Key('contains_row_$index'), ), - ], - ), - title: Text( - _items[index].value, - key: Key('title_row_$index'), - ), - subtitle: Text( - _items[index].key, - key: Key('subtitle_row_$index'), - ), + ), + ], + ), + title: Text( + _items[index].value, + key: Key('title_row_$index'), + ), + subtitle: Text( + _items[index].key, + key: Key('subtitle_row_$index'), ), ), ), - ], - ), - ); + ), + ], + ), + ); + } Future _performAction( _ItemActions action, @@ -209,13 +214,11 @@ class ItemsWidgetState extends State { aOptions: _getAndroidOptions(), ); _readAll(); - - break; case _ItemActions.edit: if (!context.mounted) return; - final result = await showDialog( + final String? result = await showDialog( context: context, - builder: (context) => _EditItemWidget(item.value), + builder: (_) => _EditItemWidget(item.value), ); if (result != null) { await _storage.write( @@ -226,10 +229,9 @@ class ItemsWidgetState extends State { ); _readAll(); } - break; case _ItemActions.containsKey: - final key = await _displayTextInputDialog(context, item.key); - final result = await _storage.containsKey(key: key); + final String key = await _displayTextInputDialog(context, item.key); + final bool result = await _storage.containsKey(key: key); if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -237,7 +239,6 @@ class ItemsWidgetState extends State { backgroundColor: result ? Colors.green : Colors.red, ), ); - break; case _ItemActions.read: final key = await _displayTextInputDialog(context, item.key); final result = @@ -248,7 +249,6 @@ class ItemsWidgetState extends State { content: Text('value: $result'), ), ); - break; } } @@ -256,33 +256,27 @@ class ItemsWidgetState extends State { BuildContext context, String key, ) async { - final controller = TextEditingController(); - controller.text = key; + final TextEditingController controller = TextEditingController(text: key); await showDialog( context: context, - builder: (context) { - return AlertDialog( - title: const Text('Check if key exists'), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('OK'), - ), - ], - content: TextField( - controller: controller, + builder: (BuildContext context) => AlertDialog( + title: const Text('Check if key exists'), + actions: [ + TextButton( + onPressed: Navigator.of(context).pop, + child: const Text('OK'), ), - ); - }, + ], + content: TextField(controller: controller), + ), ); return controller.text; } String _randomValue() { - final rand = Random(); - final codeUnits = List.generate(20, (index) { - return rand.nextInt(26) + 65; - }); + final Random rand = Random(); + final List codeUnits = + List.generate(20, (_) => rand.nextInt(26) + 65, growable: false); return String.fromCharCodes(codeUnits); } @@ -320,7 +314,7 @@ class _EditItemWidget extends StatelessWidget { } class _SecItem { - _SecItem(this.key, this.value); + const _SecItem(this.key, this.value); final String key; final String value; diff --git a/flutter_secure_storage/example/macos/.gitignore b/flutter_secure_storage/example/macos/.gitignore index d2fd3772..746adbb6 100644 --- a/flutter_secure_storage/example/macos/.gitignore +++ b/flutter_secure_storage/example/macos/.gitignore @@ -3,4 +3,5 @@ **/Pods/ # Xcode-related +**/dgph **/xcuserdata/ diff --git a/flutter_secure_storage/example/macos/Flutter/AppFrameworkInfo.plist b/flutter_secure_storage/example/macos/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 3a9c234f..00000000 --- a/flutter_secure_storage/example/macos/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - UIRequiredDeviceCapabilities - - arm64 - - MinimumOSVersion - 9.0 - - diff --git a/flutter_secure_storage/example/macos/Flutter/Debug.xcconfig b/flutter_secure_storage/example/macos/Flutter/Debug.xcconfig deleted file mode 100644 index e8efba11..00000000 --- a/flutter_secure_storage/example/macos/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/flutter_secure_storage/example/macos/Flutter/Flutter-Debug.xcconfig b/flutter_secure_storage/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/flutter_secure_storage/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_secure_storage/example/macos/Flutter/Flutter-Release.xcconfig b/flutter_secure_storage/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/flutter_secure_storage/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/flutter_secure_storage/example/macos/Flutter/Release.xcconfig b/flutter_secure_storage/example/macos/Flutter/Release.xcconfig deleted file mode 100644 index 399e9340..00000000 --- a/flutter_secure_storage/example/macos/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/flutter_secure_storage/example/macos/Podfile b/flutter_secure_storage/example/macos/Podfile index 6feac427..c795730d 100644 --- a/flutter_secure_storage/example/macos/Podfile +++ b/flutter_secure_storage/example/macos/Podfile @@ -31,13 +31,13 @@ target 'Runner' do use_modular_headers! flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) - target.build_configurations.each do |config| - config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.14' - end end end diff --git a/flutter_secure_storage/example/macos/Podfile.lock b/flutter_secure_storage/example/macos/Podfile.lock index 309774a4..e8af20e3 100644 --- a/flutter_secure_storage/example/macos/Podfile.lock +++ b/flutter_secure_storage/example/macos/Podfile.lock @@ -24,6 +24,6 @@ SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 -PODFILE CHECKSUM: ce7dbe26c78bfc7ba46736094c1e2d25982870fa +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 COCOAPODS: 1.15.2 diff --git a/flutter_secure_storage/example/macos/Runner.xcodeproj/project.pbxproj b/flutter_secure_storage/example/macos/Runner.xcodeproj/project.pbxproj index c4be3f45..fbc60377 100644 --- a/flutter_secure_storage/example/macos/Runner.xcodeproj/project.pbxproj +++ b/flutter_secure_storage/example/macos/Runner.xcodeproj/project.pbxproj @@ -21,15 +21,24 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - E45CD73893F5BFE45F83D40D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C750CFB2C1F062F3582EC1B0 /* Pods_Runner.framework */; }; + 37D5BF31BFA569A637D7F824 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E709F4ECB55EC864F19794B /* Pods_RunnerTests.framework */; }; + F34832DED3BF649CB614A94D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53988E479D6A8DD4C11D83FA /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; @@ -53,7 +62,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2DE003EC45EE74926FDBDE41 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 1E709F4ECB55EC864F19794B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -68,25 +79,45 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 53988E479D6A8DD4C11D83FA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5700AA0B5CC9A960DABC3439 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 6A412BA4BA2656225A471CEF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 93A55FE0B134677F88ED2624 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 864353CBAFBEA9E6EA9CA34D /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - C750CFB2C1F062F3582EC1B0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E8A67B2C79885F8E4DEF9875 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + AA2D7A7B6F4910F5F5345908 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + CDDFC0F540935E32A92FDFF1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + EB57D14A1F93019FBBA5F32E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 37D5BF31BFA569A637D7F824 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E45CD73893F5BFE45F83D40D /* Pods_Runner.framework in Frameworks */, + F34832DED3BF649CB614A94D /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( @@ -103,9 +134,10 @@ children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, - 72E9F3873CA23A57E77E56D2 /* Pods */, - E1DA9ECC0E2E55A3E03DA1C3 /* Frameworks */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + A6A4E9AF7B3D8C95001FEEC0 /* Pods */, ); sourceTree = ""; }; @@ -113,6 +145,7 @@ isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -152,20 +185,24 @@ path = Runner; sourceTree = ""; }; - 72E9F3873CA23A57E77E56D2 /* Pods */ = { + A6A4E9AF7B3D8C95001FEEC0 /* Pods */ = { isa = PBXGroup; children = ( - 2DE003EC45EE74926FDBDE41 /* Pods-Runner.debug.xcconfig */, - E8A67B2C79885F8E4DEF9875 /* Pods-Runner.release.xcconfig */, - 93A55FE0B134677F88ED2624 /* Pods-Runner.profile.xcconfig */, + 5700AA0B5CC9A960DABC3439 /* Pods-Runner.debug.xcconfig */, + 6A412BA4BA2656225A471CEF /* Pods-Runner.release.xcconfig */, + CDDFC0F540935E32A92FDFF1 /* Pods-Runner.profile.xcconfig */, + 864353CBAFBEA9E6EA9CA34D /* Pods-RunnerTests.debug.xcconfig */, + AA2D7A7B6F4910F5F5345908 /* Pods-RunnerTests.release.xcconfig */, + EB57D14A1F93019FBBA5F32E /* Pods-RunnerTests.profile.xcconfig */, ); path = Pods; sourceTree = ""; }; - E1DA9ECC0E2E55A3E03DA1C3 /* Frameworks */ = { + D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( - C750CFB2C1F062F3582EC1B0 /* Pods_Runner.framework */, + 53988E479D6A8DD4C11D83FA /* Pods_Runner.framework */, + 1E709F4ECB55EC864F19794B /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -173,17 +210,36 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 25D32918ED6298DCA22CD2F2 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 7315FE7A80BEE30B6C421D8E /* [CP] Check Pods Manifest.lock */, + 255CACE2421AA6292C134901 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - AA208B630E57EB0D3A1CB1F7 /* [CP] Embed Pods Frameworks */, + A2ACE478B6DE74624FC733E7 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -201,10 +257,15 @@ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; @@ -235,12 +296,20 @@ projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -253,67 +322,89 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { + 255CACE2421AA6292C134901 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { + 25D32918ED6298DCA22CD2F2 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( - Flutter/ephemeral/tripwire, + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 7315FE7A80BEE30B6C421D8E /* [CP] Check Pods Manifest.lock */ = { + 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - AA208B630E57EB0D3A1CB1F7 /* [CP] Embed Pods Frameworks */ = { + A2ACE478B6DE74624FC733E7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -333,6 +424,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -346,6 +445,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; @@ -366,11 +470,57 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 864353CBAFBEA9E6EA9CA34D /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AA2D7A7B6F4910F5F5345908 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EB57D14A1F93019FBBA5F32E /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/example"; + }; + name = Profile; + }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -394,9 +544,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -419,16 +571,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = 75Y2P2WSQQ; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.exampl; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -447,6 +598,7 @@ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -470,9 +622,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -500,6 +654,7 @@ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -523,9 +678,11 @@ CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -548,16 +705,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = 75Y2P2WSQQ; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.exampl; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -571,16 +727,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = 75Y2P2WSQQ; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.exampl; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -605,6 +760,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/flutter_secure_storage/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_secure_storage/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index ec9aa6bb..15368ecc 100644 --- a/flutter_secure_storage/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/flutter_secure_storage/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -36,8 +36,19 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - + + + + + + - - + + + + diff --git a/flutter_secure_storage/example/macos/Runner/Configs/AppInfo.xcconfig b/flutter_secure_storage/example/macos/Runner/Configs/AppInfo.xcconfig index 27a53928..b659a0f5 100644 --- a/flutter_secure_storage/example/macos/Runner/Configs/AppInfo.xcconfig +++ b/flutter_secure_storage/example/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = example PRODUCT_BUNDLE_IDENTIFIER = com.itnomads.example // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2021 com.it_nomads. All rights reserved. +PRODUCT_COPYRIGHT = Copyright © 2024 com.it_nomads. All rights reserved. diff --git a/flutter_secure_storage/example/macos/Runner/Configs/Debug.xcconfig b/flutter_secure_storage/example/macos/Runner/Configs/Debug.xcconfig index 44f79c3e..36b0fd94 100644 --- a/flutter_secure_storage/example/macos/Runner/Configs/Debug.xcconfig +++ b/flutter_secure_storage/example/macos/Runner/Configs/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Debug.xcconfig" +#include "../../Flutter/Flutter-Debug.xcconfig" #include "Warnings.xcconfig" diff --git a/flutter_secure_storage/example/macos/Runner/Configs/Release.xcconfig b/flutter_secure_storage/example/macos/Runner/Configs/Release.xcconfig index d0f462da..dff4f495 100644 --- a/flutter_secure_storage/example/macos/Runner/Configs/Release.xcconfig +++ b/flutter_secure_storage/example/macos/Runner/Configs/Release.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Release.xcconfig" +#include "../../Flutter/Flutter-Release.xcconfig" #include "Warnings.xcconfig" diff --git a/flutter_secure_storage/example/macos/Runner/MainFlutterWindow.swift b/flutter_secure_storage/example/macos/Runner/MainFlutterWindow.swift index 2722837e..3cc05eb2 100644 --- a/flutter_secure_storage/example/macos/Runner/MainFlutterWindow.swift +++ b/flutter_secure_storage/example/macos/Runner/MainFlutterWindow.swift @@ -3,7 +3,7 @@ import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() + let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) diff --git a/flutter_secure_storage/example/macos/RunnerTests/RunnerTests.swift b/flutter_secure_storage/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..61f3bd1f --- /dev/null +++ b/flutter_secure_storage/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/flutter_secure_storage/example/pubspec.yaml b/flutter_secure_storage/example/pubspec.yaml index f073d09b..d6cbd953 100644 --- a/flutter_secure_storage/example/pubspec.yaml +++ b/flutter_secure_storage/example/pubspec.yaml @@ -1,9 +1,12 @@ name: flutter_secure_storage_example description: Demonstrates how to use the flutter_secure_storage plugin. +version: 1.0.0+1 + +publish_to: 'none' + environment: - sdk: ">=2.12.0 <4.0.0" - flutter: ">=2.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: flutter: @@ -17,11 +20,11 @@ dependencies: path: ../ dev_dependencies: - flutter_driver: - sdk: flutter flutter_test: sdk: flutter - lint: ^2.0.1 + integration_test: + sdk: flutter + lint: any test: any flutter: diff --git a/flutter_secure_storage/example/test_driver/app.dart b/flutter_secure_storage/example/test_driver/app.dart deleted file mode 100644 index afea44fb..00000000 --- a/flutter_secure_storage/example/test_driver/app.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter_driver/driver_extension.dart'; -import 'package:flutter_secure_storage_example/main.dart' as app; - -void main() { - // This line enables the extension. - enableFlutterDriverExtension(); - - // Call the `main()` function of the app, or call `runApp` with - // any widget you are interested in testing. - app.main(); -} diff --git a/flutter_secure_storage/example/test_driver/app_test.dart b/flutter_secure_storage/example/test_driver/app_test.dart deleted file mode 100644 index dbe4929d..00000000 --- a/flutter_secure_storage/example/test_driver/app_test.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:flutter_driver/flutter_driver.dart'; -import 'package:test/test.dart'; - -void main() { - group('Secure Storage Example', () { - late HomePageObject pageObject; - late FlutterDriver driver; - - // Connect to the Flutter driver before running any tests. - setUpAll(() async { - driver = await FlutterDriver.connect(); - - // Workaround from - // https://github.com/flutter/flutter/issues/41029#issuecomment-544348116 - await Future.delayed(const Duration(seconds: 10)); - - pageObject = HomePageObject(driver); - - await pageObject.deleteAll(); - }); - - // Close the connection to the driver after the tests have completed. - tearDownAll(() async { - await pageObject.deleteAll(); - driver.close(); - }); - - test( - 'basic operations', - () async { - await pageObject.hasNoRow(0); - - await pageObject.addRandom(); - await pageObject.hasRow(0); - await pageObject.addRandom(); - await pageObject.hasRow(1); - - await pageObject.editRow('Row 0', 0); - await pageObject.editRow('Row 1', 1); - - await Future.delayed(const Duration(seconds: 3)); - - await pageObject.rowHasTitle('Row 0', 0); - await pageObject.rowHasTitle('Row 1', 1); - - await Future.delayed(const Duration(seconds: 3)); - - await pageObject.deleteRow(1); - await pageObject.hasNoRow(1); - - await Future.delayed(const Duration(seconds: 3)); - - await pageObject.rowHasTitle('Row 0', 0); - await pageObject.deleteRow(0); - await pageObject.hasNoRow(0); - - await Future.delayed(const Duration(seconds: 1)); - - await pageObject.isProtectedDataAvailable(); - }, - timeout: const Timeout(Duration(seconds: 120)), - ); - }); -} - -class HomePageObject { - HomePageObject(this.driver); - - final FlutterDriver driver; - final _addRandomButtonFinder = find.byValueKey('add_random'); - final _deleteAllButtonFinder = find.byValueKey('delete_all'); - final _popUpMenuButtonFinder = find.byValueKey('popup_menu'); - final _isProtectedDataAvailableButtonFinder = - find.byValueKey('is_protected_data_available'); - - Future deleteAll() async { - await driver.tap(_popUpMenuButtonFinder); - await driver.tap(_deleteAllButtonFinder); - } - - Future addRandom() async { - await driver.tap(_addRandomButtonFinder); - } - - Future editRow(String title, int index) async { - await driver.tap(find.byValueKey('popup_row_$index')); - await driver.tap(find.byValueKey('edit_row_$index')); - - await driver.tap(find.byValueKey('title_field')); - await driver.enterText(title); - await driver.tap(find.byValueKey('save')); - } - - Future rowHasTitle(String title, int index) async { - expect(await driver.getText(find.byValueKey('title_row_$index')), title); - } - - Future hasRow(int index) async { - await driver.waitFor(find.byValueKey('title_row_$index')); - } - - Future deleteRow(int index) async { - await driver.tap(find.byValueKey('popup_row_$index')); - await driver.tap(find.byValueKey('delete_row_$index')); - } - - Future hasNoRow(int index) async { - await driver.waitForAbsent(find.byValueKey('title_row_$index')); - } - - Future isProtectedDataAvailable() async { - await driver.tap(_popUpMenuButtonFinder); - await driver.tap(_isProtectedDataAvailableButtonFinder); - } -} diff --git a/flutter_secure_storage/example/web/icons/Icon-maskable-192.png b/flutter_secure_storage/example/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/flutter_secure_storage/example/web/icons/Icon-maskable-192.png differ diff --git a/flutter_secure_storage/example/web/icons/Icon-maskable-512.png b/flutter_secure_storage/example/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/flutter_secure_storage/example/web/icons/Icon-maskable-512.png differ diff --git a/flutter_secure_storage/example/web/index.html b/flutter_secure_storage/example/web/index.html index 0081e189..1aa025dd 100644 --- a/flutter_secure_storage/example/web/index.html +++ b/flutter_secure_storage/example/web/index.html @@ -10,8 +10,11 @@ For more details: * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base + + This is a placeholder for base href that will be replaced by the value of + the `--base-href` argument provided to `flutter build`. --> - + @@ -23,76 +26,13 @@ + + + example - - + diff --git a/flutter_secure_storage/example/web/manifest.json b/flutter_secure_storage/example/web/manifest.json index 8c012917..096edf8f 100644 --- a/flutter_secure_storage/example/web/manifest.json +++ b/flutter_secure_storage/example/web/manifest.json @@ -18,6 +18,18 @@ "src": "icons/Icon-512.png", "sizes": "512x512", "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" } ] }