From 31cca08af198dbfe0a70509627c8258685214e84 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 02:14:10 +0530 Subject: [PATCH 01/45] [wifi_scan,ci] `wifi_scan` workflow added --- .github/workflows/wifi_scan.yaml | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/workflows/wifi_scan.yaml diff --git a/.github/workflows/wifi_scan.yaml b/.github/workflows/wifi_scan.yaml new file mode 100644 index 00000000..b58050af --- /dev/null +++ b/.github/workflows/wifi_scan.yaml @@ -0,0 +1,91 @@ +# Build wifi_scan example +name: wifi_scan + +on: + pull_request: + paths: + - "packages/wifi_scan/**" + - ".github/workflows/wifi_scan.yaml" + +env: + PLUGIN_SCOPE: "*wifi_scan*" + PLUGIN_EXAMPLE_SCOPE: "*wifi_scan_example*" + +jobs: + android: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: "Checkout repository" + uses: actions/checkout@v2 + - name: "Install Flutter" + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: "Install Tools" + run: ./.github/workflows/scripts/install-tools.sh + - name: "Build Example" + run: ./.github/workflows/scripts/build-examples.sh android ./lib/main.dart + + ios: + runs-on: macos-latest + timeout-minutes: 30 + steps: + - name: "Checkout repository" + uses: actions/checkout@v2 + - name: "Install Flutter" + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: "Install Tools" + run: ./.github/workflows/scripts/install-tools.sh + - name: "Build Example" + run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart + +# macos: +# runs-on: macos-latest +# timeout-minutes: 30 +# steps: +# - name: "Checkout repository" +# uses: actions/checkout@v2 +# - name: "Install Flutter" +# run: ./.github/workflows/scripts/install-flutter.sh stable +# - name: "Install Tools" +# run: ./.github/workflows/scripts/install-tools.sh +# - name: "Build Example" +# run: ./.github/workflows/scripts/build-examples.sh macos ./lib/main.dart + +# linux: +# runs-on: ubuntu-latest +# timeout-minutes: 30 +# steps: +# - name: "Checkout repository" +# uses: actions/checkout@v2 +# - name: "Install Flutter" +# run: ./.github/workflows/scripts/install-flutter.sh stable +# - name: "Install Tools" +# run: ./.github/workflows/scripts/install-tools.sh +# - name: "Build Example" +# run: ./.github/workflows/scripts/build-examples.sh linux ./lib/main.dart + +# windows: +# runs-on: ubuntu-latest +# timeout-minutes: 30 +# steps: +# - name: "Checkout repository" +# uses: actions/checkout@v2 +# - name: "Install Flutter" +# run: ./.github/workflows/scripts/install-flutter.sh stable +# - name: "Install Tools" +# run: ./.github/workflows/scripts/install-tools.sh +# - name: "Build Example" +# run: ./.github/workflows/scripts/build-examples.sh windows ./lib/main.dart + +# web: +# runs-on: ubuntu-latest +# timeout-minutes: 30 +# steps: +# - name: "Checkout repository" +# uses: actions/checkout@v2 +# - name: "Install Flutter" +# run: ./.github/workflows/scripts/install-flutter.sh stable +# - name: "Install Tools" +# run: ./.github/workflows/scripts/install-tools.sh +# - name: "Build Example" +# run: ./.github/workflows/scripts/build-examples.sh web ./lib/main.dart \ No newline at end of file From fdf0274a4d84dbd8a34d9f585b7df050b7715fb5 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 10:28:59 +0530 Subject: [PATCH 02/45] [wifi_scan] plugin created from template --- packages/wifi_scan/.gitignore | 7 ++ packages/wifi_scan/.metadata | 10 +++ packages/wifi_scan/CHANGELOG.md | 3 + packages/wifi_scan/LICENSE | 1 + packages/wifi_scan/README.md | 15 ++++ packages/wifi_scan/analysis_options.yaml | 4 + packages/wifi_scan/android/.gitignore | 8 ++ packages/wifi_scan/android/build.gradle | 50 +++++++++++ packages/wifi_scan/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 ++ packages/wifi_scan/android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 3 + .../wifi/wifi_scan/WifiScanPlugin.kt | 35 ++++++++ packages/wifi_scan/example/.gitignore | 46 ++++++++++ packages/wifi_scan/example/.metadata | 10 +++ packages/wifi_scan/example/README.md | 16 ++++ .../wifi_scan/example/analysis_options.yaml | 29 ++++++ packages/wifi_scan/example/android/.gitignore | 13 +++ .../example/android/app/build.gradle | 68 ++++++++++++++ .../android/app/src/debug/AndroidManifest.xml | 7 ++ .../android/app/src/main/AndroidManifest.xml | 41 +++++++++ .../wifi/wifi_scan_example/MainActivity.kt | 6 ++ .../res/drawable-v21/launch_background.xml | 12 +++ .../main/res/drawable/launch_background.xml | 12 +++ .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 ++++ .../app/src/main/res/values/styles.xml | 18 ++++ .../app/src/profile/AndroidManifest.xml | 7 ++ .../wifi_scan/example/android/build.gradle | 29 ++++++ .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 ++ .../wifi_scan/example/android/settings.gradle | 11 +++ packages/wifi_scan/example/lib/main.dart | 62 +++++++++++++ packages/wifi_scan/example/pubspec.yaml | 84 ++++++++++++++++++ .../wifi_scan/example/test/widget_test.dart | 27 ++++++ packages/wifi_scan/lib/wifi_scan.dart | 13 +++ packages/wifi_scan/pubspec.yaml | 63 +++++++++++++ packages/wifi_scan/test/wifi_scan_test.dart | 23 +++++ 42 files changed, 769 insertions(+) create mode 100644 packages/wifi_scan/.gitignore create mode 100644 packages/wifi_scan/.metadata create mode 100644 packages/wifi_scan/CHANGELOG.md create mode 100644 packages/wifi_scan/LICENSE create mode 100644 packages/wifi_scan/README.md create mode 100644 packages/wifi_scan/analysis_options.yaml create mode 100644 packages/wifi_scan/android/.gitignore create mode 100644 packages/wifi_scan/android/build.gradle create mode 100644 packages/wifi_scan/android/gradle.properties create mode 100644 packages/wifi_scan/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/wifi_scan/android/settings.gradle create mode 100644 packages/wifi_scan/android/src/main/AndroidManifest.xml create mode 100644 packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt create mode 100644 packages/wifi_scan/example/.gitignore create mode 100644 packages/wifi_scan/example/.metadata create mode 100644 packages/wifi_scan/example/README.md create mode 100644 packages/wifi_scan/example/analysis_options.yaml create mode 100644 packages/wifi_scan/example/android/.gitignore create mode 100644 packages/wifi_scan/example/android/app/build.gradle create mode 100644 packages/wifi_scan/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/wifi_scan/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/wifi_scan/example/android/app/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan_example/MainActivity.kt create mode 100644 packages/wifi_scan/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/wifi_scan/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/wifi_scan/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/wifi_scan/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/wifi_scan/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/wifi_scan/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/wifi_scan/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/wifi_scan/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/wifi_scan/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/wifi_scan/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/wifi_scan/example/android/build.gradle create mode 100644 packages/wifi_scan/example/android/gradle.properties create mode 100644 packages/wifi_scan/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/wifi_scan/example/android/settings.gradle create mode 100644 packages/wifi_scan/example/lib/main.dart create mode 100644 packages/wifi_scan/example/pubspec.yaml create mode 100644 packages/wifi_scan/example/test/widget_test.dart create mode 100644 packages/wifi_scan/lib/wifi_scan.dart create mode 100644 packages/wifi_scan/pubspec.yaml create mode 100644 packages/wifi_scan/test/wifi_scan_test.dart diff --git a/packages/wifi_scan/.gitignore b/packages/wifi_scan/.gitignore new file mode 100644 index 00000000..e9dc58d3 --- /dev/null +++ b/packages/wifi_scan/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ diff --git a/packages/wifi_scan/.metadata b/packages/wifi_scan/.metadata new file mode 100644 index 00000000..5bed5265 --- /dev/null +++ b/packages/wifi_scan/.metadata @@ -0,0 +1,10 @@ +# 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: 18116933e77adc82f80866c928266a5b4f1ed645 + channel: stable + +project_type: plugin diff --git a/packages/wifi_scan/CHANGELOG.md b/packages/wifi_scan/CHANGELOG.md new file mode 100644 index 00000000..41cc7d81 --- /dev/null +++ b/packages/wifi_scan/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/packages/wifi_scan/LICENSE b/packages/wifi_scan/LICENSE new file mode 100644 index 00000000..ba75c69f --- /dev/null +++ b/packages/wifi_scan/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md new file mode 100644 index 00000000..d48dfa03 --- /dev/null +++ b/packages/wifi_scan/README.md @@ -0,0 +1,15 @@ +# wifi_scan + +Flutter plugin to scan for WiFi networks. + +## Getting Started + +This project is a starting point for a Flutter +[plug-in package](https://flutter.dev/developing-packages/), +a specialized package that includes platform-specific implementation code for +Android and/or iOS. + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. + diff --git a/packages/wifi_scan/analysis_options.yaml b/packages/wifi_scan/analysis_options.yaml new file mode 100644 index 00000000..a5744c1c --- /dev/null +++ b/packages/wifi_scan/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/wifi_scan/android/.gitignore b/packages/wifi_scan/android/.gitignore new file mode 100644 index 00000000..c6cbe562 --- /dev/null +++ b/packages/wifi_scan/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/packages/wifi_scan/android/build.gradle b/packages/wifi_scan/android/build.gradle new file mode 100644 index 00000000..32ba7bfc --- /dev/null +++ b/packages/wifi_scan/android/build.gradle @@ -0,0 +1,50 @@ +group 'dev.flutternetwork.wifi.wifi_scan' +version '1.0-SNAPSHOT' + +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + minSdkVersion 16 + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/wifi_scan/android/gradle.properties b/packages/wifi_scan/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/wifi_scan/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/wifi_scan/android/gradle/wrapper/gradle-wrapper.properties b/packages/wifi_scan/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3c9d0852 --- /dev/null +++ b/packages/wifi_scan/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/wifi_scan/android/settings.gradle b/packages/wifi_scan/android/settings.gradle new file mode 100644 index 00000000..a528fecb --- /dev/null +++ b/packages/wifi_scan/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'wifi_scan' diff --git a/packages/wifi_scan/android/src/main/AndroidManifest.xml b/packages/wifi_scan/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..05e169ec --- /dev/null +++ b/packages/wifi_scan/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt new file mode 100644 index 00000000..72ffaf10 --- /dev/null +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -0,0 +1,35 @@ +package dev.flutternetwork.wifi.wifi_scan + +import androidx.annotation.NonNull + +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result + +/** WifiScanPlugin */ +class WifiScanPlugin: FlutterPlugin, MethodCallHandler { + /// The MethodChannel that will the communication between Flutter and native Android + /// + /// This local reference serves to register the plugin with the Flutter Engine and unregister it + /// when the Flutter Engine is detached from the Activity + private lateinit var channel : MethodChannel + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") + channel.setMethodCallHandler(this) + } + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + if (call.method == "getPlatformVersion") { + result.success("Android ${android.os.Build.VERSION.RELEASE}") + } else { + result.notImplemented() + } + } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + } +} diff --git a/packages/wifi_scan/example/.gitignore b/packages/wifi_scan/example/.gitignore new file mode 100644 index 00000000..0fa6b675 --- /dev/null +++ b/packages/wifi_scan/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.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/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/wifi_scan/example/.metadata b/packages/wifi_scan/example/.metadata new file mode 100644 index 00000000..a5584fc3 --- /dev/null +++ b/packages/wifi_scan/example/.metadata @@ -0,0 +1,10 @@ +# 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: 18116933e77adc82f80866c928266a5b4f1ed645 + channel: stable + +project_type: app diff --git a/packages/wifi_scan/example/README.md b/packages/wifi_scan/example/README.md new file mode 100644 index 00000000..a83809be --- /dev/null +++ b/packages/wifi_scan/example/README.md @@ -0,0 +1,16 @@ +# wifi_scan_example + +Demonstrates how to use the wifi_scan plugin. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/wifi_scan/example/analysis_options.yaml b/packages/wifi_scan/example/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/packages/wifi_scan/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/wifi_scan/example/android/.gitignore b/packages/wifi_scan/example/android/.gitignore new file mode 100644 index 00000000..6f568019 --- /dev/null +++ b/packages/wifi_scan/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/packages/wifi_scan/example/android/app/build.gradle b/packages/wifi_scan/example/android/app/build.gradle new file mode 100644 index 00000000..649e2816 --- /dev/null +++ b/packages/wifi_scan/example/android/app/build.gradle @@ -0,0 +1,68 @@ +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 plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "dev.flutternetwork.wifi.wifi_scan_example" + minSdkVersion 16 + targetSdkVersion 30 + 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 + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/wifi_scan/example/android/app/src/debug/AndroidManifest.xml b/packages/wifi_scan/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..ccfbce9d --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/wifi_scan/example/android/app/src/main/AndroidManifest.xml b/packages/wifi_scan/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..b0fd83fd --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/packages/wifi_scan/example/android/app/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan_example/MainActivity.kt b/packages/wifi_scan/example/android/app/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan_example/MainActivity.kt new file mode 100644 index 00000000..6ea3a678 --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan_example/MainActivity.kt @@ -0,0 +1,6 @@ +package dev.flutternetwork.wifi.wifi_scan_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/wifi_scan/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/wifi_scan/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/wifi_scan/example/android/app/src/main/res/drawable/launch_background.xml b/packages/wifi_scan/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/wifi_scan/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/wifi_scan/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/wifi_scan/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/wifi_scan/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/wifi_scan/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/android/app/src/main/res/values-night/styles.xml b/packages/wifi_scan/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..449a9f93 --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/wifi_scan/example/android/app/src/main/res/values/styles.xml b/packages/wifi_scan/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..d74aa35c --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/wifi_scan/example/android/app/src/profile/AndroidManifest.xml b/packages/wifi_scan/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..ccfbce9d --- /dev/null +++ b/packages/wifi_scan/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/wifi_scan/example/android/build.gradle b/packages/wifi_scan/example/android/build.gradle new file mode 100644 index 00000000..ed45c658 --- /dev/null +++ b/packages/wifi_scan/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/wifi_scan/example/android/gradle.properties b/packages/wifi_scan/example/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/packages/wifi_scan/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/wifi_scan/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/wifi_scan/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..bc6a58af --- /dev/null +++ b/packages/wifi_scan/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/wifi_scan/example/android/settings.gradle b/packages/wifi_scan/example/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/packages/wifi_scan/example/android/settings.gradle @@ -0,0 +1,11 @@ +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/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart new file mode 100644 index 00000000..eb3fccac --- /dev/null +++ b/packages/wifi_scan/example/lib/main.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:wifi_scan/wifi_scan.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + String _platformVersion = 'Unknown'; + + @override + void initState() { + super.initState(); + initPlatformState(); + } + + // Platform messages are asynchronous, so we initialize in an async method. + Future initPlatformState() async { + String platformVersion; + // Platform messages may fail, so we use a try/catch PlatformException. + // We also handle the message potentially returning null. + try { + platformVersion = + await WifiScan.platformVersion ?? 'Unknown platform version'; + } on PlatformException { + platformVersion = 'Failed to get platform version.'; + } + + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) return; + + setState(() { + _platformVersion = platformVersion; + }); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: Center( + child: Text('Running on: $_platformVersion\n'), + ), + ), + ); + } +} diff --git a/packages/wifi_scan/example/pubspec.yaml b/packages/wifi_scan/example/pubspec.yaml new file mode 100644 index 00000000..22421ad9 --- /dev/null +++ b/packages/wifi_scan/example/pubspec.yaml @@ -0,0 +1,84 @@ +name: wifi_scan_example +description: Demonstrates how to use the wifi_scan plugin. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +environment: + sdk: ">=2.12.0 <3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + wifi_scan: + # When depending on this package from a real application you should use: + # wifi_scan: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^1.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/wifi_scan/example/test/widget_test.dart b/packages/wifi_scan/example/test/widget_test.dart new file mode 100644 index 00000000..4b631792 --- /dev/null +++ b/packages/wifi_scan/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// 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:wifi_scan_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart new file mode 100644 index 00000000..23640cf4 --- /dev/null +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -0,0 +1,13 @@ + +import 'dart:async'; + +import 'package:flutter/services.dart'; + +class WifiScan { + static const MethodChannel _channel = MethodChannel('wifi_scan'); + + static Future get platformVersion async { + final String? version = await _channel.invokeMethod('getPlatformVersion'); + return version; + } +} diff --git a/packages/wifi_scan/pubspec.yaml b/packages/wifi_scan/pubspec.yaml new file mode 100644 index 00000000..71875488 --- /dev/null +++ b/packages/wifi_scan/pubspec.yaml @@ -0,0 +1,63 @@ +name: wifi_scan +description: Flutter plugin to scan for WiFi networks. +version: 0.0.1 +homepage: https://github.com/alternadom/WiFiFlutter/tree/master/packages/wifi_scan + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=1.20.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^1.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' and Android 'package' identifiers should not ordinarily + # be modified. They are used by the tooling to maintain consistency when + # adding or updating assets for this project. + plugin: + platforms: + android: + package: dev.flutternetwork.wifi.wifi_scan + pluginClass: WifiScanPlugin + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart new file mode 100644 index 00000000..afe55a6a --- /dev/null +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -0,0 +1,23 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:wifi_scan/wifi_scan.dart'; + +void main() { + const MethodChannel channel = MethodChannel('wifi_scan'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + channel.setMockMethodCallHandler((MethodCall methodCall) async { + return '42'; + }); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); + + test('getPlatformVersion', () async { + expect(await WifiScan.platformVersion, '42'); + }); +} From c7432c5aacfc3edf2d4c834c99c542f53e6eaa80 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 10:30:39 +0530 Subject: [PATCH 03/45] formatting --- packages/wifi_scan/example/test/widget_test.dart | 4 ++-- packages/wifi_scan/lib/wifi_scan.dart | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/example/test/widget_test.dart b/packages/wifi_scan/example/test/widget_test.dart index 4b631792..206180ae 100644 --- a/packages/wifi_scan/example/test/widget_test.dart +++ b/packages/wifi_scan/example/test/widget_test.dart @@ -18,8 +18,8 @@ void main() { // Verify that platform version is retrieved. expect( find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data!.startsWith('Running on:'), + (Widget widget) => + widget is Text && widget.data!.startsWith('Running on:'), ), findsOneWidget, ); diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 23640cf4..d77a9d7f 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:flutter/services.dart'; From 05780d5e6abd27949ed2853a66776dea41784860 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 10:37:47 +0530 Subject: [PATCH 04/45] [wifi_scan,ci] disable "ios" job --- .github/workflows/wifi_scan.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/wifi_scan.yaml b/.github/workflows/wifi_scan.yaml index b58050af..9de22f28 100644 --- a/.github/workflows/wifi_scan.yaml +++ b/.github/workflows/wifi_scan.yaml @@ -25,18 +25,18 @@ jobs: - name: "Build Example" run: ./.github/workflows/scripts/build-examples.sh android ./lib/main.dart - ios: - runs-on: macos-latest - timeout-minutes: 30 - steps: - - name: "Checkout repository" - uses: actions/checkout@v2 - - name: "Install Flutter" - run: ./.github/workflows/scripts/install-flutter.sh stable - - name: "Install Tools" - run: ./.github/workflows/scripts/install-tools.sh - - name: "Build Example" - run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart +# ios: +# runs-on: macos-latest +# timeout-minutes: 30 +# steps: +# - name: "Checkout repository" +# uses: actions/checkout@v2 +# - name: "Install Flutter" +# run: ./.github/workflows/scripts/install-flutter.sh stable +# - name: "Install Tools" +# run: ./.github/workflows/scripts/install-tools.sh +# - name: "Build Example" +# run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart # macos: # runs-on: macos-latest From 451539a7bc74e96c905b08255dcfe3fe1ac6f600 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 10:41:06 +0530 Subject: [PATCH 05/45] [wifi_scan] renamed `WifiScan` -> `WiFiScan`; made it singleton accessible via `WiFiScan.instance` --- packages/wifi_scan/example/lib/main.dart | 2 +- packages/wifi_scan/lib/wifi_scan.dart | 9 ++++++--- packages/wifi_scan/test/wifi_scan_test.dart | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index eb3fccac..724f32da 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -31,7 +31,7 @@ class _MyAppState extends State { // We also handle the message potentially returning null. try { platformVersion = - await WifiScan.platformVersion ?? 'Unknown platform version'; + await WiFiScan.instance.platformVersion ?? 'Unknown platform version'; } on PlatformException { platformVersion = 'Failed to get platform version.'; } diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index d77a9d7f..42241daf 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -2,10 +2,13 @@ import 'dart:async'; import 'package:flutter/services.dart'; -class WifiScan { - static const MethodChannel _channel = MethodChannel('wifi_scan'); +class WiFiScan { + WiFiScan._(); - static Future get platformVersion async { + static final instance = WiFiScan._(); + final MethodChannel _channel = const MethodChannel('wifi_scan'); + + Future get platformVersion async { final String? version = await _channel.invokeMethod('getPlatformVersion'); return version; } diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index afe55a6a..d392335b 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -18,6 +18,6 @@ void main() { }); test('getPlatformVersion', () async { - expect(await WifiScan.platformVersion, '42'); + expect(await WiFiScan.instance.platformVersion, '42'); }); } From baee8995ab75de7c1c42022408e59297d95b3692 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 14:42:51 +0530 Subject: [PATCH 06/45] - [wifi_scan] `CanRequestScan` and `CanGetScannedNetworks` enum added; `WiFiNetwork` class added; `requestScan`, `canGetScannedNetworks`, `scannedNetworks` and `scannedNetworksStream` methods and getters added; `ToEnumExtension` added - [wifi_scan,test] basic test added - [wifi_scan,example] cleaned/blanked --- packages/wifi_scan/example/lib/main.dart | 35 ++----------- packages/wifi_scan/lib/src/extensions.dart | 7 +++ packages/wifi_scan/lib/wifi_scan.dart | 54 +++++++++++++++++++-- packages/wifi_scan/test/wifi_scan_test.dart | 51 +++++++++++++++++-- 4 files changed, 105 insertions(+), 42 deletions(-) create mode 100644 packages/wifi_scan/lib/src/extensions.dart diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index 724f32da..aeb5bba0 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -8,6 +8,7 @@ void main() { runApp(const MyApp()); } +// TODO: proper example app class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @@ -16,36 +17,6 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - String _platformVersion = 'Unknown'; - - @override - void initState() { - super.initState(); - initPlatformState(); - } - - // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - String platformVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - // We also handle the message potentially returning null. - try { - platformVersion = - await WiFiScan.instance.platformVersion ?? 'Unknown platform version'; - } on PlatformException { - platformVersion = 'Failed to get platform version.'; - } - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; - - setState(() { - _platformVersion = platformVersion; - }); - } - @override Widget build(BuildContext context) { return MaterialApp( @@ -53,8 +24,8 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Plugin example app'), ), - body: Center( - child: Text('Running on: $_platformVersion\n'), + body: const Center( + child: Text('TODO'), ), ), ); diff --git a/packages/wifi_scan/lib/src/extensions.dart b/packages/wifi_scan/lib/src/extensions.dart new file mode 100644 index 00000000..5e379ca0 --- /dev/null +++ b/packages/wifi_scan/lib/src/extensions.dart @@ -0,0 +1,7 @@ +import 'package:wifi_scan/wifi_scan.dart'; + +extension ToEnumExtension on int{ + toCanRequestScan()=> CanRequestScan.values[this]; + + toCanGetScannedNetworks() => CanGetScannedNetworks.values[this]; +} \ No newline at end of file diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 42241daf..88232f18 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -1,15 +1,59 @@ import 'dart:async'; import 'package:flutter/services.dart'; +import 'src/extensions.dart'; + +enum CanRequestScan { + yes, + notSupported, + noLocationPermissionRequired, + noLocationPermissionDenied, + noLocationServiceDisabled, +} + +enum CanGetScannedNetworks { + yes, + notSupported, + noLocationPermissionRequired, + noLocationPermissionDenied, + noLocationServiceDisabled, +} + +class WiFiNetwork { + WiFiNetwork._fromMap(Map map); +} class WiFiScan { WiFiScan._(); static final instance = WiFiScan._(); - final MethodChannel _channel = const MethodChannel('wifi_scan'); + final _channel = const MethodChannel('wifi_scan'); + final _scannedNetworksChannel = + const EventChannel('wifi_scan/scannedNetworksEvent'); + Stream>? _scannedNetworksStream; + + Future requestScan({bool askPermissions = true}) async => + (await _channel.invokeMethod("requestScan"))!.toCanRequestScan(); + + Future canGetScannedNetworks( + {bool askPermissions = true}) async => + (await _channel.invokeMethod("canGetScannedNetworks"))! + .toCanGetScannedNetworks(); + + Future> get scannedNetworks async => + (await _channel.invokeListMethod("scannedNetworks"))! + .map((map) => WiFiNetwork._fromMap(map)) + .toList(growable: false); - Future get platformVersion async { - final String? version = await _channel.invokeMethod('getPlatformVersion'); - return version; - } + Stream> get scannedNetworksStream => + _scannedNetworksStream ??= + _scannedNetworksChannel.receiveBroadcastStream().map((event) { + if (event is Error) throw event; + if (event is List) { + return event + .map((map) => WiFiNetwork._fromMap(map)) + .toList(growable: false); + } + return const []; + }); } diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index d392335b..092bfc79 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -1,23 +1,64 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:wifi_scan/src/extensions.dart'; import 'package:wifi_scan/wifi_scan.dart'; void main() { - const MethodChannel channel = MethodChannel('wifi_scan'); + const channel = MethodChannel('wifi_scan'); + final mockHandlers = {}; TestWidgetsFlutterBinding.ensureInitialized(); setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return '42'; + TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (call) { + final result = mockHandlers[call.method]?.call(call.arguments); + if (result is Future) return result; + return Future.value(result); }); }); tearDown(() { + mockHandlers.clear(); channel.setMockMethodCallHandler(null); }); - test('getPlatformVersion', () async { - expect(await WiFiScan.instance.platformVersion, '42'); + test('requestScan', () async { + mockHandlers["requestScan"] = (_) => 0; + expect(await WiFiScan.instance.requestScan(), CanRequestScan.yes); + }); + + test("canGetScannedNetworks", () async { + mockHandlers["canGetScannedNetworks"] = (_) => 0; + expect(await WiFiScan.instance.canGetScannedNetworks(), + CanGetScannedNetworks.yes); + }); + + test("scannedNetworks", () async { + mockHandlers["scannedNetworks"] = (_) => [{}]; + final scannedNetworks = await WiFiScan.instance.scannedNetworks; + expect(scannedNetworks.length, 1); + }); + + // TODO: firgure out way to mock EventChannel + // test("scannedNetworksStream", () async {}); + + test("ToEnumExtension.toCanScanResult", () async { + expect(0.toCanRequestScan(), CanRequestScan.yes); + expect(1.toCanRequestScan(), CanRequestScan.notSupported); + expect(2.toCanRequestScan(), CanRequestScan.noLocationPermissionRequired); + expect(3.toCanRequestScan(), CanRequestScan.noLocationPermissionDenied); + expect(4.toCanRequestScan(), CanRequestScan.noLocationServiceDisabled); + }); + + test("ToEnumExtension.toCanGetScannedNetworks", () async { + expect(0.toCanGetScannedNetworks(), CanGetScannedNetworks.yes); + expect(1.toCanGetScannedNetworks(), CanGetScannedNetworks.notSupported); + expect(2.toCanGetScannedNetworks(), + CanGetScannedNetworks.noLocationPermissionRequired); + expect(3.toCanGetScannedNetworks(), + CanGetScannedNetworks.noLocationPermissionDenied); + expect(4.toCanGetScannedNetworks(), + CanGetScannedNetworks.noLocationServiceDisabled); }); } From eb94c6dfa78a876dff0245abea7b7394adbf281e Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 14:47:54 +0530 Subject: [PATCH 07/45] formatting --- packages/wifi_scan/lib/src/extensions.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/lib/src/extensions.dart b/packages/wifi_scan/lib/src/extensions.dart index 5e379ca0..92beeb5b 100644 --- a/packages/wifi_scan/lib/src/extensions.dart +++ b/packages/wifi_scan/lib/src/extensions.dart @@ -1,7 +1,7 @@ import 'package:wifi_scan/wifi_scan.dart'; -extension ToEnumExtension on int{ - toCanRequestScan()=> CanRequestScan.values[this]; +extension ToEnumExtension on int { + toCanRequestScan() => CanRequestScan.values[this]; toCanGetScannedNetworks() => CanGetScannedNetworks.values[this]; -} \ No newline at end of file +} From 689ce89bcfb417869ab41bb2d4f83b1eaa7badf4 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 14:59:07 +0530 Subject: [PATCH 08/45] [wifi_scan] renamed: `requestScan` -> `startScan` and `CanRequestScan` -> `CanStartScan` --- packages/wifi_scan/lib/src/extensions.dart | 2 +- packages/wifi_scan/lib/wifi_scan.dart | 6 +++--- packages/wifi_scan/test/wifi_scan_test.dart | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/wifi_scan/lib/src/extensions.dart b/packages/wifi_scan/lib/src/extensions.dart index 92beeb5b..fd885f29 100644 --- a/packages/wifi_scan/lib/src/extensions.dart +++ b/packages/wifi_scan/lib/src/extensions.dart @@ -1,7 +1,7 @@ import 'package:wifi_scan/wifi_scan.dart'; extension ToEnumExtension on int { - toCanRequestScan() => CanRequestScan.values[this]; + toCanStartScan() => CanStartScan.values[this]; toCanGetScannedNetworks() => CanGetScannedNetworks.values[this]; } diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 88232f18..05759ff1 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'src/extensions.dart'; -enum CanRequestScan { +enum CanStartScan { yes, notSupported, noLocationPermissionRequired, @@ -32,8 +32,8 @@ class WiFiScan { const EventChannel('wifi_scan/scannedNetworksEvent'); Stream>? _scannedNetworksStream; - Future requestScan({bool askPermissions = true}) async => - (await _channel.invokeMethod("requestScan"))!.toCanRequestScan(); + Future startScan({bool askPermissions = true}) async => + (await _channel.invokeMethod("startScan"))!.toCanStartScan(); Future canGetScannedNetworks( {bool askPermissions = true}) async => diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index 092bfc79..b2f2fa15 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -23,9 +23,9 @@ void main() { channel.setMockMethodCallHandler(null); }); - test('requestScan', () async { - mockHandlers["requestScan"] = (_) => 0; - expect(await WiFiScan.instance.requestScan(), CanRequestScan.yes); + test('startScan', () async { + mockHandlers["startScan"] = (_) => 0; + expect(await WiFiScan.instance.startScan(), CanStartScan.yes); }); test("canGetScannedNetworks", () async { @@ -43,12 +43,12 @@ void main() { // TODO: firgure out way to mock EventChannel // test("scannedNetworksStream", () async {}); - test("ToEnumExtension.toCanScanResult", () async { - expect(0.toCanRequestScan(), CanRequestScan.yes); - expect(1.toCanRequestScan(), CanRequestScan.notSupported); - expect(2.toCanRequestScan(), CanRequestScan.noLocationPermissionRequired); - expect(3.toCanRequestScan(), CanRequestScan.noLocationPermissionDenied); - expect(4.toCanRequestScan(), CanRequestScan.noLocationServiceDisabled); + test("ToEnumExtension.toCanStartScan", () async { + expect(0.toCanStartScan(), CanStartScan.yes); + expect(1.toCanStartScan(), CanStartScan.notSupported); + expect(2.toCanStartScan(), CanStartScan.noLocationPermissionRequired); + expect(3.toCanStartScan(), CanStartScan.noLocationPermissionDenied); + expect(4.toCanStartScan(), CanStartScan.noLocationServiceDisabled); }); test("ToEnumExtension.toCanGetScannedNetworks", () async { From 88801d064a92e18349c059d1857e3103b3ef8292 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 5 Dec 2021 15:30:53 +0530 Subject: [PATCH 09/45] [wifi_scan] import fix --- packages/wifi_scan/example/lib/main.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index aeb5bba0..ea3134f1 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -1,8 +1,4 @@ import 'package:flutter/material.dart'; -import 'dart:async'; - -import 'package:flutter/services.dart'; -import 'package:wifi_scan/wifi_scan.dart'; void main() { runApp(const MyApp()); From 6148d74de0ceb2deff2062ec0277facd287c6941 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sat, 11 Dec 2021 19:54:57 +0530 Subject: [PATCH 10/45] [wifi_scan,test] separated `startScan` and `canStartScan` methods --- packages/wifi_scan/lib/wifi_scan.dart | 6 ++++-- packages/wifi_scan/test/wifi_scan_test.dart | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 05759ff1..9780d248 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -32,8 +32,10 @@ class WiFiScan { const EventChannel('wifi_scan/scannedNetworksEvent'); Stream>? _scannedNetworksStream; - Future startScan({bool askPermissions = true}) async => - (await _channel.invokeMethod("startScan"))!.toCanStartScan(); + Future canStartScan({bool askPermissions = true}) async => + (await _channel.invokeMethod("canStartScan"))!.toCanStartScan(); + + Future startScan() async => await _channel.invokeMethod("startScan"); Future canGetScannedNetworks( {bool askPermissions = true}) async => diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index b2f2fa15..5e69ca5f 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -23,9 +23,14 @@ void main() { channel.setMockMethodCallHandler(null); }); + test('canStartScan', () async { + mockHandlers["canStartScan"] = (_) => 0; + expect(await WiFiScan.instance.canStartScan(), CanStartScan.yes); + }); + test('startScan', () async { - mockHandlers["startScan"] = (_) => 0; - expect(await WiFiScan.instance.startScan(), CanStartScan.yes); + mockHandlers["startScan"] = (_) => true; + expect(await WiFiScan.instance.startScan(), true); }); test("canGetScannedNetworks", () async { From 078f06361f531b4a0d3cff351f049445dacbb0fe Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sat, 11 Dec 2021 20:31:39 +0530 Subject: [PATCH 11/45] [ios] plugin support for iOS added --- .github/workflows/wifi_scan.yaml | 24 +- packages/wifi_scan/example/ios/.gitignore | 34 ++ .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + packages/wifi_scan/example/ios/Podfile | 41 ++ .../ios/Runner.xcodeproj/project.pbxproj | 484 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 87 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../wifi_scan/example/ios/Runner/Info.plist | 47 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + packages/wifi_scan/ios/.gitignore | 38 ++ packages/wifi_scan/ios/Assets/.gitkeep | 0 .../ios/Classes/SwiftWifiScanPlugin.swift | 14 + .../wifi_scan/ios/Classes/WifiScanPlugin.h | 4 + .../wifi_scan/ios/Classes/WifiScanPlugin.m | 15 + packages/wifi_scan/ios/wifi_scan.podspec | 23 + packages/wifi_scan/pubspec.yaml | 2 + 47 files changed, 1104 insertions(+), 12 deletions(-) create mode 100644 packages/wifi_scan/example/ios/.gitignore create mode 100644 packages/wifi_scan/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/wifi_scan/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/wifi_scan/example/ios/Flutter/Release.xcconfig create mode 100644 packages/wifi_scan/example/ios/Podfile create mode 100644 packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/wifi_scan/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/wifi_scan/example/ios/Runner/AppDelegate.swift create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/wifi_scan/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/wifi_scan/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/wifi_scan/example/ios/Runner/Info.plist create mode 100644 packages/wifi_scan/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/wifi_scan/ios/.gitignore create mode 100644 packages/wifi_scan/ios/Assets/.gitkeep create mode 100644 packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift create mode 100644 packages/wifi_scan/ios/Classes/WifiScanPlugin.h create mode 100644 packages/wifi_scan/ios/Classes/WifiScanPlugin.m create mode 100644 packages/wifi_scan/ios/wifi_scan.podspec diff --git a/.github/workflows/wifi_scan.yaml b/.github/workflows/wifi_scan.yaml index 9de22f28..b58050af 100644 --- a/.github/workflows/wifi_scan.yaml +++ b/.github/workflows/wifi_scan.yaml @@ -25,18 +25,18 @@ jobs: - name: "Build Example" run: ./.github/workflows/scripts/build-examples.sh android ./lib/main.dart -# ios: -# runs-on: macos-latest -# timeout-minutes: 30 -# steps: -# - name: "Checkout repository" -# uses: actions/checkout@v2 -# - name: "Install Flutter" -# run: ./.github/workflows/scripts/install-flutter.sh stable -# - name: "Install Tools" -# run: ./.github/workflows/scripts/install-tools.sh -# - name: "Build Example" -# run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart + ios: + runs-on: macos-latest + timeout-minutes: 30 + steps: + - name: "Checkout repository" + uses: actions/checkout@v2 + - name: "Install Flutter" + run: ./.github/workflows/scripts/install-flutter.sh stable + - name: "Install Tools" + run: ./.github/workflows/scripts/install-tools.sh + - name: "Build Example" + run: ./.github/workflows/scripts/build-examples.sh ios ./lib/main.dart # macos: # runs-on: macos-latest diff --git a/packages/wifi_scan/example/ios/.gitignore b/packages/wifi_scan/example/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/packages/wifi_scan/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/wifi_scan/example/ios/Flutter/AppFrameworkInfo.plist b/packages/wifi_scan/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..8d4492f9 --- /dev/null +++ b/packages/wifi_scan/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/packages/wifi_scan/example/ios/Flutter/Debug.xcconfig b/packages/wifi_scan/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/packages/wifi_scan/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/wifi_scan/example/ios/Flutter/Release.xcconfig b/packages/wifi_scan/example/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/packages/wifi_scan/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/wifi_scan/example/ios/Podfile b/packages/wifi_scan/example/ios/Podfile new file mode 100644 index 00000000..1e8c3c90 --- /dev/null +++ b/packages/wifi_scan/example/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..830cb6a5 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,484 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DC8X5UJHS6; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutternetwork.wifi.wifiScanExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DC8X5UJHS6; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutternetwork.wifi.wifiScanExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = DC8X5UJHS6; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutternetwork.wifi.wifiScanExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/wifi_scan/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..c87d15a3 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/wifi_scan/example/ios/Runner/AppDelegate.swift b/packages/wifi_scan/example/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/wifi_scan/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/wifi_scan/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/wifi_scan/example/ios/Runner/Base.lproj/Main.storyboard b/packages/wifi_scan/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/wifi_scan/example/ios/Runner/Info.plist b/packages/wifi_scan/example/ios/Runner/Info.plist new file mode 100644 index 00000000..83f86d25 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Wifi Scan + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + wifi_scan_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/wifi_scan/example/ios/Runner/Runner-Bridging-Header.h b/packages/wifi_scan/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/packages/wifi_scan/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/wifi_scan/ios/.gitignore b/packages/wifi_scan/ios/.gitignore new file mode 100644 index 00000000..0c885071 --- /dev/null +++ b/packages/wifi_scan/ios/.gitignore @@ -0,0 +1,38 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/ephemeral/ +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/packages/wifi_scan/ios/Assets/.gitkeep b/packages/wifi_scan/ios/Assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift new file mode 100644 index 00000000..bc3e99ce --- /dev/null +++ b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift @@ -0,0 +1,14 @@ +import Flutter +import UIKit + +public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { + public static func register(with registrar: FlutterPluginRegistrar) { + let channel = FlutterMethodChannel(name: "wifi_scan", binaryMessenger: registrar.messenger()) + let instance = SwiftWifiScanPlugin() + registrar.addMethodCallDelegate(instance, channel: channel) + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + result("iOS " + UIDevice.current.systemVersion) + } +} diff --git a/packages/wifi_scan/ios/Classes/WifiScanPlugin.h b/packages/wifi_scan/ios/Classes/WifiScanPlugin.h new file mode 100644 index 00000000..9d390059 --- /dev/null +++ b/packages/wifi_scan/ios/Classes/WifiScanPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface WifiScanPlugin : NSObject +@end diff --git a/packages/wifi_scan/ios/Classes/WifiScanPlugin.m b/packages/wifi_scan/ios/Classes/WifiScanPlugin.m new file mode 100644 index 00000000..e1819dce --- /dev/null +++ b/packages/wifi_scan/ios/Classes/WifiScanPlugin.m @@ -0,0 +1,15 @@ +#import "WifiScanPlugin.h" +#if __has_include() +#import +#else +// Support project import fallback if the generated compatibility header +// is not copied when this plugin is created as a library. +// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 +#import "wifi_scan-Swift.h" +#endif + +@implementation WifiScanPlugin ++ (void)registerWithRegistrar:(NSObject*)registrar { + [SwiftWifiScanPlugin registerWithRegistrar:registrar]; +} +@end diff --git a/packages/wifi_scan/ios/wifi_scan.podspec b/packages/wifi_scan/ios/wifi_scan.podspec new file mode 100644 index 00000000..9f5d25f3 --- /dev/null +++ b/packages/wifi_scan/ios/wifi_scan.podspec @@ -0,0 +1,23 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint wifi_scan.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'wifi_scan' + s.version = '0.0.1' + s.summary = 'Flutter plugin to scan for WiFi networks.' + s.description = <<-DESC +Flutter plugin to scan for WiFi networks. + DESC + s.homepage = 'https://wifi.flutternetwork.dev' + s.license = { :file => '../LICENSE' } + s.author = { 'WiFiFlutter' => 'contact@flutternetwork.dev' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '9.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } + s.swift_version = '5.0' +end diff --git a/packages/wifi_scan/pubspec.yaml b/packages/wifi_scan/pubspec.yaml index 71875488..7b0febfd 100644 --- a/packages/wifi_scan/pubspec.yaml +++ b/packages/wifi_scan/pubspec.yaml @@ -30,6 +30,8 @@ flutter: android: package: dev.flutternetwork.wifi.wifi_scan pluginClass: WifiScanPlugin + ios: + pluginClass: WifiScanPlugin # To add assets to your plugin package, add an assets section, like this: # assets: From c9e08e6b4e8f0d3ea801d894bc9013c1982b3338 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 12 Dec 2021 11:29:14 +0530 Subject: [PATCH 12/45] [wifi_scan] breaking it into seperate dart files - removed extension - instead using helper functions --- packages/wifi_scan/lib/can.dart | 50 +++++++++++++++++ packages/wifi_scan/lib/src/extensions.dart | 7 --- packages/wifi_scan/lib/wifi_network.dart | 5 ++ packages/wifi_scan/lib/wifi_scan.dart | 59 ++++++++++----------- packages/wifi_scan/test/wifi_scan_test.dart | 54 ++++++++++++------- 5 files changed, 119 insertions(+), 56 deletions(-) create mode 100644 packages/wifi_scan/lib/can.dart delete mode 100644 packages/wifi_scan/lib/src/extensions.dart create mode 100644 packages/wifi_scan/lib/wifi_network.dart diff --git a/packages/wifi_scan/lib/can.dart b/packages/wifi_scan/lib/can.dart new file mode 100644 index 00000000..10d4cbfe --- /dev/null +++ b/packages/wifi_scan/lib/can.dart @@ -0,0 +1,50 @@ +part of 'wifi_scan.dart'; + +enum CanStartScan { + notSupported, + yes, + noLocationPermissionRequired, + noLocationPermissionDenied, + noLocationServiceDisabled, +} + +CanStartScan deserializeCanStartScan(int? canCode) { + switch (canCode) { + case 0: + return CanStartScan.notSupported; + case 1: + return CanStartScan.yes; + case 2: + return CanStartScan.noLocationPermissionRequired; + case 3: + return CanStartScan.noLocationPermissionDenied; + case 4: + return CanStartScan.noLocationServiceDisabled; + } + throw UnsupportedError("$canCode cannot be serialized to CanStartScan"); +} + +enum CanGetScannedNetworks { + notSupported, + yes, + noLocationPermissionRequired, + noLocationPermissionDenied, + noLocationServiceDisabled, +} + +CanGetScannedNetworks deserializeCanGetScannedNetworks(int? canCode) { + switch (canCode) { + case 0: + return CanGetScannedNetworks.notSupported; + case 1: + return CanGetScannedNetworks.yes; + case 2: + return CanGetScannedNetworks.noLocationPermissionRequired; + case 3: + return CanGetScannedNetworks.noLocationPermissionDenied; + case 4: + return CanGetScannedNetworks.noLocationServiceDisabled; + } + throw UnsupportedError( + "$canCode cannot be serialized to CanGetScannedNetworks"); +} diff --git a/packages/wifi_scan/lib/src/extensions.dart b/packages/wifi_scan/lib/src/extensions.dart deleted file mode 100644 index fd885f29..00000000 --- a/packages/wifi_scan/lib/src/extensions.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:wifi_scan/wifi_scan.dart'; - -extension ToEnumExtension on int { - toCanStartScan() => CanStartScan.values[this]; - - toCanGetScannedNetworks() => CanGetScannedNetworks.values[this]; -} diff --git a/packages/wifi_scan/lib/wifi_network.dart b/packages/wifi_scan/lib/wifi_network.dart new file mode 100644 index 00000000..63957920 --- /dev/null +++ b/packages/wifi_scan/lib/wifi_network.dart @@ -0,0 +1,5 @@ +part of 'wifi_scan.dart'; + +class WiFiNetwork { + WiFiNetwork._fromMap(Map map); +} diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 9780d248..2ee428c5 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -1,27 +1,9 @@ import 'dart:async'; import 'package:flutter/services.dart'; -import 'src/extensions.dart'; - -enum CanStartScan { - yes, - notSupported, - noLocationPermissionRequired, - noLocationPermissionDenied, - noLocationServiceDisabled, -} - -enum CanGetScannedNetworks { - yes, - notSupported, - noLocationPermissionRequired, - noLocationPermissionDenied, - noLocationServiceDisabled, -} -class WiFiNetwork { - WiFiNetwork._fromMap(Map map); -} +part 'can.dart'; +part 'wifi_network.dart'; class WiFiScan { WiFiScan._(); @@ -32,20 +14,35 @@ class WiFiScan { const EventChannel('wifi_scan/scannedNetworksEvent'); Stream>? _scannedNetworksStream; - Future canStartScan({bool askPermissions = true}) async => - (await _channel.invokeMethod("canStartScan"))!.toCanStartScan(); + Future canStartScan({bool askPermissions = true}) async { + final canCode = await _channel.invokeMethod( + "canStartScan", + {"askPermissions": askPermissions}, + ); + return deserializeCanStartScan(canCode); + } - Future startScan() async => await _channel.invokeMethod("startScan"); + Future startScan() async { + final isSucess = await _channel.invokeMethod("startScan"); + return isSucess!; + } Future canGetScannedNetworks( - {bool askPermissions = true}) async => - (await _channel.invokeMethod("canGetScannedNetworks"))! - .toCanGetScannedNetworks(); - - Future> get scannedNetworks async => - (await _channel.invokeListMethod("scannedNetworks"))! - .map((map) => WiFiNetwork._fromMap(map)) - .toList(growable: false); + {bool askPermissions = true}) async { + final canCode = await _channel.invokeMethod( + "canGetScannedNetworks", + {"askPermissions": askPermissions}, + ); + return deserializeCanGetScannedNetworks(canCode); + } + + Future> get scannedNetworks async { + final scannedNetworks = + await _channel.invokeListMethod("scannedNetworks"); + return scannedNetworks! + .map((map) => WiFiNetwork._fromMap(map)) + .toList(growable: false); + } Stream> get scannedNetworksStream => _scannedNetworksStream ??= diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index 5e69ca5f..2b07146d 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:wifi_scan/src/extensions.dart'; import 'package:wifi_scan/wifi_scan.dart'; void main() { @@ -24,7 +23,7 @@ void main() { }); test('canStartScan', () async { - mockHandlers["canStartScan"] = (_) => 0; + mockHandlers["canStartScan"] = (_) => 1; expect(await WiFiScan.instance.canStartScan(), CanStartScan.yes); }); @@ -34,7 +33,7 @@ void main() { }); test("canGetScannedNetworks", () async { - mockHandlers["canGetScannedNetworks"] = (_) => 0; + mockHandlers["canGetScannedNetworks"] = (_) => 1; expect(await WiFiScan.instance.canGetScannedNetworks(), CanGetScannedNetworks.yes); }); @@ -48,22 +47,41 @@ void main() { // TODO: firgure out way to mock EventChannel // test("scannedNetworksStream", () async {}); - test("ToEnumExtension.toCanStartScan", () async { - expect(0.toCanStartScan(), CanStartScan.yes); - expect(1.toCanStartScan(), CanStartScan.notSupported); - expect(2.toCanStartScan(), CanStartScan.noLocationPermissionRequired); - expect(3.toCanStartScan(), CanStartScan.noLocationPermissionDenied); - expect(4.toCanStartScan(), CanStartScan.noLocationServiceDisabled); + test("deserializeCanStartScan", () async { + // +ve test + final codes = [0, 1, 2, 3, 4]; + final enumValues = codes.map(deserializeCanStartScan).toList(); + expect(enumValues, [ + CanStartScan.notSupported, + CanStartScan.yes, + CanStartScan.noLocationPermissionRequired, + CanStartScan.noLocationPermissionDenied, + CanStartScan.noLocationServiceDisabled, + ]); + + // -ve test + expect(()=>deserializeCanGetScannedNetworks(-1), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(null), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(5), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(6), throwsUnsupportedError); }); - test("ToEnumExtension.toCanGetScannedNetworks", () async { - expect(0.toCanGetScannedNetworks(), CanGetScannedNetworks.yes); - expect(1.toCanGetScannedNetworks(), CanGetScannedNetworks.notSupported); - expect(2.toCanGetScannedNetworks(), - CanGetScannedNetworks.noLocationPermissionRequired); - expect(3.toCanGetScannedNetworks(), - CanGetScannedNetworks.noLocationPermissionDenied); - expect(4.toCanGetScannedNetworks(), - CanGetScannedNetworks.noLocationServiceDisabled); + test("deserializeCanGetScannedNetworks", () async { + // +ve test + final codes = [0, 1, 2, 3, 4]; + final enumValues = codes.map(deserializeCanGetScannedNetworks).toList(); + expect(enumValues, [ + CanGetScannedNetworks.notSupported, + CanGetScannedNetworks.yes, + CanGetScannedNetworks.noLocationPermissionRequired, + CanGetScannedNetworks.noLocationPermissionDenied, + CanGetScannedNetworks.noLocationServiceDisabled, + ]); + + // -ve test + expect(()=>deserializeCanGetScannedNetworks(-1), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(null), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(5), throwsUnsupportedError); + expect(()=>deserializeCanGetScannedNetworks(6), throwsUnsupportedError); }); } From 3a29cbe7f6cfbf659422583fcdaf9338f041b5de Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 12 Dec 2021 11:39:13 +0530 Subject: [PATCH 13/45] [wifi_scan] making "deserialization methods" private --- packages/wifi_scan/lib/can.dart | 4 +- packages/wifi_scan/lib/wifi_scan.dart | 4 +- packages/wifi_scan/test/wifi_scan_test.dart | 83 ++++++++++----------- 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/packages/wifi_scan/lib/can.dart b/packages/wifi_scan/lib/can.dart index 10d4cbfe..ed4d6c0c 100644 --- a/packages/wifi_scan/lib/can.dart +++ b/packages/wifi_scan/lib/can.dart @@ -8,7 +8,7 @@ enum CanStartScan { noLocationServiceDisabled, } -CanStartScan deserializeCanStartScan(int? canCode) { +CanStartScan _deserializeCanStartScan(int? canCode) { switch (canCode) { case 0: return CanStartScan.notSupported; @@ -32,7 +32,7 @@ enum CanGetScannedNetworks { noLocationServiceDisabled, } -CanGetScannedNetworks deserializeCanGetScannedNetworks(int? canCode) { +CanGetScannedNetworks _deserializeCanGetScannedNetworks(int? canCode) { switch (canCode) { case 0: return CanGetScannedNetworks.notSupported; diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 2ee428c5..168d3d6e 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -19,7 +19,7 @@ class WiFiScan { "canStartScan", {"askPermissions": askPermissions}, ); - return deserializeCanStartScan(canCode); + return _deserializeCanStartScan(canCode); } Future startScan() async { @@ -33,7 +33,7 @@ class WiFiScan { "canGetScannedNetworks", {"askPermissions": askPermissions}, ); - return deserializeCanGetScannedNetworks(canCode); + return _deserializeCanGetScannedNetworks(canCode); } Future> get scannedNetworks async { diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index 2b07146d..6606898f 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -23,8 +23,26 @@ void main() { }); test('canStartScan', () async { - mockHandlers["canStartScan"] = (_) => 1; - expect(await WiFiScan.instance.canStartScan(), CanStartScan.yes); + final canCodes = [0, 1, 2, 3, 4]; + final enumValues = [ + CanStartScan.notSupported, + CanStartScan.yes, + CanStartScan.noLocationPermissionRequired, + CanStartScan.noLocationPermissionDenied, + CanStartScan.noLocationServiceDisabled, + ]; + for (int i = 0; i < canCodes.length; i++) { + mockHandlers["canStartScan"] = (_) => canCodes[i]; + expect(await WiFiScan.instance.canStartScan(), enumValues[i]); + } + + // -ve test + final badCanCodes = [null, -1, 5, 6]; + for (int i = 0; i < badCanCodes.length; i++) { + mockHandlers["canStartScan"] = (_) => badCanCodes[i]; + expect(() async => await WiFiScan.instance.canStartScan(), + throwsUnsupportedError); + } }); test('startScan', () async { @@ -33,9 +51,26 @@ void main() { }); test("canGetScannedNetworks", () async { - mockHandlers["canGetScannedNetworks"] = (_) => 1; - expect(await WiFiScan.instance.canGetScannedNetworks(), - CanGetScannedNetworks.yes); + final canCodes = [0, 1, 2, 3, 4]; + final enumValues = [ + CanGetScannedNetworks.notSupported, + CanGetScannedNetworks.yes, + CanGetScannedNetworks.noLocationPermissionRequired, + CanGetScannedNetworks.noLocationPermissionDenied, + CanGetScannedNetworks.noLocationServiceDisabled, + ]; + for (int i = 0; i < canCodes.length; i++) { + mockHandlers["canGetScannedNetworks"] = (_) => canCodes[i]; + expect(await WiFiScan.instance.canGetScannedNetworks(), enumValues[i]); + } + + // -ve test + final badCanCodes = [null, -1, 5, 6]; + for (int i = 0; i < badCanCodes.length; i++) { + mockHandlers["canGetScannedNetworks"] = (_) => badCanCodes[i]; + expect(() async => await WiFiScan.instance.canGetScannedNetworks(), + throwsUnsupportedError); + } }); test("scannedNetworks", () async { @@ -46,42 +81,4 @@ void main() { // TODO: firgure out way to mock EventChannel // test("scannedNetworksStream", () async {}); - - test("deserializeCanStartScan", () async { - // +ve test - final codes = [0, 1, 2, 3, 4]; - final enumValues = codes.map(deserializeCanStartScan).toList(); - expect(enumValues, [ - CanStartScan.notSupported, - CanStartScan.yes, - CanStartScan.noLocationPermissionRequired, - CanStartScan.noLocationPermissionDenied, - CanStartScan.noLocationServiceDisabled, - ]); - - // -ve test - expect(()=>deserializeCanGetScannedNetworks(-1), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(null), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(5), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(6), throwsUnsupportedError); - }); - - test("deserializeCanGetScannedNetworks", () async { - // +ve test - final codes = [0, 1, 2, 3, 4]; - final enumValues = codes.map(deserializeCanGetScannedNetworks).toList(); - expect(enumValues, [ - CanGetScannedNetworks.notSupported, - CanGetScannedNetworks.yes, - CanGetScannedNetworks.noLocationPermissionRequired, - CanGetScannedNetworks.noLocationPermissionDenied, - CanGetScannedNetworks.noLocationServiceDisabled, - ]); - - // -ve test - expect(()=>deserializeCanGetScannedNetworks(-1), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(null), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(5), throwsUnsupportedError); - expect(()=>deserializeCanGetScannedNetworks(6), throwsUnsupportedError); - }); } From 086bdf4776e7e7637e2a936839ff3923daddedfd Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 12 Dec 2021 12:08:00 +0530 Subject: [PATCH 14/45] [android,ios] methods scaffolded --- .../wifi/wifi_scan/WifiScanPlugin.kt | 91 ++++++++++++++----- .../ios/Classes/SwiftWifiScanPlugin.swift | 14 ++- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index 72ffaf10..b3b22070 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -1,5 +1,7 @@ package dev.flutternetwork.wifi.wifi_scan +import android.content.Context +import android.net.wifi.WifiManager import androidx.annotation.NonNull import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -8,28 +10,75 @@ import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result +/** CanStartScan codes */ +private const val CAN_START_SCAN_NOT_SUPPORTED = 0 +private const val CAN_START_SCAN_YES = 1 +private const val CAN_START_SCAN_NO_LOCATION_PERMISSION_REQUIRED = 2 +private const val CAN_START_SCAN_NO_LOCATION_PERMISSION_DENIED = 3 +private const val CAN_START_SCAN_NO_LOCATION_SERVICE_DISABLED = 4 + +/** CanGetScannedResults codes */ +private const val CAN_GET_SCANNED_RESULTS_NOT_SUPPORTED = 0 +private const val CAN_GET_SCANNED_RESULTS_YES = 1 +private const val CAN_GET_SCANNED_RESULTS_NO_LOCATION_PERMISSION_REQUIRED = 2 +private const val CAN_GET_SCANNED_RESULTS_LOCATION_PERMISSION_DENIED = 3 +private const val CAN_GET_SCANNED_RESULTS_LOCATION_SERVICE_DISABLED = 4 + /** WifiScanPlugin */ -class WifiScanPlugin: FlutterPlugin, MethodCallHandler { - /// The MethodChannel that will the communication between Flutter and native Android - /// - /// This local reference serves to register the plugin with the Flutter Engine and unregister it - /// when the Flutter Engine is detached from the Activity - private lateinit var channel : MethodChannel - - override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") - channel.setMethodCallHandler(this) - } - - override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { - if (call.method == "getPlatformVersion") { - result.success("Android ${android.os.Build.VERSION.RELEASE}") - } else { - result.notImplemented() +class WifiScanPlugin : FlutterPlugin, MethodCallHandler { + private lateinit var channel: MethodChannel + private lateinit var context: Context + private var wifi: WifiManager? = null + + + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") + channel.setMethodCallHandler(this) + context = flutterPluginBinding.applicationContext + wifi = + context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + // TODO: handle wifi_scan/scannedNetworksEvent eventChannel + } + + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { + when (call.method) { + "canStartScan" -> { + val askPermission = call.argument("askPermissions") ?: return result.error( + "InvalidArg", + "askPermissions argument is null", + null + ) + result.success(canStartScan(askPermission)) + } + "startScan" -> result.success(startScan()) + "canGetScannedNetworks" -> { + val askPermission = call.argument("askPermissions") ?: return result.error( + "InvalidArg", + "askPermissions argument is null", + null + ) + result.success(canGetScannedNetworks(askPermission)) + } + "scannedNetworks" -> result.success(scannedNetworks()) + else -> result.notImplemented() + } } - } - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - } + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + wifi = null + } + + // TODO + private fun canStartScan(askPermission: Boolean): Int = CAN_START_SCAN_NOT_SUPPORTED + + // TODO + private fun startScan(): Boolean = false + + // TODO + private fun canGetScannedNetworks(askPermission: Boolean): Int = + CAN_GET_SCANNED_RESULTS_NOT_SUPPORTED + + // TODO + private fun scannedNetworks(): List> = emptyList() } diff --git a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift index bc3e99ce..fb658cea 100644 --- a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift +++ b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift @@ -6,9 +6,21 @@ public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { let channel = FlutterMethodChannel(name: "wifi_scan", binaryMessenger: registrar.messenger()) let instance = SwiftWifiScanPlugin() registrar.addMethodCallDelegate(instance, channel: channel) + // TODO: handle wifi_scan/scannedNetworksEvent eventChannel } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - result("iOS " + UIDevice.current.systemVersion) + switch(call.method){ + case "canStartScan": + return result(0) // not supported + case "startScan": + return result(false) // always fails + case "canGetScannedNetworks": + return result(0) // not supported + case "scannedNetworks": + return result([]) // empty results + default: + return result(FlutterMethodNotImplemented) + } } } From f6b108a7d0f243755e630b5c167f094fa2e75781 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 12 Dec 2021 12:08:39 +0530 Subject: [PATCH 15/45] formatting --- packages/wifi_scan/ios/Classes/WifiScanPlugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wifi_scan/ios/Classes/WifiScanPlugin.h b/packages/wifi_scan/ios/Classes/WifiScanPlugin.h index 9d390059..8e0a099e 100644 --- a/packages/wifi_scan/ios/Classes/WifiScanPlugin.h +++ b/packages/wifi_scan/ios/Classes/WifiScanPlugin.h @@ -1,4 +1,4 @@ #import -@interface WifiScanPlugin : NSObject +@interface WifiScanPlugin : NSObject @end From bca6e1221c1b8bb409ccf3fefc2485219c0c6c7d Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 12 Dec 2021 12:49:00 +0530 Subject: [PATCH 16/45] removing analysis_options.yaml file - not overriding the one in root --- packages/wifi_scan/analysis_options.yaml | 4 --- .../wifi_scan/example/analysis_options.yaml | 29 ------------------- 2 files changed, 33 deletions(-) delete mode 100644 packages/wifi_scan/analysis_options.yaml delete mode 100644 packages/wifi_scan/example/analysis_options.yaml diff --git a/packages/wifi_scan/analysis_options.yaml b/packages/wifi_scan/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/packages/wifi_scan/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/wifi_scan/example/analysis_options.yaml b/packages/wifi_scan/example/analysis_options.yaml deleted file mode 100644 index 61b6c4de..00000000 --- a/packages/wifi_scan/example/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options From 652e7597fb6c61fda49123fa9e13ae3f2df3390e Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Tue, 14 Dec 2021 21:39:21 +0530 Subject: [PATCH 17/45] - [android] implementing some methods - not tested yet - [example] added basic doc string - [wifi_scan] moved all non-wifi_scan classes/enum/fun to src - [wifi_scan] `WiFiNetwork`: added attributes and constructor - [wifi_scan,test] proper map values for mocked `scannedNetworks` handler Coded in flight AI-607 --- .../wifi/wifi_scan/WifiScanPlugin.kt | 56 ++++++++++++++----- packages/wifi_scan/example/lib/main.dart | 7 ++- packages/wifi_scan/lib/{ => src}/can.dart | 2 +- packages/wifi_scan/lib/src/wifi_network.dart | 41 ++++++++++++++ packages/wifi_scan/lib/wifi_network.dart | 5 -- packages/wifi_scan/lib/wifi_scan.dart | 4 +- packages/wifi_scan/test/wifi_scan_test.dart | 19 ++++++- 7 files changed, 107 insertions(+), 27 deletions(-) rename packages/wifi_scan/lib/{ => src}/can.dart (97%) create mode 100644 packages/wifi_scan/lib/src/wifi_network.dart delete mode 100644 packages/wifi_scan/lib/wifi_network.dart diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index b3b22070..d752046b 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -1,7 +1,9 @@ package dev.flutternetwork.wifi.wifi_scan import android.content.Context +import android.net.wifi.ScanResult import android.net.wifi.WifiManager +import android.os.Build import androidx.annotation.NonNull import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -13,16 +15,16 @@ import io.flutter.plugin.common.MethodChannel.Result /** CanStartScan codes */ private const val CAN_START_SCAN_NOT_SUPPORTED = 0 private const val CAN_START_SCAN_YES = 1 -private const val CAN_START_SCAN_NO_LOCATION_PERMISSION_REQUIRED = 2 -private const val CAN_START_SCAN_NO_LOCATION_PERMISSION_DENIED = 3 -private const val CAN_START_SCAN_NO_LOCATION_SERVICE_DISABLED = 4 +private const val CAN_START_SCAN_NO_LOC_PERM_REQUIRED = 2 +private const val CAN_START_SCAN_NO_LOC_PERM_DENIED = 3 +private const val CAN_START_SCAN_NO_LOC_DISABLED = 4 /** CanGetScannedResults codes */ -private const val CAN_GET_SCANNED_RESULTS_NOT_SUPPORTED = 0 -private const val CAN_GET_SCANNED_RESULTS_YES = 1 -private const val CAN_GET_SCANNED_RESULTS_NO_LOCATION_PERMISSION_REQUIRED = 2 -private const val CAN_GET_SCANNED_RESULTS_LOCATION_PERMISSION_DENIED = 3 -private const val CAN_GET_SCANNED_RESULTS_LOCATION_SERVICE_DISABLED = 4 +private const val CAN_GET_RESULTS_NOT_SUPPORTED = 0 +private const val CAN_GET_RESULTS_YES = 1 +private const val CAN_GET_RESULTS_NO_LOC_PERM_REQUIRED = 2 +private const val CAN_GET_RESULTS_NO_LOC_PERM_DENIED = 3 +private const val CAN_GET_RESULTS_NO_LOC_DISABLED = 4 /** WifiScanPlugin */ class WifiScanPlugin : FlutterPlugin, MethodCallHandler { @@ -69,16 +71,40 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler { wifi = null } - // TODO - private fun canStartScan(askPermission: Boolean): Int = CAN_START_SCAN_NOT_SUPPORTED + private fun canStartScan(askPermission: Boolean): Int = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) CAN_START_SCAN_NOT_SUPPORTED + else { + // TODO check if has location permission + // TODO check if can request? return noLocPermRequired or noLocPermDenied + // TODO else ask for permission - return yes (if granter) or noLocPermDenied + // TODO check if location service is enabled - return yes and noLocDisabled + CAN_START_SCAN_NOT_SUPPORTED + } - // TODO - private fun startScan(): Boolean = false + private fun startScan(): Boolean = wifi!!.startScan() // TODO private fun canGetScannedNetworks(askPermission: Boolean): Int = - CAN_GET_SCANNED_RESULTS_NOT_SUPPORTED + CAN_GET_RESULTS_NOT_SUPPORTED - // TODO - private fun scannedNetworks(): List> = emptyList() + private fun scannedNetworks(): List> { + return wifi!!.scanResults.map { network -> + mapOf( + "ssid" to network.SSID, + "bssid" to network.BSSID, + "capabilities" to network.capabilities, + "frequency" to network.frequency, + "level" to network.level, + "timestamp" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) network.timestamp else null, + "standard" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) network.wifiStandard else null, + "centerFrequency0" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.centerFreq0 else null, + "centerFrequency1" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.centerFreq1 else null, + "channelWidth" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.channelWidth else null, + "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.isPasspointNetwork else null, + "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.operatorFriendlyName else null, + "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.venueName else null, + "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.is80211mcResponder else null, + ) + } + } } diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index ea3134f1..cdba85a5 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -1,18 +1,19 @@ import 'package:flutter/material.dart'; void main() { - runApp(const MyApp()); + runApp(const MyApp._()); } -// TODO: proper example app +/// Example app for wifi_scan plugin. class MyApp extends StatefulWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp._({Key? key}) : super(key: key); @override State createState() => _MyAppState(); } class _MyAppState extends State { + // TODO: proper example app @override Widget build(BuildContext context) { return MaterialApp( diff --git a/packages/wifi_scan/lib/can.dart b/packages/wifi_scan/lib/src/can.dart similarity index 97% rename from packages/wifi_scan/lib/can.dart rename to packages/wifi_scan/lib/src/can.dart index ed4d6c0c..6dc6eaa6 100644 --- a/packages/wifi_scan/lib/can.dart +++ b/packages/wifi_scan/lib/src/can.dart @@ -1,4 +1,4 @@ -part of 'wifi_scan.dart'; +part of '../wifi_scan.dart'; enum CanStartScan { notSupported, diff --git a/packages/wifi_scan/lib/src/wifi_network.dart b/packages/wifi_scan/lib/src/wifi_network.dart new file mode 100644 index 00000000..533a9738 --- /dev/null +++ b/packages/wifi_scan/lib/src/wifi_network.dart @@ -0,0 +1,41 @@ +part of '../../wifi_scan.dart'; + +// TODO +enum WiFiStandards { unkown, legacy } + +WiFiStandards _deserializeWiFiStandards(int? standardCode) { + return WiFiStandards.unkown; +} + +class WiFiNetwork { + final String ssid; + final String bssid; + final String capabilities; + final int frequency; + final int level; + final int? timestamp; + final WiFiStandards standard; + final int? centerFrequency0; + final int? centerFrequency1; + final int? channelWidth; + final bool? isPasspoint; + final String? operatorFriendlyName; + final String? venueName; + final bool? is80211mcResponder; + + WiFiNetwork._fromMap(Map map) + : ssid = map["ssid"], + bssid = map["bssid"], + capabilities = map["capabilities"], + frequency = map["frequency"], + level = map["level"], + timestamp = map["timestamp"], + standard = _deserializeWiFiStandards(map["standard"]), + centerFrequency0 = map["centerFrequency0"], + centerFrequency1 = map["centerFrequency1"], + channelWidth = map["channelWidth"], + isPasspoint = map["isPasspoint"], + operatorFriendlyName = map["operatorFriendlyName"], + venueName = map["venueName"], + is80211mcResponder = map["is80211mcResponder"]; +} diff --git a/packages/wifi_scan/lib/wifi_network.dart b/packages/wifi_scan/lib/wifi_network.dart deleted file mode 100644 index 63957920..00000000 --- a/packages/wifi_scan/lib/wifi_network.dart +++ /dev/null @@ -1,5 +0,0 @@ -part of 'wifi_scan.dart'; - -class WiFiNetwork { - WiFiNetwork._fromMap(Map map); -} diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 168d3d6e..29300d6a 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'package:flutter/services.dart'; -part 'can.dart'; -part 'wifi_network.dart'; +part 'src/can.dart'; +part 'src/wifi_network.dart'; class WiFiScan { WiFiScan._(); diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index 6606898f..74b1b133 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -74,7 +74,24 @@ void main() { }); test("scannedNetworks", () async { - mockHandlers["scannedNetworks"] = (_) => [{}]; + mockHandlers["scannedNetworks"] = (_) => [ + { + "ssid": "my-ssid", + "bssid": "00:00:00:12", + "capabilities": "Unknown", + "frequency": 600, + "level": 5, + "timestamp": null, + "standard": null, + "centerFrequency0": null, + "centerFrequency1": null, + "channelWidth": null, + "isPasspoint": null, + "operatorFriendlyName": null, + "venueName": null, + "is80211mcResponder": null, + } + ]; final scannedNetworks = await WiFiScan.instance.scannedNetworks; expect(scannedNetworks.length, 1); }); From b94c295eac1c5a38fcc126a9e94caca44b2e67aa Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Tue, 14 Dec 2021 22:04:55 +0530 Subject: [PATCH 18/45] [android] minor fix --- .../kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index d752046b..c40dc927 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -103,7 +103,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler { "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.isPasspointNetwork else null, "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.operatorFriendlyName else null, "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.venueName else null, - "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.is80211mcResponder else null, + "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.is80211mcResponder else null ) } } From 3553043b69926e0c95de41f487dbe5af8ac47131 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Tue, 14 Dec 2021 22:06:42 +0530 Subject: [PATCH 19/45] - [android] minor fix - [example,android] various version derived from flutter tool --- packages/wifi_scan/example/android/app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/example/android/app/build.gradle b/packages/wifi_scan/example/android/app/build.gradle index 649e2816..81523995 100644 --- a/packages/wifi_scan/example/android/app/build.gradle +++ b/packages/wifi_scan/example/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + compileSdkVersion flutter.compileSdkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -44,8 +44,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "dev.flutternetwork.wifi.wifi_scan_example" - minSdkVersion 16 - targetSdkVersion 30 + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } From e10554c662083e4630d8835b18b78e697c8d619b Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 2 Jan 2022 16:28:09 +0530 Subject: [PATCH 20/45] docs: API docs added for all public member --- packages/wifi_scan/example/lib/main.dart | 5 +- packages/wifi_scan/lib/src/can.dart | 28 +++++ packages/wifi_scan/lib/src/wifi_network.dart | 126 +++++++++++++++++-- packages/wifi_scan/lib/wifi_scan.dart | 25 ++++ 4 files changed, 174 insertions(+), 10 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index cdba85a5..3732cfa9 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; void main() { - runApp(const MyApp._()); + runApp(const MyApp()); } /// Example app for wifi_scan plugin. class MyApp extends StatefulWidget { - const MyApp._({Key? key}) : super(key: key); + /// Default constructor for [MyApp] widget. + const MyApp({Key? key}) : super(key: key); @override State createState() => _MyAppState(); diff --git a/packages/wifi_scan/lib/src/can.dart b/packages/wifi_scan/lib/src/can.dart index 6dc6eaa6..711c05ef 100644 --- a/packages/wifi_scan/lib/src/can.dart +++ b/packages/wifi_scan/lib/src/can.dart @@ -1,10 +1,24 @@ part of '../wifi_scan.dart'; +/// Result for [WiFiScan.canStartScan] method. enum CanStartScan { + /// Functionality is not supported. notSupported, + + /// It is ok to call functionality. yes, + + /// Location permission is required. + /// + /// A prompt for permission can be requested. noLocationPermissionRequired, + + /// Location permission is denied. + /// + /// Need to ask user to manually allow from settings. noLocationPermissionDenied, + + /// Location service needs to be enabled. noLocationServiceDisabled, } @@ -24,11 +38,25 @@ CanStartScan _deserializeCanStartScan(int? canCode) { throw UnsupportedError("$canCode cannot be serialized to CanStartScan"); } +/// Result for [WiFiScan.canGetScannedNetworks] method. enum CanGetScannedNetworks { + /// Functionality is not supported. notSupported, + + /// It is ok to call functionality. yes, + + /// Location permission is required. + /// + /// A prompt for permission can be requested. noLocationPermissionRequired, + + /// Location permission is denied. + /// + /// Need to ask user to manually allow from settings. noLocationPermissionDenied, + + /// Location service needs to be enabled. noLocationServiceDisabled, } diff --git a/packages/wifi_scan/lib/src/wifi_network.dart b/packages/wifi_scan/lib/src/wifi_network.dart index 533a9738..e6a9ba0f 100644 --- a/packages/wifi_scan/lib/src/wifi_network.dart +++ b/packages/wifi_scan/lib/src/wifi_network.dart @@ -1,26 +1,136 @@ part of '../../wifi_scan.dart'; -// TODO -enum WiFiStandards { unkown, legacy } +/// WiFi standards. +enum WiFiStandards { + /// Unknown. + unkown, + + /// Wi-Fi 802.11a/b/g. + legacy, + + /// Wi-Fi 802.11n (Wi-Fi 4). + n, + + /// Wi-Fi 802.11ac (Wi-Fi 5). + ac, + + /// Wi-Fi 802.11ax (Wi-Fi 6). + ax, + + /// Wi-Fi 802.11ad. + ad, +} WiFiStandards _deserializeWiFiStandards(int? standardCode) { - return WiFiStandards.unkown; + switch (standardCode) { + case 1: + return WiFiStandards.legacy; + case 4: + return WiFiStandards.n; + case 5: + return WiFiStandards.ac; + case 6: + return WiFiStandards.ax; + case 7: + return WiFiStandards.ad; + default: + return WiFiStandards.unkown; + } } +/// Channel bandwidth supported by WiFi. +enum WiFiChannelWidth { + /// Unknown. + unkown, + + /// 20 MHZ. + mhz20, + + /// 40 MHZ. + mhz40, + + /// 40 MHZ. + mhz80, + + /// 160 MHZ. + mhz160, + + /// 160 MHZ, but 80MHZ + 80MHZ. + mhz80Plus80, +} + +WiFiChannelWidth _deserializeWiFiChannelWidth(int? channelWidthCode) { + switch (channelWidthCode) { + case 0: + return WiFiChannelWidth.mhz20; + case 1: + return WiFiChannelWidth.mhz40; + case 2: + return WiFiChannelWidth.mhz80; + case 3: + return WiFiChannelWidth.mhz160; + case 4: + return WiFiChannelWidth.mhz80Plus80; + default: + return WiFiChannelWidth.unkown; + } +} + +/// Describes information about a detected access point. class WiFiNetwork { + /// The network name. final String ssid; + + /// The address of the access point. final String bssid; + + /// Describes authentication and other schemes supported by the access point. final String capabilities; - final int frequency; - final int level; - final int? timestamp; + + /// WiFi standard supported by the access poit. final WiFiStandards standard; + + /// The detected signal level in dBm, also known as the RSSI. + final int level; + + /// Channel bandwidth of the access point. + final WiFiChannelWidth? channelWidth; + + /// The primary 20MHz frequency of the channel over which the client is + /// communicating with the AP. + /// + /// The value is in MHz. + final int frequency; + + /// Center frequency of the access point. + /// + /// For [WiFiChannelWidth.mhz20] bandwidth, it is null. + /// For [WiFiChannelWidth.mhz80Plus80] bandwidth, it is the center frequency + /// of the first segment. final int? centerFrequency0; + + /// Center frequency of the access point. + /// + /// Only used for [WiFiChannelWidth.mhz80Plus80] bandwidth, it is the center + /// frequency of the secod segment. final int? centerFrequency1; - final int? channelWidth; + + /// Timestamp in microseconds (since boot) when this result was last seen. + final int? timestamp; + + /// Indicates if the access point is a Passpoint (Hotspot 2.0). final bool? isPasspoint; + + /// Indicates Passpoint operator name published by access point. final String? operatorFriendlyName; + + /// Indicates venue name published by access point. + /// + /// Only available on Passpoint network and if published by access point. final String? venueName; + + /// Indicates if the access point can respond to IEEE 802.11mc (WiFi RTT) + /// ranging requests. final bool? is80211mcResponder; WiFiNetwork._fromMap(Map map) @@ -33,7 +143,7 @@ class WiFiNetwork { standard = _deserializeWiFiStandards(map["standard"]), centerFrequency0 = map["centerFrequency0"], centerFrequency1 = map["centerFrequency1"], - channelWidth = map["channelWidth"], + channelWidth = _deserializeWiFiChannelWidth(map["channelWidth"]), isPasspoint = map["isPasspoint"], operatorFriendlyName = map["operatorFriendlyName"], venueName = map["venueName"], diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 29300d6a..77d2ce92 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -5,15 +5,26 @@ import 'package:flutter/services.dart'; part 'src/can.dart'; part 'src/wifi_network.dart'; +/// The [WiFiScan] entry point. +/// +/// To get a new instance, call [WiFiScan.instance]. class WiFiScan { WiFiScan._(); + /// Singleton instance of [WiFiScan]. static final instance = WiFiScan._(); + final _channel = const MethodChannel('wifi_scan'); final _scannedNetworksChannel = const EventChannel('wifi_scan/scannedNetworksEvent'); Stream>? _scannedNetworksStream; + /// Checks if it is ok to call [startScan]. + /// + /// Necesearry platform requirements, like permissions dependent services, + /// configuration, etc are checked. + /// + /// Set [askPermissions] flag to ask user for necessary permissions. Future canStartScan({bool askPermissions = true}) async { final canCode = await _channel.invokeMethod( "canStartScan", @@ -22,11 +33,18 @@ class WiFiScan { return _deserializeCanStartScan(canCode); } + /// Future startScan() async { final isSucess = await _channel.invokeMethod("startScan"); return isSucess!; } + /// Checks if it is ok to call [scannedNetworks] or [scannedNetworksStream]. + /// + /// Necesearry platform requirements, like permissions dependent services, + /// configuration, etc are checked. + /// + /// Set [askPermissions] flag to ask user for necessary permissions. Future canGetScannedNetworks( {bool askPermissions = true}) async { final canCode = await _channel.invokeMethod( @@ -36,6 +54,9 @@ class WiFiScan { return _deserializeCanGetScannedNetworks(canCode); } + /// Get scanned networks. + /// + /// This are cached networks from last scan performed. Future> get scannedNetworks async { final scannedNetworks = await _channel.invokeListMethod("scannedNetworks"); @@ -44,6 +65,10 @@ class WiFiScan { .toList(growable: false); } + /// Stream of scanned networks. + /// + /// New results are added to stream when platform performs the scan, either by + /// itself or trigger with [startScan]. Stream> get scannedNetworksStream => _scannedNetworksStream ??= _scannedNetworksChannel.receiveBroadcastStream().map((event) { From 998aa5868d326ae346286837e1e1c83e4307a2af Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 2 Jan 2022 16:46:02 +0530 Subject: [PATCH 21/45] docs: improve API docs --- packages/wifi_scan/lib/wifi_scan.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 77d2ce92..4522eb49 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -33,7 +33,11 @@ class WiFiScan { return _deserializeCanStartScan(canCode); } + /// Request a Wi-Fi scan. /// + /// Return value indicates if the "scan" is being triggered. + /// + /// Should call [canStartScan] as a check before calling this method. Future startScan() async { final isSucess = await _channel.invokeMethod("startScan"); return isSucess!; @@ -56,7 +60,9 @@ class WiFiScan { /// Get scanned networks. /// - /// This are cached networks from last scan performed. + /// This are cached networks from most recently performed scan. + /// + /// Should call [canGetScannedNetworks] as a check before calling this method. Future> get scannedNetworks async { final scannedNetworks = await _channel.invokeListMethod("scannedNetworks"); @@ -69,6 +75,8 @@ class WiFiScan { /// /// New results are added to stream when platform performs the scan, either by /// itself or trigger with [startScan]. + /// + /// Should call [canGetScannedNetworks] as a check before calling this method. Stream> get scannedNetworksStream => _scannedNetworksStream ??= _scannedNetworksChannel.receiveBroadcastStream().map((event) { From 6fd30817da89aa55c85e685d46654f9daf87b241 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 2 Jan 2022 17:16:47 +0530 Subject: [PATCH 22/45] minor: todo added --- packages/wifi_scan/lib/src/wifi_network.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/wifi_scan/lib/src/wifi_network.dart b/packages/wifi_scan/lib/src/wifi_network.dart index e6a9ba0f..4dfe870d 100644 --- a/packages/wifi_scan/lib/src/wifi_network.dart +++ b/packages/wifi_scan/lib/src/wifi_network.dart @@ -85,6 +85,7 @@ class WiFiNetwork { final String bssid; /// Describes authentication and other schemes supported by the access point. + // TODO: parse this for proper enums for - security final String capabilities; /// WiFi standard supported by the access poit. From 222bd63addf5eb772b46122dd4f20a2b7ce29050 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 2 Jan 2022 17:45:07 +0530 Subject: [PATCH 23/45] example: basic UI added --- packages/wifi_scan/example/lib/main.dart | 101 ++++++++++++++++++++++- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index 3732cfa9..a03afc52 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -1,4 +1,6 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:wifi_scan/wifi_scan.dart'; void main() { runApp(const MyApp()); @@ -14,7 +16,53 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - // TODO: proper example app + // TODO: integrate streamed results + bool shouldStream = false; + List networks = []; + + void showSnackBar(BuildContext context, String message) { + if (kDebugMode) print(message); + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar(SnackBar(content: Text(message))); + } + + Future _startScan(BuildContext context) async { + // check if can-startScan + final can = await WiFiScan.instance.canStartScan(); + // if can-not, then show error + if (can != CanStartScan.yes) { + showSnackBar(context, "Cannot start scan: $can"); + return; + } + showSnackBar(context, "startScan: ${await WiFiScan.instance.startScan()}"); + } + + Future _fetchScannedResults(BuildContext context) async { + // check if can-getScannedResults + final can = await WiFiScan.instance.canGetScannedNetworks(); + // if can-not, then show error + if (can != CanGetScannedNetworks.yes) { + showSnackBar(context, "Cannot get scanned results: $can"); + networks = []; + return; + } + networks = await WiFiScan.instance.scannedNetworks; + } + + Widget _buildWifiNetworkList(BuildContext context) => networks.isEmpty + ? const Text("NO SCANNED RESULTS") + : ListView.builder( + itemCount: networks.length, + itemBuilder: (context, i) => ListTile( + title: Text(networks[i].ssid), + onTap: () => showDialog( + context: context, + builder: (context) => Text(networks[i].ssid), + ), + ), + ); + @override Widget build(BuildContext context) { return MaterialApp( @@ -22,8 +70,55 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Plugin example app'), ), - body: const Center( - child: Text('TODO'), + body: Builder( + builder: (context) => Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ElevatedButton.icon( + icon: const Icon(Icons.perm_scan_wifi), + label: const Text('SCAN'), + onPressed: () => _startScan(context), + ), + ElevatedButton.icon( + icon: const Icon(Icons.refresh), + label: const Text('GET'), + onPressed: () async { + await _fetchScannedResults(context); + setState(() {}); + }, + ), + Row( + children: [ + const Text("STREAM"), + Switch( + value: shouldStream, + onChanged: (v) => setState(() => shouldStream = v), + ), + ], + ) + ], + ), + const Divider(), + Flexible( + child: Center( + child: FutureBuilder( + future: _fetchScannedResults(context), + builder: (context, snapshot) => + snapshot.connectionState == ConnectionState.done + ? _buildWifiNetworkList(context) + : const CircularProgressIndicator(), + ), + ), + ), + ], + ), + ), ), ), ); From d28c51ed25573ed4a36fba655e20c77843582195 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 9 Jan 2022 18:41:14 +0530 Subject: [PATCH 24/45] - [can,tests] `CanStartScan` and `CanGetScannedNetworks`: added value `noLocationPermissionUpgradeAccuracy`; adjusted deserializers and tests for it - [android,manifest] added required permissions - [android] `WifiScanPlugin`: completed all implementation --- .../android/src/main/AndroidManifest.xml | 7 + .../wifi/wifi_scan/WifiScanPlugin.kt | 213 +++++++++++++++--- packages/wifi_scan/lib/src/can.dart | 14 ++ packages/wifi_scan/test/wifi_scan_test.dart | 10 +- 4 files changed, 213 insertions(+), 31 deletions(-) diff --git a/packages/wifi_scan/android/src/main/AndroidManifest.xml b/packages/wifi_scan/android/src/main/AndroidManifest.xml index 05e169ec..084415b0 100644 --- a/packages/wifi_scan/android/src/main/AndroidManifest.xml +++ b/packages/wifi_scan/android/src/main/AndroidManifest.xml @@ -1,3 +1,10 @@ + + + + + + + diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index c40dc927..b2733191 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -1,91 +1,250 @@ package dev.flutternetwork.wifi.wifi_scan +import android.Manifest +import android.app.Activity import android.content.Context -import android.net.wifi.ScanResult +import android.content.pm.PackageManager +import android.location.LocationManager import android.net.wifi.WifiManager import android.os.Build import androidx.annotation.NonNull - +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.core.location.LocationManagerCompat import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result +import io.flutter.plugin.common.PluginRegistry +import kotlin.random.Random + +/** Error Codes */ +private const val ERROR_INVALID_ARGS = "InvalidArgs" +private const val ERROR_NULL_ACTIVITY = "NullActivity" /** CanStartScan codes */ private const val CAN_START_SCAN_NOT_SUPPORTED = 0 private const val CAN_START_SCAN_YES = 1 private const val CAN_START_SCAN_NO_LOC_PERM_REQUIRED = 2 private const val CAN_START_SCAN_NO_LOC_PERM_DENIED = 3 -private const val CAN_START_SCAN_NO_LOC_DISABLED = 4 +private const val CAN_START_SCAN_NO_LOC_PERM_UPGRADE_ACCURACY = 4 +private const val CAN_START_SCAN_NO_LOC_DISABLED = 5 /** CanGetScannedResults codes */ private const val CAN_GET_RESULTS_NOT_SUPPORTED = 0 private const val CAN_GET_RESULTS_YES = 1 private const val CAN_GET_RESULTS_NO_LOC_PERM_REQUIRED = 2 private const val CAN_GET_RESULTS_NO_LOC_PERM_DENIED = 3 -private const val CAN_GET_RESULTS_NO_LOC_DISABLED = 4 +private const val CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY = 4 +private const val CAN_GET_RESULTS_NO_LOC_DISABLED = 5 + +/** Magic codes */ +private const val ASK_FOR_LOC_PERM = -1 + +typealias PermissionAskCallback = (status: LocPermStatus) -> Any +typealias PermissionResultCallback = (grantResults: IntArray) -> Boolean + +enum class LocPermStatus { + GRANTED, UPGRADE_TO_FINE, DENIED +} -/** WifiScanPlugin */ -class WifiScanPlugin : FlutterPlugin, MethodCallHandler { +/** WifiScanPlugin + * + * Useful links: + * - https://developer.android.com/guide/topics/connectivity/wifi-scan + * - https://developer.android.com/reference/android/net/wifi/WifiManager + * - https://developer.android.com/reference/android/net/wifi/ScanResult + * - https://developer.android.com/training/location/permissions + * */ +class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, + PluginRegistry.RequestPermissionsResultListener { private lateinit var channel: MethodChannel private lateinit var context: Context + private var activity: Activity? = null private var wifi: WifiManager? = null - + private val requestPermissionCookie = mutableMapOf() + private val locationPermissionCoarse = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION) + private val locationPermissionFine = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) + private val locationPermissionBoth = locationPermissionCoarse + locationPermissionFine override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") channel.setMethodCallHandler(this) context = flutterPluginBinding.applicationContext - wifi = - context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager // TODO: handle wifi_scan/scannedNetworksEvent eventChannel } + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + channel.setMethodCallHandler(null) + wifi = null + } + + + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + activity = binding.activity + binding.addRequestPermissionsResultListener(this) + } + + override fun onDetachedFromActivityForConfigChanges() { + activity = null + } + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { + activity = binding.activity + binding.addRequestPermissionsResultListener(this) + } + + override fun onDetachedFromActivity() { + activity = null + } + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { when (call.method) { "canStartScan" -> { val askPermission = call.argument("askPermissions") ?: return result.error( - "InvalidArg", + ERROR_INVALID_ARGS, "askPermissions argument is null", null ) - result.success(canStartScan(askPermission)) + when (val canCode = canStartScan(askPermission)) { + ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> + result.success( + when (status) { + LocPermStatus.GRANTED -> canStartScan(askPermission = false) + LocPermStatus.UPGRADE_TO_FINE -> CAN_START_SCAN_NO_LOC_PERM_UPGRADE_ACCURACY + LocPermStatus.DENIED -> CAN_START_SCAN_NO_LOC_PERM_DENIED + } + ) + } + else -> result.success(canCode) + } } "startScan" -> result.success(startScan()) "canGetScannedNetworks" -> { val askPermission = call.argument("askPermissions") ?: return result.error( - "InvalidArg", + ERROR_INVALID_ARGS, "askPermissions argument is null", null ) - result.success(canGetScannedNetworks(askPermission)) + when (val canCode = canGetScannedNetworks(askPermission)) { + ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> + when (status) { + LocPermStatus.GRANTED -> canGetScannedNetworks(askPermission = false) + LocPermStatus.UPGRADE_TO_FINE -> CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY + LocPermStatus.DENIED -> CAN_GET_RESULTS_NO_LOC_PERM_DENIED + } + } + else -> result.success(canCode) + } } "scannedNetworks" -> result.success(scannedNetworks()) else -> result.notImplemented() } } - override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) - wifi = null + + override fun onRequestPermissionsResult( + requestCode: Int, permissions: Array?, grantResults: IntArray? + ): Boolean { + if (grantResults != null) { + return requestPermissionCookie[requestCode]?.invoke(grantResults) ?: false + } + return false + } + + /** + * ACCESS_FINE_LOCATION required for: SDK >= Q[29] or tSDK >= Q[29] + */ + private fun requiresFineLocation(): Boolean = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q + + private fun hasLocationPermission(): Boolean { + val permissions = when { + requiresFineLocation() -> locationPermissionFine + else -> locationPermissionBoth + } + return permissions.any { permission -> + ContextCompat.checkSelfPermission(context, + permission) == PackageManager.PERMISSION_GRANTED + } } - private fun canStartScan(askPermission: Boolean): Int = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) CAN_START_SCAN_NOT_SUPPORTED - else { - // TODO check if has location permission - // TODO check if can request? return noLocPermRequired or noLocPermDenied - // TODO else ask for permission - return yes (if granter) or noLocPermDenied - // TODO check if location service is enabled - return yes and noLocDisabled - CAN_START_SCAN_NOT_SUPPORTED + private fun askForLocationPermission(result: Result, callback: PermissionAskCallback) { + // check if has activity - return error if null + if (activity == null) return result.error(ERROR_NULL_ACTIVITY, + "Cannot ask for location permission.", + "Looks like called from non-Activity.") + // make permissions + val requiresFine = requiresFineLocation() + // - for SDK > R[30] - cannot only ask for FINE + val requiresFineButAskBoth = requiresFine && Build.VERSION.SDK_INT > Build.VERSION_CODES.R + val permissions = when { + requiresFineButAskBoth -> locationPermissionBoth + requiresFine -> locationPermissionFine + else -> locationPermissionCoarse } + // request permission - add result-handler in requestPermissionCookie + val permissionCode = 6560000 + Random.Default.nextInt(10000) + requestPermissionCookie[permissionCode] = { grantArray -> + // invoke callback with proper status + callback.invoke( + when { + // GRANTED: if all granted + grantArray.all { it == PackageManager.PERMISSION_GRANTED } -> { + LocPermStatus.GRANTED + } + // UPGRADE_TO_FINE: if requiresFineButAskBoth and COARSE granted + requiresFineButAskBoth && grantArray.first() == PackageManager.PERMISSION_GRANTED -> { + LocPermStatus.UPGRADE_TO_FINE + } + else -> LocPermStatus.DENIED + } + ) + true + } + ActivityCompat.requestPermissions(activity!!, permissions, permissionCode) + } + + private fun isLocationEnabled(): Boolean = + LocationManagerCompat.isLocationEnabled( + context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager + ) + + private fun canStartScan(askPermission: Boolean): Int { + val hasLocPerm = hasLocationPermission() + val isLocEnabled = isLocationEnabled() + return when { + // for SDK < P[28] : Not in guide, should not require any additional permissions + Build.VERSION.SDK_INT < Build.VERSION_CODES.P -> CAN_START_SCAN_YES + // for SDK >= Q[29]: CHANGE_WIFI_STATE & ACCESS_x_LOCATION & "Location enabled" + hasLocPerm && isLocEnabled -> CAN_START_SCAN_YES + hasLocPerm -> CAN_START_SCAN_NO_LOC_DISABLED + askPermission -> ASK_FOR_LOC_PERM + else -> CAN_START_SCAN_NO_LOC_PERM_REQUIRED + } + } private fun startScan(): Boolean = wifi!!.startScan() - // TODO - private fun canGetScannedNetworks(askPermission: Boolean): Int = - CAN_GET_RESULTS_NOT_SUPPORTED + private fun canGetScannedNetworks(askPermission: Boolean): Int { + val hasLocPerm = hasLocationPermission() + val isLocEnabled = isLocationEnabled() + return when { + // for SDK <= O_MR1[27]: CHANGE_WIFI_STATE is enough + // for SDK == P[28]: Not in guide, should be same as P[27] + Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> CAN_GET_RESULTS_YES + // for SDK >= Q[29]: ACCESS_WIFI_STATE & ACCESS_x_LOCATION & "Location enabled" + hasLocPerm && isLocEnabled -> CAN_GET_RESULTS_YES + hasLocPerm -> CAN_GET_RESULTS_NO_LOC_DISABLED + askPermission -> ASK_FOR_LOC_PERM + else -> CAN_GET_RESULTS_NO_LOC_PERM_REQUIRED + } + } + private fun scannedNetworks(): List> { return wifi!!.scanResults.map { network -> diff --git a/packages/wifi_scan/lib/src/can.dart b/packages/wifi_scan/lib/src/can.dart index 711c05ef..391e84cd 100644 --- a/packages/wifi_scan/lib/src/can.dart +++ b/packages/wifi_scan/lib/src/can.dart @@ -18,6 +18,11 @@ enum CanStartScan { /// Need to ask user to manually allow from settings. noLocationPermissionDenied, + /// Location permission accuracy needs to be upgraded. + /// + /// Need to ask user to manually allow from settings. + noLocationPermissionUpgradeAccuracy, + /// Location service needs to be enabled. noLocationServiceDisabled, } @@ -33,6 +38,8 @@ CanStartScan _deserializeCanStartScan(int? canCode) { case 3: return CanStartScan.noLocationPermissionDenied; case 4: + return CanStartScan.noLocationPermissionUpgradeAccuracy; + case 5: return CanStartScan.noLocationServiceDisabled; } throw UnsupportedError("$canCode cannot be serialized to CanStartScan"); @@ -56,6 +63,11 @@ enum CanGetScannedNetworks { /// Need to ask user to manually allow from settings. noLocationPermissionDenied, + /// Location permission accuracy needs to be upgraded. + /// + /// Need to ask user to manually allow from settings. + noLocationPermissionUpgradeAccuracy, + /// Location service needs to be enabled. noLocationServiceDisabled, } @@ -71,6 +83,8 @@ CanGetScannedNetworks _deserializeCanGetScannedNetworks(int? canCode) { case 3: return CanGetScannedNetworks.noLocationPermissionDenied; case 4: + return CanGetScannedNetworks.noLocationPermissionUpgradeAccuracy; + case 5: return CanGetScannedNetworks.noLocationServiceDisabled; } throw UnsupportedError( diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index 74b1b133..a4ef5f3c 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -23,12 +23,13 @@ void main() { }); test('canStartScan', () async { - final canCodes = [0, 1, 2, 3, 4]; + final canCodes = [0, 1, 2, 3, 4, 5]; final enumValues = [ CanStartScan.notSupported, CanStartScan.yes, CanStartScan.noLocationPermissionRequired, CanStartScan.noLocationPermissionDenied, + CanStartScan.noLocationPermissionUpgradeAccuracy, CanStartScan.noLocationServiceDisabled, ]; for (int i = 0; i < canCodes.length; i++) { @@ -37,7 +38,7 @@ void main() { } // -ve test - final badCanCodes = [null, -1, 5, 6]; + final badCanCodes = [null, -1, 6, 7]; for (int i = 0; i < badCanCodes.length; i++) { mockHandlers["canStartScan"] = (_) => badCanCodes[i]; expect(() async => await WiFiScan.instance.canStartScan(), @@ -51,12 +52,13 @@ void main() { }); test("canGetScannedNetworks", () async { - final canCodes = [0, 1, 2, 3, 4]; + final canCodes = [0, 1, 2, 3, 4, 5]; final enumValues = [ CanGetScannedNetworks.notSupported, CanGetScannedNetworks.yes, CanGetScannedNetworks.noLocationPermissionRequired, CanGetScannedNetworks.noLocationPermissionDenied, + CanGetScannedNetworks.noLocationPermissionUpgradeAccuracy, CanGetScannedNetworks.noLocationServiceDisabled, ]; for (int i = 0; i < canCodes.length; i++) { @@ -65,7 +67,7 @@ void main() { } // -ve test - final badCanCodes = [null, -1, 5, 6]; + final badCanCodes = [null, -1, 6, 7]; for (int i = 0; i < badCanCodes.length; i++) { mockHandlers["canGetScannedNetworks"] = (_) => badCanCodes[i]; expect(() async => await WiFiScan.instance.canGetScannedNetworks(), From 530905d1dbac4d3466f222845fed8862728eadb8 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 9 Jan 2022 19:25:02 +0530 Subject: [PATCH 25/45] renaming - `WiFiNetwork` -> `WiFiAccessPoint` - `scannedNetworks` -> `getScannedResults` - `scannedNetworksStream` -> `onScannedResultsAvailable` - `CanGetScannedNetworks` -> `CanGetScannedResults` --- .../wifi/wifi_scan/WifiScanPlugin.kt | 44 ++++++------- packages/wifi_scan/example/lib/main.dart | 65 +++++++++++-------- .../ios/Classes/SwiftWifiScanPlugin.swift | 6 +- .../{wifi_network.dart => accesspoint.dart} | 6 +- packages/wifi_scan/lib/src/can.dart | 18 ++--- packages/wifi_scan/lib/wifi_scan.dart | 63 +++++++++--------- packages/wifi_scan/test/wifi_scan_test.dart | 30 ++++----- 7 files changed, 120 insertions(+), 112 deletions(-) rename packages/wifi_scan/lib/src/{wifi_network.dart => accesspoint.dart} (97%) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index b2733191..b3b833f6 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -75,7 +75,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, channel.setMethodCallHandler(this) context = flutterPluginBinding.applicationContext wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager - // TODO: handle wifi_scan/scannedNetworksEvent eventChannel + // TODO: handle wifi_scan/onScannedResultsAvailable eventChannel } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { @@ -124,16 +124,16 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } } "startScan" -> result.success(startScan()) - "canGetScannedNetworks" -> { + "canGetScannedResults" -> { val askPermission = call.argument("askPermissions") ?: return result.error( ERROR_INVALID_ARGS, "askPermissions argument is null", null ) - when (val canCode = canGetScannedNetworks(askPermission)) { + when (val canCode = canGetScannedResults(askPermission)) { ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> when (status) { - LocPermStatus.GRANTED -> canGetScannedNetworks(askPermission = false) + LocPermStatus.GRANTED -> canGetScannedResults(askPermission = false) LocPermStatus.UPGRADE_TO_FINE -> CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY LocPermStatus.DENIED -> CAN_GET_RESULTS_NO_LOC_PERM_DENIED } @@ -141,7 +141,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, else -> result.success(canCode) } } - "scannedNetworks" -> result.success(scannedNetworks()) + "getScannedResults" -> result.success(getScannedResults()) else -> result.notImplemented() } } @@ -230,7 +230,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, private fun startScan(): Boolean = wifi!!.startScan() - private fun canGetScannedNetworks(askPermission: Boolean): Int { + private fun canGetScannedResults(askPermission: Boolean): Int { val hasLocPerm = hasLocationPermission() val isLocEnabled = isLocationEnabled() return when { @@ -246,23 +246,23 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } - private fun scannedNetworks(): List> { - return wifi!!.scanResults.map { network -> + private fun getScannedResults(): List> { + return wifi!!.scanResults.map { ap -> mapOf( - "ssid" to network.SSID, - "bssid" to network.BSSID, - "capabilities" to network.capabilities, - "frequency" to network.frequency, - "level" to network.level, - "timestamp" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) network.timestamp else null, - "standard" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) network.wifiStandard else null, - "centerFrequency0" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.centerFreq0 else null, - "centerFrequency1" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.centerFreq1 else null, - "channelWidth" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.channelWidth else null, - "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.isPasspointNetwork else null, - "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.operatorFriendlyName else null, - "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.venueName else null, - "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) network.is80211mcResponder else null + "ssid" to ap.SSID, + "bssid" to ap.BSSID, + "capabilities" to ap.capabilities, + "frequency" to ap.frequency, + "level" to ap.level, + "timestamp" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ap.timestamp else null, + "standard" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ap.wifiStandard else null, + "centerFrequency0" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq0 else null, + "centerFrequency1" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq1 else null, + "channelWidth" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.channelWidth else null, + "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.isPasspointNetwork else null, + "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.operatorFriendlyName else null, + "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.venueName else null, + "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.is80211mcResponder else null ) } } diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index a03afc52..8e95cf4b 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -16,9 +16,11 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { + bool shouldCheck = false; + // TODO: integrate streamed results bool shouldStream = false; - List networks = []; + List accessPoints = []; void showSnackBar(BuildContext context, String message) { if (kDebugMode) print(message); @@ -28,37 +30,49 @@ class _MyAppState extends State { } Future _startScan(BuildContext context) async { - // check if can-startScan - final can = await WiFiScan.instance.canStartScan(); - // if can-not, then show error - if (can != CanStartScan.yes) { - showSnackBar(context, "Cannot start scan: $can"); - return; + if (shouldCheck) { + // check if can-startScan + final can = await WiFiScan.instance.canStartScan(); + // if can-not, then show error + if (can != CanStartScan.yes) { + showSnackBar(context, "Cannot start scan: $can"); + return; + } } showSnackBar(context, "startScan: ${await WiFiScan.instance.startScan()}"); } Future _fetchScannedResults(BuildContext context) async { - // check if can-getScannedResults - final can = await WiFiScan.instance.canGetScannedNetworks(); - // if can-not, then show error - if (can != CanGetScannedNetworks.yes) { - showSnackBar(context, "Cannot get scanned results: $can"); - networks = []; - return; + if (shouldCheck) { + // check if can-getScannedResults + final can = await WiFiScan.instance.canGetScannedResults(); + // if can-not, then show error + if (can != CanGetScannedResults.yes) { + showSnackBar(context, "Cannot get scanned results: $can"); + accessPoints = []; + return; + } } - networks = await WiFiScan.instance.scannedNetworks; + accessPoints = await WiFiScan.instance.getScannedResults(); } - Widget _buildWifiNetworkList(BuildContext context) => networks.isEmpty + Widget _buildSwitch(String label, bool value, ValueChanged onChanged) => + Row( + children: [ + Text(label), + Switch(value: value, onChanged: onChanged), + ], + ); + + Widget _buildWifiNetworkList(BuildContext context) => accessPoints.isEmpty ? const Text("NO SCANNED RESULTS") : ListView.builder( - itemCount: networks.length, + itemCount: accessPoints.length, itemBuilder: (context, i) => ListTile( - title: Text(networks[i].ssid), + title: Text(accessPoints[i].ssid), onTap: () => showDialog( context: context, - builder: (context) => Text(networks[i].ssid), + builder: (context) => Text(accessPoints[i].ssid), ), ), ); @@ -77,6 +91,8 @@ class _MyAppState extends State { mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ + _buildSwitch("SHOULD CHECK", shouldCheck, + (v) => setState(() => shouldCheck = v)), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -93,15 +109,8 @@ class _MyAppState extends State { setState(() {}); }, ), - Row( - children: [ - const Text("STREAM"), - Switch( - value: shouldStream, - onChanged: (v) => setState(() => shouldStream = v), - ), - ], - ) + _buildSwitch("STREAM", shouldStream, + (v) => setState(() => shouldStream = v)), ], ), const Divider(), diff --git a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift index fb658cea..93a59d67 100644 --- a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift +++ b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift @@ -6,7 +6,7 @@ public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { let channel = FlutterMethodChannel(name: "wifi_scan", binaryMessenger: registrar.messenger()) let instance = SwiftWifiScanPlugin() registrar.addMethodCallDelegate(instance, channel: channel) - // TODO: handle wifi_scan/scannedNetworksEvent eventChannel + // TODO: handle wifi_scan/onScannedResultsAvailable eventChannel } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -15,9 +15,9 @@ public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { return result(0) // not supported case "startScan": return result(false) // always fails - case "canGetScannedNetworks": + case "canGetScannedResults": return result(0) // not supported - case "scannedNetworks": + case "getScannedResults": return result([]) // empty results default: return result(FlutterMethodNotImplemented) diff --git a/packages/wifi_scan/lib/src/wifi_network.dart b/packages/wifi_scan/lib/src/accesspoint.dart similarity index 97% rename from packages/wifi_scan/lib/src/wifi_network.dart rename to packages/wifi_scan/lib/src/accesspoint.dart index 4dfe870d..44e07b78 100644 --- a/packages/wifi_scan/lib/src/wifi_network.dart +++ b/packages/wifi_scan/lib/src/accesspoint.dart @@ -1,4 +1,4 @@ -part of '../../wifi_scan.dart'; +part of '../wifi_scan.dart'; /// WiFi standards. enum WiFiStandards { @@ -77,7 +77,7 @@ WiFiChannelWidth _deserializeWiFiChannelWidth(int? channelWidthCode) { } /// Describes information about a detected access point. -class WiFiNetwork { +class WiFiAccessPoint { /// The network name. final String ssid; @@ -134,7 +134,7 @@ class WiFiNetwork { /// ranging requests. final bool? is80211mcResponder; - WiFiNetwork._fromMap(Map map) + WiFiAccessPoint._fromMap(Map map) : ssid = map["ssid"], bssid = map["bssid"], capabilities = map["capabilities"], diff --git a/packages/wifi_scan/lib/src/can.dart b/packages/wifi_scan/lib/src/can.dart index 391e84cd..35917924 100644 --- a/packages/wifi_scan/lib/src/can.dart +++ b/packages/wifi_scan/lib/src/can.dart @@ -45,8 +45,8 @@ CanStartScan _deserializeCanStartScan(int? canCode) { throw UnsupportedError("$canCode cannot be serialized to CanStartScan"); } -/// Result for [WiFiScan.canGetScannedNetworks] method. -enum CanGetScannedNetworks { +/// Result for [WiFiScan.canGetScannedResults] method. +enum CanGetScannedResults { /// Functionality is not supported. notSupported, @@ -72,20 +72,20 @@ enum CanGetScannedNetworks { noLocationServiceDisabled, } -CanGetScannedNetworks _deserializeCanGetScannedNetworks(int? canCode) { +CanGetScannedResults _deserializeCanGetScannedResults(int? canCode) { switch (canCode) { case 0: - return CanGetScannedNetworks.notSupported; + return CanGetScannedResults.notSupported; case 1: - return CanGetScannedNetworks.yes; + return CanGetScannedResults.yes; case 2: - return CanGetScannedNetworks.noLocationPermissionRequired; + return CanGetScannedResults.noLocationPermissionRequired; case 3: - return CanGetScannedNetworks.noLocationPermissionDenied; + return CanGetScannedResults.noLocationPermissionDenied; case 4: - return CanGetScannedNetworks.noLocationPermissionUpgradeAccuracy; + return CanGetScannedResults.noLocationPermissionUpgradeAccuracy; case 5: - return CanGetScannedNetworks.noLocationServiceDisabled; + return CanGetScannedResults.noLocationServiceDisabled; } throw UnsupportedError( "$canCode cannot be serialized to CanGetScannedNetworks"); diff --git a/packages/wifi_scan/lib/wifi_scan.dart b/packages/wifi_scan/lib/wifi_scan.dart index 4522eb49..205d7df4 100644 --- a/packages/wifi_scan/lib/wifi_scan.dart +++ b/packages/wifi_scan/lib/wifi_scan.dart @@ -2,10 +2,11 @@ import 'dart:async'; import 'package:flutter/services.dart'; +part 'src/accesspoint.dart'; + part 'src/can.dart'; -part 'src/wifi_network.dart'; -/// The [WiFiScan] entry point. +/// The `wifi_scan` plugin entry point. /// /// To get a new instance, call [WiFiScan.instance]. class WiFiScan { @@ -15,21 +16,20 @@ class WiFiScan { static final instance = WiFiScan._(); final _channel = const MethodChannel('wifi_scan'); - final _scannedNetworksChannel = - const EventChannel('wifi_scan/scannedNetworksEvent'); - Stream>? _scannedNetworksStream; + final _scannedResultsAvailableChannel = + const EventChannel('wifi_scan/onScannedResultsAvailable'); + Stream>? _onScannedResultsAvailable; - /// Checks if it is ok to call [startScan]. + /// Checks if it is ok to invoke [startScan]. /// /// Necesearry platform requirements, like permissions dependent services, /// configuration, etc are checked. /// /// Set [askPermissions] flag to ask user for necessary permissions. Future canStartScan({bool askPermissions = true}) async { - final canCode = await _channel.invokeMethod( - "canStartScan", - {"askPermissions": askPermissions}, - ); + final canCode = await _channel.invokeMethod("canStartScan", { + "askPermissions": askPermissions, + }); return _deserializeCanStartScan(canCode); } @@ -43,49 +43,48 @@ class WiFiScan { return isSucess!; } - /// Checks if it is ok to call [scannedNetworks] or [scannedNetworksStream]. + /// Checks if it is ok to invoke [getScannedResults] or [onScannedResultsAvailable]. /// /// Necesearry platform requirements, like permissions dependent services, /// configuration, etc are checked. /// /// Set [askPermissions] flag to ask user for necessary permissions. - Future canGetScannedNetworks( + Future canGetScannedResults( {bool askPermissions = true}) async { - final canCode = await _channel.invokeMethod( - "canGetScannedNetworks", - {"askPermissions": askPermissions}, - ); - return _deserializeCanGetScannedNetworks(canCode); + final canCode = await _channel.invokeMethod("canGetScannedResults", { + "askPermissions": askPermissions, + }); + return _deserializeCanGetScannedResults(canCode); } - /// Get scanned networks. + /// Get scanned access point. /// - /// This are cached networks from most recently performed scan. + /// This are cached accesss points from most recently performed scan. /// - /// Should call [canGetScannedNetworks] as a check before calling this method. - Future> get scannedNetworks async { - final scannedNetworks = - await _channel.invokeListMethod("scannedNetworks"); - return scannedNetworks! - .map((map) => WiFiNetwork._fromMap(map)) + /// Should call [canGetScannedResults] as a check before calling this method. + Future> getScannedResults() async { + final scannedResults = + await _channel.invokeListMethod("getScannedResults"); + return scannedResults! + .map((map) => WiFiAccessPoint._fromMap(map)) .toList(growable: false); } - /// Stream of scanned networks. + /// Fires whenever new scanned results are available. /// /// New results are added to stream when platform performs the scan, either by /// itself or trigger with [startScan]. /// - /// Should call [canGetScannedNetworks] as a check before calling this method. - Stream> get scannedNetworksStream => - _scannedNetworksStream ??= - _scannedNetworksChannel.receiveBroadcastStream().map((event) { + /// Should call [canGetScannedResults] as a check before calling this method. + Stream> get onScannedResultsAvailable => + _onScannedResultsAvailable ??= + _scannedResultsAvailableChannel.receiveBroadcastStream().map((event) { if (event is Error) throw event; if (event is List) { return event - .map((map) => WiFiNetwork._fromMap(map)) + .map((map) => WiFiAccessPoint._fromMap(map)) .toList(growable: false); } - return const []; + return const []; }); } diff --git a/packages/wifi_scan/test/wifi_scan_test.dart b/packages/wifi_scan/test/wifi_scan_test.dart index a4ef5f3c..9f84ec28 100644 --- a/packages/wifi_scan/test/wifi_scan_test.dart +++ b/packages/wifi_scan/test/wifi_scan_test.dart @@ -51,32 +51,32 @@ void main() { expect(await WiFiScan.instance.startScan(), true); }); - test("canGetScannedNetworks", () async { + test("CanGetScannedResults", () async { final canCodes = [0, 1, 2, 3, 4, 5]; final enumValues = [ - CanGetScannedNetworks.notSupported, - CanGetScannedNetworks.yes, - CanGetScannedNetworks.noLocationPermissionRequired, - CanGetScannedNetworks.noLocationPermissionDenied, - CanGetScannedNetworks.noLocationPermissionUpgradeAccuracy, - CanGetScannedNetworks.noLocationServiceDisabled, + CanGetScannedResults.notSupported, + CanGetScannedResults.yes, + CanGetScannedResults.noLocationPermissionRequired, + CanGetScannedResults.noLocationPermissionDenied, + CanGetScannedResults.noLocationPermissionUpgradeAccuracy, + CanGetScannedResults.noLocationServiceDisabled, ]; for (int i = 0; i < canCodes.length; i++) { - mockHandlers["canGetScannedNetworks"] = (_) => canCodes[i]; - expect(await WiFiScan.instance.canGetScannedNetworks(), enumValues[i]); + mockHandlers["canGetScannedResults"] = (_) => canCodes[i]; + expect(await WiFiScan.instance.canGetScannedResults(), enumValues[i]); } // -ve test final badCanCodes = [null, -1, 6, 7]; for (int i = 0; i < badCanCodes.length; i++) { - mockHandlers["canGetScannedNetworks"] = (_) => badCanCodes[i]; - expect(() async => await WiFiScan.instance.canGetScannedNetworks(), + mockHandlers["canGetScannedResults"] = (_) => badCanCodes[i]; + expect(() async => await WiFiScan.instance.canGetScannedResults(), throwsUnsupportedError); } }); - test("scannedNetworks", () async { - mockHandlers["scannedNetworks"] = (_) => [ + test("getScannedResults", () async { + mockHandlers["getScannedResults"] = (_) => [ { "ssid": "my-ssid", "bssid": "00:00:00:12", @@ -94,10 +94,10 @@ void main() { "is80211mcResponder": null, } ]; - final scannedNetworks = await WiFiScan.instance.scannedNetworks; + final scannedNetworks = await WiFiScan.instance.getScannedResults(); expect(scannedNetworks.length, 1); }); // TODO: firgure out way to mock EventChannel - // test("scannedNetworksStream", () async {}); + // test("onScannedResultsAvailable", () async {}); } From 1c4ff68757ac9f710ca32868002c41baa686ce81 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 9 Jan 2022 23:36:20 +0530 Subject: [PATCH 26/45] - [accesspoint] docs improved for `level` - [ios] added `wifi_scan/onScannedResultsAvailable` eventChannel with `DummyStreamHandler` - [android] added `wifi_scan/onScannedResultsAvailable` eventChannel; `canGetScannedResults` - always checking loc-perm and loc-enabled - [example,ios] project file updated after build - [example] integrated `WiFiScan.onScannedResultsAvailable` stream --- .../android/src/main/AndroidManifest.xml | 2 +- .../wifi/wifi_scan/WifiScanPlugin.kt | 91 ++++++++++----- .../ios/Runner.xcodeproj/project.pbxproj | 68 +++++++++++ .../contents.xcworkspacedata | 3 + packages/wifi_scan/example/lib/main.dart | 106 ++++++++++++++---- .../ios/Classes/SwiftWifiScanPlugin.swift | 22 +++- packages/wifi_scan/lib/src/accesspoint.dart | 15 ++- 7 files changed, 250 insertions(+), 57 deletions(-) diff --git a/packages/wifi_scan/android/src/main/AndroidManifest.xml b/packages/wifi_scan/android/src/main/AndroidManifest.xml index 084415b0..54f7b9a0 100644 --- a/packages/wifi_scan/android/src/main/AndroidManifest.xml +++ b/packages/wifi_scan/android/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ package="dev.flutternetwork.wifi.wifi_scan"> - + diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index b3b833f6..6e81a730 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -2,7 +2,10 @@ package dev.flutternetwork.wifi.wifi_scan import android.Manifest import android.app.Activity +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.content.pm.PackageManager import android.location.LocationManager import android.net.wifi.WifiManager @@ -14,6 +17,8 @@ import androidx.core.location.LocationManagerCompat import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.EventChannel.EventSink import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler @@ -60,26 +65,48 @@ enum class LocPermStatus { * - https://developer.android.com/training/location/permissions * */ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, - PluginRegistry.RequestPermissionsResultListener { - private lateinit var channel: MethodChannel + PluginRegistry.RequestPermissionsResultListener, EventChannel.StreamHandler { private lateinit var context: Context private var activity: Activity? = null private var wifi: WifiManager? = null + private var wifiScanReceiver: BroadcastReceiver? = null private val requestPermissionCookie = mutableMapOf() private val locationPermissionCoarse = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION) private val locationPermissionFine = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) private val locationPermissionBoth = locationPermissionCoarse + locationPermissionFine + // plugin interfaces + private lateinit var channel: MethodChannel + private lateinit var eventChannel: EventChannel + // single sink - to send + private var eventSink: EventSink? = null + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") - channel.setMethodCallHandler(this) context = flutterPluginBinding.applicationContext wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager - // TODO: handle wifi_scan/onScannedResultsAvailable eventChannel + // set broadcast receiver - listening for new scannedResults + wifiScanReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { + eventSink?.success(getScannedResults()) + } + } + } + val intentFilter = IntentFilter() + intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) + context.registerReceiver(wifiScanReceiver, intentFilter) + + // set Flutter channels - 1 for method, 1 for event + channel = MethodChannel(flutterPluginBinding.binaryMessenger, "wifi_scan") + channel.setMethodCallHandler(this) + eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, + "wifi_scan/onScannedResultsAvailable") + eventChannel.setStreamHandler(this) } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) + eventChannel.setStreamHandler(null) wifi = null } @@ -102,6 +129,17 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, activity = null } + override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + eventSink = events + // put getScannedResults in sink - to start with + eventSink?.success(getScannedResults()) + } + + override fun onCancel(arguments: Any?) { + eventSink?.endOfStream() + eventSink = null + } + override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { when (call.method) { "canStartScan" -> { @@ -157,7 +195,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } /** - * ACCESS_FINE_LOCATION required for: SDK >= Q[29] or tSDK >= Q[29] + * ACCESS_FINE_LOCATION required for: SDK >= Q[29] and tSDK >= Q[29] */ private fun requiresFineLocation(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && context.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q @@ -231,13 +269,10 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, private fun startScan(): Boolean = wifi!!.startScan() private fun canGetScannedResults(askPermission: Boolean): Int { + // ACCESS_WIFI_STATE & ACCESS_x_LOCATION & "Location enabled" val hasLocPerm = hasLocationPermission() val isLocEnabled = isLocationEnabled() return when { - // for SDK <= O_MR1[27]: CHANGE_WIFI_STATE is enough - // for SDK == P[28]: Not in guide, should be same as P[27] - Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> CAN_GET_RESULTS_YES - // for SDK >= Q[29]: ACCESS_WIFI_STATE & ACCESS_x_LOCATION & "Location enabled" hasLocPerm && isLocEnabled -> CAN_GET_RESULTS_YES hasLocPerm -> CAN_GET_RESULTS_NO_LOC_DISABLED askPermission -> ASK_FOR_LOC_PERM @@ -246,24 +281,22 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } - private fun getScannedResults(): List> { - return wifi!!.scanResults.map { ap -> - mapOf( - "ssid" to ap.SSID, - "bssid" to ap.BSSID, - "capabilities" to ap.capabilities, - "frequency" to ap.frequency, - "level" to ap.level, - "timestamp" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ap.timestamp else null, - "standard" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ap.wifiStandard else null, - "centerFrequency0" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq0 else null, - "centerFrequency1" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq1 else null, - "channelWidth" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.channelWidth else null, - "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.isPasspointNetwork else null, - "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.operatorFriendlyName else null, - "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.venueName else null, - "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.is80211mcResponder else null - ) - } + private fun getScannedResults(): List> = wifi!!.scanResults.map { ap -> + mapOf( + "ssid" to ap.SSID, + "bssid" to ap.BSSID, + "capabilities" to ap.capabilities, + "frequency" to ap.frequency, + "level" to ap.level, + "timestamp" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ap.timestamp else null, + "standard" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ap.wifiStandard else null, + "centerFrequency0" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq0 else null, + "centerFrequency1" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.centerFreq1 else null, + "channelWidth" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.channelWidth else null, + "isPasspoint" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.isPasspointNetwork else null, + "operatorFriendlyName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.operatorFriendlyName else null, + "venueName" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.venueName else null, + "is80211mcResponder" to if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ap.is80211mcResponder else null + ) } } diff --git a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj index 830cb6a5..1a83e33e 100644 --- a/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/wifi_scan/example/ios/Runner.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + ED879899797BD40D00C7B393 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6681C9196B2BF084ED992EA /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -29,12 +30,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 121E5D67847E04B5C947BCDE /* 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 = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 82A6DCFC7EA9D7C1336EF2EA /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -42,6 +45,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A6681C9196B2BF084ED992EA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C5F3F3F716039D241CAC1708 /* 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -49,12 +54,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + ED879899797BD40D00C7B393 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1CADE8A57AF19FCDC38BD916 /* Pods */ = { + isa = PBXGroup; + children = ( + C5F3F3F716039D241CAC1708 /* Pods-Runner.debug.xcconfig */, + 121E5D67847E04B5C947BCDE /* Pods-Runner.release.xcconfig */, + 82A6DCFC7EA9D7C1336EF2EA /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 69D99339F5B441DA08C72CDB /* Frameworks */ = { + isa = PBXGroup; + children = ( + A6681C9196B2BF084ED992EA /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +97,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 1CADE8A57AF19FCDC38BD916 /* Pods */, + 69D99339F5B441DA08C72CDB /* Frameworks */, ); sourceTree = ""; }; @@ -105,12 +132,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + BDFFD52AD972BFD0CCAF76A4 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 9119DAADF478773DD2355190 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -183,6 +212,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 9119DAADF478773DD2355190 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -197,6 +243,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + BDFFD52AD972BFD0CCAF76A4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + 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; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/wifi_scan/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index 8e95cf4b..17a38097 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -16,9 +16,7 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - bool shouldCheck = false; - - // TODO: integrate streamed results + bool shouldCheck = true; bool shouldStream = false; List accessPoints = []; @@ -42,7 +40,7 @@ class _MyAppState extends State { showSnackBar(context, "startScan: ${await WiFiScan.instance.startScan()}"); } - Future _fetchScannedResults(BuildContext context) async { + Future _canGetScannedResults(BuildContext context) async { if (shouldCheck) { // check if can-getScannedResults final can = await WiFiScan.instance.canGetScannedResults(); @@ -50,10 +48,10 @@ class _MyAppState extends State { if (can != CanGetScannedResults.yes) { showSnackBar(context, "Cannot get scanned results: $can"); accessPoints = []; - return; + return false; } } - accessPoints = await WiFiScan.instance.getScannedResults(); + return true; } Widget _buildSwitch(String label, bool value, ValueChanged onChanged) => @@ -64,17 +62,82 @@ class _MyAppState extends State { ], ); - Widget _buildWifiNetworkList(BuildContext context) => accessPoints.isEmpty + Widget _buildInfo(String label, dynamic value) => Container( + decoration: const BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.grey))), + child: Row( + children: [ + Text("$label: ", + style: const TextStyle(fontWeight: FontWeight.bold)), + Expanded(child: Text(value.toString())) + ], + ), + ); + + Widget _buildWifiApList(BuildContext context) => accessPoints.isEmpty ? const Text("NO SCANNED RESULTS") : ListView.builder( itemCount: accessPoints.length, - itemBuilder: (context, i) => ListTile( - title: Text(accessPoints[i].ssid), - onTap: () => showDialog( - context: context, - builder: (context) => Text(accessPoints[i].ssid), - ), - ), + itemBuilder: (context, i) { + final ap = accessPoints[i]; + final title = ap.ssid.isNotEmpty ? ap.ssid : "**EMPTY**"; + final signalIcon = ap.level >= -80 + ? Icons.signal_wifi_4_bar + : Icons.signal_wifi_0_bar; + return ListTile( + visualDensity: VisualDensity.compact, + leading: Icon(signalIcon), + title: Text(title), + subtitle: Text(ap.capabilities), + onTap: () => showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(title), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildInfo("BSSDI", ap.bssid), + _buildInfo("Capability", ap.capabilities), + _buildInfo("frequency", "${ap.frequency}MHz"), + _buildInfo("level", ap.level), + _buildInfo("standard", ap.standard), + _buildInfo( + "centerFrequency0", "${ap.centerFrequency0}MHz"), + _buildInfo( + "centerFrequency1", "${ap.centerFrequency1}MHz"), + _buildInfo("channelWidth", ap.channelWidth), + _buildInfo("isPasspoint", ap.isPasspoint), + _buildInfo( + "operatorFriendlyName", ap.operatorFriendlyName), + _buildInfo("venueName", ap.venueName), + _buildInfo("is80211mcResponder", ap.is80211mcResponder), + ], + ), + ), + ), + ); + }, + ); + + Widget _buildWifiAPStreamable(BuildContext context) => !shouldStream + ? _buildWifiApList(context) + : FutureBuilder( + future: _canGetScannedResults(context), + builder: (context, snapshotCan) { + if (snapshotCan.connectionState != ConnectionState.done) { + return const CircularProgressIndicator(); + } + return StreamBuilder>( + stream: WiFiScan.instance.onScannedResultsAvailable, + builder: (context, snapshot) { + if (snapshotCan.data ?? false) { + // update accesspoint if available + accessPoints = snapshot.data ?? accessPoints; + } + return _buildWifiApList(context); + }, + ); + }, ); @override @@ -105,8 +168,11 @@ class _MyAppState extends State { icon: const Icon(Icons.refresh), label: const Text('GET'), onPressed: () async { - await _fetchScannedResults(context); - setState(() {}); + if (await _canGetScannedResults(context)) { + accessPoints = + await WiFiScan.instance.getScannedResults(); + setState(() {}); + } }, ), _buildSwitch("STREAM", shouldStream, @@ -116,13 +182,7 @@ class _MyAppState extends State { const Divider(), Flexible( child: Center( - child: FutureBuilder( - future: _fetchScannedResults(context), - builder: (context, snapshot) => - snapshot.connectionState == ConnectionState.done - ? _buildWifiNetworkList(context) - : const CircularProgressIndicator(), - ), + child: _buildWifiAPStreamable(context), ), ), ], diff --git a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift index 93a59d67..7b7df852 100644 --- a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift +++ b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift @@ -1,12 +1,18 @@ import Flutter -import UIKit public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "wifi_scan", binaryMessenger: registrar.messenger()) let instance = SwiftWifiScanPlugin() + // set Flutter channels - 1 for method, 1 for event + let channel = FlutterMethodChannel( + name: "wifi_scan", binaryMessenger: registrar.messenger() + ) registrar.addMethodCallDelegate(instance, channel: channel) - // TODO: handle wifi_scan/onScannedResultsAvailable eventChannel + let eventChannel = FlutterEventChannel( + name: "wifi_scan/onScannedResultsAvailable", + binaryMessenger: registrar.messenger() + ) + eventChannel.setStreamHandler(DummyStreamHandler()) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { @@ -24,3 +30,13 @@ public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { } } } + + +class DummyStreamHandler: NSObject, FlutterStreamHandler{ + func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + return nil + } + func onCancel(withArguments arguments: Any?) -> FlutterError? { + return nil + } +} diff --git a/packages/wifi_scan/lib/src/accesspoint.dart b/packages/wifi_scan/lib/src/accesspoint.dart index 44e07b78..777f1b72 100644 --- a/packages/wifi_scan/lib/src/accesspoint.dart +++ b/packages/wifi_scan/lib/src/accesspoint.dart @@ -91,7 +91,20 @@ class WiFiAccessPoint { /// WiFi standard supported by the access poit. final WiFiStandards standard; - /// The detected signal level in dBm, also known as the RSSI. + /// The detected signal strength in dBm, also known as the RSSI. + /// + /// The value is in negative integer, the greater the value, the stronger the + /// signal. The closer the value is to 0, the stronger the received signal + /// has been. + /// + /// Following data can be used to determine signal quality: + /// -30 dBm = Excellent + /// -67 dBm = Very Good + /// -70 dBm = Okay + /// -80 dBm = Not Good + /// -90 dBm = Unusable + /// For more info - https://www.securedgenetworks.com/blog/wifi-signal-strength. + // TODO: rename to rssi or signalStrength - and give additional enum for level final int level; /// Channel bandwidth of the access point. From af346a1a9463d239b1ecfe1cf30d874076ef4897 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 9 Jan 2022 23:47:33 +0530 Subject: [PATCH 27/45] [example] minor changes --- packages/wifi_scan/example/lib/main.dart | 32 ++++++++++++++---------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index 17a38097..5ce3b82b 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -17,7 +17,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { bool shouldCheck = true; - bool shouldStream = false; + bool shouldStream = true; List accessPoints = []; void showSnackBar(BuildContext context, String message) { @@ -127,13 +127,13 @@ class _MyAppState extends State { if (snapshotCan.connectionState != ConnectionState.done) { return const CircularProgressIndicator(); } + // return without stream - if can't + if (!(snapshotCan.data ?? false)) return _buildWifiApList(context); return StreamBuilder>( stream: WiFiScan.instance.onScannedResultsAvailable, builder: (context, snapshot) { - if (snapshotCan.data ?? false) { - // update accesspoint if available - accessPoints = snapshot.data ?? accessPoints; - } + // update accesspoint if available + accessPoints = snapshot.data ?? accessPoints; return _buildWifiApList(context); }, ); @@ -154,16 +154,9 @@ class _MyAppState extends State { mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildSwitch("SHOULD CHECK", shouldCheck, - (v) => setState(() => shouldCheck = v)), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - ElevatedButton.icon( - icon: const Icon(Icons.perm_scan_wifi), - label: const Text('SCAN'), - onPressed: () => _startScan(context), - ), ElevatedButton.icon( icon: const Icon(Icons.refresh), label: const Text('GET'), @@ -175,8 +168,21 @@ class _MyAppState extends State { } }, ), + ElevatedButton.icon( + icon: const Icon(Icons.perm_scan_wifi), + label: const Text('SCAN'), + onPressed: () => _startScan(context), + ), + ], + ), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildSwitch("SHOULD CHECK", shouldCheck, + (v) => setState(() => shouldCheck = v)), _buildSwitch("STREAM", shouldStream, - (v) => setState(() => shouldStream = v)), + (v) => setState(() => shouldStream = v)), ], ), const Divider(), From 43b043af1c929a45c952f6b1c5f16c66e95b06e0 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 9 Jan 2022 23:50:57 +0530 Subject: [PATCH 28/45] formatting --- packages/wifi_scan/example/lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wifi_scan/example/lib/main.dart b/packages/wifi_scan/example/lib/main.dart index 5ce3b82b..6cc19b29 100644 --- a/packages/wifi_scan/example/lib/main.dart +++ b/packages/wifi_scan/example/lib/main.dart @@ -180,9 +180,9 @@ class _MyAppState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildSwitch("SHOULD CHECK", shouldCheck, - (v) => setState(() => shouldCheck = v)), + (v) => setState(() => shouldCheck = v)), _buildSwitch("STREAM", shouldStream, - (v) => setState(() => shouldStream = v)), + (v) => setState(() => shouldStream = v)), ], ), const Divider(), From 2968707b865a2b7bcdd983493d3b9d09d2ba279a Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Mon, 10 Jan 2022 17:35:52 +0530 Subject: [PATCH 29/45] [android] unregister `wifiScanReceiver` in `onDetachedFromEngine` --- .../kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index 6e81a730..8e839934 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -108,6 +108,8 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, channel.setMethodCallHandler(null) eventChannel.setStreamHandler(null) wifi = null + context.unregisterReceiver(wifiScanReceiver) + wifiScanReceiver = null } From 7a3a66ce66f916cb5a9a46ebf5bc8106c22b173e Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Mon, 10 Jan 2022 18:12:22 +0530 Subject: [PATCH 30/45] fix: sending result of `canGetScannedResults` - when asked for loc-perm --- .../wifi/wifi_scan/WifiScanPlugin.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index 8e839934..aa5b7cfb 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -10,6 +10,7 @@ import android.content.pm.PackageManager import android.location.LocationManager import android.net.wifi.WifiManager import android.os.Build +import android.util.Log import androidx.annotation.NonNull import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat @@ -66,6 +67,7 @@ enum class LocPermStatus { * */ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.RequestPermissionsResultListener, EventChannel.StreamHandler { + private val logTag = javaClass.simpleName private lateinit var context: Context private var activity: Activity? = null private var wifi: WifiManager? = null @@ -172,11 +174,14 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ) when (val canCode = canGetScannedResults(askPermission)) { ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> - when (status) { - LocPermStatus.GRANTED -> canGetScannedResults(askPermission = false) - LocPermStatus.UPGRADE_TO_FINE -> CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY - LocPermStatus.DENIED -> CAN_GET_RESULTS_NO_LOC_PERM_DENIED - } + Log.d(logTag, "canGetScannedResults -> askPerm: status: $status") + result.success( + when (status) { + LocPermStatus.GRANTED -> canGetScannedResults(askPermission = false) + LocPermStatus.UPGRADE_TO_FINE -> CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY + LocPermStatus.DENIED -> CAN_GET_RESULTS_NO_LOC_PERM_DENIED + } + ) } else -> result.success(canCode) } @@ -190,7 +195,9 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, override fun onRequestPermissionsResult( requestCode: Int, permissions: Array?, grantResults: IntArray? ): Boolean { + Log.d(logTag, "onRequestPermissionsResult: arguments ($requestCode, $permissions, $grantResults)") if (grantResults != null) { + Log.d(logTag, "requestPermissionCookie: $requestPermissionCookie") return requestPermissionCookie[requestCode]?.invoke(grantResults) ?: false } return false @@ -231,6 +238,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, val permissionCode = 6560000 + Random.Default.nextInt(10000) requestPermissionCookie[permissionCode] = { grantArray -> // invoke callback with proper status + Log.d(logTag, "permissionResultCallback: args($grantArray)") callback.invoke( when { // GRANTED: if all granted From 1815cf10c8eeefe87e77f9a66117eb85a590446d Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Mon, 10 Jan 2022 18:17:58 +0530 Subject: [PATCH 31/45] minor --- .../kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index aa5b7cfb..1e5432fd 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -133,7 +133,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, activity = null } - override fun onListen(arguments: Any?, events: EventChannel.EventSink?) { + override fun onListen(arguments: Any?, events: EventSink?) { eventSink = events // put getScannedResults in sink - to start with eventSink?.success(getScannedResults()) From 50594ac8fc9d3e7c2d4f746d963d57371920debd Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Mon, 10 Jan 2022 18:45:33 +0530 Subject: [PATCH 32/45] reformatting - removed named typedef - removed `result` arg from `askForLocationPermission` - renamed and moved inside enum class `LocPermStatus` -> `AskLocPermResult` --- .../wifi/wifi_scan/WifiScanPlugin.kt | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt index 1e5432fd..db0a1b53 100644 --- a/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt +++ b/packages/wifi_scan/android/src/main/kotlin/dev/flutternetwork/wifi/wifi_scan/WifiScanPlugin.kt @@ -50,13 +50,6 @@ private const val CAN_GET_RESULTS_NO_LOC_DISABLED = 5 /** Magic codes */ private const val ASK_FOR_LOC_PERM = -1 -typealias PermissionAskCallback = (status: LocPermStatus) -> Any -typealias PermissionResultCallback = (grantResults: IntArray) -> Boolean - -enum class LocPermStatus { - GRANTED, UPGRADE_TO_FINE, DENIED -} - /** WifiScanPlugin * * Useful links: @@ -72,7 +65,7 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, private var activity: Activity? = null private var wifi: WifiManager? = null private var wifiScanReceiver: BroadcastReceiver? = null - private val requestPermissionCookie = mutableMapOf() + private val requestPermissionCookie = mutableMapOf Boolean>() private val locationPermissionCoarse = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION) private val locationPermissionFine = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) private val locationPermissionBoth = locationPermissionCoarse + locationPermissionFine @@ -153,14 +146,25 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, null ) when (val canCode = canStartScan(askPermission)) { - ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> - result.success( - when (status) { - LocPermStatus.GRANTED -> canStartScan(askPermission = false) - LocPermStatus.UPGRADE_TO_FINE -> CAN_START_SCAN_NO_LOC_PERM_UPGRADE_ACCURACY - LocPermStatus.DENIED -> CAN_START_SCAN_NO_LOC_PERM_DENIED + ASK_FOR_LOC_PERM -> askForLocationPermission {askResult -> + when (askResult) { + AskLocPermResult.GRANTED -> { + result.success(canStartScan(askPermission = false)) + } + AskLocPermResult.UPGRADE_TO_FINE -> { + result.success(CAN_START_SCAN_NO_LOC_PERM_UPGRADE_ACCURACY) + } + AskLocPermResult.DENIED -> { + result.success(CAN_START_SCAN_NO_LOC_PERM_DENIED) + } + AskLocPermResult.ERROR_NO_ACTIVITY -> { + result.error( + ERROR_NULL_ACTIVITY, + "Cannot ask for location permission.", + "Looks like called from non-Activity." + ) } - ) + } } else -> result.success(canCode) } @@ -173,15 +177,25 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, null ) when (val canCode = canGetScannedResults(askPermission)) { - ASK_FOR_LOC_PERM -> askForLocationPermission(result) { status -> - Log.d(logTag, "canGetScannedResults -> askPerm: status: $status") - result.success( - when (status) { - LocPermStatus.GRANTED -> canGetScannedResults(askPermission = false) - LocPermStatus.UPGRADE_TO_FINE -> CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY - LocPermStatus.DENIED -> CAN_GET_RESULTS_NO_LOC_PERM_DENIED + ASK_FOR_LOC_PERM -> askForLocationPermission { askResult -> + when (askResult) { + AskLocPermResult.GRANTED -> { + result.success(canGetScannedResults(askPermission = false)) } - ) + AskLocPermResult.UPGRADE_TO_FINE -> { + result.success(CAN_GET_RESULTS_NO_LOC_PERM_UPGRADE_ACCURACY) + } + AskLocPermResult.DENIED -> { + result.success(CAN_GET_RESULTS_NO_LOC_PERM_DENIED) + } + AskLocPermResult.ERROR_NO_ACTIVITY -> { + result.error( + ERROR_NULL_ACTIVITY, + "Cannot ask for location permission.", + "Looks like called from non-Activity." + ) + } + } } else -> result.success(canCode) } @@ -220,11 +234,13 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } } - private fun askForLocationPermission(result: Result, callback: PermissionAskCallback) { + private enum class AskLocPermResult { + GRANTED, UPGRADE_TO_FINE, DENIED, ERROR_NO_ACTIVITY + } + + private fun askForLocationPermission(callback: (AskLocPermResult) -> Unit) { // check if has activity - return error if null - if (activity == null) return result.error(ERROR_NULL_ACTIVITY, - "Cannot ask for location permission.", - "Looks like called from non-Activity.") + if (activity == null) return callback.invoke(AskLocPermResult.ERROR_NO_ACTIVITY) // make permissions val requiresFine = requiresFineLocation() // - for SDK > R[30] - cannot only ask for FINE @@ -237,19 +253,19 @@ class WifiScanPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, // request permission - add result-handler in requestPermissionCookie val permissionCode = 6560000 + Random.Default.nextInt(10000) requestPermissionCookie[permissionCode] = { grantArray -> - // invoke callback with proper status + // invoke callback with proper askResult Log.d(logTag, "permissionResultCallback: args($grantArray)") callback.invoke( when { // GRANTED: if all granted grantArray.all { it == PackageManager.PERMISSION_GRANTED } -> { - LocPermStatus.GRANTED + AskLocPermResult.GRANTED } // UPGRADE_TO_FINE: if requiresFineButAskBoth and COARSE granted requiresFineButAskBoth && grantArray.first() == PackageManager.PERMISSION_GRANTED -> { - LocPermStatus.UPGRADE_TO_FINE + AskLocPermResult.UPGRADE_TO_FINE } - else -> LocPermStatus.DENIED + else -> AskLocPermResult.DENIED } ) true From 7a29169024554235ea23a99842e94c134398ff79 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Tue, 11 Jan 2022 13:02:31 +0530 Subject: [PATCH 33/45] [ios] docomment explaining dummy implementation --- packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift index 7b7df852..b0412b39 100644 --- a/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift +++ b/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift @@ -1,5 +1,8 @@ import Flutter +// Since no API for scanning or getting scanned results in iOS. +// This class is just a "dummy" implementation with sane returns. +// It is maintained to avoid `MissingPluginException`. public class SwiftWifiScanPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { let instance = SwiftWifiScanPlugin() From 437965d667bd2dff48ea67d7c85ba5e9a723e06a Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 01:07:03 +0530 Subject: [PATCH 34/45] [LICENSE] copied from wifi_iot --- packages/wifi_scan/LICENSE | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/wifi_scan/LICENSE b/packages/wifi_scan/LICENSE index ba75c69f..d36bc92e 100644 --- a/packages/wifi_scan/LICENSE +++ b/packages/wifi_scan/LICENSE @@ -1 +1,21 @@ -TODO: Add your license here. +MIT License + +Copyright (c) 2018 AlternaDom + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From e7da3f3046270a21bcb17cd1a7d1d8ef73846991 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 03:27:32 +0530 Subject: [PATCH 35/45] [README] added - with platform support, usage, resources, issues & feedback sections --- packages/wifi_scan/README.md | 142 ++++++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 10 deletions(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index d48dfa03..fb5d5b1f 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -1,15 +1,137 @@ -# wifi_scan +

