├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── flutter_ble │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── build.gradle └── settings.gradle ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ ├── Generated.xcconfig │ ├── flutter_export_environment.sh │ └── AppFrameworkInfo.plist ├── Runner │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ └── Info.plist ├── Runner.xcworkspace │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── RunnerTests │ └── RunnerTests.swift └── Podfile ├── .gitignore ├── test └── widget_test.dart ├── analysis_options.yaml ├── .metadata ├── pubspec.yaml ├── pubspec.lock ├── lib └── main.dart └── README.md /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenow/flutter-ble/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_ble/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_ble 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GeneratedPluginRegistrant_h 8 | #define GeneratedPluginRegistrant_h 9 | 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface GeneratedPluginRegistrant : NSObject 15 | + (void)registerWithRegistry:(NSObject*)registry; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | #endif /* GeneratedPluginRegistrant_h */ 20 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Flutter/Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=/Users/kevin/flutter 3 | FLUTTER_APPLICATION_PATH=/Users/kevin/Projects/flutter_ble 4 | COCOAPODS_PARALLEL_CODE_SIGN=true 5 | FLUTTER_TARGET=lib/main.dart 6 | FLUTTER_BUILD_DIR=build 7 | FLUTTER_BUILD_NAME=1.0.0 8 | FLUTTER_BUILD_NUMBER=1 9 | EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 10 | EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 11 | DART_OBFUSCATION=false 12 | TRACK_WIDGET_CREATION=true 13 | TREE_SHAKE_ICONS=false 14 | PACKAGE_CONFIG=.dart_tool/package_config.json 15 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/kevin/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/kevin/Projects/flutter_ble" 5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true" 6 | export "FLUTTER_TARGET=lib/main.dart" 7 | export "FLUTTER_BUILD_DIR=build" 8 | export "FLUTTER_BUILD_NAME=1.0.0" 9 | export "FLUTTER_BUILD_NUMBER=1" 10 | export "DART_OBFUSCATION=false" 11 | export "TRACK_WIDGET_CREATION=true" 12 | export "TREE_SHAKE_ICONS=false" 13 | export "PACKAGE_CONFIG=.dart_tool/package_config.json" 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "7.3.0" apply false 23 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 24 | } 25 | 26 | include ":app" 27 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #import "GeneratedPluginRegistrant.h" 8 | 9 | #if __has_include() 10 | #import 11 | #else 12 | @import flutter_blue_plus; 13 | #endif 14 | 15 | #if __has_include() 16 | #import 17 | #else 18 | @import permission_handler_apple; 19 | #endif 20 | 21 | @implementation GeneratedPluginRegistrant 22 | 23 | + (void)registerWithRegistry:(NSObject*)registry { 24 | [FlutterBluePlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterBluePlusPlugin"]]; 25 | [PermissionHandlerPlugin registerWithRegistrar:[registry registrarForPlugin:@"PermissionHandlerPlugin"]]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_ble/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 17 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 18 | - platform: android 19 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 20 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 21 | - platform: ios 22 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 23 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 24 | - platform: linux 25 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 26 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 27 | - platform: macos 28 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 29 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 30 | - platform: web 31 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 32 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 33 | - platform: windows 34 | create_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 35 | base_revision: 6928314d505d2bb4777be05e45d7808a5aa91d2a 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Flutter Ble 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_ble 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.example.flutter_ble" 27 | compileSdk flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.example.flutter_ble" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion 21 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies {} 68 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 22 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_ble 2 | description: "A new Flutter project." 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 6 | 7 | # The following defines the version and build number for your application. 8 | # A version number is three numbers separated by dots, like 1.2.43 9 | # followed by an optional build number separated by a +. 10 | # Both the version and the builder number may be overridden in flutter 11 | # build by specifying --build-name and --build-number, respectively. 12 | # In Android, build-name is used as versionName while build-number used as versionCode. 13 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 14 | # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. 15 | # Read more about iOS versioning at 16 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 17 | # In Windows, build-name is used as the major, minor, and patch parts 18 | # of the product and file versions while build-number is used as the build suffix. 19 | version: 2.0.0+1 20 | 21 | environment: 22 | sdk: '>=3.3.0 <4.0.0' 23 | 24 | # Dependencies specify other packages that your package needs in order to work. 25 | # To automatically upgrade your package dependencies to the latest versions 26 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 27 | # dependencies can be manually updated by changing the version numbers below to 28 | # the latest version available on pub.dev. To see which dependencies have newer 29 | # versions available, run `flutter pub outdated`. 30 | dependencies: 31 | flutter: 32 | sdk: flutter 33 | 34 | 35 | # The following adds the Cupertino Icons font to your application. 36 | # Use with the CupertinoIcons class for iOS style icons. 37 | cupertino_icons: ^1.0.6 38 | flutter_blue_plus: ^1.32.1 39 | permission_handler: ^11.3.1 40 | 41 | dev_dependencies: 42 | flutter_test: 43 | sdk: flutter 44 | 45 | # The "flutter_lints" package below contains a set of recommended lints to 46 | # encourage good coding practices. The lint set provided by the package is 47 | # activated in the `analysis_options.yaml` file located at the root of your 48 | # package. See that file for information about deactivating specific lint 49 | # rules and activating additional ones. 50 | flutter_lints: ^3.0.0 51 | 52 | # For information on the generic Dart part of this file, see the 53 | # following page: https://dart.dev/tools/pub/pubspec 54 | 55 | # The following section is specific to Flutter packages. 56 | flutter: 57 | 58 | # The following line ensures that the Material Icons font is 59 | # included with your application, so that you can use the icons in 60 | # the material Icons class. 61 | uses-material-design: true 62 | 63 | # To add assets to your application, add an assets section, like this: 64 | # assets: 65 | # - images/a_dot_burr.jpeg 66 | # - images/a_dot_ham.jpeg 67 | 68 | # An image asset can refer to one or more resolution-specific "variants", see 69 | # https://flutter.dev/assets-and-images/#resolution-aware 70 | 71 | # For details regarding adding assets from package dependencies, see 72 | # https://flutter.dev/assets-and-images/#from-packages 73 | 74 | # To add custom fonts to your application, add a fonts section here, 75 | # in this "flutter" section. Each entry in this list should have a 76 | # "family" key with the font family name, and a "fonts" key with a 77 | # list giving the asset and other descriptors for the font. For 78 | # example: 79 | # fonts: 80 | # - family: Schyler 81 | # fonts: 82 | # - asset: fonts/Schyler-Regular.ttf 83 | # - asset: fonts/Schyler-Italic.ttf 84 | # style: italic 85 | # - family: Trajan Pro 86 | # fonts: 87 | # - asset: fonts/TrajanPro.ttf 88 | # - asset: fonts/TrajanPro_Bold.ttf 89 | # weight: 700 90 | # 91 | # For details regarding fonts from package dependencies, 92 | # see https://flutter.dev/custom-fonts/#from-packages 93 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.18.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.6" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_blue_plus: 66 | dependency: "direct main" 67 | description: 68 | name: flutter_blue_plus 69 | sha256: "5851041708b21601bfff50ebf4b05f8bd7b4f1dd7a2a69b82bdf7e5c2c2efb53" 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "1.32.1" 73 | flutter_lints: 74 | dependency: "direct dev" 75 | description: 76 | name: flutter_lints 77 | sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" 78 | url: "https://pub.dev" 79 | source: hosted 80 | version: "3.0.2" 81 | flutter_test: 82 | dependency: "direct dev" 83 | description: flutter 84 | source: sdk 85 | version: "0.0.0" 86 | flutter_web_plugins: 87 | dependency: transitive 88 | description: flutter 89 | source: sdk 90 | version: "0.0.0" 91 | leak_tracker: 92 | dependency: transitive 93 | description: 94 | name: leak_tracker 95 | sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" 96 | url: "https://pub.dev" 97 | source: hosted 98 | version: "10.0.0" 99 | leak_tracker_flutter_testing: 100 | dependency: transitive 101 | description: 102 | name: leak_tracker_flutter_testing 103 | sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 104 | url: "https://pub.dev" 105 | source: hosted 106 | version: "2.0.1" 107 | leak_tracker_testing: 108 | dependency: transitive 109 | description: 110 | name: leak_tracker_testing 111 | sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "2.0.1" 115 | lints: 116 | dependency: transitive 117 | description: 118 | name: lints 119 | sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "3.0.0" 123 | matcher: 124 | dependency: transitive 125 | description: 126 | name: matcher 127 | sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "0.12.16+1" 131 | material_color_utilities: 132 | dependency: transitive 133 | description: 134 | name: material_color_utilities 135 | sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "0.8.0" 139 | meta: 140 | dependency: transitive 141 | description: 142 | name: meta 143 | sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "1.11.0" 147 | path: 148 | dependency: transitive 149 | description: 150 | name: path 151 | sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "1.9.0" 155 | permission_handler: 156 | dependency: "direct main" 157 | description: 158 | name: permission_handler 159 | sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "11.3.1" 163 | permission_handler_android: 164 | dependency: transitive 165 | description: 166 | name: permission_handler_android 167 | sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "12.0.5" 171 | permission_handler_apple: 172 | dependency: transitive 173 | description: 174 | name: permission_handler_apple 175 | sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "9.4.4" 179 | permission_handler_html: 180 | dependency: transitive 181 | description: 182 | name: permission_handler_html 183 | sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "0.1.1" 187 | permission_handler_platform_interface: 188 | dependency: transitive 189 | description: 190 | name: permission_handler_platform_interface 191 | sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "4.2.1" 195 | permission_handler_windows: 196 | dependency: transitive 197 | description: 198 | name: permission_handler_windows 199 | sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "0.2.1" 203 | plugin_platform_interface: 204 | dependency: transitive 205 | description: 206 | name: plugin_platform_interface 207 | sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "2.1.8" 211 | sky_engine: 212 | dependency: transitive 213 | description: flutter 214 | source: sdk 215 | version: "0.0.99" 216 | source_span: 217 | dependency: transitive 218 | description: 219 | name: source_span 220 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 221 | url: "https://pub.dev" 222 | source: hosted 223 | version: "1.10.0" 224 | stack_trace: 225 | dependency: transitive 226 | description: 227 | name: stack_trace 228 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" 229 | url: "https://pub.dev" 230 | source: hosted 231 | version: "1.11.1" 232 | stream_channel: 233 | dependency: transitive 234 | description: 235 | name: stream_channel 236 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 237 | url: "https://pub.dev" 238 | source: hosted 239 | version: "2.1.2" 240 | string_scanner: 241 | dependency: transitive 242 | description: 243 | name: string_scanner 244 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 245 | url: "https://pub.dev" 246 | source: hosted 247 | version: "1.2.0" 248 | term_glyph: 249 | dependency: transitive 250 | description: 251 | name: term_glyph 252 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 253 | url: "https://pub.dev" 254 | source: hosted 255 | version: "1.2.1" 256 | test_api: 257 | dependency: transitive 258 | description: 259 | name: test_api 260 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" 261 | url: "https://pub.dev" 262 | source: hosted 263 | version: "0.6.1" 264 | vector_math: 265 | dependency: transitive 266 | description: 267 | name: vector_math 268 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 269 | url: "https://pub.dev" 270 | source: hosted 271 | version: "2.1.4" 272 | vm_service: 273 | dependency: transitive 274 | description: 275 | name: vm_service 276 | sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 277 | url: "https://pub.dev" 278 | source: hosted 279 | version: "13.0.0" 280 | sdks: 281 | dart: ">=3.3.0 <4.0.0" 282 | flutter: ">=3.16.0" 283 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:flutter_blue_plus/flutter_blue_plus.dart'; 6 | import 'package:permission_handler/permission_handler.dart'; 7 | 8 | void main() => runApp(const MyApp()); 9 | 10 | class MyApp extends StatelessWidget { 11 | const MyApp({super.key}); 12 | 13 | @override 14 | Widget build(BuildContext context) => MaterialApp( 15 | title: 'BLE Demo', 16 | theme: ThemeData( 17 | primarySwatch: Colors.blue, 18 | ), 19 | home: MyHomePage(title: 'Flutter BLE Demo'), 20 | ); 21 | } 22 | 23 | class MyHomePage extends StatefulWidget { 24 | MyHomePage({Key? key, required this.title}) : super(key: key); 25 | 26 | final String title; 27 | final List devicesList = []; 28 | final Map> readValues = >{}; 29 | 30 | @override 31 | MyHomePageState createState() => MyHomePageState(); 32 | } 33 | 34 | class MyHomePageState extends State { 35 | final _writeController = TextEditingController(); 36 | BluetoothDevice? _connectedDevice; 37 | List _services = []; 38 | 39 | _addDeviceTolist(final BluetoothDevice device) { 40 | if (!widget.devicesList.contains(device)) { 41 | setState(() { 42 | widget.devicesList.add(device); 43 | }); 44 | } 45 | } 46 | 47 | _initBluetooth() async { 48 | var subscription = FlutterBluePlus.onScanResults.listen( 49 | (results) { 50 | if (results.isNotEmpty) { 51 | for (ScanResult result in results) { 52 | _addDeviceTolist(result.device); 53 | } 54 | } 55 | }, 56 | onError: (e) => ScaffoldMessenger.of(context).showSnackBar( 57 | SnackBar( 58 | content: Text(e.toString()), 59 | ), 60 | ), 61 | ); 62 | 63 | FlutterBluePlus.cancelWhenScanComplete(subscription); 64 | 65 | await FlutterBluePlus.adapterState.where((val) => val == BluetoothAdapterState.on).first; 66 | 67 | await FlutterBluePlus.startScan(); 68 | 69 | await FlutterBluePlus.isScanning.where((val) => val == false).first; 70 | FlutterBluePlus.connectedDevices.map((device) { 71 | _addDeviceTolist(device); 72 | }); 73 | } 74 | 75 | @override 76 | void initState() { 77 | () async { 78 | var status = await Permission.location.status; 79 | if (status.isDenied) { 80 | final status = await Permission.location.request(); 81 | if (status.isGranted || status.isLimited) { 82 | _initBluetooth(); 83 | } 84 | } else if (status.isGranted || status.isLimited) { 85 | _initBluetooth(); 86 | } 87 | 88 | if (await Permission.location.status.isPermanentlyDenied) { 89 | openAppSettings(); 90 | } 91 | }(); 92 | super.initState(); 93 | } 94 | 95 | ListView _buildListViewOfDevices() { 96 | List containers = []; 97 | for (BluetoothDevice device in widget.devicesList) { 98 | containers.add( 99 | SizedBox( 100 | height: 50, 101 | child: Row( 102 | children: [ 103 | Expanded( 104 | child: Column( 105 | children: [ 106 | Text(device.platformName == '' ? '(unknown device)' : device.advName), 107 | Text(device.remoteId.toString()), 108 | ], 109 | ), 110 | ), 111 | TextButton( 112 | child: const Text( 113 | 'Connect', 114 | style: TextStyle(color: Colors.black), 115 | ), 116 | onPressed: () async { 117 | FlutterBluePlus.stopScan(); 118 | try { 119 | await device.connect(); 120 | } on PlatformException catch (e) { 121 | if (e.code != 'already_connected') { 122 | rethrow; 123 | } 124 | } finally { 125 | _services = await device.discoverServices(); 126 | } 127 | setState(() { 128 | _connectedDevice = device; 129 | }); 130 | }, 131 | ), 132 | ], 133 | ), 134 | ), 135 | ); 136 | } 137 | 138 | return ListView( 139 | padding: const EdgeInsets.all(8), 140 | children: [ 141 | ...containers, 142 | ], 143 | ); 144 | } 145 | 146 | List _buildReadWriteNotifyButton(BluetoothCharacteristic characteristic) { 147 | List buttons = []; 148 | 149 | if (characteristic.properties.read) { 150 | buttons.add( 151 | ButtonTheme( 152 | minWidth: 10, 153 | height: 20, 154 | child: Padding( 155 | padding: const EdgeInsets.symmetric(horizontal: 4), 156 | child: TextButton( 157 | child: const Text('READ', style: TextStyle(color: Colors.black)), 158 | onPressed: () async { 159 | var sub = characteristic.lastValueStream.listen((value) { 160 | setState(() { 161 | widget.readValues[characteristic.uuid] = value; 162 | }); 163 | }); 164 | await characteristic.read(); 165 | sub.cancel(); 166 | }, 167 | ), 168 | ), 169 | ), 170 | ); 171 | } 172 | if (characteristic.properties.write) { 173 | buttons.add( 174 | ButtonTheme( 175 | minWidth: 10, 176 | height: 20, 177 | child: Padding( 178 | padding: const EdgeInsets.symmetric(horizontal: 4), 179 | child: ElevatedButton( 180 | child: const Text('WRITE', style: TextStyle(color: Colors.black)), 181 | onPressed: () async { 182 | await showDialog( 183 | context: context, 184 | builder: (BuildContext context) { 185 | return AlertDialog( 186 | title: const Text("Write"), 187 | content: Row( 188 | children: [ 189 | Expanded( 190 | child: TextField( 191 | controller: _writeController, 192 | ), 193 | ), 194 | ], 195 | ), 196 | actions: [ 197 | TextButton( 198 | child: const Text("Send"), 199 | onPressed: () { 200 | characteristic.write(utf8.encode(_writeController.value.text)); 201 | Navigator.pop(context); 202 | }, 203 | ), 204 | TextButton( 205 | child: const Text("Cancel"), 206 | onPressed: () { 207 | Navigator.pop(context); 208 | }, 209 | ), 210 | ], 211 | ); 212 | }); 213 | }, 214 | ), 215 | ), 216 | ), 217 | ); 218 | } 219 | if (characteristic.properties.notify) { 220 | buttons.add( 221 | ButtonTheme( 222 | minWidth: 10, 223 | height: 20, 224 | child: Padding( 225 | padding: const EdgeInsets.symmetric(horizontal: 4), 226 | child: ElevatedButton( 227 | child: const Text('NOTIFY', style: TextStyle(color: Colors.black)), 228 | onPressed: () async { 229 | characteristic.lastValueStream.listen((value) { 230 | setState(() { 231 | widget.readValues[characteristic.uuid] = value; 232 | }); 233 | }); 234 | await characteristic.setNotifyValue(true); 235 | }, 236 | ), 237 | ), 238 | ), 239 | ); 240 | } 241 | 242 | return buttons; 243 | } 244 | 245 | ListView _buildConnectDeviceView() { 246 | List containers = []; 247 | 248 | for (BluetoothService service in _services) { 249 | List characteristicsWidget = []; 250 | 251 | for (BluetoothCharacteristic characteristic in service.characteristics) { 252 | characteristicsWidget.add( 253 | Align( 254 | alignment: Alignment.centerLeft, 255 | child: Column( 256 | children: [ 257 | Row( 258 | children: [ 259 | Text(characteristic.uuid.toString(), style: const TextStyle(fontWeight: FontWeight.bold)), 260 | ], 261 | ), 262 | Row( 263 | children: [ 264 | ..._buildReadWriteNotifyButton(characteristic), 265 | ], 266 | ), 267 | Row( 268 | children: [ 269 | Expanded(child: Text('Value: ${widget.readValues[characteristic.uuid]}')), 270 | ], 271 | ), 272 | const Divider(), 273 | ], 274 | ), 275 | ), 276 | ); 277 | } 278 | containers.add( 279 | ExpansionTile(title: Text(service.uuid.toString()), children: characteristicsWidget), 280 | ); 281 | } 282 | 283 | return ListView( 284 | padding: const EdgeInsets.all(8), 285 | children: [ 286 | ...containers, 287 | ], 288 | ); 289 | } 290 | 291 | ListView _buildView() { 292 | if (_connectedDevice != null) { 293 | return _buildConnectDeviceView(); 294 | } 295 | return _buildListViewOfDevices(); 296 | } 297 | 298 | @override 299 | Widget build(BuildContext context) => Scaffold( 300 | appBar: AppBar( 301 | title: Text(widget.title), 302 | ), 303 | body: _buildView(), 304 | ); 305 | } 306 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter BLE 2 | 3 | Do you want to play with your IoT devices using Bluetooth, but you cannot put any software in it? Here we are going to see how to communicate through Bluetooth with your IoT device using a phone application. 4 | 5 | Is it for Android or iOS? Both! We are going to use Flutter as a development framework for mobile app. We are going to write an nRF connect light where we will be able to scan, connect, read and write on devices. 6 | 7 | 8 | There is no official documentation about using Bluetooth with Flutter, simply because it is not officially supported by the framework, that’s why we are going to use [flutter_blue_plus](https://pub.dev/packages/flutter_blue_plus) as a dependency. 9 | 10 | # Add flutter_blue_plus as dependency 11 | 12 | ```sh 13 | flutter pub add flutter_blue_plus 14 | ``` 15 | 16 | # Change the minSdkVersion for Android 17 | 18 | flutter_blue_plus is compatible only from version 21 of Android SDK so you should change this in android/app/build.gradle: 19 | 20 | ```groovy 21 | Android { 22 | defaultConfig { 23 | minSdkVersion: 21 24 | ``` 25 | 26 | # Add permissions for Bluetooth 27 | 28 | We need to add the permission to use Bluetooth and access location: 29 | 30 | ## Android 31 | 32 | In the AndroidManifest.xml let’s add: 33 | 34 | ```xml 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ``` 44 | 45 | ## iOS 46 | 47 | In the Info.plist let’s add: 48 | 49 | ```xml 50 | NSBluetoothAlwaysUsageDescription 51 | Need BLE permission 52 | NSBluetoothPeripheralUsageDescription 53 | Need BLE permission 54 | NSLocationAlwaysAndWhenInUseUsageDescription 55 | Need Location permission 56 | NSLocationAlwaysUsageDescription 57 | Need Location permission 58 | NSLocationWhenInUseUsageDescription 59 | Need Location permission 60 | ``` 61 | 62 | For location permissions on iOS see more at https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services 63 | 64 | # Let’s begin 65 | 66 | Here is our main.dart for now: 67 | 68 | ```dart 69 | import 'package:flutter/material.dart'; 70 | 71 | void main() => runApp(MyApp()); 72 | 73 | class MyApp extends StatelessWidget { 74 | @override 75 | Widget build(BuildContext context) => MaterialApp( 76 | title: 'BLE Demo', 77 | theme: ThemeData( 78 | primarySwatch: Colors.blue, 79 | ), 80 | home: MyHomePage(title: 'Flutter BLE Demo'), 81 | ); 82 | } 83 | 84 | class MyHomePage extends StatefulWidget { 85 | MyHomePage({Key key, this.title}) : super(key: key); 86 | 87 | final String title; 88 | 89 | @override 90 | _MyHomePageState createState() => _MyHomePageState(); 91 | } 92 | 93 | class _MyHomePageState extends State { 94 | @override 95 | Widget build(BuildContext context) => Scaffold( 96 | appBar: AppBar( 97 | title: Text(widget.title), 98 | ), 99 | body: Column( 100 | children: [], 101 | ), 102 | ); 103 | } 104 | ``` 105 | 106 | Let’s import flutter_blue_plus: 107 | 108 | ```dart 109 | import 'package:flutter_blue/flutter_blue_plus.dart'; 110 | ``` 111 | 112 | And add the flutter_blue instance inside our MyHomePage widget: 113 | 114 | ```dart 115 | final FlutterBluePlus flutterBlue = FlutterBluePlus.instance; 116 | ``` 117 | 118 | We will be able to access it by using the widget.flutterBlue property inside our _MyHomePageState widget. 119 | 120 | # Scanning Bluetooth devices 121 | 122 | Now let’s start scanning for Bluetooth devices and display them in a ListView. 123 | 124 | First let’s add a List containing our devices inside our MyHomePage class: 125 | 126 | 127 | ```dart 128 | final List devicesList = new List(); 129 | ``` 130 | 131 | And write a method in our _MyHomePage class which will help fill this in list: 132 | 133 | ```dart 134 | _addDeviceTolist(final BluetoothDevice device) { 135 | if (!widget.devicesList.contains(device)) { 136 | setState(() { 137 | widget.devicesList.add(device); 138 | }); 139 | } 140 | } 141 | ``` 142 | 143 | Now let’s fill it in by starting a scan inside the initState method of _MyHomePage: 144 | 145 | 146 | ⚠️ When starting a scan you will only list the devices which are not already connected. So we are also going to add the connected devices to our list by accessing the connectedDevices attribute of our FlutterBlue instance. 147 | 148 | ```dart 149 | @override 150 | void initState() { 151 | () async { 152 | var status = await Permission.location.status; 153 | if (status.isDenied) { 154 | final status = await Permission.location.request(); 155 | if (status.isGranted || status.isLimited) { 156 | _initBluetooth(); 157 | } 158 | } else if (status.isGranted || status.isLimited) { 159 | _initBluetooth(); 160 | } 161 | 162 | if (await Permission.location.status.isPermanentlyDenied) { 163 | openAppSettings(); 164 | } 165 | }(); 166 | super.initState(); 167 | } 168 | ``` 169 | 170 | and here is the _initBluetooth method: 171 | 172 | ```dart 173 | _initBluetooth() async { 174 | var subscription = FlutterBluePlus.onScanResults.listen( 175 | (results) { 176 | if (results.isNotEmpty) { 177 | for (ScanResult result in results) { 178 | _addDeviceTolist(result.device); 179 | } 180 | } 181 | }, 182 | onError: (e) => ScaffoldMessenger.of(context).showSnackBar( 183 | SnackBar( 184 | content: Text(e.toString()), 185 | ), 186 | ), 187 | ); 188 | 189 | FlutterBluePlus.cancelWhenScanComplete(subscription); 190 | 191 | await FlutterBluePlus.adapterState.where((val) => val == BluetoothAdapterState.on).first; 192 | 193 | await FlutterBluePlus.startScan(); 194 | 195 | await FlutterBluePlus.isScanning.where((val) => val == false).first; 196 | FlutterBluePlus.connectedDevices.map((device) { 197 | _addDeviceTolist(device); 198 | }); 199 | } 200 | ``` 201 | 202 | Now our List will be filled in with devices which FlutterBlue finds by scanning. 203 | 204 | Let’s now build our ListView with the deviceList as content: 205 | 206 | ```dart 207 | ListView _buildListViewOfDevices() { 208 | List containers = new List(); 209 | for (BluetoothDevice device in widget.devicesList) { 210 | containers.add( 211 | Container( 212 | height: 50, 213 | child: Row( 214 | children: [ 215 | Expanded( 216 | child: Column( 217 | children: [ 218 | Text(device.name == '' ? '(unknown device)' : device.name), 219 | Text(device.id.toString()), 220 | ], 221 | ), 222 | ), 223 | FlatButton( 224 | color: Colors.blue, 225 | child: Text( 226 | 'Connect', 227 | style: TextStyle(color: Colors.black), 228 | ), 229 | onPressed: () {}, 230 | ), 231 | ], 232 | ), 233 | ), 234 | ); 235 | } 236 | 237 | return ListView( 238 | padding: const EdgeInsets.all(8), 239 | children: [ 240 | ...containers, 241 | ], 242 | ); 243 | } 244 | ``` 245 | 246 | Assign this listView as the body of our main Scaffold: 247 | 248 | 249 | ```dart 250 | @override 251 | Widget build(BuildContext context) => Scaffold( 252 | appBar: AppBar( 253 | title: Text(widget.title), 254 | ), 255 | body: _buildListViewOfDevices(), 256 | ); 257 | ``` 258 | 259 | Now we should have a list of nearby Bluetooth-enabled devices. Next we will connect to one of them and display the services and characteristics it has. 260 | 261 | # Connect to a device and display services with characteristics 262 | 263 | For the sake of readability we will not create a new view to connect to a device but rather adapt the current content of MyHomePage to make it depend on whether we are connected or not. For that we are first going to add a function which will return the right view to display. 264 | 265 | So let’s add a State representing the device we are connecting to and the list of services it exposes in _MyHomePageState: 266 | 267 | 268 | ```dart 269 | @override 270 | Widget build(BuildContext context) => Scaffold( 271 | appBar: AppBar( 272 | title: Text(widget.title), 273 | ), 274 | body: _buildListViewOfDevices(), 275 | ); 276 | 277 | And the function: 278 | 279 | ```dart 280 | ListView _buildView() { 281 | if (_connectedDevice != null) { 282 | return _buildConnectDeviceView(); 283 | } 284 | return _buildListViewOfDevices(); 285 | } 286 | ``` 287 | 288 | The _buildConnectDeviceView method which does not do so much for now: 289 | 290 | ```dart 291 | ListView _buildConnectDeviceView() { 292 | return ListView( 293 | padding: const EdgeInsets.all(8), 294 | children: [], 295 | ); 296 | } 297 | ``` 298 | 299 | Now our build method will return this _buildView: 300 | 301 | ```dart 302 | @override 303 | Widget build(BuildContext context) => Scaffold( 304 | appBar: AppBar( 305 | title: Text(widget.title), 306 | ), 307 | body: _buildView(), 308 | ); 309 | ``` 310 | 311 | And finally we can add some logic to the onPressed method of our FlatButton where we will stop FlutterBlue’s scan, connect to the device and set this device in our previously created state _connectedDevice plus getting the services of this device and display a list. 312 | 313 | ```dart 314 | onPressed: () { 315 | setState(() async { 316 | widget.flutterBlue.stopScan(); 317 | try { 318 | await device.connect(); 319 | } catch (e) { 320 | if (e.code != 'already_connected') { 321 | throw e; 322 | } 323 | } finally { 324 | _services = await device.discoverServices(); 325 | } 326 | _connectedDevice = device; 327 | }); 328 | } 329 | ``` 330 | 331 | Change the _buildConnectDeviceView like so: 332 | 333 | ```dart 334 | ListView _buildConnectDeviceView() { 335 | List containers = new List(); 336 | for (BluetoothService service in _services) { 337 | containers.add( 338 | Container( 339 | height: 50, 340 | child: Row( 341 | children: [ 342 | Expanded( 343 | child: Column( 344 | children: [ 345 | Text(service.uuid.toString()), 346 | ], 347 | ), 348 | ), 349 | ], 350 | ), 351 | ), 352 | ); 353 | } 354 | 355 | return ListView( 356 | padding: const EdgeInsets.all(8), 357 | children: [ 358 | ...containers, 359 | ], 360 | ); 361 | } 362 | ``` 363 | 364 | # Display characteristics 365 | 366 | We have now a list of services at our disposal. We will display the characteristics for each service and add buttons depending on if we can read, write or notify about this feature. 367 | 368 | Our new _buildConnectDeviceView looks like this: 369 | 370 | ```dart 371 | ListView _buildConnectDeviceView() { 372 | List containers = new List(); 373 | 374 | for (BluetoothService service in _services) { 375 | List characteristicsWidget = new List(); 376 | for (BluetoothCharacteristic characteristic in service.characteristics) { 377 | characteristic.value.listen((value) { 378 | print(value); 379 | }); 380 | characteristicsWidget.add( 381 | Align( 382 | alignment: Alignment.centerLeft, 383 | child: Column( 384 | children: [ 385 | Row( 386 | children: [ 387 | Text(characteristic.uuid.toString(), style: TextStyle(fontWeight: FontWeight.bold)), 388 | ], 389 | ), 390 | Row( 391 | children: [ 392 | ..._buildReadWriteNotifyButton(characteristic), 393 | ], 394 | ), 395 | Divider(), 396 | ], 397 | ), 398 | ), 399 | ); 400 | } 401 | containers.add( 402 | Container( 403 | child: ExpansionTile( 404 | title: Text(service.uuid.toString()), 405 | children: characteristicsWidget), 406 | ), 407 | ); 408 | } 409 | 410 | return ListView( 411 | padding: const EdgeInsets.all(8), 412 | children: [ 413 | ...containers, 414 | ], 415 | ); 416 | } 417 | ``` 418 | 419 | And we add a function computing our buttons: 420 | 421 | ```dart 422 | List _buildReadWriteNotifyButton( 423 | BluetoothCharacteristic characteristic) { 424 | List buttons = new List(); 425 | 426 | if (characteristic.properties.read) { 427 | buttons.add( 428 | ButtonTheme( 429 | minWidth: 10, 430 | height: 20, 431 | child: Padding( 432 | padding: const EdgeInsets.symmetric(horizontal: 4), 433 | child: RaisedButton( 434 | color: Colors.blue, 435 | child: Text('READ', style: TextStyle(color: Colors.black)), 436 | onPressed: () {}, 437 | ), 438 | ), 439 | ), 440 | ); 441 | } 442 | if (characteristic.properties.write) { 443 | buttons.add( 444 | ButtonTheme( 445 | minWidth: 10, 446 | height: 20, 447 | child: Padding( 448 | padding: const EdgeInsets.symmetric(horizontal: 4), 449 | child: RaisedButton( 450 | child: Text('WRITE', style: TextStyle(color: Colors.black)), 451 | onPressed: () {}, 452 | ), 453 | ), 454 | ), 455 | ); 456 | } 457 | if (characteristic.properties.notify) { 458 | buttons.add( 459 | ButtonTheme( 460 | minWidth: 10, 461 | height: 20, 462 | child: Padding( 463 | padding: const EdgeInsets.symmetric(horizontal: 4), 464 | child: RaisedButton( 465 | child: Text('NOTIFY', style: TextStyle(color: Colors.black)), 466 | onPressed: () {}, 467 | ), 468 | ), 469 | ), 470 | ); 471 | } 472 | 473 | return buttons; 474 | } 475 | ``` 476 | 477 | # Read, write and receive notifications from a characteristic 478 | 479 | Last step is to add logic on our read, write and notify buttons. 480 | 481 | We will first add a Map to store our values by characteristic to be able to display them. 482 | 483 | In our MyHomePage class let’s add the following: 484 | 485 | ```dart 486 | final Map> readValues = new Map>(); 487 | ``` 488 | 489 | Then let’s add a new Row in our _buildConnectDeviceView method to display our value: 490 | 491 | ```dart 492 | Row( 493 | children: [ 494 | Expanded(child: Text('Value: ' + 495 | widget.readValues[characteristic.uuid].toString())), 496 | ], 497 | ), 498 | ``` 499 | 500 | ## Read 501 | 502 | First let’s add the logic in the onPressed method of the read button: 503 | 504 | ```dart 505 | onPressed: () async { 506 | var sub = characteristic.value.listen((value) { 507 | setState(() { 508 | widget.readValues[characteristic.uuid] = value; 509 | }); 510 | }); 511 | await characteristic.read(); 512 | sub.cancel(); 513 | }, 514 | ``` 515 | 516 | Here we first listen on characteristic changes and store its new value in our previously created Map. It will then update our view and display the updated value. 517 | 518 | ## Write 519 | 520 | In order to send data to the device we will create a TextField field inside a dialog, link a controller to it and send its content. 521 | 522 | So let’s add a controller to our _MyHomePageState: 523 | 524 | ```dart 525 | final _writeController = TextEditingController(); 526 | ``` 527 | 528 | And create our dialog with the logic inside the onPressed method of the write button: 529 | 530 | ```dart 531 | onPressed: () async { 532 | await showDialog( 533 | context: context, 534 | builder: (BuildContext context) { 535 | return AlertDialog( 536 | title: Text("Write"), 537 | content: Row( 538 | children: [ 539 | Expanded( 540 | child: TextField( 541 | controller: _writeController, 542 | ), 543 | ), 544 | ], 545 | ), 546 | actions: [ 547 | FlatButton( 548 | child: Text("Send"), 549 | onPressed: () { 550 | characteristic.write(utf8 551 | .encode(_writeController.value.text)); 552 | Navigator.pop(context); 553 | }, 554 | ), 555 | FlatButton( 556 | child: Text("Cancel"), 557 | onPressed: () { 558 | Navigator.pop(context); 559 | }, 560 | ), 561 | ], 562 | ); 563 | }); 564 | }, 565 | ``` 566 | 567 | So we simply call the characteristic’s write function with our input value passed to it, converted to a byte array using dart:convert 568 | 569 | ## Notify 570 | 571 | Notify is simply a callback executed every time the characteristic’s value handling the notifications is updated: 572 | 573 | ```dart 574 | onPressed: () async { 575 | characteristic.value.listen((value) { 576 | widget.readValues[characteristic.uuid] = value; 577 | }); 578 | await characteristic.setNotifyValue(true); 579 | }, 580 | ``` 581 | 582 | Now every time the value of this characteristic changes we are notified about it, and this also updates the value in our UI. 583 | 584 | Now we have a full application which can scan Bluetooth devices, connect to them, display their services, read their values, update them and be notified about changes :) -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 97C146E61CF9000F007C117D /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 97C146ED1CF9000F007C117D; 25 | remoteInfo = Runner; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXCopyFilesBuildPhase section */ 30 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 10; 35 | files = ( 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXCopyFilesBuildPhase section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 44 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 45 | 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 46 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 48 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 49 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 50 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 51 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 52 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 53 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 331C8082294A63A400263BE5 /* RunnerTests */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 331C807B294A618700263BE5 /* RunnerTests.swift */, 75 | ); 76 | path = RunnerTests; 77 | sourceTree = ""; 78 | }; 79 | 9740EEB11CF90186004384FC /* Flutter */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 83 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 84 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 85 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 86 | ); 87 | name = Flutter; 88 | sourceTree = ""; 89 | }; 90 | 97C146E51CF9000F007C117D = { 91 | isa = PBXGroup; 92 | children = ( 93 | 9740EEB11CF90186004384FC /* Flutter */, 94 | 97C146F01CF9000F007C117D /* Runner */, 95 | 97C146EF1CF9000F007C117D /* Products */, 96 | 331C8082294A63A400263BE5 /* RunnerTests */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | 97C146EF1CF9000F007C117D /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 97C146EE1CF9000F007C117D /* Runner.app */, 104 | 331C8081294A63A400263BE5 /* RunnerTests.xctest */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | 97C146F01CF9000F007C117D /* Runner */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 113 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 114 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 115 | 97C147021CF9000F007C117D /* Info.plist */, 116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 118 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 119 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 120 | ); 121 | path = Runner; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | 331C8080294A63A400263BE5 /* RunnerTests */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; 130 | buildPhases = ( 131 | 331C807D294A63A400263BE5 /* Sources */, 132 | 331C807F294A63A400263BE5 /* Resources */, 133 | ); 134 | buildRules = ( 135 | ); 136 | dependencies = ( 137 | 331C8086294A63A400263BE5 /* PBXTargetDependency */, 138 | ); 139 | name = RunnerTests; 140 | productName = RunnerTests; 141 | productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; 142 | productType = "com.apple.product-type.bundle.unit-test"; 143 | }; 144 | 97C146ED1CF9000F007C117D /* Runner */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 147 | buildPhases = ( 148 | 9740EEB61CF901F6004384FC /* Run Script */, 149 | 97C146EA1CF9000F007C117D /* Sources */, 150 | 97C146EB1CF9000F007C117D /* Frameworks */, 151 | 97C146EC1CF9000F007C117D /* Resources */, 152 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 153 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = Runner; 160 | productName = Runner; 161 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 97C146E61CF9000F007C117D /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | BuildIndependentTargetsInParallel = YES; 171 | LastUpgradeCheck = 1510; 172 | ORGANIZATIONNAME = ""; 173 | TargetAttributes = { 174 | 331C8080294A63A400263BE5 = { 175 | CreatedOnToolsVersion = 14.0; 176 | TestTargetID = 97C146ED1CF9000F007C117D; 177 | }; 178 | 97C146ED1CF9000F007C117D = { 179 | CreatedOnToolsVersion = 7.3.1; 180 | LastSwiftMigration = 1100; 181 | }; 182 | }; 183 | }; 184 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 185 | compatibilityVersion = "Xcode 9.3"; 186 | developmentRegion = en; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | Base, 191 | ); 192 | mainGroup = 97C146E51CF9000F007C117D; 193 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 97C146ED1CF9000F007C117D /* Runner */, 198 | 331C8080294A63A400263BE5 /* RunnerTests */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 331C807F294A63A400263BE5 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | 97C146EC1CF9000F007C117D /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 216 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 217 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 218 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXResourcesBuildPhase section */ 223 | 224 | /* Begin PBXShellScriptBuildPhase section */ 225 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | alwaysOutOfDate = 1; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | inputPaths = ( 232 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", 233 | ); 234 | name = "Thin Binary"; 235 | outputPaths = ( 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | shellPath = /bin/sh; 239 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 240 | }; 241 | 9740EEB61CF901F6004384FC /* Run Script */ = { 242 | isa = PBXShellScriptBuildPhase; 243 | alwaysOutOfDate = 1; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | ); 247 | inputPaths = ( 248 | ); 249 | name = "Run Script"; 250 | outputPaths = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | shellPath = /bin/sh; 254 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 255 | }; 256 | /* End PBXShellScriptBuildPhase section */ 257 | 258 | /* Begin PBXSourcesBuildPhase section */ 259 | 331C807D294A63A400263BE5 /* Sources */ = { 260 | isa = PBXSourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | 97C146EA1CF9000F007C117D /* Sources */ = { 268 | isa = PBXSourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 272 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXTargetDependency section */ 279 | 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { 280 | isa = PBXTargetDependency; 281 | target = 97C146ED1CF9000F007C117D /* Runner */; 282 | targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; 283 | }; 284 | /* End PBXTargetDependency section */ 285 | 286 | /* Begin PBXVariantGroup section */ 287 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | 97C146FB1CF9000F007C117D /* Base */, 291 | ); 292 | name = Main.storyboard; 293 | sourceTree = ""; 294 | }; 295 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | 97C147001CF9000F007C117D /* Base */, 299 | ); 300 | name = LaunchScreen.storyboard; 301 | sourceTree = ""; 302 | }; 303 | /* End PBXVariantGroup section */ 304 | 305 | /* Begin XCBuildConfiguration section */ 306 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_COMMA = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 322 | CLANG_WARN_EMPTY_BODY = YES; 323 | CLANG_WARN_ENUM_CONVERSION = YES; 324 | CLANG_WARN_INFINITE_RECURSION = YES; 325 | CLANG_WARN_INT_CONVERSION = YES; 326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 338 | ENABLE_NS_ASSERTIONS = NO; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 341 | GCC_C_LANGUAGE_STANDARD = gnu99; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 350 | MTL_ENABLE_DEBUG_INFO = NO; 351 | SDKROOT = iphoneos; 352 | SUPPORTED_PLATFORMS = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | VALIDATE_PRODUCT = YES; 355 | }; 356 | name = Profile; 357 | }; 358 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 359 | isa = XCBuildConfiguration; 360 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 361 | buildSettings = { 362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 363 | CLANG_ENABLE_MODULES = YES; 364 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 365 | DEVELOPMENT_TEAM = 55BAZ8LVP4; 366 | ENABLE_BITCODE = NO; 367 | INFOPLIST_FILE = Runner/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "@executable_path/Frameworks", 371 | ); 372 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 375 | SWIFT_VERSION = 5.0; 376 | VERSIONING_SYSTEM = "apple-generic"; 377 | }; 378 | name = Profile; 379 | }; 380 | 331C8088294A63A400263BE5 /* Debug */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | BUNDLE_LOADER = "$(TEST_HOST)"; 384 | CODE_SIGN_STYLE = Automatic; 385 | CURRENT_PROJECT_VERSION = 1; 386 | GENERATE_INFOPLIST_FILE = YES; 387 | MARKETING_VERSION = 1.0; 388 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle.RunnerTests; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 391 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 392 | SWIFT_VERSION = 5.0; 393 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 394 | }; 395 | name = Debug; 396 | }; 397 | 331C8089294A63A400263BE5 /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | BUNDLE_LOADER = "$(TEST_HOST)"; 401 | CODE_SIGN_STYLE = Automatic; 402 | CURRENT_PROJECT_VERSION = 1; 403 | GENERATE_INFOPLIST_FILE = YES; 404 | MARKETING_VERSION = 1.0; 405 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle.RunnerTests; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | SWIFT_VERSION = 5.0; 408 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 409 | }; 410 | name = Release; 411 | }; 412 | 331C808A294A63A400263BE5 /* Profile */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | BUNDLE_LOADER = "$(TEST_HOST)"; 416 | CODE_SIGN_STYLE = Automatic; 417 | CURRENT_PROJECT_VERSION = 1; 418 | GENERATE_INFOPLIST_FILE = YES; 419 | MARKETING_VERSION = 1.0; 420 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle.RunnerTests; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | SWIFT_VERSION = 5.0; 423 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; 424 | }; 425 | name = Profile; 426 | }; 427 | 97C147031CF9000F007C117D /* Debug */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 432 | CLANG_ANALYZER_NONNULL = YES; 433 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 434 | CLANG_CXX_LIBRARY = "libc++"; 435 | CLANG_ENABLE_MODULES = YES; 436 | CLANG_ENABLE_OBJC_ARC = YES; 437 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 438 | CLANG_WARN_BOOL_CONVERSION = YES; 439 | CLANG_WARN_COMMA = YES; 440 | CLANG_WARN_CONSTANT_CONVERSION = YES; 441 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 442 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 443 | CLANG_WARN_EMPTY_BODY = YES; 444 | CLANG_WARN_ENUM_CONVERSION = YES; 445 | CLANG_WARN_INFINITE_RECURSION = YES; 446 | CLANG_WARN_INT_CONVERSION = YES; 447 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 448 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 449 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 450 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 451 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 452 | CLANG_WARN_STRICT_PROTOTYPES = YES; 453 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 454 | CLANG_WARN_UNREACHABLE_CODE = YES; 455 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 456 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 457 | COPY_PHASE_STRIP = NO; 458 | DEBUG_INFORMATION_FORMAT = dwarf; 459 | ENABLE_STRICT_OBJC_MSGSEND = YES; 460 | ENABLE_TESTABILITY = YES; 461 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 462 | GCC_C_LANGUAGE_STANDARD = gnu99; 463 | GCC_DYNAMIC_NO_PIC = NO; 464 | GCC_NO_COMMON_BLOCKS = YES; 465 | GCC_OPTIMIZATION_LEVEL = 0; 466 | GCC_PREPROCESSOR_DEFINITIONS = ( 467 | "DEBUG=1", 468 | "$(inherited)", 469 | ); 470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 472 | GCC_WARN_UNDECLARED_SELECTOR = YES; 473 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 474 | GCC_WARN_UNUSED_FUNCTION = YES; 475 | GCC_WARN_UNUSED_VARIABLE = YES; 476 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 477 | MTL_ENABLE_DEBUG_INFO = YES; 478 | ONLY_ACTIVE_ARCH = YES; 479 | SDKROOT = iphoneos; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 97C147041CF9000F007C117D /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ALWAYS_SEARCH_USER_PATHS = NO; 488 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 489 | CLANG_ANALYZER_NONNULL = YES; 490 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 491 | CLANG_CXX_LIBRARY = "libc++"; 492 | CLANG_ENABLE_MODULES = YES; 493 | CLANG_ENABLE_OBJC_ARC = YES; 494 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 495 | CLANG_WARN_BOOL_CONVERSION = YES; 496 | CLANG_WARN_COMMA = YES; 497 | CLANG_WARN_CONSTANT_CONVERSION = YES; 498 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 499 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INFINITE_RECURSION = YES; 503 | CLANG_WARN_INT_CONVERSION = YES; 504 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 505 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 506 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 507 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 508 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 509 | CLANG_WARN_STRICT_PROTOTYPES = YES; 510 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 511 | CLANG_WARN_UNREACHABLE_CODE = YES; 512 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 513 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 514 | COPY_PHASE_STRIP = NO; 515 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 516 | ENABLE_NS_ASSERTIONS = NO; 517 | ENABLE_STRICT_OBJC_MSGSEND = YES; 518 | ENABLE_USER_SCRIPT_SANDBOXING = NO; 519 | GCC_C_LANGUAGE_STANDARD = gnu99; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 522 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 523 | GCC_WARN_UNDECLARED_SELECTOR = YES; 524 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 525 | GCC_WARN_UNUSED_FUNCTION = YES; 526 | GCC_WARN_UNUSED_VARIABLE = YES; 527 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 528 | MTL_ENABLE_DEBUG_INFO = NO; 529 | SDKROOT = iphoneos; 530 | SUPPORTED_PLATFORMS = iphoneos; 531 | SWIFT_COMPILATION_MODE = wholemodule; 532 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 533 | TARGETED_DEVICE_FAMILY = "1,2"; 534 | VALIDATE_PRODUCT = YES; 535 | }; 536 | name = Release; 537 | }; 538 | 97C147061CF9000F007C117D /* Debug */ = { 539 | isa = XCBuildConfiguration; 540 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 541 | buildSettings = { 542 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 543 | CLANG_ENABLE_MODULES = YES; 544 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 545 | DEVELOPMENT_TEAM = 55BAZ8LVP4; 546 | ENABLE_BITCODE = NO; 547 | INFOPLIST_FILE = Runner/Info.plist; 548 | LD_RUNPATH_SEARCH_PATHS = ( 549 | "$(inherited)", 550 | "@executable_path/Frameworks", 551 | ); 552 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle; 553 | PRODUCT_NAME = "$(TARGET_NAME)"; 554 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 555 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 556 | SWIFT_VERSION = 5.0; 557 | VERSIONING_SYSTEM = "apple-generic"; 558 | }; 559 | name = Debug; 560 | }; 561 | 97C147071CF9000F007C117D /* Release */ = { 562 | isa = XCBuildConfiguration; 563 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 564 | buildSettings = { 565 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 566 | CLANG_ENABLE_MODULES = YES; 567 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 568 | DEVELOPMENT_TEAM = 55BAZ8LVP4; 569 | ENABLE_BITCODE = NO; 570 | INFOPLIST_FILE = Runner/Info.plist; 571 | LD_RUNPATH_SEARCH_PATHS = ( 572 | "$(inherited)", 573 | "@executable_path/Frameworks", 574 | ); 575 | PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBle; 576 | PRODUCT_NAME = "$(TARGET_NAME)"; 577 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 578 | SWIFT_VERSION = 5.0; 579 | VERSIONING_SYSTEM = "apple-generic"; 580 | }; 581 | name = Release; 582 | }; 583 | /* End XCBuildConfiguration section */ 584 | 585 | /* Begin XCConfigurationList section */ 586 | 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { 587 | isa = XCConfigurationList; 588 | buildConfigurations = ( 589 | 331C8088294A63A400263BE5 /* Debug */, 590 | 331C8089294A63A400263BE5 /* Release */, 591 | 331C808A294A63A400263BE5 /* Profile */, 592 | ); 593 | defaultConfigurationIsVisible = 0; 594 | defaultConfigurationName = Release; 595 | }; 596 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 597 | isa = XCConfigurationList; 598 | buildConfigurations = ( 599 | 97C147031CF9000F007C117D /* Debug */, 600 | 97C147041CF9000F007C117D /* Release */, 601 | 249021D3217E4FDB00AE95B9 /* Profile */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 97C147061CF9000F007C117D /* Debug */, 610 | 97C147071CF9000F007C117D /* Release */, 611 | 249021D4217E4FDB00AE95B9 /* Profile */, 612 | ); 613 | defaultConfigurationIsVisible = 0; 614 | defaultConfigurationName = Release; 615 | }; 616 | /* End XCConfigurationList section */ 617 | }; 618 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 619 | } 620 | --------------------------------------------------------------------------------