WiFiFlutter| wifi_scan

-Flutter plugin to scan for WiFi networks. +

+ + analysis + + + pub.dev + + + pub points + + + popularity + + + likes + +

-## Getting Started +--- +This plugin allows Flutter apps to trigger WiFi scan and get scanned results. -This project is a starting point for a Flutter -[plug-in package](https://flutter.dev/developing-packages/), -a specialized package that includes platform-specific implementation code for -Android and/or iOS. +> This plugin is part of [WiFiFlutter][wf_home] suite, enabling various WiFi services for Flutter. -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Platform Support +| Platform | Status | Min. Version | API | Notes | +| :------: | :----: |:------------:| :---: |:-----:| +| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | | +| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation. | + +## Usage +The entry point for the plugin is the singleton instance `WiFiScan.instance`. + +### Start scan +You can trigger full WiFi scan with `WiFiScan.startScan` API, as shown below: +```dart +// check if platform support and necessary requirements +final can = await WiFiScan.instance.canStartScan(askPermissions: true); +if (can == CanStartScan.yes){ + // start full scan async-ly + final isScanning = await WiFiScan.instance.startScan(); + // ... +} else { + // ... check and handle other cases with CanStartScan values +} +``` + +For more details, you can read documentation of [`WiFiScan.startScan`][doc_startScan], [`WiFiScan.canStartScan`][doc_canStartScan] and [`CanStartScan`][doc_enum_CanStartScan]. + +### Get scanned results +You can get scanned results with `WiFiScan.getScannedResults` API, as shown below: +```dart +// check if platform support and necessary requirements +final can = await WiFiScan.instance.canGetScannedResults(askPermissions: true); +if (can == CanGetScannedResults.yes){ + // get scanned results + final accessPoints = await WiFiScan.instance.getScannedResults(); + // ... +} else { + // ... check and handle other cases with CanGetScannedResults values +} +``` + +> **NOTE:** `getScannedResults` API can be used independently of `startScan` API. This returns the latest available scanned results. + +For more details, you can read documentation of [`WiFiScan.getScannedResults`][doc_getScannedResults], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. + +### Get notified when scanned results available +You can get notified when new scanned results are available, as shown below: +```dart +// initialize accessPoints and subscription +List accessPoints = []; +StreamSubscription> subscription; + +void _startListeningToScannedResults(){ +// check if platform support and necessary requirements + final can = await WiFiScan.instance.canGetScannedResults(askPermissions: true); + if (can == CanGetScannedResults.yes){ + // listen to onScannedResultsAvailable stream + subscription = WiFiScan.instance.onScannedResultsAvailable.listen((results){ + // update accessPoints + setState((){ + accessPoints = results; + }); + }); + // ... + } else { + // ... check and handle other cases with CanGetScannedResults values + } +} + +// make sure to cancel subscription after you are done +@override +dispose() { + super.dispose(); + subscription?.cancel(); +} +``` + +Additionally, `WiFiScan.onScannedResultsAvailable` API can also be used with Flutter's [`StreamBuilder`][flutter_StreamBuilder] widget. + +> **NOTE:** `onScannedResultsAvailable` API can be used independently of `startScan` API. The notification can also be result of a full scan performed by platform or other app. + +For more details, you can read documentation of [`WiFiScan.onScannedResultsAvailable`][doc_onScannedResultsAvailable], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. + +## Resources +- 📖[API docs][docs] +- 💻[Example app][example] + +## Issues and feedback + +Please file WiFiFlutter specific issues, bugs, or feature requests in our [issue tracker][wf_issue]. + +To contribute a change to this plugin, please review our [contribution guide][wf_contrib] and open a [pull request][wf_pull]. + + +[wf_home]: https://wifi.flutternetwork.dev/ +[wf_issue]: https://github.com/flutternetwork/WiFiFlutter/issues/new +[wf_contrib]: https://github.com/flutternetwork/WiFiFlutter/blob/master/CONTRIBUTING.md +[wf_pull]: https://github.com/flutternetwork/WiFiFlutter/pulls + +[docs]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/wifi_scan-library.html +[example]: https://github.com/flutternetwork/WiFiFlutter/tree/master/packages/wifi_scan/example + +[doc_startScan]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/startScan.html +[doc_canStartScan]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/canStartScan.html +[doc_enum_CanStartScan]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/CanStartScan.html +[doc_getScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/getScannedResults.html +[doc_canGetScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/canGetScannedResults.html +[doc_enum_CanGetScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/CanGetScannedResults.html +[doc_onScannedResultsAvailable]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/onScannedResultsAvailable.html + +[flutter_StreamBuilder]: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html + +[android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager \ No newline at end of file From a9410f796a1c6271289f54165ff1a90619685b94 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 03:38:38 +0530 Subject: [PATCH 36/45] [README] added doc-link for `WiFiAccessPoint`; minor fix --- packages/wifi_scan/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index fb5d5b1f..e3c240fa 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -65,14 +65,14 @@ if (can == CanGetScannedResults.yes){ > **NOTE:** `getScannedResults` API can be used independently of `startScan` API. This returns the latest available scanned results. -For more details, you can read documentation of [`WiFiScan.getScannedResults`][doc_getScannedResults], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. +For more details, you can read documentation of [`WiFiScan.getScannedResults`][doc_getScannedResults], `WiFiAccessPoint`[doc_WiFiAccessPoint], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. ### Get notified when scanned results available You can get notified when new scanned results are available, as shown below: ```dart // initialize accessPoints and subscription List accessPoints = []; -StreamSubscription> subscription; +StreamSubscription>? subscription; void _startListeningToScannedResults(){ // check if platform support and necessary requirements @@ -103,7 +103,7 @@ Additionally, `WiFiScan.onScannedResultsAvailable` API can also be used with Flu > **NOTE:** `onScannedResultsAvailable` API can be used independently of `startScan` API. The notification can also be result of a full scan performed by platform or other app. -For more details, you can read documentation of [`WiFiScan.onScannedResultsAvailable`][doc_onScannedResultsAvailable], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. +For more details, you can read documentation of [`WiFiScan.onScannedResultsAvailable`][doc_onScannedResultsAvailable], `WiFiAccessPoint`[doc_WiFiAccessPoint], [`WiFiScan.canGetScannedResults`][doc_canGetScannedResults] and [`CanGetScannedResults`][doc_enum_CanGetScannedResults]. ## Resources - 📖[API docs][docs] @@ -128,6 +128,7 @@ To contribute a change to this plugin, please review our [contribution guide][wf [doc_canStartScan]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/canStartScan.html [doc_enum_CanStartScan]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/CanStartScan.html [doc_getScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/getScannedResults.html +[doc_WiFiAccessPoint]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiAccessPoint.html [doc_canGetScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/canGetScannedResults.html [doc_enum_CanGetScannedResults]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/CanGetScannedResults.html [doc_onScannedResultsAvailable]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/WiFiScan/onScannedResultsAvailable.html From fc042017736d76ca6dc16832eafd9bab63c563a6 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 03:44:28 +0530 Subject: [PATCH 37/45] [README] added link to Android guide on WiFi scan --- packages/wifi_scan/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index e3c240fa..6d9ee030 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -27,8 +27,8 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| -| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | | -| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation. | +| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | [Android guide on WiFi scanning][android_guide] | +| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation | ## Usage The entry point for the plugin is the singleton instance `WiFiScan.instance`. @@ -135,4 +135,5 @@ To contribute a change to this plugin, please review our [contribution guide][wf [flutter_StreamBuilder]: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html -[android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager \ No newline at end of file +[android_guide]: https://developer.android.com/guide/topics/connectivity/wifi-scan +[android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager From e23946c0a634d66c6265b3713c53d8138f69e7a4 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 03:53:57 +0530 Subject: [PATCH 38/45] [README] android - notes on throttling --- packages/wifi_scan/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index 6d9ee030..73a3f535 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -27,7 +27,7 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| -| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | [Android guide on WiFi scanning][android_guide] | +| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | For SDK >= 26(O) scans are [throttled][android_throttling]. | | **iOS** | ✔️ | 9.0 | No API available | Dummy implementation | ## Usage @@ -135,5 +135,5 @@ To contribute a change to this plugin, please review our [contribution guide][wf [flutter_StreamBuilder]: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html -[android_guide]: https://developer.android.com/guide/topics/connectivity/wifi-scan +[android_throttling]: https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling [android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager From e1cbcbc8bb438aba00a9d225e9e7a326cb3f8268 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:02:13 +0530 Subject: [PATCH 39/45] [readme] ios: clarify "dummy" implementation --- packages/wifi_scan/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index 73a3f535..bc153933 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -28,7 +28,7 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| | **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | For SDK >= 26(O) scans are [throttled][android_throttling]. | -| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation | +| **iOS** | ✔️ | 9.0 | No API available | Dummy but sane implementation. | ## Usage The entry point for the plugin is the singleton instance `WiFiScan.instance`. From 6c47dd452f3d5e1d3d08fafe54112578bd03df9f Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:03:13 +0530 Subject: [PATCH 40/45] [readme] ios: improve notes --- packages/wifi_scan/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index bc153933..a42f7853 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -28,7 +28,7 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| | **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | For SDK >= 26(O) scans are [throttled][android_throttling]. | -| **iOS** | ✔️ | 9.0 | No API available | Dummy but sane implementation. | +| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation with sane static returns. | ## Usage The entry point for the plugin is the singleton instance `WiFiScan.instance`. From 5566016ced0dc6e464dde2194815f268ff2ad9cc Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:05:42 +0530 Subject: [PATCH 41/45] [readme] ios: link to dummy class --- packages/wifi_scan/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index a42f7853..ce7b7d13 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -28,7 +28,7 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| | **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | For SDK >= 26(O) scans are [throttled][android_throttling]. | -| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation with sane static returns. | +| **iOS** | ✔️ | 9.0 | No API available | Dummy implementation with [sane static returns][ios_dummy]. | ## Usage The entry point for the plugin is the singleton instance `WiFiScan.instance`. @@ -137,3 +137,5 @@ To contribute a change to this plugin, please review our [contribution guide][wf [android_throttling]: https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling [android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager + +[ios_dummy]: https://github.com/flutternetwork/WiFiFlutter/blob/master/packages/wifi_scan/ios/Classes/SwiftWifiScanPlugin.swift From ea58870dedd85706e54501a633c7e0c7a8e73c10 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:08:58 +0530 Subject: [PATCH 42/45] [readme] android: added guide link in API column --- packages/wifi_scan/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index ce7b7d13..86302e07 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -27,7 +27,7 @@ This plugin allows Flutter apps to trigger WiFi scan and get scanned results. | Platform | Status | Min. Version | API | Notes | | :------: | :----: |:------------:| :---: |:-----:| -| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] | For SDK >= 26(O) scans are [throttled][android_throttling]. | +| **Android** | ✔️ | 16 (J) | Scan related APIs in [`WifiManager`][android_WifiManager] *[[Guide][android_guide]]* | For SDK >= 26(O) scans are [throttled][android_throttling]. | | **iOS** | ✔️ | 9.0 | No API available | Dummy implementation with [sane static returns][ios_dummy]. | ## Usage @@ -135,6 +135,7 @@ To contribute a change to this plugin, please review our [contribution guide][wf [flutter_StreamBuilder]: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html +[android_guide]: https://developer.android.com/guide/topics/connectivity/wifi-scan [android_throttling]: https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling [android_WifiManager]: https://developer.android.com/reference/android/net/wifi/WifiManager From 3c51442068040c90d4d974192d4ade12cff839fe Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:17:35 +0530 Subject: [PATCH 43/45] minor: change description - replace "networks" -> "access points" --- README.md | 4 ++-- packages/wifi_scan/ios/wifi_scan.podspec | 4 ++-- packages/wifi_scan/pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6f8433d8..344845c3 100644 --- a/README.md +++ b/README.md @@ -72,14 +72,14 @@ Flutter plugin for basic WiFi information and functionalities. ### `wifi_scan` > [![wifi_scan][scan_workflow_badge]][scan_workflow] [![wifi_scan][scan_pub_badge]][scan_pub] [![pub points][scan_pub_points_badge]][scan_pub_points] -Flutter plugin to scan for WiFi networks. +Flutter plugin to scan for WiFi access points. [[View Source][scan_code]] #### Platform Support | Android | iOS | | :-----: | :-: | -| ❌ | ➖ | +| ✔️ | | --- diff --git a/packages/wifi_scan/ios/wifi_scan.podspec b/packages/wifi_scan/ios/wifi_scan.podspec index 9f5d25f3..9a0f3a73 100644 --- a/packages/wifi_scan/ios/wifi_scan.podspec +++ b/packages/wifi_scan/ios/wifi_scan.podspec @@ -5,9 +5,9 @@ Pod::Spec.new do |s| s.name = 'wifi_scan' s.version = '0.0.1' - s.summary = 'Flutter plugin to scan for WiFi networks.' + s.summary = 'Flutter plugin to scan for WiFi access points.' s.description = <<-DESC -Flutter plugin to scan for WiFi networks. +Flutter plugin to scan for WiFi access points. DESC s.homepage = 'https://wifi.flutternetwork.dev' s.license = { :file => '../LICENSE' } diff --git a/packages/wifi_scan/pubspec.yaml b/packages/wifi_scan/pubspec.yaml index 7b0febfd..530cb752 100644 --- a/packages/wifi_scan/pubspec.yaml +++ b/packages/wifi_scan/pubspec.yaml @@ -1,5 +1,5 @@ name: wifi_scan -description: Flutter plugin to scan for WiFi networks. +description: Flutter plugin to scan for WiFi access points. version: 0.0.1 homepage: https://github.com/alternadom/WiFiFlutter/tree/master/packages/wifi_scan From 485313101194999d2edde7c83e1ec544aba3159f Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:26:07 +0530 Subject: [PATCH 44/45] [readme] using `switch` to handle `can` values --- packages/wifi_scan/README.md | 45 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index 86302e07..93c5298e 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -38,12 +38,13 @@ You can trigger full WiFi scan with `WiFiScan.startScan` API, as shown below: ```dart // check if platform support and necessary requirements final can = await WiFiScan.instance.canStartScan(askPermissions: true); -if (can == CanStartScan.yes){ - // start full scan async-ly - final isScanning = await WiFiScan.instance.startScan(); - // ... -} else { - // ... check and handle other cases with CanStartScan values +switch(can) { + case CanStartScan.yes: + // start full scan async-ly + final isScanning = await WiFiScan.instance.startScan(); + //... + break; + // ... handle other cases of CanStartScan values } ``` @@ -54,12 +55,13 @@ You can get scanned results with `WiFiScan.getScannedResults` API, as shown belo ```dart // check if platform support and necessary requirements final can = await WiFiScan.instance.canGetScannedResults(askPermissions: true); -if (can == CanGetScannedResults.yes){ - // get scanned results - final accessPoints = await WiFiScan.instance.getScannedResults(); - // ... -} else { - // ... check and handle other cases with CanGetScannedResults values +switch(can) { + case CanGetScannedResults.yes: + // get scanned results + final accessPoints = await WiFiScan.instance.getScannedResults(); + // ... + break; + // ... handle other cases of CanGetScannedResults values } ``` @@ -77,17 +79,16 @@ StreamSubscription>? subscription; void _startListeningToScannedResults(){ // check if platform support and necessary requirements final can = await WiFiScan.instance.canGetScannedResults(askPermissions: true); - if (can == CanGetScannedResults.yes){ - // listen to onScannedResultsAvailable stream - subscription = WiFiScan.instance.onScannedResultsAvailable.listen((results){ - // update accessPoints - setState((){ - accessPoints = results; + switch(can) { + case CanGetScannedResults.yes: + // listen to onScannedResultsAvailable stream + subscription = WiFiScan.instance.onScannedResultsAvailable.listen((results) { + // update accessPoints + setState(() => accessPoints = results); }); - }); - // ... - } else { - // ... check and handle other cases with CanGetScannedResults values + // ... + break; + // ... handle other cases of CanGetScannedResults values } } From fe8956c08f7db13d5d15f2f10cf5fd6232953b60 Mon Sep 17 00:00:00 2001 From: Harsh Bhikadia Date: Sun, 16 Jan 2022 04:36:26 +0530 Subject: [PATCH 45/45] [readme] added plugin-checklist link --- packages/wifi_scan/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/wifi_scan/README.md b/packages/wifi_scan/README.md index 93c5298e..4bad3c3e 100644 --- a/packages/wifi_scan/README.md +++ b/packages/wifi_scan/README.md @@ -114,7 +114,7 @@ For more details, you can read documentation of [`WiFiScan.onScannedResultsAvail Please file WiFiFlutter specific issues, bugs, or feature requests in our [issue tracker][wf_issue]. -To contribute a change to this plugin, please review our [contribution guide][wf_contrib] and open a [pull request][wf_pull]. +To contribute a change to this plugin, please review plugin [checklist for 1.0][checklist], our [contribution guide][wf_contrib] and open a [pull request][wf_pull]. [wf_home]: https://wifi.flutternetwork.dev/ @@ -122,6 +122,7 @@ To contribute a change to this plugin, please review our [contribution guide][wf [wf_contrib]: https://github.com/flutternetwork/WiFiFlutter/blob/master/CONTRIBUTING.md [wf_pull]: https://github.com/flutternetwork/WiFiFlutter/pulls +[checklist]: https://github.com/flutternetwork/WiFiFlutter/issues/188 [docs]: https://pub.dev/documentation/wifi_scan/latest/wifi_scan/wifi_scan-library.html [example]: https://github.com/flutternetwork/WiFiFlutter/tree/master/packages/wifi_scan/example