Add All the files from the touchpad_demonstrator Flutter App which can be build for Android and iOS

This commit is contained in:
Richard Stern
2019-06-04 16:51:24 +02:00
parent 26fcc2491c
commit a951e9518d
1340 changed files with 12844936 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" />
</component>
</module>
+27
View File
@@ -0,0 +1,27 @@
<component name="libraryTable">
<library name="Dart SDK">
<CLASSES>
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/async" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/cli" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/collection" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/convert" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/core" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/developer" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/html" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/indexed_db" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/io" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/isolate" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/js" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/js_util" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/math" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/mirrors" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/svg" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/typed_data" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/web_audio" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/web_gl" />
<root url="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/web_sql" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="Flutter Plugins" type="FlutterPluginsLibraryType">
<CLASSES>
<root url="file://$PROJECT_DIR$" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="7">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="6">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Android API 28 Platform" project-jdk-type="Android SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/flutter_blue.iml" filepath="$PROJECT_DIR$/.idea/flutter_blue.iml" />
</modules>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+957
View File
@@ -0,0 +1,957 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="ChangeListManager">
<list default="true" id="f9a2a7b0-be08-4e0c-ac22-29d107d17eef" name="Default" comment="Fixed possible NPE [Android].">
<change afterPath="$PROJECT_DIR$/.idea/encodings.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/flutter_blue.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="602">
<caret line="172" column="10" selection-start-line="172" selection-start-column="10" selection-end-line="172" selection-end-column="10" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-139" />
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/protos/flutterblue.proto">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="3128">
<caret line="184" column="20" selection-start-line="184" selection-start-column="20" selection-end-line="184" selection-end-column="20" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/protos/regenerate.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204">
<caret line="12" column="3" selection-start-line="12" selection-start-column="3" selection-end-line="12" selection-end-column="51" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/test/guid_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="34">
<caret line="5" column="48" selection-start-line="5" selection-start-column="48" selection-end-line="5" selection-end-column="48" />
<folding>
<element signature="e#0#1997#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="238">
<caret line="14" selection-start-line="14" selection-end-line="14" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_device.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="3604">
<caret line="214" column="20" selection-start-line="214" selection-start-column="20" selection-end-line="214" selection-end-column="20" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_service.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="187">
<caret line="13" column="8" selection-start-line="13" selection-start-column="8" selection-end-line="13" selection-end-column="8" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/constants.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="68">
<caret line="6" column="30" selection-start-line="6" selection-start-column="30" selection-end-line="6" selection-end-column="30" />
<folding>
<element signature="e#0#240#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>disconnect</find>
<find>connectGatt</find>
<find>getConnectedDevices</find>
<find>rapidreboot</find>
<find>discover</find>
<find>print</find>
<find>getConnect</find>
<find>new</find>
<find>const</find>
<find>theme</find>
<find>state</find>
<find>children</find>
<find>new</find>
<find>_readCharacteristic</find>
<find>have you called discoverServices() yet?</find>
<find>toServicesResultProto</find>
<find>const</find>
<find>OnNotificationResponse</find>
<find>OnValueChanged</find>
<find>OnCharacteristicChanged</find>
<find>writeCharacteristic</find>
<find>_methodStream</find>
<find>_methodStreamController</find>
<find>_value.value</find>
</findStrings>
<replaceStrings>
<replace>OnCharacteristicChanged</replace>
<replace>OnValueChanged</replace>
<replace>lastValue</replace>
</replaceStrings>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="reactivex" />
</map>
</option>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/android/.gitignore" />
<option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/android/flutter_blue_android.iml" />
<option value="$PROJECT_DIR$/flutter_blue.iml" />
<option value="$PROJECT_DIR$/.gitignore" />
<option value="$PROJECT_DIR$/example/.gitignore" />
<option value="$PROJECT_DIR$/example/flutter_blue_example.iml" />
<option value="$PROJECT_DIR$/example/android/flutter_blue_example_android.iml" />
<option value="$PROJECT_DIR$/example/android/build.gradle" />
<option value="$PROJECT_DIR$/example/android/settings.gradle" />
<option value="$PROJECT_DIR$/example/android/app/build.gradle" />
<option value="$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml" />
<option value="$PROJECT_DIR$/test/guid_test.dart" />
<option value="$PROJECT_DIR$/example/test/widget_test.dart" />
<option value="$PROJECT_DIR$/lib/src/constants.dart" />
<option value="$PROJECT_DIR$/lib/src/guid.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/flutter_blue.dart" />
<option value="$PROJECT_DIR$/lib/src/bluetooth_service.dart" />
<option value="$PROJECT_DIR$/protos/regenerate.md" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pauldemarco/flutterblue/ProtoMaker.java" />
<option value="$PROJECT_DIR$/ios/Classes/FlutterBluePlugin.m" />
<option value="$PROJECT_DIR$/protos/flutterblue.proto" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pauldemarco/flutterblue/FlutterBluePlugin.java" />
<option value="$PROJECT_DIR$/lib/src/flutter_blue.dart" />
<option value="$PROJECT_DIR$/lib/src/bluetooth_device.dart" />
<option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/lib/src/bluetooth_descriptor.dart" />
<option value="$PROJECT_DIR$/lib/src/bluetooth_characteristic.dart" />
<option value="$PROJECT_DIR$/example/lib/widgets.dart" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="67" />
<option name="y" value="25" />
<option name="width" value="2493" />
<option name="height" value="1415" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="flutterblue" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" />
<item name="test" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="ios" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="ios" type="462c0819:PsiDirectoryNode" />
<item name="Classes" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="protos" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="site" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="flutter_blue" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_blue" type="462c0819:PsiDirectoryNode" />
<item name="test" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="PackagesPane" />
<pane id="Scope" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="android.sdk.path" value="$PROJECT_DIR$/../Android/Sdk" />
<property name="dart.analysis.tool.window.force.activate" value="false" />
<property name="io.flutter.reload.alreadyRun" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../auto_data2" />
<property name="settings.editor.selected.configurable" value="flutter.settings" />
<property name="show.migrate.to.gradle.popup" value="false" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example" />
<recent name="$PROJECT_DIR$/example/android/app/src/main" />
<recent name="$PROJECT_DIR$/example/android" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/example/android" />
<recent name="$PROJECT_DIR$/android" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager" selected="Flutter.main.dart">
<configuration default="true" type="Application" factoryName="Application">
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration name="main.dart" type="FlutterRunConfigurationType" factoryName="Flutter">
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
<method v="2" />
</configuration>
<configuration name="tests in guid_test.dart" type="FlutterTestConfigType" factoryName="Flutter Test" temporary="true" nameIsGenerated="true">
<option name="testFile" value="$PROJECT_DIR$/test/guid_test.dart" />
<method v="2" />
</configuration>
<configuration default="true" type="JUnit" factoryName="JUnit">
<option name="TEST_OBJECT" value="class" />
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="TestNG">
<option name="WORKING_DIRECTORY" value="%MODULE_WORKING_DIR%" />
<properties />
<listeners />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<list>
<item itemvalue="Flutter.main.dart" />
<item itemvalue="Flutter Test.tests in guid_test.dart" />
</list>
<recent_temporary>
<list>
<item itemvalue="Flutter Test.tests in guid_test.dart" />
<item itemvalue="Flutter Test.tests in guid_test.dart" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="f9a2a7b0-be08-4e0c-ac22-29d107d17eef" name="Default" comment="" />
<created>1544553457689</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1544553457689</updated>
</task>
<task id="LOCAL-00001" summary="[Android] Print newState for onConnectionStateChange.">
<created>1544560338903</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1544560338903</updated>
</task>
<task id="LOCAL-00002" summary="Expose autoConnect as a parameter to connect().">
<created>1544560382943</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1544560382943</updated>
</task>
<task id="LOCAL-00003" summary="Updated plugin to latest plugin structure [Dart] [Android].">
<created>1545352112921</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1545352112921</updated>
</task>
<task id="LOCAL-00004" summary="Setup servicesDiscoveredChannel before invoking method. Fixes #107">
<created>1545515736219</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1545515736219</updated>
</task>
<task id="LOCAL-00005" summary="Fix uuid bug in startScan18.">
<created>1545515757574</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1545515757574</updated>
</task>
<task id="LOCAL-00006" summary="dartfmt on src folder.">
<created>1545515836257</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1545515836257</updated>
</task>
<task id="LOCAL-00007" summary="Casting to bool for isAvailable/isOn. Fixes #122">
<created>1545517807282</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1545517807282</updated>
</task>
<task id="LOCAL-00008" summary="[Dart] [Android] Standardize logging across plugin, iOS still needed. #45">
<created>1545874873867</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1545874873867</updated>
</task>
<task id="LOCAL-00009" summary="Put connect and disconnect into BluetoothDevice.">
<created>1545932798247</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1545932798247</updated>
</task>
<task id="LOCAL-00010" summary="Moved methods from BluetoothDevice to Characteristic/Descriptor. Updated README and example app.">
<created>1545935205691</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1545935205691</updated>
</task>
<task id="LOCAL-00011" summary="Removed optional new and const from Example main.dart">
<created>1545935270355</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1545935270355</updated>
</task>
<task id="LOCAL-00012" summary="Disconnect gatt first so callback fires, then close it. Fixes #160">
<created>1545953402903</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1545953402903</updated>
</task>
<task id="LOCAL-00013" summary="Fixed possible NPE [Android].">
<created>1545953693422</created>
<option name="number" value="00013" />
<option name="presentableId" value="LOCAL-00013" />
<option name="project" value="LOCAL" />
<updated>1545953693422</updated>
</task>
<task id="LOCAL-00014" summary="Override hashcode/equals for ScanResult and BluetoothDevice.">
<created>1546024874325</created>
<option name="number" value="00014" />
<option name="presentableId" value="LOCAL-00014" />
<option name="project" value="LOCAL" />
<updated>1546024874325</updated>
</task>
<task id="LOCAL-00015" summary="Fix NPE in connect function.">
<created>1546024919847</created>
<option name="number" value="00015" />
<option name="presentableId" value="LOCAL-00015" />
<option name="project" value="LOCAL" />
<updated>1546024919847</updated>
</task>
<task id="LOCAL-00016" summary="Stop throwing error on Android when services are empty.">
<created>1546030924796</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1546030924796</updated>
</task>
<task id="LOCAL-00017" summary="Make updateDescriptors private to library.">
<created>1546036375910</created>
<option name="number" value="00017" />
<option name="presentableId" value="LOCAL-00017" />
<option name="project" value="LOCAL" />
<updated>1546036375910</updated>
</task>
<task id="LOCAL-00018" summary="Remove default constructors for Device/Service/Characteristic/Descriptor.">
<created>1546037137956</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1546037137956</updated>
</task>
<task id="LOCAL-00019" summary="OnValueChanged -&gt; OnCharacteristicChanged. Moved value stream to characteristic.&#10;&#10;This is the beginning of the API overhaul to a fully reactive plugin.">
<created>1546038169112</created>
<option name="number" value="00019" />
<option name="presentableId" value="LOCAL-00019" />
<option name="project" value="LOCAL" />
<updated>1546038169112</updated>
</task>
<task id="LOCAL-00020" summary="Updating iOS files to latest plugin structure.">
<created>1546055451744</created>
<option name="number" value="00020" />
<option name="presentableId" value="LOCAL-00020" />
<option name="project" value="LOCAL" />
<updated>1546055451744</updated>
</task>
<task id="LOCAL-00021" summary="Updating iOS project files.">
<created>1546055492253</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1546055492253</updated>
</task>
<task id="LOCAL-00022" summary="Fix bug in scan.">
<created>1549315985478</created>
<option name="number" value="00022" />
<option name="presentableId" value="LOCAL-00022" />
<option name="project" value="LOCAL" />
<updated>1549315985478</updated>
</task>
<option name="localTasksCounter" value="23" />
<servers />
</component>
<component name="TestHistory">
<history-entry file="tests_in_guid_test_dart - 2018.12.20 at 19h 19m 44s.xml">
<configuration name="tests in guid_test.dart" configurationId="FlutterTestConfigType" />
</history-entry>
<history-entry file="tests_in_guid_test_dart - 2018.12.20 at 19h 21m 27s.xml">
<configuration name="tests in guid_test.dart" configurationId="FlutterTestConfigType" />
</history-entry>
</component>
<component name="TodoView">
<todo-panel id="selected-file">
<is-autoscroll-to-source value="true" />
</todo-panel>
<todo-panel id="all">
<are-packages-shown value="true" />
<is-autoscroll-to-source value="true" />
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="67" y="25" width="2493" height="1415" extended-state="6" />
<layout>
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.38087454" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info id="Designer" order="2" />
<window_info id="Image Layers" order="3" />
<window_info id="Favorites" order="4" side_tool="true" />
<window_info id="Capture Tool" order="5" />
<window_info id="Captures" order="6" weight="0.25" />
<window_info id="UI Designer" order="7" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.3299532" />
<window_info anchor="bottom" id="Run" order="2" weight="0.3299532" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" weight="0.3299532" />
<window_info anchor="bottom" id="Dart Analysis" order="7" weight="0.3299532" />
<window_info active="true" anchor="bottom" id="Terminal" order="8" visible="true" weight="0.32970452" />
<window_info anchor="bottom" id="Event Log" order="9" side_tool="true" />
<window_info anchor="bottom" id="Version Control" order="10" weight="0.44409937" />
<window_info anchor="bottom" id="Flutter Performance" order="11" side_tool="true" />
<window_info anchor="bottom" id="Messages" order="12" weight="0.3299532" />
<window_info anchor="right" id="Maven" />
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Flutter Inspector" order="3" />
<window_info anchor="right" id="Capture Analysis" order="4" />
<window_info anchor="right" id="Flutter Outline" order="5" />
<window_info anchor="right" id="Palette&#9;" order="6" />
<window_info anchor="right" id="Theme Preview" order="7" />
<window_info anchor="right" id="Palette" order="8" />
<window_info anchor="right" id="Maven Projects" order="9" />
</layout>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="[Android] Print newState for onConnectionStateChange." />
<MESSAGE value="Expose autoConnect as a parameter to connect()." />
<MESSAGE value="Updated plugin to latest plugin structure [Dart] [Android]." />
<MESSAGE value="Setup servicesDiscoveredChannel before invoking method. Fixes #107" />
<MESSAGE value="Fix uuid bug in startScan18." />
<MESSAGE value="dartfmt on src folder." />
<MESSAGE value="Casting to bool for isAvailable/isOn. Fixes #122" />
<MESSAGE value="[Dart] [Android] Standardize logging across plugin, iOS still needed. #45" />
<MESSAGE value="Put connect and disconnect into BluetoothDevice." />
<MESSAGE value="Moved methods from BluetoothDevice to Characteristic/Descriptor. Updated README and example app." />
<MESSAGE value="Removed optional new and const from Example main.dart" />
<MESSAGE value="Disconnect gatt first so callback fires, then close it. Fixes #160" />
<MESSAGE value="Fixed possible NPE [Android]." />
<MESSAGE value="Override hashcode/equals for ScanResult and BluetoothDevice." />
<MESSAGE value="Fix NPE in connect function." />
<MESSAGE value="Stop throwing error on Android when services are empty." />
<MESSAGE value="Make updateDescriptors private to library." />
<MESSAGE value="Remove default constructors for Device/Service/Characteristic/Descriptor." />
<MESSAGE value="OnValueChanged -&gt; OnCharacteristicChanged. Moved value stream to characteristic.&#10;&#10;This is the beginning of the API overhaul to a fully reactive plugin." />
<MESSAGE value="Updating iOS files to latest plugin structure." />
<MESSAGE value="Updating iOS project files." />
<MESSAGE value="Fix bug in scan." />
<option name="LAST_COMMIT_MESSAGE" value="Fix bug in scan." />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/example/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/android/local.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/android/gradlew">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="307">
<caret line="38" column="40" lean-forward="true" selection-start-line="38" selection-start-column="40" selection-end-line="38" selection-end-column="40" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="288">
<caret line="16" column="43" selection-start-line="16" selection-start-column="43" selection-end-line="16" selection-end-column="43" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/settings.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="15" lean-forward="true" selection-start-line="15" selection-end-line="15" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/java/com/pauldemarco/flutterblueexample/MainActivity.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="126">
<caret line="7" column="13" selection-start-line="7" selection-start-column="13" selection-end-line="7" selection-end-column="13" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="126">
<caret line="8" column="19" selection-start-line="8" selection-start-column="19" selection-end-line="8" selection-end-column="19" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/res/values/styles.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/example/test/widget_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="144">
<caret line="13" column="1" lean-forward="true" selection-start-line="13" selection-start-column="1" selection-end-line="13" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/gen/flutterblue.pb.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="288">
<caret line="107" column="26" selection-start-line="107" selection-start-column="26" selection-end-line="107" selection-end-column="26" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/bin/cache/pkg/sky_engine/lib/async/future.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="600">
<caret line="311" column="17" selection-start-line="311" selection-start-column="17" selection-end-line="311" selection-end-column="17" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/bin/cache/pkg/sky_engine/lib/async/timer.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-426">
<caret line="44" column="10" selection-start-line="44" selection-start-column="10" selection-end-line="44" selection-end-column="10" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/gen/Flutterblue.pbobjc.h">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/theme_data.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="276">
<caret line="432" column="20" selection-start-line="432" selection-start-column="20" selection-end-line="432" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/app.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="248">
<caret line="405" column="59" lean-forward="true" selection-start-line="405" selection-start-column="59" selection-end-line="405" selection-end-column="59" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/colors.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="276">
<caret line="828" column="29" selection-start-line="828" selection-start-column="29" selection-end-line="828" selection-end-column="29" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/bin/cache/pkg/sky_engine/lib/core/set.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2880">
<caret line="162" column="7" selection-start-line="162" selection-start-column="7" selection-end-line="162" selection-end-column="7" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="306">
<caret line="17" lean-forward="true" selection-start-line="17" selection-end-line="17" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/refresh_indicator.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="276">
<caret line="36" column="8" selection-start-line="36" selection-start-column="8" selection-end-line="36" selection-end-column="8" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/bin/cache/pkg/sky_engine/lib/async/stream.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="438">
<caret line="1166" column="16" selection-start-line="1166" selection-start-column="16" selection-end-line="1166" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../.pub-cache/hosted/pub.dartlang.org/rxdart-0.20.0/lib/src/subjects/publish_subject.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="432">
<caret line="27" column="6" selection-start-line="27" selection-start-column="6" selection-end-line="27" selection-end-column="6" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../.pub-cache/hosted/pub.dartlang.org/rxdart-0.20.0/lib/src/observables/observable.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="384">
<caret line="2125" column="16" selection-start-line="2125" selection-start-column="16" selection-end-line="2125" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/expansion_tile.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="266">
<caret line="31" column="46" selection-start-line="31" selection-start-column="38" selection-end-line="31" selection-end-column="46" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/widgets/preferred_size.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="415">
<caret line="44" column="8" selection-start-line="44" selection-start-column="8" selection-end-line="44" selection-end-column="8" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/animation/animations.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1248">
<caret line="372" column="2" selection-start-line="372" selection-start-column="2" selection-end-line="372" selection-end-column="2" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="594">
<caret line="35" column="8" selection-start-line="35" selection-start-column="8" selection-end-line="35" selection-end-column="8" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/widgets/implicit_animations.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="276">
<caret line="1248" column="8" selection-start-line="1248" selection-start-column="8" selection-end-line="1248" selection-end-column="8" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../.pub-cache/hosted/pub.dartlang.org/vector_math-2.0.8/lib/src/vector_math_64/matrix4.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-858">
<caret line="262" column="18" selection-start-line="262" selection-start-column="18" selection-end-line="262" selection-end-column="18" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/material/progress_indicator.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-1560">
<caret line="404" column="21" selection-start-line="404" selection-start-column="21" selection-end-line="404" selection-end-column="21" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../flutter/packages/flutter/lib/src/widgets/transitions.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="186">
<caret line="242" column="108" selection-start-line="242" selection-start-column="24" selection-end-line="242" selection-end-column="108" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pauldemarco/flutterblue/ProtoMaker.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="738">
<caret line="207" column="1" selection-start-line="207" selection-start-column="1" selection-end-line="207" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/FlutterBluePlugin.m">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="181">
<caret line="436" column="45" selection-start-line="436" selection-start-column="45" selection-end-line="436" selection-end-column="45" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-630">
<caret line="22" lean-forward="true" selection-start-line="22" selection-end-line="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_descriptor.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="234">
<caret line="15" column="22" selection-start-line="15" selection-start-column="22" selection-end-line="15" selection-end-column="22" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/widgets.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="451">
<caret line="250" column="6" selection-start-line="250" selection-start-column="6" selection-end-line="250" selection-end-column="6" />
<folding>
<element signature="e#0#39#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_characteristic.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="900">
<caret line="52" column="3" selection-start-line="52" selection-start-column="3" selection-end-line="52" selection-end-column="3" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2304">
<caret line="134" selection-start-line="134" selection-end-line="134" />
<folding>
<element signature="e#0#9013#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/java/com/pauldemarco/flutterblue/FlutterBluePlugin.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2700">
<caret line="196" column="66" selection-start-line="196" selection-start-column="56" selection-end-line="196" selection-end-column="66" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/guid.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="510">
<caret line="32" column="27" selection-start-line="32" selection-start-column="27" selection-end-line="32" selection-end-column="27" />
<folding>
<element signature="e#0#2874#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_blue.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="170">
<caret line="12" selection-start-line="12" selection-end-line="12" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/protos/flutterblue.proto">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="3128">
<caret line="184" column="20" selection-start-line="184" selection-start-column="20" selection-end-line="184" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/protos/regenerate.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204">
<caret line="12" column="3" selection-start-line="12" selection-start-column="3" selection-end-line="12" selection-end-column="51" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/test/guid_test.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="34">
<caret line="5" column="48" selection-start-line="5" selection-start-column="48" selection-end-line="5" selection-end-column="48" />
<folding>
<element signature="e#0#1997#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_device.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="3604">
<caret line="214" column="20" selection-start-line="214" selection-start-column="20" selection-end-line="214" selection-end-column="20" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/bluetooth_service.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="187">
<caret line="13" column="8" selection-start-line="13" selection-start-column="8" selection-end-line="13" selection-end-column="8" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/constants.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="68">
<caret line="6" column="30" selection-start-line="6" selection-start-column="30" selection-end-line="6" selection-end-column="30" />
<folding>
<element signature="e#0#240#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="238">
<caret line="14" selection-start-line="14" selection-end-line="14" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/lib/src/flutter_blue.dart">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="602">
<caret line="172" column="10" selection-start-line="172" selection-start-column="10" selection-end-line="172" selection-end-column="10" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-139" />
</provider>
</entry>
</component>
</project>
+92
View File
@@ -0,0 +1,92 @@
## 0.5.0
* **Breaking change**. Migrate from the deprecated original Android Support
Library to AndroidX. This shouldn't result in any functional changes, but it
requires any Android apps using this plugin to [also
migrate](https://developer.android.com/jetpack/androidx/migrate) if they're
using the original support library.
## 0.4.2+1
* Upgrade Android Gradle plugin to 3.3.0
* Refresh iOS build files
## 0.4.2
* Set the verbosity of log messages with `setLogLevel`
* Updated iOS and Android project files
* `autoConnect` now configurable for Android
* Various bug fixes
## 0.4.1
* Fixed bug where setNotifyValue wasn't properly awaitable.
* Various UI bug fixes to example app.
* Removed unnecessary intl dependencies in example app.
## 0.4.0
* **Breaking change**. Manufacturer Data is now a `Map` of manufacturer ID's.
* Service UUID's, service data, tx power level packets fixed in advertising data.
* Example app updated to show advertising data.
* Various other bug fixes.
## 0.3.4
* Updated to use the latest protobuf (^0.9.0+1)
* Updated other dependencies
## 0.3.3
* `scan` `withServices` to filter by service UUID's (iOS)
* Error handled when trying to scan with adapter off (Android)
## 0.3.2
* Runtime permissions for Android
* `scan` `withServices` to filter by service UUID's (Android)
* Scan mode can be specified (Android)
* Now targets the latest android SDK
* Dart 2 compatibility
## 0.3.1
* Now allows simultaneous notifications of characteristics
* Fixed bug on iOS that was returning `discoverServices` too early
## 0.3.0
* iOS support added
* Bug fixed in example causing discoverServices to be called multiple times
* Various other bug fixes
## 0.2.4
* **Breaking change**. Upgraded to Gradle 4.1 and Android Studio Gradle plugin
3.0.1. Older Flutter projects need to upgrade their Gradle setup as well in
order to use this version of the plugin. Instructions can be found
[here](https://github.com/flutter/flutter/wiki/Updating-Flutter-projects-to-Gradle-4.1-and-Android-Studio-Gradle-plugin-3.0.1).
## 0.2.3
* Bug fixes
## 0.2.2
* **Breaking changes**:
* `startScan` renamed to `scan`
* `ScanResult` now returns a `BluetoothDevice`
* `connect` now takes a `BluetoothDevice` and returns Stream<BluetoothDeviceState>
* Added parameter `timeout` to `connect`
* Automatic disconnect on deviceConnection.cancel()
## 0.2.1
* **Breaking change**. Removed `stopScan` from API, use `scanSubscription.cancel()` instead
* Automatically stops scan when `startScan` subscription is canceled (thanks to @brianegan)
* Added `timeout` parameter to `startScan`
* Updated example app to show new scan functionality
## 0.2.0
* Added state and onStateChanged for BluetoothDevice
* Updated example to show new functionality
## 0.1.1
* Fixed image for pub.dartlang.org
## 0.1.0
* Characteristic notifications/indications.
* Merged in Guid library, removed from pubspec.yaml.
## 0.0.1 - September 1st, 2017
* Initial Release.
+27
View File
@@ -0,0 +1,27 @@
Copyright 2017 Paul DeMarco. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Buffalo PC Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+119
View File
@@ -0,0 +1,119 @@
[![pub package](https://img.shields.io/pub/v/flutter_blue.svg)](https://pub.dartlang.org/packages/flutter_blue)
<br>
<p align="center">
<img alt="FlutterBlue" src="https://github.com/pauldemarco/flutter_blue/blob/master/site/flutterblue.png?raw=true" />
</p>
<br><br>
## Introduction
FlutterBlue is a bluetooth plugin for [Flutter](http://www.flutter.io), a new mobile SDK to help developers build modern apps for iOS and Android.
## Cross-Platform Bluetooth LE
FlutterBlue aims to offer the most from both platforms (iOS and Android).
Using the FlutterBlue instance, you can scan for and connect to nearby devices ([BluetoothDevice](#bluetoothdevice-api)).
Once connected to a device, the BluetoothDevice object can discover services ([BluetoothService](lib/src/bluetooth_service.dart)), characteristics ([BluetoothCharacteristic](lib/src/bluetooth_characteristic.dart)), and descriptors ([BluetoothDescriptor](lib/src/bluetooth_descriptor.dart)).
The BluetoothDevice object is then used to directly interact with characteristics and descriptors.
## Usage
### Obtain an instance
```dart
FlutterBlue flutterBlue = FlutterBlue.instance;
```
### Scan for devices
```dart
/// Start scanning
var scanSubscription = flutterBlue.scan().listen((scanResult) {
// do something with scan result
});
/// Stop scanning
scanSubscription.cancel();
```
### Connect to a device
```dart
/// Create a connection to the device
var deviceConnection = flutterBlue.connect(device).listen((s) {
if(s == BluetoothDeviceState.connected) {
// device is connected, do something
}
});
/// Disconnect from device
deviceConnection.cancel();
```
### Discover services
```dart
List<BluetoothService> services = await device.discoverServices();
services.forEach((service) {
// do something with service
});
```
### Read and write characteristics
```dart
// Reads all characteristics
var characteristics = service.characteristics;
for(BluetoothCharacteristic c in characteristics) {
List<int> value = await device.readCharacteristic(c);
print(value);
}
// Writes to a characteristic
await device.writeCharacteristic(c, [0x12, 0x34])
```
### Read and write descriptors
```dart
// Reads all descriptors
var descriptors = characteristic.descriptors;
for(BluetoothDescriptor d in descriptors) {
List<int> value = await device.readDescriptor(d);
print(value);
}
// Writes to a descriptor
await device.writeDescriptor(d, [0x12, 0x34])
```
### Set notifications
```dart
await device.setNotifyValue(characteristic, true);
device.onValueChanged(characteristic).listen((value) {
// do something with new value
});
```
## Reference
### FlutterBlue API
| | Android | iOS | Description |
| :--------------- | :----------------: | :------------------: | :-------------------------------- |
| scan | :white_check_mark: | :white_check_mark: | Starts a scan for Bluetooth Low Energy devices. |
| connect | :white_check_mark: | :white_check_mark: | Establishes a connection to the Bluetooth Device. |
| state | :white_check_mark: | :white_check_mark: | Gets the current state of the Bluetooth Adapter. |
| onStateChanged | :white_check_mark: | :white_check_mark: | Stream of state changes for the Bluetooth Adapter. |
### BluetoothDevice API
| | Android | iOS | Description |
| :-------------------------- | :------------------: | :------------------: | :-------------------------------- |
| discoverServices | :white_check_mark: | :white_check_mark: | Discovers services offered by the remote device as well as their characteristics and descriptors. |
| services | :white_check_mark: | :white_check_mark: | Gets a list of services. Requires that discoverServices() has completed. |
| readCharacteristic | :white_check_mark: | :white_check_mark: | Retrieves the value of a specified characteristic. |
| readDescriptor | :white_check_mark: | :white_check_mark: | Retrieves the value of a specified descriptor. |
| writeCharacteristic | :white_check_mark: | :white_check_mark: | Writes the value of a characteristic. |
| writeDescriptor | :white_check_mark: | :white_check_mark: | Writes the value of a descriptor. |
| setNotifyValue | :white_check_mark: | :white_check_mark: | Sets notifications or indications on the specified characteristic. |
| onValueChanged | :white_check_mark: | :white_check_mark: | Notifies when the characteristic's value has changed. |
| state | :white_check_mark: | :white_check_mark: | Gets the current state of the Bluetooth Device. |
| onStateChanged | :white_check_mark: | :white_check_mark: | Notifies of state changes for the Bluetooth Device. |
## Troubleshooting
### Scanning for service UUID's doesn't return any results
Make sure the device is advertising which service UUID's it supports. This is found in the advertisement
packet as **UUID 16 bit complete list** or **UUID 128 bit complete list**.
+74
View File
@@ -0,0 +1,74 @@
group 'com.pauldemarco.flutterblue'
version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.7'
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.google.protobuf'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
dependencies {
// Required for local unit tests (JUnit 4 framework)
testImplementation 'junit:junit:4.12'
implementation 'androidx.core:core:1.0.1'
//compile files('/home/paul/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar')
}
sourceSets {
main {
proto {
srcDir '../protos'
}
}
}
}
protobuf {
// Configure the protoc executable
protoc {
// Download from repositories
artifact = 'com.google.protobuf:protoc:3.6.1'
}
plugins {
javalite {
// The codegen for lite comes as a separate artifact
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite { }
}
}
}
}
dependencies {
implementation 'com.google.protobuf:protobuf-lite:3.0.1'
}
@@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M
@@ -0,0 +1 @@
rootProject.name = 'flutter_blue'
@@ -0,0 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pauldemarco.flutterblue">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
</manifest>
@@ -0,0 +1,136 @@
// Copyright 2017, the Flutter project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.pauldemarco.flutterblue;
import com.google.protobuf.ByteString;
import com.pauldemarco.flutterblue.Protos.AdvertisementData;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
/**
* Parser of Bluetooth Advertisement packets.
*/
class AdvertisementParser {
/**
* Parses packet data into {@link AdvertisementData} structure.
*
* @param rawData The scan record data.
* @return An AdvertisementData proto object.
* @throws ArrayIndexOutOfBoundsException if the input is truncated.
*/
static AdvertisementData parse(byte[] rawData) {
ByteBuffer data = ByteBuffer.wrap(rawData).asReadOnlyBuffer().order(ByteOrder.LITTLE_ENDIAN);
AdvertisementData.Builder ret = AdvertisementData.newBuilder();
boolean seenLongLocalName = false;
do {
int length = data.get() & 0xFF;
if (length == 0) {
break;
}
if (length > data.remaining()) {
throw new ArrayIndexOutOfBoundsException("Not enough data.");
}
int type = data.get() & 0xFF;
length--;
switch (type) {
case 0x08: // Short local name.
case 0x09: { // Long local name.
if (seenLongLocalName) {
// Prefer the long name over the short.
data.position(data.position() + length);
break;
}
byte[] name = new byte[length];
data.get(name);
try {
ret.setLocalName(new String(name, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
if (type == 0x09) {
seenLongLocalName = true;
}
break;
}
case 0x0A: { // Power level.
ret.setTxPowerLevel(Protos.Int32Value.newBuilder().setValue(data.get()));
break;
}
case 0x16: // Service Data with 16 bit UUID.
case 0x20: // Service Data with 32 bit UUID.
case 0x21: { // Service Data with 128 bit UUID.
UUID uuid;
int remainingDataLength = 0;
if (type == 0x16 || type == 0x20) {
long uuidValue;
if (type == 0x16) {
uuidValue = data.getShort() & 0xFFFF;
remainingDataLength = length - 2;
} else {
uuidValue = data.getInt() & 0xFFFFFFFF;
remainingDataLength = length - 4;
}
uuid = UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", uuidValue));
} else {
long msb = data.getLong();
long lsb = data.getLong();
uuid = new UUID(msb, lsb);
remainingDataLength = length - 16;
}
byte[] remainingData = new byte[remainingDataLength];
data.get(remainingData);
ret.putServiceData(uuid.toString(), ByteString.copyFrom(remainingData));
break;
}
case 0xFF: {// Manufacturer specific data.
if(length < 2) {
throw new ArrayIndexOutOfBoundsException("Not enough data for Manufacturer specific data.");
}
int manufacturerId = data.getShort();
if((length - 2) > 0) {
byte[] msd = new byte[length - 2];
data.get(msd);
ret.putManufacturerData(manufacturerId, ByteString.copyFrom(msd));
}
break;
}
default: {
data.position(data.position() + length);
break;
}
}
} while (true);
return ret.build();
}
}
@@ -0,0 +1,886 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.pauldemarco.flutterblue;
import android.Manifest;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.ParcelUuid;
import android.util.Log;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.EventSink;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener;
/**
* FlutterBluePlugin
*/
public class FlutterBluePlugin implements MethodCallHandler, RequestPermissionsResultListener {
private static final String TAG = "FlutterBluePlugin";
private static final String NAMESPACE = "plugins.pauldemarco.com/flutter_blue";
private static final int REQUEST_COARSE_LOCATION_PERMISSIONS = 1452;
static final private UUID CCCD_ID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private final Registrar registrar;
private final MethodChannel channel;
private final EventChannel stateChannel;
private final EventChannel scanResultChannel;
private final EventChannel servicesDiscoveredChannel;
private final EventChannel characteristicReadChannel;
private final EventChannel descriptorReadChannel;
private final BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private final Map<String, BluetoothGatt> mGattServers = new HashMap<>();
private LogLevel logLevel = LogLevel.EMERGENCY;
// Pending call and result for startScan, in the case where permissions are needed
private MethodCall pendingCall;
private Result pendingResult;
/**
* Plugin registration.
*/
public static void registerWith(Registrar registrar) {
final FlutterBluePlugin instance = new FlutterBluePlugin(registrar);
registrar.addRequestPermissionsResultListener(instance);
}
FlutterBluePlugin(Registrar r){
this.registrar = r;
this.channel = new MethodChannel(registrar.messenger(), NAMESPACE+"/methods");
this.stateChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/state");
this.scanResultChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/scanResult");
this.servicesDiscoveredChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/servicesDiscovered");
this.characteristicReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/characteristicRead");
this.descriptorReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/descriptorRead");
this.mBluetoothManager = (BluetoothManager) r.activity().getSystemService(Context.BLUETOOTH_SERVICE);
this.mBluetoothAdapter = mBluetoothManager.getAdapter();
channel.setMethodCallHandler(this);
stateChannel.setStreamHandler(stateHandler);
scanResultChannel.setStreamHandler(scanResultsHandler);
servicesDiscoveredChannel.setStreamHandler(servicesDiscoveredHandler);
characteristicReadChannel.setStreamHandler(characteristicReadHandler);
descriptorReadChannel.setStreamHandler(descriptorReadHandler);
}
@Override
public void onMethodCall(MethodCall call, Result result) {
if(mBluetoothAdapter == null && !"isAvailable".equals(call.method)) {
result.error("bluetooth_unavailable", "the device does not have bluetooth", null);
return;
}
switch (call.method) {
case "setLogLevel":
{
int logLevelIndex = (int)call.arguments;
logLevel = LogLevel.values()[logLevelIndex];
result.success(null);
break;
}
case "state":
{
Protos.BluetoothState.Builder p = Protos.BluetoothState.newBuilder();
try {
switch(mBluetoothAdapter.getState()) {
case BluetoothAdapter.STATE_OFF:
p.setState(Protos.BluetoothState.State.OFF);
break;
case BluetoothAdapter.STATE_ON:
p.setState(Protos.BluetoothState.State.ON);
break;
case BluetoothAdapter.STATE_TURNING_OFF:
p.setState(Protos.BluetoothState.State.TURNING_OFF);
break;
case BluetoothAdapter.STATE_TURNING_ON:
p.setState(Protos.BluetoothState.State.TURNING_ON);
break;
default:
p.setState(Protos.BluetoothState.State.UNKNOWN);
break;
}
} catch (SecurityException e) {
p.setState(Protos.BluetoothState.State.UNAUTHORIZED);
}
result.success(p.build().toByteArray());
break;
}
case "isAvailable":
{
result.success(mBluetoothAdapter != null);
break;
}
case "isOn":
{
result.success(mBluetoothAdapter.isEnabled());
break;
}
case "startScan":
{
if (ContextCompat.checkSelfPermission(registrar.activity(), Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
registrar.activity(),
new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION
},
REQUEST_COARSE_LOCATION_PERMISSIONS);
pendingCall = call;
pendingResult = result;
break;
}
startScan(call, result);
break;
}
case "stopScan":
{
stopScan();
result.success(null);
break;
}
case "connect":
{
byte[] data = call.arguments();
Protos.ConnectRequest options;
try {
options = Protos.ConnectRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
String deviceId = options.getRemoteId();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceId);
boolean isConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT).contains(device);
// If device is already connected, return error
if(mGattServers.containsKey(deviceId) && isConnected) {
result.error("already_connected", "connection with device already exists", null);
return;
}
// If device was connected to previously but is now disconnected, attempt a reconnect
if(mGattServers.containsKey(deviceId) && !isConnected) {
if(!mGattServers.get(deviceId).connect()){
result.error("reconnect_error", "error when reconnecting to device", null);
return;
}
}
// New request, connect and add gattServer to Map
BluetoothGatt gattServer = device.connectGatt(registrar.activity(), options.getAndroidAutoConnect(), mGattCallback);
mGattServers.put(deviceId, gattServer);
result.success(null);
break;
}
case "disconnect":
{
String deviceId = (String)call.arguments;
BluetoothGatt gattServer = mGattServers.remove(deviceId);
if(gattServer != null) {
gattServer.close();
}
result.success(null);
break;
}
case "deviceState":
{
String deviceId = (String)call.arguments;
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceId);
int state = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT);
try {
result.success(ProtoMaker.from(device, state).toByteArray());
} catch(Exception e) {
result.error("device_state_error", e.getMessage(), null);
}
break;
}
case "discoverServices":
{
String deviceId = (String)call.arguments;
BluetoothGatt gattServer = mGattServers.get(deviceId);
if(gattServer == null) {
result.error("discover_services_error", "no instance of BluetoothGatt, have you connected first?", null);
return;
}
if(gattServer.discoverServices()) {
result.success(null);
} else {
result.error("discover_services_error", "unknown reason", null);
}
break;
}
case "services":
{
String deviceId = (String)call.arguments;
BluetoothGatt gattServer = mGattServers.get(deviceId);
if(gattServer == null) {
result.error("get_services_error", "no instance of BluetoothGatt, have you connected first?", null);
return;
}
if(gattServer.getServices().isEmpty()) {
result.error("get_services_error", "services are empty, have you called discoverServices() yet?", null);
return;
}
Protos.DiscoverServicesResult.Builder p = Protos.DiscoverServicesResult.newBuilder();
p.setRemoteId(deviceId);
for(BluetoothGattService s : gattServer.getServices()){
p.addServices(ProtoMaker.from(gattServer.getDevice(), s, gattServer));
}
result.success(p.build().toByteArray());
break;
}
case "readCharacteristic":
{
byte[] data = call.arguments();
Protos.ReadCharacteristicRequest request;
try {
request = Protos.ReadCharacteristicRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
} catch(Exception e) {
result.error("read_characteristic_error", e.getMessage(), null);
return;
}
if(gattServer.readCharacteristic(characteristic)) {
result.success(null);
} else {
result.error("read_characteristic_error", "unknown reason, may occur if readCharacteristic was called before last read finished.", null);
}
break;
}
case "readDescriptor":
{
byte[] data = call.arguments();
Protos.ReadDescriptorRequest request;
try {
request = Protos.ReadDescriptorRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor descriptor;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
descriptor = locateDescriptor(characteristic, request.getDescriptorUuid());
} catch(Exception e) {
result.error("read_descriptor_error", e.getMessage(), null);
return;
}
if(gattServer.readDescriptor(descriptor)) {
result.success(null);
} else {
result.error("read_descriptor_error", "unknown reason, may occur if readDescriptor was called before last read finished.", null);
}
break;
}
case "writeCharacteristic":
{
byte[] data = call.arguments();
Protos.WriteCharacteristicRequest request;
try {
request = Protos.WriteCharacteristicRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
} catch(Exception e) {
result.error("write_characteristic_error", e.getMessage(), null);
return;
}
// Set characteristic to new value
if(!characteristic.setValue(request.getValue().toByteArray())){
result.error("write_characteristic_error", "could not set the local value of characteristic", null);
}
// Apply the correct write type
if(request.getWriteType() == Protos.WriteCharacteristicRequest.WriteType.WITHOUT_RESPONSE) {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
} else {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
}
if(!gattServer.writeCharacteristic(characteristic)){
result.error("write_characteristic_error", "writeCharacteristic failed", null);
return;
}
result.success(null);
break;
}
case "writeDescriptor":
{
byte[] data = call.arguments();
Protos.WriteDescriptorRequest request;
try {
request = Protos.WriteDescriptorRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor descriptor;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
descriptor = locateDescriptor(characteristic, request.getDescriptorUuid());
} catch(Exception e) {
result.error("write_descriptor_error", e.getMessage(), null);
return;
}
// Set descriptor to new value
if(!descriptor.setValue(request.getValue().toByteArray())){
result.error("write_descriptor_error", "could not set the local value for descriptor", null);
}
if(!gattServer.writeDescriptor(descriptor)){
result.error("write_descriptor_error", "writeCharacteristic failed", null);
return;
}
result.success(null);
break;
}
case "setNotification":
{
byte[] data = call.arguments();
Protos.SetNotificationRequest request;
try {
request = Protos.SetNotificationRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}
BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor cccDescriptor;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
cccDescriptor = characteristic.getDescriptor(CCCD_ID);
if(cccDescriptor == null) {
throw new Exception("could not locate CCCD descriptor for characteristic: " +characteristic.getUuid().toString());
}
} catch(Exception e) {
result.error("set_notification_error", e.getMessage(), null);
return;
}
byte[] value = null;
if(request.getEnable()) {
boolean canNotify = (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0;
boolean canIndicate = (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0;
if(!canIndicate && !canNotify) {
result.error("set_notification_error", "the characteristic cannot notify or indicate", null);
return;
}
if(canIndicate) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
}
if(canNotify) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
}
} else {
value = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
}
if(!gattServer.setCharacteristicNotification(characteristic, request.getEnable())){
result.error("set_notification_error", "could not set characteristic notifications to :" + request.getEnable(), null);
return;
}
if(!cccDescriptor.setValue(value)) {
result.error("set_notification_error", "error when setting the descriptor value to: " + value, null);
return;
}
if(!gattServer.writeDescriptor(cccDescriptor)) {
result.error("set_notification_error", "error when writing the descriptor", null);
return;
}
result.success(null);
break;
}
default:
{
result.notImplemented();
break;
}
}
}
@Override
public boolean onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_COARSE_LOCATION_PERMISSIONS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startScan(pendingCall, pendingResult);
} else {
pendingResult.error(
"no_permissions", "flutter_blue plugin requires location permissions for scanning", null);
pendingResult = null;
pendingCall = null;
}
return true;
}
return false;
}
private BluetoothGatt locateGatt(String remoteId) throws Exception {
BluetoothGatt gattServer = mGattServers.get(remoteId);
if(gattServer == null) {
throw new Exception("no instance of BluetoothGatt, have you connected first?");
}
return gattServer;
}
private BluetoothGattCharacteristic locateCharacteristic(BluetoothGatt gattServer, String serviceId, String secondaryServiceId, String characteristicId) throws Exception {
BluetoothGattService primaryService = gattServer.getService(UUID.fromString(serviceId));
if(primaryService == null) {
throw new Exception("service (" + serviceId + ") could not be located on the device");
}
BluetoothGattService secondaryService = null;
if(secondaryServiceId.length() > 0) {
for(BluetoothGattService s : primaryService.getIncludedServices()){
if(s.getUuid().equals(UUID.fromString(secondaryServiceId))){
secondaryService = s;
}
}
if(secondaryService == null) {
throw new Exception("secondary service (" + secondaryServiceId + ") could not be located on the device");
}
}
BluetoothGattService service = (secondaryService != null) ? secondaryService : primaryService;
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicId));
if(characteristic == null) {
throw new Exception("characteristic (" + characteristicId + ") could not be located in the service ("+service.getUuid().toString()+")");
}
return characteristic;
}
private BluetoothGattDescriptor locateDescriptor(BluetoothGattCharacteristic characteristic, String descriptorId) throws Exception {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(descriptorId));
if(descriptor == null) {
throw new Exception("descriptor (" + descriptorId + ") could not be located in the characteristic ("+characteristic.getUuid().toString()+")");
}
return descriptor;
}
private final StreamHandler stateHandler = new StreamHandler() {
private EventSink sink;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
sink.success(Protos.BluetoothState.newBuilder().setState(Protos.BluetoothState.State.OFF).build().toByteArray());
break;
case BluetoothAdapter.STATE_TURNING_OFF:
sink.success(Protos.BluetoothState.newBuilder().setState(Protos.BluetoothState.State.TURNING_OFF).build().toByteArray());
break;
case BluetoothAdapter.STATE_ON:
sink.success(Protos.BluetoothState.newBuilder().setState(Protos.BluetoothState.State.ON).build().toByteArray());
break;
case BluetoothAdapter.STATE_TURNING_ON:
sink.success(Protos.BluetoothState.newBuilder().setState(Protos.BluetoothState.State.TURNING_ON).build().toByteArray());
break;
}
}
}
};
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
sink = eventSink;
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registrar.activity().registerReceiver(mReceiver, filter);
}
@Override
public void onCancel(Object o) {
sink = null;
registrar.activity().unregisterReceiver(mReceiver);
}
};
private void startScan(MethodCall call, Result result) {
byte[] data = call.arguments();
Protos.ScanSettings settings;
try {
settings = Protos.ScanSettings.newBuilder().mergeFrom(data).build();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startScan21(settings);
} else {
startScan18(settings);
}
result.success(null);
} catch (Exception e) {
result.error("startScan", e.getMessage(), e);
}
}
private void stopScan() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
stopScan21();
} else {
stopScan18();
}
}
private ScanCallback scanCallback21;
@TargetApi(21)
private ScanCallback getScanCallback21() {
if(scanCallback21 == null){
scanCallback21 = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if(scanResultsSink != null) {
Protos.ScanResult scanResult = ProtoMaker.from(result.getDevice(), result);
scanResultsSink.success(scanResult.toByteArray());
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
};
}
return scanCallback21;
}
@TargetApi(21)
private void startScan21(Protos.ScanSettings proto) throws IllegalStateException {
BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
if(scanner == null) throw new IllegalStateException("getBluetoothLeScanner() is null. Is the Adapter on?");
int scanMode = proto.getAndroidScanMode();
int count = proto.getServiceUuidsCount();
List<ScanFilter> filters = new ArrayList<>(count);
for(int i = 0; i < count; i++) {
String uuid = proto.getServiceUuids(i);
ScanFilter f = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(uuid)).build();
filters.add(f);
}
ScanSettings settings = new ScanSettings.Builder().setScanMode(scanMode).build();
scanner.startScan(filters, settings, getScanCallback21());
}
@TargetApi(21)
private void stopScan21() {
BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
if(scanner != null) scanner.stopScan(getScanCallback21());
}
private BluetoothAdapter.LeScanCallback scanCallback18;
private BluetoothAdapter.LeScanCallback getScanCallback18() {
if(scanCallback18 == null) {
scanCallback18 = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi,
byte[] scanRecord) {
if(scanResultsSink != null) {
Protos.ScanResult scanResult = ProtoMaker.from(bluetoothDevice, scanRecord, rssi);
scanResultsSink.success(scanResult.toByteArray());
}
}
};
}
return scanCallback18;
}
private void startScan18(Protos.ScanSettings proto) throws IllegalStateException {
List<String> serviceUuids = proto.getServiceUuidsList();
UUID[] uuids = new UUID[serviceUuids.size()];
for(int i = 0; i < serviceUuids.size(); i++) {
uuids[i] = UUID.fromString(serviceUuids.get(i));
}
boolean success = mBluetoothAdapter.startLeScan(uuids, getScanCallback18());
if(!success) throw new IllegalStateException("getBluetoothLeScanner() is null. Is the Adapter on?");
}
private void stopScan18() {
mBluetoothAdapter.stopLeScan(getScanCallback18());
}
private EventSink scanResultsSink;
private final StreamHandler scanResultsHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
scanResultsSink = eventSink;
}
@Override
public void onCancel(Object o) {
scanResultsSink = null;
}
};
private EventSink servicesDiscoveredSink;
private final StreamHandler servicesDiscoveredHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
servicesDiscoveredSink = eventSink;
}
@Override
public void onCancel(Object o) {
servicesDiscoveredSink = null;
}
};
private EventSink characteristicReadSink;
private final StreamHandler characteristicReadHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
characteristicReadSink = eventSink;
}
@Override
public void onCancel(Object o) {
characteristicReadSink = null;
}
};
private EventSink descriptorReadSink;
private final StreamHandler descriptorReadHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
descriptorReadSink = eventSink;
}
@Override
public void onCancel(Object o) {
descriptorReadSink = null;
}
};
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
log(LogLevel.DEBUG, "[onConnectionStateChange] status: " + status + " newState: " + newState);
channel.invokeMethod("DeviceState", ProtoMaker.from(gatt.getDevice(), newState).toByteArray());
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
log(LogLevel.DEBUG, "[onServicesDiscovered] count: " + gatt.getServices().size() + " status: " + status);
if(servicesDiscoveredSink != null) {
Protos.DiscoverServicesResult.Builder p = Protos.DiscoverServicesResult.newBuilder();
p.setRemoteId(gatt.getDevice().getAddress());
for(BluetoothGattService s : gatt.getServices()) {
p.addServices(ProtoMaker.from(gatt.getDevice(), s, gatt));
}
servicesDiscoveredSink.success(p.build().toByteArray());
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
log(LogLevel.DEBUG, "[onCharacteristicRead] uuid: " + characteristic.getUuid().toString() + " status: " + status);
if(characteristicReadSink != null) {
Protos.ReadCharacteristicResponse.Builder p = Protos.ReadCharacteristicResponse.newBuilder();
p.setRemoteId(gatt.getDevice().getAddress());
p.setCharacteristic(ProtoMaker.from(characteristic, gatt));
characteristicReadSink.success(p.build().toByteArray());
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
log(LogLevel.DEBUG, "[onCharacteristicWrite] uuid: " + characteristic.getUuid().toString() + " status: " + status);
Protos.WriteCharacteristicRequest.Builder request = Protos.WriteCharacteristicRequest.newBuilder();
request.setRemoteId(gatt.getDevice().getAddress());
request.setCharacteristicUuid(characteristic.getUuid().toString());
request.setServiceUuid(characteristic.getService().getUuid().toString());
Protos.WriteCharacteristicResponse.Builder p = Protos.WriteCharacteristicResponse.newBuilder();
p.setRequest(request);
p.setSuccess(status == BluetoothGatt.GATT_SUCCESS);
channel.invokeMethod("WriteCharacteristicResponse", p.build().toByteArray());
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
log(LogLevel.DEBUG, "[onCharacteristicChanged] uuid: " + characteristic.getUuid().toString());
Protos.OnNotificationResponse.Builder p = Protos.OnNotificationResponse.newBuilder();
p.setRemoteId(gatt.getDevice().getAddress());
p.setCharacteristic(ProtoMaker.from(characteristic, gatt));
channel.invokeMethod("OnValueChanged", p.build().toByteArray());
}
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
log(LogLevel.DEBUG, "[onDescriptorRead] uuid: " + descriptor.getUuid().toString() + " status: " + status);
if(descriptorReadSink != null) {
// Rebuild the ReadAttributeRequest and send back along with response
Protos.ReadDescriptorRequest.Builder q = Protos.ReadDescriptorRequest.newBuilder();
q.setRemoteId(gatt.getDevice().getAddress());
q.setCharacteristicUuid(descriptor.getCharacteristic().getUuid().toString());
q.setDescriptorUuid(descriptor.getUuid().toString());
if(descriptor.getCharacteristic().getService().getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
q.setServiceUuid(descriptor.getCharacteristic().getService().getUuid().toString());
} else {
// Reverse search to find service
for(BluetoothGattService s : gatt.getServices()) {
for(BluetoothGattService ss : s.getIncludedServices()) {
if(ss.getUuid().equals(descriptor.getCharacteristic().getService().getUuid())){
q.setServiceUuid(s.getUuid().toString());
q.setSecondaryServiceUuid(ss.getUuid().toString());
break;
}
}
}
}
Protos.ReadDescriptorResponse.Builder p = Protos.ReadDescriptorResponse.newBuilder();
p.setRequest(q);
p.setValue(ByteString.copyFrom(descriptor.getValue()));
descriptorReadSink.success(p.build().toByteArray());
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
log(LogLevel.DEBUG, "[onDescriptorWrite] uuid: " + descriptor.getUuid().toString() + " status: " + status);
Protos.WriteDescriptorRequest.Builder request = Protos.WriteDescriptorRequest.newBuilder();
request.setRemoteId(gatt.getDevice().getAddress());
request.setDescriptorUuid(descriptor.getUuid().toString());
request.setCharacteristicUuid(descriptor.getCharacteristic().getUuid().toString());
request.setServiceUuid(descriptor.getCharacteristic().getService().getUuid().toString());
Protos.WriteDescriptorResponse.Builder p = Protos.WriteDescriptorResponse.newBuilder();
p.setRequest(request);
p.setSuccess(status == BluetoothGatt.GATT_SUCCESS);
channel.invokeMethod("WriteDescriptorResponse", p.build().toByteArray());
if(descriptor.getUuid().compareTo(CCCD_ID) == 0) {
// SetNotificationResponse
Protos.SetNotificationResponse.Builder q = Protos.SetNotificationResponse.newBuilder();
q.setRemoteId(gatt.getDevice().getAddress());
q.setCharacteristic(ProtoMaker.from(descriptor.getCharacteristic(), gatt));
channel.invokeMethod("SetNotificationResponse", q.build().toByteArray());
}
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
log(LogLevel.DEBUG, "[onReliableWriteCompleted] status: " + status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
log(LogLevel.DEBUG, "[onReadRemoteRssi] rssi: " + rssi + " status: " + status);
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
log(LogLevel.DEBUG, "[onMtuChanged] mtu: " + mtu + " status: " + status);
}
};
enum LogLevel
{
EMERGENCY, ALERT, CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG;
}
private void log(LogLevel level, String message) {
if(level.ordinal() <= logLevel.ordinal()) {
Log.d(TAG, message);
}
}
}
@@ -0,0 +1,206 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.pauldemarco.flutterblue;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.os.Build;
import android.os.Parcel;
import android.os.ParcelUuid;
import android.util.Log;
import android.util.SparseArray;
import com.google.protobuf.ByteString;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Created by paul on 8/31/17.
*/
public class ProtoMaker {
private static final UUID CCCD_UUID = UUID.fromString("000002902-0000-1000-8000-00805f9b34fb");
static Protos.ScanResult from(BluetoothDevice device, byte[] advertisementData, int rssi) {
Protos.ScanResult.Builder p = Protos.ScanResult.newBuilder();
p.setDevice(from(device));
if(advertisementData != null && advertisementData.length > 0)
p.setAdvertisementData(AdvertisementParser.parse(advertisementData));
p.setRssi(rssi);
return p.build();
}
@TargetApi(21)
static Protos.ScanResult from(BluetoothDevice device, ScanResult scanResult) {
Protos.ScanResult.Builder p = Protos.ScanResult.newBuilder();
p.setDevice(from(device));
Protos.AdvertisementData.Builder a = Protos.AdvertisementData.newBuilder();
ScanRecord scanRecord = scanResult.getScanRecord();
if(Build.VERSION.SDK_INT >= 26) {
a.setConnectable(scanResult.isConnectable());
} else {
if(scanRecord != null) {
int flags = scanRecord.getAdvertiseFlags();
a.setConnectable((flags & 0x2) > 0);
}
}
if(scanRecord != null) {
String deviceName = scanRecord.getDeviceName();
if(deviceName != null) {
a.setLocalName(deviceName);
}
int txPower = scanRecord.getTxPowerLevel();
if(txPower != Integer.MIN_VALUE) {
a.setTxPowerLevel(Protos.Int32Value.newBuilder().setValue(txPower));
}
// Manufacturer Specific Data
SparseArray<byte[]> msd = scanRecord.getManufacturerSpecificData();
for (int i = 0; i < msd.size(); i++) {
int key = msd.keyAt(i);
byte[] value = msd.valueAt(i);
a.putManufacturerData(key, ByteString.copyFrom(value));
}
// Service Data
Map<ParcelUuid, byte[]> serviceData = scanRecord.getServiceData();
for (Map.Entry<ParcelUuid, byte[]> entry : serviceData.entrySet()) {
ParcelUuid key = entry.getKey();
byte[] value = entry.getValue();
a.putServiceData(key.getUuid().toString(), ByteString.copyFrom(value));
}
// Service UUIDs
List<ParcelUuid> serviceUuids = scanRecord.getServiceUuids();
if(serviceUuids != null) {
for (ParcelUuid s : serviceUuids) {
a.addServiceUuids(s.getUuid().toString());
}
}
}
p.setRssi(scanResult.getRssi());
p.setAdvertisementData(a.build());
return p.build();
}
static Protos.BluetoothDevice from(BluetoothDevice device) {
Protos.BluetoothDevice.Builder p = Protos.BluetoothDevice.newBuilder();
p.setRemoteId(device.getAddress());
String name = device.getName();
if(name != null) {
p.setName(name);
}
switch(device.getType()){
case BluetoothDevice.DEVICE_TYPE_LE:
p.setType(Protos.BluetoothDevice.Type.LE);
break;
case BluetoothDevice.DEVICE_TYPE_CLASSIC:
p.setType(Protos.BluetoothDevice.Type.CLASSIC);
break;
case BluetoothDevice.DEVICE_TYPE_DUAL:
p.setType(Protos.BluetoothDevice.Type.DUAL);
break;
default:
p.setType(Protos.BluetoothDevice.Type.UNKNOWN);
break;
}
return p.build();
}
static Protos.BluetoothService from(BluetoothDevice device, BluetoothGattService service, BluetoothGatt gatt) {
Protos.BluetoothService.Builder p = Protos.BluetoothService.newBuilder();
p.setRemoteId(device.getAddress());
p.setUuid(service.getUuid().toString());
p.setIsPrimary(service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY);
for(BluetoothGattCharacteristic c : service.getCharacteristics()) {
p.addCharacteristics(from(c, gatt));
}
for(BluetoothGattService s : service.getIncludedServices()) {
p.addIncludedServices(from(device, s, gatt));
}
return p.build();
}
static Protos.BluetoothCharacteristic from(BluetoothGattCharacteristic characteristic, BluetoothGatt gatt) {
Protos.BluetoothCharacteristic.Builder p = Protos.BluetoothCharacteristic.newBuilder();
p.setUuid(characteristic.getUuid().toString());
p.setProperties(from(characteristic.getProperties()));
if(characteristic.getValue() != null)
p.setValue(ByteString.copyFrom(characteristic.getValue()));
for(BluetoothGattDescriptor d : characteristic.getDescriptors()) {
p.addDescriptors(from(d));
}
if(characteristic.getService().getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
p.setServiceUuid(characteristic.getService().getUuid().toString());
} else {
// Reverse search to find service
for(BluetoothGattService s : gatt.getServices()) {
for(BluetoothGattService ss : s.getIncludedServices()) {
if(ss.getUuid().equals(characteristic.getService().getUuid())){
p.setServiceUuid(s.getUuid().toString());
p.setSecondaryServiceUuid(ss.getUuid().toString());
break;
}
}
}
}
return p.build();
}
static Protos.BluetoothDescriptor from(BluetoothGattDescriptor descriptor) {
Protos.BluetoothDescriptor.Builder p = Protos.BluetoothDescriptor.newBuilder();
p.setUuid(descriptor.getUuid().toString());
p.setCharacteristicUuid(descriptor.getCharacteristic().getUuid().toString());
p.setServiceUuid(descriptor.getCharacteristic().getService().getUuid().toString());
if(descriptor.getValue() != null)
p.setValue(ByteString.copyFrom(descriptor.getValue()));
return p.build();
}
static Protos.CharacteristicProperties from(int properties) {
return Protos.CharacteristicProperties.newBuilder()
.setBroadcast((properties & 1) != 0)
.setRead((properties & 2) != 0)
.setWriteWithoutResponse((properties & 4) != 0)
.setWrite((properties & 8) != 0)
.setNotify((properties & 16) != 0)
.setIndicate((properties & 32) != 0)
.setAuthenticatedSignedWrites((properties & 64) != 0)
.setExtendedProperties((properties & 128) != 0)
.setNotifyEncryptionRequired((properties & 256) != 0)
.setIndicateEncryptionRequired((properties & 512) != 0)
.build();
}
static Protos.DeviceStateResponse from(BluetoothDevice device, int state) {
Protos.DeviceStateResponse.Builder p = Protos.DeviceStateResponse.newBuilder();
switch(state) {
case BluetoothProfile.STATE_DISCONNECTING:
p.setState(Protos.DeviceStateResponse.BluetoothDeviceState.DISCONNECTING);
break;
case BluetoothProfile.STATE_CONNECTED:
p.setState(Protos.DeviceStateResponse.BluetoothDeviceState.CONNECTED);
break;
case BluetoothProfile.STATE_CONNECTING:
p.setState(Protos.DeviceStateResponse.BluetoothDeviceState.CONNECTING);
break;
case BluetoothProfile.STATE_DISCONNECTED:
p.setState(Protos.DeviceStateResponse.BluetoothDeviceState.DISCONNECTED);
break;
default:
break;
}
p.setRemoteId(device.getAddress());
return p.build();
}
}
+8
View File
@@ -0,0 +1,8 @@
# flutter_blue_example
Demonstrates how to use the flutter_blue plugin.
## Getting Started
For help getting started with Flutter, view our online
[documentation](http://flutter.io/).
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/android">
<sourceFolder url="file://$MODULE_DIR$/android/app/src/main/java" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Flutter for Android" level="project" />
</component>
</module>
@@ -0,0 +1,61 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.pauldemarco.flutterblueexample"
minSdkVersion 19
targetSdkVersion 27
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.2-alpha01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01'
}
@@ -0,0 +1,39 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pauldemarco.flutterblueexample">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="flutter_blue_example"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,14 @@
package com.pauldemarco.flutterblueexample;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
@@ -0,0 +1,29 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
@@ -0,0 +1,3 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M
@@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
@@ -0,0 +1,15 @@
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
@@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1,510 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlueExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlueExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterBlueExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,6 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
@@ -0,0 +1,13 @@
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
@@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>flutter_blue_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,9 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
+328
View File
@@ -0,0 +1,328 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:flutter_blue_example/widgets.dart';
void main() {
runApp(new FlutterBlueApp());
}
class FlutterBlueApp extends StatefulWidget {
FlutterBlueApp({Key key, this.title}) : super(key: key);
final String title;
@override
_FlutterBlueAppState createState() => new _FlutterBlueAppState();
}
class _FlutterBlueAppState extends State<FlutterBlueApp> {
FlutterBlue _flutterBlue = FlutterBlue.instance;
/// Scanning
StreamSubscription _scanSubscription;
Map<DeviceIdentifier, ScanResult> scanResults = new Map();
bool isScanning = false;
/// State
StreamSubscription _stateSubscription;
BluetoothState state = BluetoothState.unknown;
/// Device
BluetoothDevice device;
bool get isConnected => (device != null);
StreamSubscription deviceConnection;
StreamSubscription deviceStateSubscription;
List<BluetoothService> services = new List();
Map<Guid, StreamSubscription> valueChangedSubscriptions = {};
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;
@override
void initState() {
super.initState();
// Immediately get the state of FlutterBlue
_flutterBlue.state.then((s) {
setState(() {
state = s;
});
});
// Subscribe to state changes
_stateSubscription = _flutterBlue.onStateChanged().listen((s) {
setState(() {
state = s;
});
});
}
@override
void dispose() {
_stateSubscription?.cancel();
_stateSubscription = null;
_scanSubscription?.cancel();
_scanSubscription = null;
deviceConnection?.cancel();
deviceConnection = null;
super.dispose();
}
_startScan() {
_scanSubscription = _flutterBlue
.scan(
timeout: const Duration(seconds: 5),
/*withServices: [
new Guid('0000180F-0000-1000-8000-00805F9B34FB')
]*/
)
.listen((scanResult) {
print('localName: ${scanResult.advertisementData.localName}');
print(
'manufacturerData: ${scanResult.advertisementData.manufacturerData}');
print('serviceData: ${scanResult.advertisementData.serviceData}');
setState(() {
scanResults[scanResult.device.id] = scanResult;
});
}, onDone: _stopScan);
setState(() {
isScanning = true;
});
}
_stopScan() {
_scanSubscription?.cancel();
_scanSubscription = null;
setState(() {
isScanning = false;
});
}
_connect(BluetoothDevice d) async {
device = d;
// Connect to device
deviceConnection = _flutterBlue
.connect(device, timeout: const Duration(seconds: 4))
.listen(
null,
onDone: _disconnect,
);
// Update the connection state immediately
device.state.then((s) {
setState(() {
deviceState = s;
});
});
// Subscribe to connection changes
deviceStateSubscription = device.onStateChanged().listen((s) {
setState(() {
deviceState = s;
});
if (s == BluetoothDeviceState.connected) {
device.discoverServices().then((s) {
setState(() {
services = s;
});
});
}
});
}
_disconnect() {
// Remove all value changed listeners
valueChangedSubscriptions.forEach((uuid, sub) => sub.cancel());
valueChangedSubscriptions.clear();
deviceStateSubscription?.cancel();
deviceStateSubscription = null;
deviceConnection?.cancel();
deviceConnection = null;
setState(() {
device = null;
});
}
_readCharacteristic(BluetoothCharacteristic c) async {
await device.readCharacteristic(c);
setState(() {});
}
_writeCharacteristic(BluetoothCharacteristic c) async {
await device.writeCharacteristic(c, [0x12, 0x34],
type: CharacteristicWriteType.withResponse);
setState(() {});
}
_readDescriptor(BluetoothDescriptor d) async {
await device.readDescriptor(d);
setState(() {});
}
_writeDescriptor(BluetoothDescriptor d) async {
await device.writeDescriptor(d, [0x12, 0x34]);
setState(() {});
}
_setNotification(BluetoothCharacteristic c) async {
if (c.isNotifying) {
await device.setNotifyValue(c, false);
// Cancel subscription
valueChangedSubscriptions[c.uuid]?.cancel();
valueChangedSubscriptions.remove(c.uuid);
} else {
await device.setNotifyValue(c, true);
// ignore: cancel_subscriptions
final sub = device.onValueChanged(c).listen((d) {
setState(() {
print('onValueChanged $d');
});
});
// Add to map
valueChangedSubscriptions[c.uuid] = sub;
}
setState(() {});
}
_refreshDeviceState(BluetoothDevice d) async {
var state = await d.state;
setState(() {
deviceState = state;
print('State refreshed: $deviceState');
});
}
_buildScanningButton() {
if (isConnected || state != BluetoothState.on) {
return null;
}
if (isScanning) {
return new FloatingActionButton(
child: new Icon(Icons.stop),
onPressed: _stopScan,
backgroundColor: Colors.red,
);
} else {
return new FloatingActionButton(
child: new Icon(Icons.search), onPressed: _startScan);
}
}
_buildScanResultTiles() {
return scanResults.values
.map((r) => ScanResultTile(
result: r,
onTap: () => _connect(r.device),
))
.toList();
}
List<Widget> _buildServiceTiles() {
return services
.map(
(s) => new ServiceTile(
service: s,
characteristicTiles: s.characteristics
.map(
(c) => new CharacteristicTile(
characteristic: c,
onReadPressed: () => _readCharacteristic(c),
onWritePressed: () => _writeCharacteristic(c),
onNotificationPressed: () => _setNotification(c),
descriptorTiles: c.descriptors
.map(
(d) => new DescriptorTile(
descriptor: d,
onReadPressed: () => _readDescriptor(d),
onWritePressed: () =>
_writeDescriptor(d),
),
)
.toList(),
),
)
.toList(),
),
)
.toList();
}
_buildActionButtons() {
if (isConnected) {
return <Widget>[
new IconButton(
icon: const Icon(Icons.cancel),
onPressed: () => _disconnect(),
)
];
}
}
_buildAlertTile() {
return new Container(
color: Colors.redAccent,
child: new ListTile(
title: new Text(
'Bluetooth adapter is ${state.toString().substring(15)}',
style: Theme.of(context).primaryTextTheme.subhead,
),
trailing: new Icon(
Icons.error,
color: Theme.of(context).primaryTextTheme.subhead.color,
),
),
);
}
_buildDeviceStateTile() {
return new ListTile(
leading: (deviceState == BluetoothDeviceState.connected)
? const Icon(Icons.bluetooth_connected)
: const Icon(Icons.bluetooth_disabled),
title: new Text('Device is ${deviceState.toString().split('.')[1]}.'),
subtitle: new Text('${device.id}'),
trailing: new IconButton(
icon: const Icon(Icons.refresh),
onPressed: () => _refreshDeviceState(device),
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
));
}
_buildProgressBarTile() {
return new LinearProgressIndicator();
}
@override
Widget build(BuildContext context) {
var tiles = new List<Widget>();
if (state != BluetoothState.on) {
tiles.add(_buildAlertTile());
}
if (isConnected) {
tiles.add(_buildDeviceStateTile());
tiles.addAll(_buildServiceTiles());
} else {
tiles.addAll(_buildScanResultTiles());
}
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('FlutterBlue'),
actions: _buildActionButtons(),
),
floatingActionButton: _buildScanningButton(),
body: new Stack(
children: <Widget>[
(isScanning) ? _buildProgressBarTile() : new Container(),
new ListView(
children: tiles,
)
],
),
),
);
}
}
+280
View File
@@ -0,0 +1,280 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);
final ScanResult result;
final VoidCallback onTap;
Widget _buildTitle(BuildContext context) {
if (result.device.name.length > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(result.device.name),
Text(
result.device.id.toString(),
style: Theme.of(context).textTheme.caption,
)
],
);
} else {
return Text(result.device.id.toString());
}
}
Widget _buildAdvRow(BuildContext context, String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title, style: Theme.of(context).textTheme.caption),
SizedBox(
width: 12.0,
),
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.caption
.apply(color: Colors.black),
softWrap: true,
),
),
],
),
);
}
String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
}
String getNiceManufacturerData(Map<int, List<int>> data) {
if (data.isEmpty) {
return null;
}
List<String> res = [];
data.forEach((id, bytes) {
res.add(
'${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
});
return res.join(', ');
}
String getNiceServiceData(Map<String, List<int>> data) {
if (data.isEmpty) {
return null;
}
List<String> res = [];
data.forEach((id, bytes) {
res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
});
return res.join(', ');
}
@override
Widget build(BuildContext context) {
return ExpansionTile(
title: _buildTitle(context),
leading: Text(result.rssi.toString()),
trailing: RaisedButton(
child: Text('CONNECT'),
color: Colors.black,
textColor: Colors.white,
onPressed: (result.advertisementData.connectable) ? onTap : null,
),
children: <Widget>[
_buildAdvRow(
context, 'Complete Local Name', result.advertisementData.localName),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(
context,
'Manufacturer Data',
getNiceManufacturerData(
result.advertisementData.manufacturerData) ??
'N/A'),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)
? result.advertisementData.serviceUuids.join(', ').toUpperCase()
: 'N/A'),
_buildAdvRow(context, 'Service Data',
getNiceServiceData(result.advertisementData.serviceData) ?? 'N/A'),
],
);
}
}
class ServiceTile extends StatelessWidget {
final BluetoothService service;
final List<CharacteristicTile> characteristicTiles;
const ServiceTile({Key key, this.service, this.characteristicTiles})
: super(key: key);
@override
Widget build(BuildContext context) {
if (characteristicTiles.length > 0) {
return new ExpansionTile(
title: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Service'),
new Text(
'0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
children: characteristicTiles,
);
} else {
return new ListTile(
title: const Text('Service'),
subtitle: new Text(
'0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
);
}
}
}
class CharacteristicTile extends StatelessWidget {
final BluetoothCharacteristic characteristic;
final List<DescriptorTile> descriptorTiles;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
final VoidCallback onNotificationPressed;
const CharacteristicTile(
{Key key,
this.characteristic,
this.descriptorTiles,
this.onReadPressed,
this.onWritePressed,
this.onNotificationPressed})
: super(key: key);
@override
Widget build(BuildContext context) {
var actions = new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new IconButton(
icon: new Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onReadPressed,
),
new IconButton(
icon: new Icon(Icons.file_upload,
color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
onPressed: onWritePressed,
),
new IconButton(
icon: new Icon(
characteristic.isNotifying ? Icons.sync_disabled : Icons.sync,
color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
onPressed: onNotificationPressed,
)
],
);
var title = new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Characteristic'),
new Text(
'0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
);
if (descriptorTiles.length > 0) {
return new ExpansionTile(
title: new ListTile(
title: title,
subtitle: new Text(characteristic.value.toString()),
contentPadding: EdgeInsets.all(0.0),
),
trailing: actions,
children: descriptorTiles,
);
} else {
return new ListTile(
title: title,
subtitle: new Text(characteristic.value.toString()),
trailing: actions,
);
}
}
}
class DescriptorTile extends StatelessWidget {
final BluetoothDescriptor descriptor;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
const DescriptorTile(
{Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
: super(key: key);
@override
Widget build(BuildContext context) {
var title = new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text('Descriptor'),
new Text(
'0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
);
return new ListTile(
title: title,
subtitle: new Text(descriptor.value.toString()),
trailing: new Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new IconButton(
icon: new Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onReadPressed,
),
new IconButton(
icon: new Icon(
Icons.file_upload,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onWritePressed,
)
],
),
);
}
}
+20
View File
@@ -0,0 +1,20 @@
name: flutter_blue_example
description: Demonstrates how to use the flutter_blue plugin.
publish_to: 'none'
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter_blue:
path: ../
flutter:
uses-material-design: true
@@ -0,0 +1,14 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('First test', (WidgetTester tester) async {
// TODO: Add tests
});
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" />
</component>
</module>
@@ -0,0 +1,15 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#import <Flutter/Flutter.h>
#import <CoreBluetooth/CoreBluetooth.h>
#define NAMESPACE @"plugins.pauldemarco.com/flutter_blue"
@interface FlutterBluePlugin : NSObject<FlutterPlugin, CBCentralManagerDelegate, CBPeripheralDelegate>
@end
@interface FlutterBlueStreamHandler : NSObject<FlutterStreamHandler>
@property FlutterEventSink sink;
@end
@@ -0,0 +1,753 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#import "FlutterBluePlugin.h"
#import "Flutterblue.pbobjc.h"
@interface CBUUID (CBUUIDAdditionsFlutterBlue)
- (NSString *)fullUUIDString;
@end
@implementation CBUUID (CBUUIDAdditionsFlutterBlue)
- (NSString *)fullUUIDString {
if(self.UUIDString.length == 4) {
return [[NSString stringWithFormat:@"0000%@-0000-1000-8000-00805F9B34FB", self.UUIDString] lowercaseString];
}
return [self.UUIDString lowercaseString];
}
@end
typedef NS_ENUM(NSUInteger, LogLevel) {
emergency = 0,
alert = 1,
critical = 2,
error = 3,
warning = 4,
notice = 5,
info = 6,
debug = 7
};
@interface FlutterBluePlugin ()
@property(nonatomic, retain) NSObject<FlutterPluginRegistrar> *registrar;
@property(nonatomic, retain) FlutterMethodChannel *channel;
@property(nonatomic, retain) FlutterBlueStreamHandler *stateStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *scanResultStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *servicesDiscoveredStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *characteristicReadStreamHandler;
@property(nonatomic, retain) FlutterBlueStreamHandler *descriptorReadStreamHandler;
@property(nonatomic, retain) CBCentralManager *centralManager;
@property(nonatomic) NSMutableDictionary *scannedPeripherals;
@property(nonatomic) NSMutableArray *servicesThatNeedDiscovered;
@property(nonatomic) NSMutableArray *characteristicsThatNeedDiscovered;
@property(nonatomic) LogLevel logLevel;
@end
@implementation FlutterBluePlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:NAMESPACE @"/methods"
binaryMessenger:[registrar messenger]];
FlutterEventChannel* stateChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/state" binaryMessenger:[registrar messenger]];
FlutterEventChannel* scanResultChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/scanResult" binaryMessenger:[registrar messenger]];
FlutterEventChannel* servicesDiscoveredChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/servicesDiscovered" binaryMessenger:[registrar messenger]];
FlutterEventChannel* characteristicReadChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/characteristicRead" binaryMessenger:[registrar messenger]];
FlutterEventChannel* descriptorReadChannel = [FlutterEventChannel eventChannelWithName:NAMESPACE @"/descriptorRead" binaryMessenger:[registrar messenger]];
FlutterBluePlugin* instance = [[FlutterBluePlugin alloc] init];
instance.channel = channel;
instance.centralManager = [[CBCentralManager alloc] initWithDelegate:instance queue:nil];
instance.scannedPeripherals = [NSMutableDictionary new];
instance.servicesThatNeedDiscovered = [NSMutableArray new];
instance.characteristicsThatNeedDiscovered = [NSMutableArray new];
instance.logLevel = emergency;
// STATE
FlutterBlueStreamHandler* stateStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[stateChannel setStreamHandler:stateStreamHandler];
instance.stateStreamHandler = stateStreamHandler;
// SCAN RESULTS
FlutterBlueStreamHandler* scanResultStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[scanResultChannel setStreamHandler:scanResultStreamHandler];
instance.scanResultStreamHandler = scanResultStreamHandler;
// SERVICES DISCOVERED
FlutterBlueStreamHandler* servicesDiscoveredStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[servicesDiscoveredChannel setStreamHandler:servicesDiscoveredStreamHandler];
instance.servicesDiscoveredStreamHandler = servicesDiscoveredStreamHandler;
// CHARACTERISTIC READ
FlutterBlueStreamHandler* characteristicReadStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[characteristicReadChannel setStreamHandler:characteristicReadStreamHandler];
instance.characteristicReadStreamHandler = characteristicReadStreamHandler;
// DESCRIPTOR READ
FlutterBlueStreamHandler* descriptorReadStreamHandler = [[FlutterBlueStreamHandler alloc] init];
[descriptorReadChannel setStreamHandler:descriptorReadStreamHandler];
instance.descriptorReadStreamHandler = descriptorReadStreamHandler;
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"setLogLevel" isEqualToString:call.method]) {
NSNumber *logLevelIndex = [call arguments];
_logLevel = (LogLevel)[logLevelIndex integerValue];
result(nil);
} else if ([@"state" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [self toFlutterData:[self toBluetoothStateProto:self->_centralManager.state]];
result(data);
} else if([@"isAvailable" isEqualToString:call.method]) {
if(self.centralManager.state != CBManagerStateUnsupported && self.centralManager.state != CBManagerStateUnknown) {
result(@(YES));
} else {
result(@(NO));
}
} else if([@"isOn" isEqualToString:call.method]) {
if(self.centralManager.state == CBManagerStatePoweredOn) {
result(@(YES));
} else {
result(@(NO));
}
} else if([@"startScan" isEqualToString:call.method]) {
// Clear any existing scan results
[self.scannedPeripherals removeAllObjects];
// TODO: Request Permission?
FlutterStandardTypedData *data = [call arguments];
ProtosScanSettings *request = [[ProtosScanSettings alloc] initWithData:[data data] error:nil];
// UUID Service filter
NSArray *uuids = [NSArray array];
for (int i = 0; i < [request serviceUuidsArray_Count]; i++) {
NSString *u = [request.serviceUuidsArray objectAtIndex:i];
uuids = [uuids arrayByAddingObject:[CBUUID UUIDWithString:u]];
}
// TODO: iOS Scan Options (#35)
[self->_centralManager scanForPeripheralsWithServices:uuids options:nil];
result(nil);
} else if([@"stopScan" isEqualToString:call.method]) {
[self->_centralManager stopScan];
result(nil);
} else if([@"connect" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosConnectRequest *request = [[ProtosConnectRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
CBPeripheral *peripheral = [_scannedPeripherals objectForKey:remoteId];
if(peripheral == nil) {
@throw [FlutterError errorWithCode:@"connect"
message:@"Peripheral not found"
details:nil];
}
// TODO: Implement Connect options (#36)
[_centralManager connectPeripheral:peripheral options:nil];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"disconnect" isEqualToString:call.method]) {
NSString *remoteId = [call arguments];
@try {
CBPeripheral *peripheral = [self findPeripheral:remoteId];
[_centralManager cancelPeripheralConnection:peripheral];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"deviceState" isEqualToString:call.method]) {
NSString *remoteId = [call arguments];
@try {
CBPeripheral *peripheral = [self findPeripheral:remoteId];
result([self toFlutterData:[self toDeviceStateProto:peripheral state:peripheral.state]]);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"discoverServices" isEqualToString:call.method]) {
NSString *remoteId = [call arguments];
@try {
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Clear helper arrays
[_servicesThatNeedDiscovered removeAllObjects];
[_characteristicsThatNeedDiscovered removeAllObjects ];
[peripheral discoverServices:nil];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"services" isEqualToString:call.method]) {
NSString *remoteId = [call arguments];
@try {
CBPeripheral *peripheral = [self findPeripheral:remoteId];
result([self toFlutterData:[self toServicesResultProto:peripheral]]);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"readCharacteristic" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosReadCharacteristicRequest *request = [[ProtosReadCharacteristicRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
// Find peripheral
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Find characteristic
CBCharacteristic *characteristic = [self locateCharacteristic:[request characteristicUuid] peripheral:peripheral serviceId:[request serviceUuid] secondaryServiceId:[request secondaryServiceUuid]];
// Trigger a read
[peripheral readValueForCharacteristic:characteristic];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"readDescriptor" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosReadDescriptorRequest *request = [[ProtosReadDescriptorRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
// Find peripheral
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Find characteristic
CBCharacteristic *characteristic = [self locateCharacteristic:[request characteristicUuid] peripheral:peripheral serviceId:[request serviceUuid] secondaryServiceId:[request secondaryServiceUuid]];
// Find descriptor
CBDescriptor *descriptor = [self locateDescriptor:[request descriptorUuid] characteristic:characteristic];
[peripheral readValueForDescriptor:descriptor];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"writeCharacteristic" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosWriteCharacteristicRequest *request = [[ProtosWriteCharacteristicRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
// Find peripheral
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Find characteristic
CBCharacteristic *characteristic = [self locateCharacteristic:[request characteristicUuid] peripheral:peripheral serviceId:[request serviceUuid] secondaryServiceId:[request secondaryServiceUuid]];
// Get correct write type
CBCharacteristicWriteType type = ([request writeType] == ProtosWriteCharacteristicRequest_WriteType_WithoutResponse) ? CBCharacteristicWriteWithoutResponse : CBCharacteristicWriteWithResponse;
// Write to characteristic
[peripheral writeValue:[request value] forCharacteristic:characteristic type:type];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"writeDescriptor" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosWriteDescriptorRequest *request = [[ProtosWriteDescriptorRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
// Find peripheral
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Find characteristic
CBCharacteristic *characteristic = [self locateCharacteristic:[request characteristicUuid] peripheral:peripheral serviceId:[request serviceUuid] secondaryServiceId:[request secondaryServiceUuid]];
// Find descriptor
CBDescriptor *descriptor = [self locateDescriptor:[request descriptorUuid] characteristic:characteristic];
// Write descriptor
[peripheral writeValue:[request value] forDescriptor:descriptor];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else if([@"setNotification" isEqualToString:call.method]) {
FlutterStandardTypedData *data = [call arguments];
ProtosSetNotificationRequest *request = [[ProtosSetNotificationRequest alloc] initWithData:[data data] error:nil];
NSString *remoteId = [request remoteId];
@try {
// Find peripheral
CBPeripheral *peripheral = [self findPeripheral:remoteId];
// Find characteristic
CBCharacteristic *characteristic = [self locateCharacteristic:[request characteristicUuid] peripheral:peripheral serviceId:[request serviceUuid] secondaryServiceId:[request secondaryServiceUuid]];
// Set notification value
[peripheral setNotifyValue:[request enable] forCharacteristic:characteristic];
result(nil);
} @catch(FlutterError *e) {
result(e);
}
} else {
result(FlutterMethodNotImplemented);
}
}
- (CBPeripheral*)findPeripheral:(NSString*)remoteId {
NSArray<CBPeripheral*> *peripherals = [_centralManager retrievePeripheralsWithIdentifiers:@[[[NSUUID alloc] initWithUUIDString:remoteId]]];
CBPeripheral *peripheral;
for(CBPeripheral *p in peripherals) {
if([[p.identifier UUIDString] isEqualToString:remoteId]) {
peripheral = p;
break;
}
}
if(peripheral == nil) {
@throw [FlutterError errorWithCode:@"findPeripheral"
message:@"Peripheral not found"
details:nil];
}
return peripheral;
}
- (CBCharacteristic*)locateCharacteristic:(NSString*)characteristicId peripheral:(CBPeripheral*)peripheral serviceId:(NSString*)serviceId secondaryServiceId:(NSString*)secondaryServiceId {
CBService *primaryService = [self getServiceFromArray:serviceId array:[peripheral services]];
if(primaryService == nil || [primaryService isPrimary] == false) {
@throw [FlutterError errorWithCode:@"locateCharacteristic"
message:@"service could not be located on the device"
details:nil];
}
CBService *secondaryService;
if(secondaryServiceId.length) {
secondaryService = [self getServiceFromArray:secondaryServiceId array:[primaryService includedServices]];
@throw [FlutterError errorWithCode:@"locateCharacteristic"
message:@"secondary service could not be located on the device"
details:secondaryServiceId];
}
CBService *service = (secondaryService != nil) ? secondaryService : primaryService;
CBCharacteristic *characteristic = [self getCharacteristicFromArray:characteristicId array:[service characteristics]];
if(characteristic == nil) {
@throw [FlutterError errorWithCode:@"locateCharacteristic"
message:@"characteristic could not be located on the device"
details:nil];
}
return characteristic;
}
- (CBDescriptor*)locateDescriptor:(NSString*)descriptorId characteristic:(CBCharacteristic*)characteristic {
CBDescriptor *descriptor = [self getDescriptorFromArray:descriptorId array:[characteristic descriptors]];
if(descriptor == nil) {
@throw [FlutterError errorWithCode:@"locateDescriptor"
message:@"descriptor could not be located on the device"
details:nil];
}
return descriptor;
}
// Reverse search to find primary service
- (CBService*)findPrimaryService:(CBService*)secondaryService peripheral:(CBPeripheral*)peripheral {
for(CBService *s in [peripheral services]) {
for(CBService *ss in [s includedServices]) {
if([[ss.UUID UUIDString] isEqualToString:[secondaryService.UUID UUIDString]]) {
return s;
}
}
}
return nil;
}
- (CBDescriptor*)findCCCDescriptor:(CBCharacteristic*)characteristic {
for(CBDescriptor *d in characteristic.descriptors) {
if([d.UUID.UUIDString isEqualToString:@"2902"]) {
return d;
}
}
return nil;
}
- (CBService*)getServiceFromArray:(NSString*)uuidString array:(NSArray<CBService*>*)array {
for(CBService *s in array) {
if([[s UUID] isEqual:[CBUUID UUIDWithString:uuidString]]) {
return s;
}
}
return nil;
}
- (CBCharacteristic*)getCharacteristicFromArray:(NSString*)uuidString array:(NSArray<CBCharacteristic*>*)array {
for(CBCharacteristic *c in array) {
if([[c UUID] isEqual:[CBUUID UUIDWithString:uuidString]]) {
return c;
}
}
return nil;
}
- (CBDescriptor*)getDescriptorFromArray:(NSString*)uuidString array:(NSArray<CBDescriptor*>*)array {
for(CBDescriptor *d in array) {
if([[d UUID] isEqual:[CBUUID UUIDWithString:uuidString]]) {
return d;
}
}
return nil;
}
//
// CBCentralManagerDelegate methods
//
- (void)centralManagerDidUpdateState:(nonnull CBCentralManager *)central {
if(_stateStreamHandler.sink != nil) {
FlutterStandardTypedData *data = [self toFlutterData:[self toBluetoothStateProto:self->_centralManager.state]];
self.stateStreamHandler.sink(data);
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
[self.scannedPeripherals setObject:peripheral
forKey:[[peripheral identifier] UUIDString]];
if(_scanResultStreamHandler.sink != nil) {
FlutterStandardTypedData *data = [self toFlutterData:[self toScanResultProto:peripheral advertisementData:advertisementData RSSI:RSSI]];
_scanResultStreamHandler.sink(data);
}
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(@"didConnectPeripheral");
// Register self as delegate for peripheral
peripheral.delegate = self;
// Send connection state
[_channel invokeMethod:@"DeviceState" arguments:[self toFlutterData:[self toDeviceStateProto:peripheral state:peripheral.state]]];
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"didDisconnectPeripheral");
// Unregister self as delegate for peripheral, not working #42
peripheral.delegate = nil;
// Send connection state
[_channel invokeMethod:@"DeviceState" arguments:[self toFlutterData:[self toDeviceStateProto:peripheral state:peripheral.state]]];
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
// TODO:?
}
//
// CBPeripheralDelegate methods
//
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
NSLog(@"didDiscoverServices");
// Loop through and discover characteristics and secondary services
[_servicesThatNeedDiscovered addObjectsFromArray:peripheral.services];
for(CBService *s in [peripheral services]) {
NSLog(@"Found service: %@", [s.UUID UUIDString]);
[peripheral discoverCharacteristics:nil forService:s];
// [peripheral discoverIncludedServices:nil forService:s]; // Secondary services in the future (#8)
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
NSLog(@"didDiscoverCharacteristicsForService");
// Loop through and discover descriptors for characteristics
[_servicesThatNeedDiscovered removeObject:service];
[_characteristicsThatNeedDiscovered addObjectsFromArray:service.characteristics];
for(CBCharacteristic *c in [service characteristics]) {
[peripheral discoverDescriptorsForCharacteristic:c];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didDiscoverDescriptorsForCharacteristic");
[_characteristicsThatNeedDiscovered removeObject:characteristic];
if(_servicesThatNeedDiscovered.count > 0 || _characteristicsThatNeedDiscovered.count > 0) {
// Still discovering
return;
}
// Send updated tree
if(_servicesDiscoveredStreamHandler.sink != nil) {
ProtosDiscoverServicesResult *result = [self toServicesResultProto:peripheral];
_servicesDiscoveredStreamHandler.sink([self toFlutterData:result]);
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(CBService *)service error:(NSError *)error {
NSLog(@"didDiscoverIncludedServicesForService");
// Loop through and discover characteristics for secondary services
for(CBService *ss in [service includedServices]) {
[peripheral discoverCharacteristics:nil forService:ss];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didUpdateValueForCharacteristic %@", [peripheral.identifier UUIDString]);
if(_characteristicReadStreamHandler.sink != nil) {
ProtosReadCharacteristicResponse *result = [[ProtosReadCharacteristicResponse alloc] init];
[result setRemoteId:[peripheral.identifier UUIDString]];
[result setCharacteristic:[self toCharacteristicProto:characteristic]];
_characteristicReadStreamHandler.sink([self toFlutterData:result]);
}
// on iOS, this method also handle notification values
ProtosOnNotificationResponse *result = [[ProtosOnNotificationResponse alloc] init];
[result setRemoteId:[peripheral.identifier UUIDString]];
[result setCharacteristic:[self toCharacteristicProto:characteristic]];
[_channel invokeMethod:@"OnValueChanged" arguments:[self toFlutterData:result]];
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didWriteValueForCharacteristic");
ProtosWriteCharacteristicRequest *request = [[ProtosWriteCharacteristicRequest alloc] init];
[request setRemoteId:[peripheral.identifier UUIDString]];
[request setCharacteristicUuid:[characteristic.UUID fullUUIDString]];
[request setServiceUuid:[characteristic.service.UUID fullUUIDString]];
ProtosWriteCharacteristicResponse *result = [[ProtosWriteCharacteristicResponse alloc] init];
[result setRequest:request];
[result setSuccess:(error == nil)];
[_channel invokeMethod:@"WriteCharacteristicResponse" arguments:[self toFlutterData:result]];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@"didUpdateNotificationStateForCharacteristic");
// Read CCC descriptor of characteristic
CBDescriptor *cccd = [self findCCCDescriptor:characteristic];
if(cccd == nil || error != nil) {
// Send error
ProtosSetNotificationResponse *response = [[ProtosSetNotificationResponse alloc] init];
[response setRemoteId:[peripheral.identifier UUIDString]];
[response setCharacteristic:[self toCharacteristicProto:characteristic]];
[response setSuccess:false];
[_channel invokeMethod:@"SetNotificationResponse" arguments:[self toFlutterData:response]];
return;
}
// Request a read
[peripheral readValueForDescriptor:cccd];
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error {
if(_descriptorReadStreamHandler.sink != nil) {
ProtosReadDescriptorRequest *q = [[ProtosReadDescriptorRequest alloc] init];
[q setRemoteId:[peripheral.identifier UUIDString]];
[q setCharacteristicUuid:[descriptor.characteristic.UUID fullUUIDString]];
[q setDescriptorUuid:[descriptor.UUID fullUUIDString]];
if([descriptor.characteristic.service isPrimary]) {
[q setServiceUuid:[descriptor.characteristic.service.UUID fullUUIDString]];
} else {
[q setSecondaryServiceUuid:[descriptor.characteristic.service.UUID fullUUIDString]];
CBService *primaryService = [self findPrimaryService:[descriptor.characteristic service] peripheral:[descriptor.characteristic.service peripheral]];
[q setServiceUuid:[primaryService.UUID fullUUIDString]];
}
ProtosReadDescriptorResponse *result = [[ProtosReadDescriptorResponse alloc] init];
[result setRequest:q];
int value = [descriptor.value intValue];
[result setValue:[NSData dataWithBytes:&value length:sizeof(value)]];
_descriptorReadStreamHandler.sink([self toFlutterData:result]);
}
// If descriptor is CCCD, send a SetNotificationResponse in case anything is awaiting
if([descriptor.UUID.UUIDString isEqualToString:@"2902"]){
ProtosSetNotificationResponse *response = [[ProtosSetNotificationResponse alloc] init];
[response setRemoteId:[peripheral.identifier UUIDString]];
[response setCharacteristic:[self toCharacteristicProto:descriptor.characteristic]];
[response setSuccess:true];
[_channel invokeMethod:@"SetNotificationResponse" arguments:[self toFlutterData:response]];
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error {
ProtosWriteDescriptorRequest *request = [[ProtosWriteDescriptorRequest alloc] init];
[request setRemoteId:[peripheral.identifier UUIDString]];
[request setCharacteristicUuid:[descriptor.characteristic.UUID fullUUIDString]];
[request setDescriptorUuid:[descriptor.UUID fullUUIDString]];
if([descriptor.characteristic.service isPrimary]) {
[request setServiceUuid:[descriptor.characteristic.service.UUID fullUUIDString]];
} else {
[request setSecondaryServiceUuid:[descriptor.characteristic.service.UUID fullUUIDString]];
CBService *primaryService = [self findPrimaryService:[descriptor.characteristic service] peripheral:[descriptor.characteristic.service peripheral]];
[request setServiceUuid:[primaryService.UUID fullUUIDString]];
}
ProtosWriteDescriptorResponse *result = [[ProtosWriteDescriptorResponse alloc] init];
[result setRequest:request];
[result setSuccess:(error == nil)];
[_channel invokeMethod:@"WriteDescriptorResponse" arguments:[self toFlutterData:result]];
}
//
// Proto Helper methods
//
- (FlutterStandardTypedData*)toFlutterData:(GPBMessage*)proto {
FlutterStandardTypedData *data = [FlutterStandardTypedData typedDataWithBytes:[[proto data] copy]];
return data;
}
- (ProtosBluetoothState*)toBluetoothStateProto:(CBManagerState)state {
ProtosBluetoothState *result = [[ProtosBluetoothState alloc] init];
switch(state) {
case CBManagerStateResetting:
[result setState:ProtosBluetoothState_State_TurningOn];
break;
case CBManagerStateUnsupported:
[result setState:ProtosBluetoothState_State_Unavailable];
break;
case CBManagerStateUnauthorized:
[result setState:ProtosBluetoothState_State_Unauthorized];
break;
case CBManagerStatePoweredOff:
[result setState:ProtosBluetoothState_State_Off];
break;
case CBManagerStatePoweredOn:
[result setState:ProtosBluetoothState_State_On];
break;
default:
[result setState:ProtosBluetoothState_State_Unknown];
break;
}
return result;
}
- (ProtosScanResult*)toScanResultProto:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
ProtosScanResult *result = [[ProtosScanResult alloc] init];
[result setDevice:[self toDeviceProto:peripheral]];
[result setRssi:[RSSI intValue]];
ProtosAdvertisementData *ads = [[ProtosAdvertisementData alloc] init];
[ads setConnectable:[advertisementData[CBAdvertisementDataIsConnectable] boolValue]];
[ads setLocalName:advertisementData[CBAdvertisementDataLocalNameKey]];
// Tx Power Level
NSNumber *txPower = advertisementData[CBAdvertisementDataTxPowerLevelKey];
if(txPower != nil) {
ProtosInt32Value *txPowerWrapper = [[ProtosInt32Value alloc] init];
[txPowerWrapper setValue:[txPower intValue]];
[ads setTxPowerLevel:txPowerWrapper];
}
// Manufacturer Specific Data
NSData *manufData = advertisementData[CBAdvertisementDataManufacturerDataKey];
if(manufData.length > 2) {
unsigned short manufacturerId;
[manufData getBytes:&manufacturerId length:2];
[[ads manufacturerData] setObject:[manufData subdataWithRange:NSMakeRange(2, manufData.length - 2)] forKey:manufacturerId];
}
// Service Data
NSDictionary *serviceData = advertisementData[CBAdvertisementDataServiceDataKey];
for (CBUUID *uuid in serviceData) {
[[ads serviceData] setObject:serviceData[uuid] forKey:uuid.UUIDString];
}
// Service Uuids
NSArray *serviceUuids = advertisementData[CBAdvertisementDataServiceUUIDsKey];
for (CBUUID *uuid in serviceUuids) {
[[ads serviceUuidsArray] addObject:uuid.UUIDString];
}
[result setAdvertisementData:ads];
return result;
}
- (ProtosBluetoothDevice*)toDeviceProto:(CBPeripheral *)peripheral {
ProtosBluetoothDevice *result = [[ProtosBluetoothDevice alloc] init];
[result setName:[peripheral name]];
[result setRemoteId:[[peripheral identifier] UUIDString]];
[result setType:ProtosBluetoothDevice_Type_Le]; // TODO: Does iOS differentiate?
return result;
}
- (ProtosDeviceStateResponse*)toDeviceStateProto:(CBPeripheral *)peripheral state:(CBPeripheralState)state {
ProtosDeviceStateResponse *result = [[ProtosDeviceStateResponse alloc] init];
switch(state) {
case CBPeripheralStateDisconnected:
[result setState:ProtosDeviceStateResponse_BluetoothDeviceState_Disconnected];
break;
case CBPeripheralStateConnecting:
[result setState:ProtosDeviceStateResponse_BluetoothDeviceState_Connecting];
break;
case CBPeripheralStateConnected:
[result setState:ProtosDeviceStateResponse_BluetoothDeviceState_Connected];
break;
case CBPeripheralStateDisconnecting:
[result setState:ProtosDeviceStateResponse_BluetoothDeviceState_Disconnecting];
break;
}
[result setRemoteId:[[peripheral identifier] UUIDString]];
return result;
}
- (ProtosDiscoverServicesResult*)toServicesResultProto:(CBPeripheral *)peripheral {
ProtosDiscoverServicesResult *result = [[ProtosDiscoverServicesResult alloc] init];
[result setRemoteId:[peripheral.identifier UUIDString]];
NSMutableArray *servicesProtos = [NSMutableArray new];
for(CBService *s in [peripheral services]) {
[servicesProtos addObject:[self toServiceProto:peripheral service:s]];
}
[result setServicesArray:servicesProtos];
return result;
}
- (ProtosBluetoothService*)toServiceProto:(CBPeripheral *)peripheral service:(CBService *)service {
ProtosBluetoothService *result = [[ProtosBluetoothService alloc] init];
NSLog(@"peripheral uuid:%@", [peripheral.identifier UUIDString]);
NSLog(@"service uuid:%@", [service.UUID fullUUIDString]);
[result setRemoteId:[peripheral.identifier UUIDString]];
[result setUuid:[service.UUID fullUUIDString]];
[result setIsPrimary:[service isPrimary]];
// Characteristic Array
NSMutableArray *characteristicProtos = [NSMutableArray new];
for(CBCharacteristic *c in [service characteristics]) {
[characteristicProtos addObject:[self toCharacteristicProto:c]];
}
[result setCharacteristicsArray:characteristicProtos];
// Included Services Array
NSMutableArray *includedServicesProtos = [NSMutableArray new];
for(CBService *s in [service includedServices]) {
[includedServicesProtos addObject:[self toServiceProto:peripheral service:s]];
}
[result setIncludedServicesArray:includedServicesProtos];
return result;
}
- (ProtosBluetoothCharacteristic*)toCharacteristicProto:(CBCharacteristic *)characteristic {
ProtosBluetoothCharacteristic *result = [[ProtosBluetoothCharacteristic alloc] init];
[result setUuid:[characteristic.UUID fullUUIDString]];
[result setProperties:[self toCharacteristicPropsProto:characteristic.properties]];
[result setValue:[characteristic value]];
NSLog(@"uuid: %@ value: %@", [characteristic.UUID fullUUIDString], [characteristic value]);
NSMutableArray *descriptorProtos = [NSMutableArray new];
for(CBDescriptor *d in [characteristic descriptors]) {
[descriptorProtos addObject:[self toDescriptorProto:d]];
}
[result setDescriptorsArray:descriptorProtos];
if([characteristic.service isPrimary]) {
[result setServiceUuid:[characteristic.service.UUID fullUUIDString]];
} else {
// Reverse search to find service and secondary service UUID
[result setSecondaryServiceUuid:[characteristic.service.UUID fullUUIDString]];
CBService *primaryService = [self findPrimaryService:[characteristic service] peripheral:[characteristic.service peripheral]];
[result setServiceUuid:[primaryService.UUID fullUUIDString]];
}
return result;
}
- (ProtosBluetoothDescriptor*)toDescriptorProto:(CBDescriptor *)descriptor {
ProtosBluetoothDescriptor *result = [[ProtosBluetoothDescriptor alloc] init];
[result setUuid:[descriptor.UUID fullUUIDString]];
[result setCharacteristicUuid:[descriptor.characteristic.UUID fullUUIDString]];
[result setServiceUuid:[descriptor.characteristic.service.UUID fullUUIDString]];
int value = [descriptor.value intValue];
[result setValue:[NSData dataWithBytes:&value length:sizeof(value)]];
return result;
}
- (ProtosCharacteristicProperties*)toCharacteristicPropsProto:(CBCharacteristicProperties)props {
ProtosCharacteristicProperties *result = [[ProtosCharacteristicProperties alloc] init];
[result setBroadcast:(props & CBCharacteristicPropertyBroadcast) != 0];
[result setRead:(props & CBCharacteristicPropertyRead) != 0];
[result setWriteWithoutResponse:(props & CBCharacteristicPropertyWriteWithoutResponse) != 0];
[result setWrite:(props & CBCharacteristicPropertyWrite) != 0];
[result setNotify:(props & CBCharacteristicPropertyNotify) != 0];
[result setIndicate:(props & CBCharacteristicPropertyIndicate) != 0];
[result setAuthenticatedSignedWrites:(props & CBCharacteristicPropertyAuthenticatedSignedWrites) != 0];
[result setExtendedProperties:(props & CBCharacteristicPropertyExtendedProperties) != 0];
[result setNotifyEncryptionRequired:(props & CBCharacteristicPropertyNotifyEncryptionRequired) != 0];
[result setIndicateEncryptionRequired:(props & CBCharacteristicPropertyIndicateEncryptionRequired) != 0];
return result;
}
- (void)log:(LogLevel)level format:(NSString *)format, ... {
if(level <= _logLevel) {
va_list args;
va_start(args, format);
// NSString* formattedMessage = [[NSString alloc] initWithFormat:format arguments:args];
NSLog(format, args);
va_end(args);
}
}
@end
@implementation FlutterBlueStreamHandler
- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
self.sink = eventSink;
return nil;
}
- (FlutterError*)onCancelWithArguments:(id)arguments {
self.sink = nil;
return nil;
}
@end
@@ -0,0 +1,46 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'flutter_blue'
s.version = '0.0.1'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
A new flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.dependency '!ProtoCompiler'
s.framework = 'CoreBluetooth'
protoc = ENV['PWD'] + '/Pods/!ProtoCompiler/protoc'
objc_out = 'gen'
proto_in = '../protos'
s.prepare_command = <<-CMD
mkdir -p #{objc_out}
#{protoc} \
--objc_out=#{objc_out} \
--proto_path=#{proto_in} \
#{proto_in}/*.proto
CMD
s.subspec 'Protos' do |ss|
ss.source_files = 'gen/**/*.pbobjc.{h,m}'
ss.header_mappings_dir = 'gen'
ss.requires_arc = false
ss.dependency 'Protobuf'
end
s.pod_target_xcconfig = {
# This is needed by all pods that depend on Protobuf:
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
}
s.ios.deployment_target = '8.0'
end
@@ -0,0 +1,733 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: flutterblue.proto
// This CPP symbol can be defined to use imports that match up to the framework
// imports needed when using CocoaPods.
#if !defined(GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS)
#define GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS 0
#endif
#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
#import <Protobuf/GPBProtocolBuffers.h>
#else
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CF_EXTERN_C_BEGIN
@class ProtosAdvertisementData;
@class ProtosBluetoothCharacteristic;
@class ProtosBluetoothDescriptor;
@class ProtosBluetoothDevice;
@class ProtosBluetoothService;
@class ProtosCharacteristicProperties;
@class ProtosInt32Value;
@class ProtosReadDescriptorRequest;
@class ProtosWriteCharacteristicRequest;
@class ProtosWriteDescriptorRequest;
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Enum ProtosBluetoothState_State
typedef GPB_ENUM(ProtosBluetoothState_State) {
/**
* Value used if any message's field encounters a value that is not defined
* by this enum. The message will also have C functions to get/set the rawValue
* of the field.
**/
ProtosBluetoothState_State_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
ProtosBluetoothState_State_Unknown = 0,
ProtosBluetoothState_State_Unavailable = 1,
ProtosBluetoothState_State_Unauthorized = 2,
ProtosBluetoothState_State_TurningOn = 3,
ProtosBluetoothState_State_On = 4,
ProtosBluetoothState_State_TurningOff = 5,
ProtosBluetoothState_State_Off = 6,
};
GPBEnumDescriptor *ProtosBluetoothState_State_EnumDescriptor(void);
/**
* Checks to see if the given value is defined by the enum or was not known at
* the time this source was generated.
**/
BOOL ProtosBluetoothState_State_IsValidValue(int32_t value);
#pragma mark - Enum ProtosBluetoothDevice_Type
typedef GPB_ENUM(ProtosBluetoothDevice_Type) {
/**
* Value used if any message's field encounters a value that is not defined
* by this enum. The message will also have C functions to get/set the rawValue
* of the field.
**/
ProtosBluetoothDevice_Type_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
ProtosBluetoothDevice_Type_Unknown = 0,
ProtosBluetoothDevice_Type_Classic = 1,
ProtosBluetoothDevice_Type_Le = 2,
ProtosBluetoothDevice_Type_Dual = 3,
};
GPBEnumDescriptor *ProtosBluetoothDevice_Type_EnumDescriptor(void);
/**
* Checks to see if the given value is defined by the enum or was not known at
* the time this source was generated.
**/
BOOL ProtosBluetoothDevice_Type_IsValidValue(int32_t value);
#pragma mark - Enum ProtosWriteCharacteristicRequest_WriteType
typedef GPB_ENUM(ProtosWriteCharacteristicRequest_WriteType) {
/**
* Value used if any message's field encounters a value that is not defined
* by this enum. The message will also have C functions to get/set the rawValue
* of the field.
**/
ProtosWriteCharacteristicRequest_WriteType_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
ProtosWriteCharacteristicRequest_WriteType_WithResponse = 0,
ProtosWriteCharacteristicRequest_WriteType_WithoutResponse = 1,
};
GPBEnumDescriptor *ProtosWriteCharacteristicRequest_WriteType_EnumDescriptor(void);
/**
* Checks to see if the given value is defined by the enum or was not known at
* the time this source was generated.
**/
BOOL ProtosWriteCharacteristicRequest_WriteType_IsValidValue(int32_t value);
#pragma mark - Enum ProtosDeviceStateResponse_BluetoothDeviceState
typedef GPB_ENUM(ProtosDeviceStateResponse_BluetoothDeviceState) {
/**
* Value used if any message's field encounters a value that is not defined
* by this enum. The message will also have C functions to get/set the rawValue
* of the field.
**/
ProtosDeviceStateResponse_BluetoothDeviceState_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
ProtosDeviceStateResponse_BluetoothDeviceState_Disconnected = 0,
ProtosDeviceStateResponse_BluetoothDeviceState_Connecting = 1,
ProtosDeviceStateResponse_BluetoothDeviceState_Connected = 2,
ProtosDeviceStateResponse_BluetoothDeviceState_Disconnecting = 3,
};
GPBEnumDescriptor *ProtosDeviceStateResponse_BluetoothDeviceState_EnumDescriptor(void);
/**
* Checks to see if the given value is defined by the enum or was not known at
* the time this source was generated.
**/
BOOL ProtosDeviceStateResponse_BluetoothDeviceState_IsValidValue(int32_t value);
#pragma mark - ProtosFlutterblueRoot
/**
* Exposes the extension registry for this file.
*
* The base class provides:
* @code
* + (GPBExtensionRegistry *)extensionRegistry;
* @endcode
* which is a @c GPBExtensionRegistry that includes all the extensions defined by
* this file and all files that it depends on.
**/
@interface ProtosFlutterblueRoot : GPBRootObject
@end
#pragma mark - ProtosInt32Value
typedef GPB_ENUM(ProtosInt32Value_FieldNumber) {
ProtosInt32Value_FieldNumber_Value = 1,
};
/**
* Wrapper message for `int32`.
*
* Allows for nullability of fields in messages
**/
@interface ProtosInt32Value : GPBMessage
/** The int32 value. */
@property(nonatomic, readwrite) int32_t value;
@end
#pragma mark - ProtosBluetoothState
typedef GPB_ENUM(ProtosBluetoothState_FieldNumber) {
ProtosBluetoothState_FieldNumber_State = 1,
};
@interface ProtosBluetoothState : GPBMessage
@property(nonatomic, readwrite) ProtosBluetoothState_State state;
@end
/**
* Fetches the raw value of a @c ProtosBluetoothState's @c state property, even
* if the value was not defined by the enum at the time the code was generated.
**/
int32_t ProtosBluetoothState_State_RawValue(ProtosBluetoothState *message);
/**
* Sets the raw value of an @c ProtosBluetoothState's @c state property, allowing
* it to be set to a value that was not defined by the enum at the time the code
* was generated.
**/
void SetProtosBluetoothState_State_RawValue(ProtosBluetoothState *message, int32_t value);
#pragma mark - ProtosAdvertisementData
typedef GPB_ENUM(ProtosAdvertisementData_FieldNumber) {
ProtosAdvertisementData_FieldNumber_LocalName = 1,
ProtosAdvertisementData_FieldNumber_TxPowerLevel = 2,
ProtosAdvertisementData_FieldNumber_Connectable = 3,
ProtosAdvertisementData_FieldNumber_ManufacturerData = 4,
ProtosAdvertisementData_FieldNumber_ServiceData = 5,
ProtosAdvertisementData_FieldNumber_ServiceUuidsArray = 6,
};
@interface ProtosAdvertisementData : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *localName;
@property(nonatomic, readwrite, strong, null_resettable) ProtosInt32Value *txPowerLevel;
/** Test to see if @c txPowerLevel has been set. */
@property(nonatomic, readwrite) BOOL hasTxPowerLevel;
@property(nonatomic, readwrite) BOOL connectable;
/** Map of manufacturers to their data */
@property(nonatomic, readwrite, strong, null_resettable) GPBInt32ObjectDictionary<NSData*> *manufacturerData;
/** The number of items in @c manufacturerData without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger manufacturerData_Count;
/** Map of service UUIDs to their data. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary<NSString*, NSData*> *serviceData;
/** The number of items in @c serviceData without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger serviceData_Count;
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *serviceUuidsArray;
/** The number of items in @c serviceUuidsArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger serviceUuidsArray_Count;
@end
#pragma mark - ProtosScanSettings
typedef GPB_ENUM(ProtosScanSettings_FieldNumber) {
ProtosScanSettings_FieldNumber_AndroidScanMode = 1,
ProtosScanSettings_FieldNumber_ServiceUuidsArray = 2,
};
@interface ProtosScanSettings : GPBMessage
@property(nonatomic, readwrite) int32_t androidScanMode;
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<NSString*> *serviceUuidsArray;
/** The number of items in @c serviceUuidsArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger serviceUuidsArray_Count;
@end
#pragma mark - ProtosScanResult
typedef GPB_ENUM(ProtosScanResult_FieldNumber) {
ProtosScanResult_FieldNumber_Device = 1,
ProtosScanResult_FieldNumber_AdvertisementData = 2,
ProtosScanResult_FieldNumber_Rssi = 3,
};
@interface ProtosScanResult : GPBMessage
/** The received peer's ID. */
@property(nonatomic, readwrite, strong, null_resettable) ProtosBluetoothDevice *device;
/** Test to see if @c device has been set. */
@property(nonatomic, readwrite) BOOL hasDevice;
@property(nonatomic, readwrite, strong, null_resettable) ProtosAdvertisementData *advertisementData;
/** Test to see if @c advertisementData has been set. */
@property(nonatomic, readwrite) BOOL hasAdvertisementData;
@property(nonatomic, readwrite) int32_t rssi;
@end
#pragma mark - ProtosConnectRequest
typedef GPB_ENUM(ProtosConnectRequest_FieldNumber) {
ProtosConnectRequest_FieldNumber_RemoteId = 1,
ProtosConnectRequest_FieldNumber_AndroidAutoConnect = 2,
};
@interface ProtosConnectRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite) BOOL androidAutoConnect;
@end
#pragma mark - ProtosBluetoothDevice
typedef GPB_ENUM(ProtosBluetoothDevice_FieldNumber) {
ProtosBluetoothDevice_FieldNumber_RemoteId = 1,
ProtosBluetoothDevice_FieldNumber_Name = 2,
ProtosBluetoothDevice_FieldNumber_Type = 3,
};
@interface ProtosBluetoothDevice : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *name;
@property(nonatomic, readwrite) ProtosBluetoothDevice_Type type;
@end
/**
* Fetches the raw value of a @c ProtosBluetoothDevice's @c type property, even
* if the value was not defined by the enum at the time the code was generated.
**/
int32_t ProtosBluetoothDevice_Type_RawValue(ProtosBluetoothDevice *message);
/**
* Sets the raw value of an @c ProtosBluetoothDevice's @c type property, allowing
* it to be set to a value that was not defined by the enum at the time the code
* was generated.
**/
void SetProtosBluetoothDevice_Type_RawValue(ProtosBluetoothDevice *message, int32_t value);
#pragma mark - ProtosBluetoothService
typedef GPB_ENUM(ProtosBluetoothService_FieldNumber) {
ProtosBluetoothService_FieldNumber_Uuid = 1,
ProtosBluetoothService_FieldNumber_RemoteId = 2,
ProtosBluetoothService_FieldNumber_IsPrimary = 3,
ProtosBluetoothService_FieldNumber_CharacteristicsArray = 4,
ProtosBluetoothService_FieldNumber_IncludedServicesArray = 5,
};
@interface ProtosBluetoothService : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *uuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
/** Indicates whether the type of service is primary or secondary. */
@property(nonatomic, readwrite) BOOL isPrimary;
/** A list of characteristics that have been discovered in this service. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<ProtosBluetoothCharacteristic*> *characteristicsArray;
/** The number of items in @c characteristicsArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger characteristicsArray_Count;
/** A list of included services that have been discovered in this service. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<ProtosBluetoothService*> *includedServicesArray;
/** The number of items in @c includedServicesArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger includedServicesArray_Count;
@end
#pragma mark - ProtosBluetoothCharacteristic
typedef GPB_ENUM(ProtosBluetoothCharacteristic_FieldNumber) {
ProtosBluetoothCharacteristic_FieldNumber_Uuid = 1,
ProtosBluetoothCharacteristic_FieldNumber_ServiceUuid = 2,
ProtosBluetoothCharacteristic_FieldNumber_SecondaryServiceUuid = 3,
ProtosBluetoothCharacteristic_FieldNumber_DescriptorsArray = 4,
ProtosBluetoothCharacteristic_FieldNumber_Properties = 5,
ProtosBluetoothCharacteristic_FieldNumber_Value = 6,
};
@interface ProtosBluetoothCharacteristic : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *uuid;
/** The service that this characteristic belongs to. */
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
/** The secondary service if nested */
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
/** A list of descriptors that have been discovered in this characteristic. */
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<ProtosBluetoothDescriptor*> *descriptorsArray;
/** The number of items in @c descriptorsArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger descriptorsArray_Count;
/** The properties of the characteristic. */
@property(nonatomic, readwrite, strong, null_resettable) ProtosCharacteristicProperties *properties;
/** Test to see if @c properties has been set. */
@property(nonatomic, readwrite) BOOL hasProperties;
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
@end
#pragma mark - ProtosBluetoothDescriptor
typedef GPB_ENUM(ProtosBluetoothDescriptor_FieldNumber) {
ProtosBluetoothDescriptor_FieldNumber_Uuid = 1,
ProtosBluetoothDescriptor_FieldNumber_ServiceUuid = 2,
ProtosBluetoothDescriptor_FieldNumber_CharacteristicUuid = 3,
ProtosBluetoothDescriptor_FieldNumber_Value = 4,
};
@interface ProtosBluetoothDescriptor : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *uuid;
/** The service that this descriptor belongs to. */
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
/** The characteristic that this descriptor belongs to. */
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
@end
#pragma mark - ProtosCharacteristicProperties
typedef GPB_ENUM(ProtosCharacteristicProperties_FieldNumber) {
ProtosCharacteristicProperties_FieldNumber_Broadcast = 1,
ProtosCharacteristicProperties_FieldNumber_Read = 2,
ProtosCharacteristicProperties_FieldNumber_WriteWithoutResponse = 3,
ProtosCharacteristicProperties_FieldNumber_Write = 4,
ProtosCharacteristicProperties_FieldNumber_Notify = 5,
ProtosCharacteristicProperties_FieldNumber_Indicate = 6,
ProtosCharacteristicProperties_FieldNumber_AuthenticatedSignedWrites = 7,
ProtosCharacteristicProperties_FieldNumber_ExtendedProperties = 8,
ProtosCharacteristicProperties_FieldNumber_NotifyEncryptionRequired = 9,
ProtosCharacteristicProperties_FieldNumber_IndicateEncryptionRequired = 10,
};
@interface ProtosCharacteristicProperties : GPBMessage
@property(nonatomic, readwrite) BOOL broadcast;
@property(nonatomic, readwrite) BOOL read;
@property(nonatomic, readwrite) BOOL writeWithoutResponse;
@property(nonatomic, readwrite) BOOL write;
@property(nonatomic, readwrite) BOOL notify;
@property(nonatomic, readwrite) BOOL indicate;
@property(nonatomic, readwrite) BOOL authenticatedSignedWrites;
@property(nonatomic, readwrite) BOOL extendedProperties;
@property(nonatomic, readwrite) BOOL notifyEncryptionRequired;
@property(nonatomic, readwrite) BOOL indicateEncryptionRequired;
@end
#pragma mark - ProtosDiscoverServicesResult
typedef GPB_ENUM(ProtosDiscoverServicesResult_FieldNumber) {
ProtosDiscoverServicesResult_FieldNumber_RemoteId = 1,
ProtosDiscoverServicesResult_FieldNumber_ServicesArray = 2,
};
@interface ProtosDiscoverServicesResult : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray<ProtosBluetoothService*> *servicesArray;
/** The number of items in @c servicesArray without causing the array to be created. */
@property(nonatomic, readonly) NSUInteger servicesArray_Count;
@end
#pragma mark - ProtosReadCharacteristicRequest
typedef GPB_ENUM(ProtosReadCharacteristicRequest_FieldNumber) {
ProtosReadCharacteristicRequest_FieldNumber_RemoteId = 1,
ProtosReadCharacteristicRequest_FieldNumber_CharacteristicUuid = 2,
ProtosReadCharacteristicRequest_FieldNumber_ServiceUuid = 3,
ProtosReadCharacteristicRequest_FieldNumber_SecondaryServiceUuid = 4,
};
@interface ProtosReadCharacteristicRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
@end
#pragma mark - ProtosReadCharacteristicResponse
typedef GPB_ENUM(ProtosReadCharacteristicResponse_FieldNumber) {
ProtosReadCharacteristicResponse_FieldNumber_RemoteId = 1,
ProtosReadCharacteristicResponse_FieldNumber_Characteristic = 2,
};
@interface ProtosReadCharacteristicResponse : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, strong, null_resettable) ProtosBluetoothCharacteristic *characteristic;
/** Test to see if @c characteristic has been set. */
@property(nonatomic, readwrite) BOOL hasCharacteristic;
@end
#pragma mark - ProtosReadDescriptorRequest
typedef GPB_ENUM(ProtosReadDescriptorRequest_FieldNumber) {
ProtosReadDescriptorRequest_FieldNumber_RemoteId = 1,
ProtosReadDescriptorRequest_FieldNumber_DescriptorUuid = 2,
ProtosReadDescriptorRequest_FieldNumber_ServiceUuid = 3,
ProtosReadDescriptorRequest_FieldNumber_SecondaryServiceUuid = 4,
ProtosReadDescriptorRequest_FieldNumber_CharacteristicUuid = 5,
};
@interface ProtosReadDescriptorRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *descriptorUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@end
#pragma mark - ProtosReadDescriptorResponse
typedef GPB_ENUM(ProtosReadDescriptorResponse_FieldNumber) {
ProtosReadDescriptorResponse_FieldNumber_Request = 1,
ProtosReadDescriptorResponse_FieldNumber_Value = 2,
};
@interface ProtosReadDescriptorResponse : GPBMessage
@property(nonatomic, readwrite, strong, null_resettable) ProtosReadDescriptorRequest *request;
/** Test to see if @c request has been set. */
@property(nonatomic, readwrite) BOOL hasRequest;
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
@end
#pragma mark - ProtosWriteCharacteristicRequest
typedef GPB_ENUM(ProtosWriteCharacteristicRequest_FieldNumber) {
ProtosWriteCharacteristicRequest_FieldNumber_RemoteId = 1,
ProtosWriteCharacteristicRequest_FieldNumber_CharacteristicUuid = 2,
ProtosWriteCharacteristicRequest_FieldNumber_ServiceUuid = 3,
ProtosWriteCharacteristicRequest_FieldNumber_SecondaryServiceUuid = 4,
ProtosWriteCharacteristicRequest_FieldNumber_WriteType = 5,
ProtosWriteCharacteristicRequest_FieldNumber_Value = 6,
};
@interface ProtosWriteCharacteristicRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
@property(nonatomic, readwrite) ProtosWriteCharacteristicRequest_WriteType writeType;
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
@end
/**
* Fetches the raw value of a @c ProtosWriteCharacteristicRequest's @c writeType property, even
* if the value was not defined by the enum at the time the code was generated.
**/
int32_t ProtosWriteCharacteristicRequest_WriteType_RawValue(ProtosWriteCharacteristicRequest *message);
/**
* Sets the raw value of an @c ProtosWriteCharacteristicRequest's @c writeType property, allowing
* it to be set to a value that was not defined by the enum at the time the code
* was generated.
**/
void SetProtosWriteCharacteristicRequest_WriteType_RawValue(ProtosWriteCharacteristicRequest *message, int32_t value);
#pragma mark - ProtosWriteCharacteristicResponse
typedef GPB_ENUM(ProtosWriteCharacteristicResponse_FieldNumber) {
ProtosWriteCharacteristicResponse_FieldNumber_Request = 1,
ProtosWriteCharacteristicResponse_FieldNumber_Success = 2,
};
@interface ProtosWriteCharacteristicResponse : GPBMessage
@property(nonatomic, readwrite, strong, null_resettable) ProtosWriteCharacteristicRequest *request;
/** Test to see if @c request has been set. */
@property(nonatomic, readwrite) BOOL hasRequest;
@property(nonatomic, readwrite) BOOL success;
@end
#pragma mark - ProtosWriteDescriptorRequest
typedef GPB_ENUM(ProtosWriteDescriptorRequest_FieldNumber) {
ProtosWriteDescriptorRequest_FieldNumber_RemoteId = 1,
ProtosWriteDescriptorRequest_FieldNumber_DescriptorUuid = 2,
ProtosWriteDescriptorRequest_FieldNumber_ServiceUuid = 3,
ProtosWriteDescriptorRequest_FieldNumber_SecondaryServiceUuid = 4,
ProtosWriteDescriptorRequest_FieldNumber_CharacteristicUuid = 5,
ProtosWriteDescriptorRequest_FieldNumber_Value = 6,
};
@interface ProtosWriteDescriptorRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *descriptorUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSData *value;
@end
#pragma mark - ProtosWriteDescriptorResponse
typedef GPB_ENUM(ProtosWriteDescriptorResponse_FieldNumber) {
ProtosWriteDescriptorResponse_FieldNumber_Request = 1,
ProtosWriteDescriptorResponse_FieldNumber_Success = 2,
};
@interface ProtosWriteDescriptorResponse : GPBMessage
@property(nonatomic, readwrite, strong, null_resettable) ProtosWriteDescriptorRequest *request;
/** Test to see if @c request has been set. */
@property(nonatomic, readwrite) BOOL hasRequest;
@property(nonatomic, readwrite) BOOL success;
@end
#pragma mark - ProtosSetNotificationRequest
typedef GPB_ENUM(ProtosSetNotificationRequest_FieldNumber) {
ProtosSetNotificationRequest_FieldNumber_RemoteId = 1,
ProtosSetNotificationRequest_FieldNumber_ServiceUuid = 2,
ProtosSetNotificationRequest_FieldNumber_SecondaryServiceUuid = 3,
ProtosSetNotificationRequest_FieldNumber_CharacteristicUuid = 4,
ProtosSetNotificationRequest_FieldNumber_Enable = 5,
};
@interface ProtosSetNotificationRequest : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, copy, null_resettable) NSString *serviceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *secondaryServiceUuid;
@property(nonatomic, readwrite, copy, null_resettable) NSString *characteristicUuid;
@property(nonatomic, readwrite) BOOL enable;
@end
#pragma mark - ProtosSetNotificationResponse
typedef GPB_ENUM(ProtosSetNotificationResponse_FieldNumber) {
ProtosSetNotificationResponse_FieldNumber_RemoteId = 1,
ProtosSetNotificationResponse_FieldNumber_Characteristic = 2,
ProtosSetNotificationResponse_FieldNumber_Success = 3,
};
@interface ProtosSetNotificationResponse : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, strong, null_resettable) ProtosBluetoothCharacteristic *characteristic;
/** Test to see if @c characteristic has been set. */
@property(nonatomic, readwrite) BOOL hasCharacteristic;
@property(nonatomic, readwrite) BOOL success;
@end
#pragma mark - ProtosOnNotificationResponse
typedef GPB_ENUM(ProtosOnNotificationResponse_FieldNumber) {
ProtosOnNotificationResponse_FieldNumber_RemoteId = 1,
ProtosOnNotificationResponse_FieldNumber_Characteristic = 2,
};
@interface ProtosOnNotificationResponse : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite, strong, null_resettable) ProtosBluetoothCharacteristic *characteristic;
/** Test to see if @c characteristic has been set. */
@property(nonatomic, readwrite) BOOL hasCharacteristic;
@end
#pragma mark - ProtosDeviceStateResponse
typedef GPB_ENUM(ProtosDeviceStateResponse_FieldNumber) {
ProtosDeviceStateResponse_FieldNumber_RemoteId = 1,
ProtosDeviceStateResponse_FieldNumber_State = 2,
};
@interface ProtosDeviceStateResponse : GPBMessage
@property(nonatomic, readwrite, copy, null_resettable) NSString *remoteId;
@property(nonatomic, readwrite) ProtosDeviceStateResponse_BluetoothDeviceState state;
@end
/**
* Fetches the raw value of a @c ProtosDeviceStateResponse's @c state property, even
* if the value was not defined by the enum at the time the code was generated.
**/
int32_t ProtosDeviceStateResponse_State_RawValue(ProtosDeviceStateResponse *message);
/**
* Sets the raw value of an @c ProtosDeviceStateResponse's @c state property, allowing
* it to be set to a value that was not defined by the enum at the time the code
* was generated.
**/
void SetProtosDeviceStateResponse_State_RawValue(ProtosDeviceStateResponse *message, int32_t value);
NS_ASSUME_NONNULL_END
CF_EXTERN_C_END
#pragma clang diagnostic pop
// @@protoc_insertion_point(global_scope)
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library flutter_blue;
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'gen/flutterblue.pb.dart' as protos;
part 'src/bluetooth_characteristic.dart';
part 'src/bluetooth_descriptor.dart';
part 'src/bluetooth_device.dart';
part 'src/bluetooth_service.dart';
part 'src/constants.dart';
part 'src/flutter_blue.dart';
part 'src/guid.dart';
@@ -0,0 +1,987 @@
///
// Generated code. Do not modify.
// source: flutterblue.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore: UNUSED_SHOWN_NAME
import 'dart:core' show int, bool, double, String, List, Map, override;
import 'package:protobuf/protobuf.dart' as $pb;
import 'flutterblue.pbenum.dart';
export 'flutterblue.pbenum.dart';
class Int32Value extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('Int32Value')
..a<int>(1, 'value', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
Int32Value() : super();
Int32Value.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
Int32Value.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
Int32Value clone() => new Int32Value()..mergeFromMessage(this);
Int32Value copyWith(void Function(Int32Value) updates) => super.copyWith((message) => updates(message as Int32Value));
$pb.BuilderInfo get info_ => _i;
static Int32Value create() => new Int32Value();
static $pb.PbList<Int32Value> createRepeated() => new $pb.PbList<Int32Value>();
static Int32Value getDefault() => _defaultInstance ??= create()..freeze();
static Int32Value _defaultInstance;
static void $checkItem(Int32Value v) {
if (v is! Int32Value) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get value => $_get(0, 0);
set value(int v) { $_setSignedInt32(0, v); }
bool hasValue() => $_has(0);
void clearValue() => clearField(1);
}
class BluetoothState extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BluetoothState')
..e<BluetoothState_State>(1, 'state', $pb.PbFieldType.OE, BluetoothState_State.UNKNOWN, BluetoothState_State.valueOf, BluetoothState_State.values)
..hasRequiredFields = false
;
BluetoothState() : super();
BluetoothState.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BluetoothState.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BluetoothState clone() => new BluetoothState()..mergeFromMessage(this);
BluetoothState copyWith(void Function(BluetoothState) updates) => super.copyWith((message) => updates(message as BluetoothState));
$pb.BuilderInfo get info_ => _i;
static BluetoothState create() => new BluetoothState();
static $pb.PbList<BluetoothState> createRepeated() => new $pb.PbList<BluetoothState>();
static BluetoothState getDefault() => _defaultInstance ??= create()..freeze();
static BluetoothState _defaultInstance;
static void $checkItem(BluetoothState v) {
if (v is! BluetoothState) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
BluetoothState_State get state => $_getN(0);
set state(BluetoothState_State v) { setField(1, v); }
bool hasState() => $_has(0);
void clearState() => clearField(1);
}
class AdvertisementData extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('AdvertisementData')
..aOS(1, 'localName')
..a<Int32Value>(2, 'txPowerLevel', $pb.PbFieldType.OM, Int32Value.getDefault, Int32Value.create)
..aOB(3, 'connectable')
..m<int, List<int>>(4, 'manufacturerData', $pb.PbFieldType.O3, $pb.PbFieldType.OY)
..m<String, List<int>>(5, 'serviceData', $pb.PbFieldType.OS, $pb.PbFieldType.OY)
..pPS(6, 'serviceUuids')
..hasRequiredFields = false
;
AdvertisementData() : super();
AdvertisementData.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
AdvertisementData.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
AdvertisementData clone() => new AdvertisementData()..mergeFromMessage(this);
AdvertisementData copyWith(void Function(AdvertisementData) updates) => super.copyWith((message) => updates(message as AdvertisementData));
$pb.BuilderInfo get info_ => _i;
static AdvertisementData create() => new AdvertisementData();
static $pb.PbList<AdvertisementData> createRepeated() => new $pb.PbList<AdvertisementData>();
static AdvertisementData getDefault() => _defaultInstance ??= create()..freeze();
static AdvertisementData _defaultInstance;
static void $checkItem(AdvertisementData v) {
if (v is! AdvertisementData) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get localName => $_getS(0, '');
set localName(String v) { $_setString(0, v); }
bool hasLocalName() => $_has(0);
void clearLocalName() => clearField(1);
Int32Value get txPowerLevel => $_getN(1);
set txPowerLevel(Int32Value v) { setField(2, v); }
bool hasTxPowerLevel() => $_has(1);
void clearTxPowerLevel() => clearField(2);
bool get connectable => $_get(2, false);
set connectable(bool v) { $_setBool(2, v); }
bool hasConnectable() => $_has(2);
void clearConnectable() => clearField(3);
Map<int, List<int>> get manufacturerData => $_getMap(3);
Map<String, List<int>> get serviceData => $_getMap(4);
List<String> get serviceUuids => $_getList(5);
}
class ScanSettings extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ScanSettings')
..a<int>(1, 'androidScanMode', $pb.PbFieldType.O3)
..pPS(2, 'serviceUuids')
..hasRequiredFields = false
;
ScanSettings() : super();
ScanSettings.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ScanSettings.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ScanSettings clone() => new ScanSettings()..mergeFromMessage(this);
ScanSettings copyWith(void Function(ScanSettings) updates) => super.copyWith((message) => updates(message as ScanSettings));
$pb.BuilderInfo get info_ => _i;
static ScanSettings create() => new ScanSettings();
static $pb.PbList<ScanSettings> createRepeated() => new $pb.PbList<ScanSettings>();
static ScanSettings getDefault() => _defaultInstance ??= create()..freeze();
static ScanSettings _defaultInstance;
static void $checkItem(ScanSettings v) {
if (v is! ScanSettings) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
int get androidScanMode => $_get(0, 0);
set androidScanMode(int v) { $_setSignedInt32(0, v); }
bool hasAndroidScanMode() => $_has(0);
void clearAndroidScanMode() => clearField(1);
List<String> get serviceUuids => $_getList(1);
}
class ScanResult extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ScanResult')
..a<BluetoothDevice>(1, 'device', $pb.PbFieldType.OM, BluetoothDevice.getDefault, BluetoothDevice.create)
..a<AdvertisementData>(2, 'advertisementData', $pb.PbFieldType.OM, AdvertisementData.getDefault, AdvertisementData.create)
..a<int>(3, 'rssi', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
ScanResult() : super();
ScanResult.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ScanResult.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ScanResult clone() => new ScanResult()..mergeFromMessage(this);
ScanResult copyWith(void Function(ScanResult) updates) => super.copyWith((message) => updates(message as ScanResult));
$pb.BuilderInfo get info_ => _i;
static ScanResult create() => new ScanResult();
static $pb.PbList<ScanResult> createRepeated() => new $pb.PbList<ScanResult>();
static ScanResult getDefault() => _defaultInstance ??= create()..freeze();
static ScanResult _defaultInstance;
static void $checkItem(ScanResult v) {
if (v is! ScanResult) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
BluetoothDevice get device => $_getN(0);
set device(BluetoothDevice v) { setField(1, v); }
bool hasDevice() => $_has(0);
void clearDevice() => clearField(1);
AdvertisementData get advertisementData => $_getN(1);
set advertisementData(AdvertisementData v) { setField(2, v); }
bool hasAdvertisementData() => $_has(1);
void clearAdvertisementData() => clearField(2);
int get rssi => $_get(2, 0);
set rssi(int v) { $_setSignedInt32(2, v); }
bool hasRssi() => $_has(2);
void clearRssi() => clearField(3);
}
class ConnectRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ConnectRequest')
..aOS(1, 'remoteId')
..aOB(2, 'androidAutoConnect')
..hasRequiredFields = false
;
ConnectRequest() : super();
ConnectRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ConnectRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ConnectRequest clone() => new ConnectRequest()..mergeFromMessage(this);
ConnectRequest copyWith(void Function(ConnectRequest) updates) => super.copyWith((message) => updates(message as ConnectRequest));
$pb.BuilderInfo get info_ => _i;
static ConnectRequest create() => new ConnectRequest();
static $pb.PbList<ConnectRequest> createRepeated() => new $pb.PbList<ConnectRequest>();
static ConnectRequest getDefault() => _defaultInstance ??= create()..freeze();
static ConnectRequest _defaultInstance;
static void $checkItem(ConnectRequest v) {
if (v is! ConnectRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
bool get androidAutoConnect => $_get(1, false);
set androidAutoConnect(bool v) { $_setBool(1, v); }
bool hasAndroidAutoConnect() => $_has(1);
void clearAndroidAutoConnect() => clearField(2);
}
class BluetoothDevice extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BluetoothDevice')
..aOS(1, 'remoteId')
..aOS(2, 'name')
..e<BluetoothDevice_Type>(3, 'type', $pb.PbFieldType.OE, BluetoothDevice_Type.UNKNOWN, BluetoothDevice_Type.valueOf, BluetoothDevice_Type.values)
..hasRequiredFields = false
;
BluetoothDevice() : super();
BluetoothDevice.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BluetoothDevice.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BluetoothDevice clone() => new BluetoothDevice()..mergeFromMessage(this);
BluetoothDevice copyWith(void Function(BluetoothDevice) updates) => super.copyWith((message) => updates(message as BluetoothDevice));
$pb.BuilderInfo get info_ => _i;
static BluetoothDevice create() => new BluetoothDevice();
static $pb.PbList<BluetoothDevice> createRepeated() => new $pb.PbList<BluetoothDevice>();
static BluetoothDevice getDefault() => _defaultInstance ??= create()..freeze();
static BluetoothDevice _defaultInstance;
static void $checkItem(BluetoothDevice v) {
if (v is! BluetoothDevice) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get name => $_getS(1, '');
set name(String v) { $_setString(1, v); }
bool hasName() => $_has(1);
void clearName() => clearField(2);
BluetoothDevice_Type get type => $_getN(2);
set type(BluetoothDevice_Type v) { setField(3, v); }
bool hasType() => $_has(2);
void clearType() => clearField(3);
}
class BluetoothService extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BluetoothService')
..aOS(1, 'uuid')
..aOS(2, 'remoteId')
..aOB(3, 'isPrimary')
..pp<BluetoothCharacteristic>(4, 'characteristics', $pb.PbFieldType.PM, BluetoothCharacteristic.$checkItem, BluetoothCharacteristic.create)
..pp<BluetoothService>(5, 'includedServices', $pb.PbFieldType.PM, BluetoothService.$checkItem, BluetoothService.create)
..hasRequiredFields = false
;
BluetoothService() : super();
BluetoothService.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BluetoothService.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BluetoothService clone() => new BluetoothService()..mergeFromMessage(this);
BluetoothService copyWith(void Function(BluetoothService) updates) => super.copyWith((message) => updates(message as BluetoothService));
$pb.BuilderInfo get info_ => _i;
static BluetoothService create() => new BluetoothService();
static $pb.PbList<BluetoothService> createRepeated() => new $pb.PbList<BluetoothService>();
static BluetoothService getDefault() => _defaultInstance ??= create()..freeze();
static BluetoothService _defaultInstance;
static void $checkItem(BluetoothService v) {
if (v is! BluetoothService) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get uuid => $_getS(0, '');
set uuid(String v) { $_setString(0, v); }
bool hasUuid() => $_has(0);
void clearUuid() => clearField(1);
String get remoteId => $_getS(1, '');
set remoteId(String v) { $_setString(1, v); }
bool hasRemoteId() => $_has(1);
void clearRemoteId() => clearField(2);
bool get isPrimary => $_get(2, false);
set isPrimary(bool v) { $_setBool(2, v); }
bool hasIsPrimary() => $_has(2);
void clearIsPrimary() => clearField(3);
List<BluetoothCharacteristic> get characteristics => $_getList(3);
List<BluetoothService> get includedServices => $_getList(4);
}
class BluetoothCharacteristic extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BluetoothCharacteristic')
..aOS(1, 'uuid')
..aOS(2, 'serviceUuid')
..aOS(3, 'secondaryServiceUuid')
..pp<BluetoothDescriptor>(4, 'descriptors', $pb.PbFieldType.PM, BluetoothDescriptor.$checkItem, BluetoothDescriptor.create)
..a<CharacteristicProperties>(5, 'properties', $pb.PbFieldType.OM, CharacteristicProperties.getDefault, CharacteristicProperties.create)
..a<List<int>>(6, 'value', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
BluetoothCharacteristic() : super();
BluetoothCharacteristic.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BluetoothCharacteristic.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BluetoothCharacteristic clone() => new BluetoothCharacteristic()..mergeFromMessage(this);
BluetoothCharacteristic copyWith(void Function(BluetoothCharacteristic) updates) => super.copyWith((message) => updates(message as BluetoothCharacteristic));
$pb.BuilderInfo get info_ => _i;
static BluetoothCharacteristic create() => new BluetoothCharacteristic();
static $pb.PbList<BluetoothCharacteristic> createRepeated() => new $pb.PbList<BluetoothCharacteristic>();
static BluetoothCharacteristic getDefault() => _defaultInstance ??= create()..freeze();
static BluetoothCharacteristic _defaultInstance;
static void $checkItem(BluetoothCharacteristic v) {
if (v is! BluetoothCharacteristic) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get uuid => $_getS(0, '');
set uuid(String v) { $_setString(0, v); }
bool hasUuid() => $_has(0);
void clearUuid() => clearField(1);
String get serviceUuid => $_getS(1, '');
set serviceUuid(String v) { $_setString(1, v); }
bool hasServiceUuid() => $_has(1);
void clearServiceUuid() => clearField(2);
String get secondaryServiceUuid => $_getS(2, '');
set secondaryServiceUuid(String v) { $_setString(2, v); }
bool hasSecondaryServiceUuid() => $_has(2);
void clearSecondaryServiceUuid() => clearField(3);
List<BluetoothDescriptor> get descriptors => $_getList(3);
CharacteristicProperties get properties => $_getN(4);
set properties(CharacteristicProperties v) { setField(5, v); }
bool hasProperties() => $_has(4);
void clearProperties() => clearField(5);
List<int> get value => $_getN(5);
set value(List<int> v) { $_setBytes(5, v); }
bool hasValue() => $_has(5);
void clearValue() => clearField(6);
}
class BluetoothDescriptor extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('BluetoothDescriptor')
..aOS(1, 'uuid')
..aOS(2, 'serviceUuid')
..aOS(3, 'characteristicUuid')
..a<List<int>>(4, 'value', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
BluetoothDescriptor() : super();
BluetoothDescriptor.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
BluetoothDescriptor.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
BluetoothDescriptor clone() => new BluetoothDescriptor()..mergeFromMessage(this);
BluetoothDescriptor copyWith(void Function(BluetoothDescriptor) updates) => super.copyWith((message) => updates(message as BluetoothDescriptor));
$pb.BuilderInfo get info_ => _i;
static BluetoothDescriptor create() => new BluetoothDescriptor();
static $pb.PbList<BluetoothDescriptor> createRepeated() => new $pb.PbList<BluetoothDescriptor>();
static BluetoothDescriptor getDefault() => _defaultInstance ??= create()..freeze();
static BluetoothDescriptor _defaultInstance;
static void $checkItem(BluetoothDescriptor v) {
if (v is! BluetoothDescriptor) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get uuid => $_getS(0, '');
set uuid(String v) { $_setString(0, v); }
bool hasUuid() => $_has(0);
void clearUuid() => clearField(1);
String get serviceUuid => $_getS(1, '');
set serviceUuid(String v) { $_setString(1, v); }
bool hasServiceUuid() => $_has(1);
void clearServiceUuid() => clearField(2);
String get characteristicUuid => $_getS(2, '');
set characteristicUuid(String v) { $_setString(2, v); }
bool hasCharacteristicUuid() => $_has(2);
void clearCharacteristicUuid() => clearField(3);
List<int> get value => $_getN(3);
set value(List<int> v) { $_setBytes(3, v); }
bool hasValue() => $_has(3);
void clearValue() => clearField(4);
}
class CharacteristicProperties extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('CharacteristicProperties')
..aOB(1, 'broadcast')
..aOB(2, 'read')
..aOB(3, 'writeWithoutResponse')
..aOB(4, 'write')
..aOB(5, 'notify')
..aOB(6, 'indicate')
..aOB(7, 'authenticatedSignedWrites')
..aOB(8, 'extendedProperties')
..aOB(9, 'notifyEncryptionRequired')
..aOB(10, 'indicateEncryptionRequired')
..hasRequiredFields = false
;
CharacteristicProperties() : super();
CharacteristicProperties.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
CharacteristicProperties.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
CharacteristicProperties clone() => new CharacteristicProperties()..mergeFromMessage(this);
CharacteristicProperties copyWith(void Function(CharacteristicProperties) updates) => super.copyWith((message) => updates(message as CharacteristicProperties));
$pb.BuilderInfo get info_ => _i;
static CharacteristicProperties create() => new CharacteristicProperties();
static $pb.PbList<CharacteristicProperties> createRepeated() => new $pb.PbList<CharacteristicProperties>();
static CharacteristicProperties getDefault() => _defaultInstance ??= create()..freeze();
static CharacteristicProperties _defaultInstance;
static void $checkItem(CharacteristicProperties v) {
if (v is! CharacteristicProperties) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
bool get broadcast => $_get(0, false);
set broadcast(bool v) { $_setBool(0, v); }
bool hasBroadcast() => $_has(0);
void clearBroadcast() => clearField(1);
bool get read => $_get(1, false);
set read(bool v) { $_setBool(1, v); }
bool hasRead() => $_has(1);
void clearRead() => clearField(2);
bool get writeWithoutResponse => $_get(2, false);
set writeWithoutResponse(bool v) { $_setBool(2, v); }
bool hasWriteWithoutResponse() => $_has(2);
void clearWriteWithoutResponse() => clearField(3);
bool get write => $_get(3, false);
set write(bool v) { $_setBool(3, v); }
bool hasWrite() => $_has(3);
void clearWrite() => clearField(4);
bool get notify => $_get(4, false);
set notify(bool v) { $_setBool(4, v); }
bool hasNotify() => $_has(4);
void clearNotify() => clearField(5);
bool get indicate => $_get(5, false);
set indicate(bool v) { $_setBool(5, v); }
bool hasIndicate() => $_has(5);
void clearIndicate() => clearField(6);
bool get authenticatedSignedWrites => $_get(6, false);
set authenticatedSignedWrites(bool v) { $_setBool(6, v); }
bool hasAuthenticatedSignedWrites() => $_has(6);
void clearAuthenticatedSignedWrites() => clearField(7);
bool get extendedProperties => $_get(7, false);
set extendedProperties(bool v) { $_setBool(7, v); }
bool hasExtendedProperties() => $_has(7);
void clearExtendedProperties() => clearField(8);
bool get notifyEncryptionRequired => $_get(8, false);
set notifyEncryptionRequired(bool v) { $_setBool(8, v); }
bool hasNotifyEncryptionRequired() => $_has(8);
void clearNotifyEncryptionRequired() => clearField(9);
bool get indicateEncryptionRequired => $_get(9, false);
set indicateEncryptionRequired(bool v) { $_setBool(9, v); }
bool hasIndicateEncryptionRequired() => $_has(9);
void clearIndicateEncryptionRequired() => clearField(10);
}
class DiscoverServicesResult extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('DiscoverServicesResult')
..aOS(1, 'remoteId')
..pp<BluetoothService>(2, 'services', $pb.PbFieldType.PM, BluetoothService.$checkItem, BluetoothService.create)
..hasRequiredFields = false
;
DiscoverServicesResult() : super();
DiscoverServicesResult.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
DiscoverServicesResult.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
DiscoverServicesResult clone() => new DiscoverServicesResult()..mergeFromMessage(this);
DiscoverServicesResult copyWith(void Function(DiscoverServicesResult) updates) => super.copyWith((message) => updates(message as DiscoverServicesResult));
$pb.BuilderInfo get info_ => _i;
static DiscoverServicesResult create() => new DiscoverServicesResult();
static $pb.PbList<DiscoverServicesResult> createRepeated() => new $pb.PbList<DiscoverServicesResult>();
static DiscoverServicesResult getDefault() => _defaultInstance ??= create()..freeze();
static DiscoverServicesResult _defaultInstance;
static void $checkItem(DiscoverServicesResult v) {
if (v is! DiscoverServicesResult) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
List<BluetoothService> get services => $_getList(1);
}
class ReadCharacteristicRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReadCharacteristicRequest')
..aOS(1, 'remoteId')
..aOS(2, 'characteristicUuid')
..aOS(3, 'serviceUuid')
..aOS(4, 'secondaryServiceUuid')
..hasRequiredFields = false
;
ReadCharacteristicRequest() : super();
ReadCharacteristicRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReadCharacteristicRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReadCharacteristicRequest clone() => new ReadCharacteristicRequest()..mergeFromMessage(this);
ReadCharacteristicRequest copyWith(void Function(ReadCharacteristicRequest) updates) => super.copyWith((message) => updates(message as ReadCharacteristicRequest));
$pb.BuilderInfo get info_ => _i;
static ReadCharacteristicRequest create() => new ReadCharacteristicRequest();
static $pb.PbList<ReadCharacteristicRequest> createRepeated() => new $pb.PbList<ReadCharacteristicRequest>();
static ReadCharacteristicRequest getDefault() => _defaultInstance ??= create()..freeze();
static ReadCharacteristicRequest _defaultInstance;
static void $checkItem(ReadCharacteristicRequest v) {
if (v is! ReadCharacteristicRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get characteristicUuid => $_getS(1, '');
set characteristicUuid(String v) { $_setString(1, v); }
bool hasCharacteristicUuid() => $_has(1);
void clearCharacteristicUuid() => clearField(2);
String get serviceUuid => $_getS(2, '');
set serviceUuid(String v) { $_setString(2, v); }
bool hasServiceUuid() => $_has(2);
void clearServiceUuid() => clearField(3);
String get secondaryServiceUuid => $_getS(3, '');
set secondaryServiceUuid(String v) { $_setString(3, v); }
bool hasSecondaryServiceUuid() => $_has(3);
void clearSecondaryServiceUuid() => clearField(4);
}
class ReadCharacteristicResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReadCharacteristicResponse')
..aOS(1, 'remoteId')
..a<BluetoothCharacteristic>(2, 'characteristic', $pb.PbFieldType.OM, BluetoothCharacteristic.getDefault, BluetoothCharacteristic.create)
..hasRequiredFields = false
;
ReadCharacteristicResponse() : super();
ReadCharacteristicResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReadCharacteristicResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReadCharacteristicResponse clone() => new ReadCharacteristicResponse()..mergeFromMessage(this);
ReadCharacteristicResponse copyWith(void Function(ReadCharacteristicResponse) updates) => super.copyWith((message) => updates(message as ReadCharacteristicResponse));
$pb.BuilderInfo get info_ => _i;
static ReadCharacteristicResponse create() => new ReadCharacteristicResponse();
static $pb.PbList<ReadCharacteristicResponse> createRepeated() => new $pb.PbList<ReadCharacteristicResponse>();
static ReadCharacteristicResponse getDefault() => _defaultInstance ??= create()..freeze();
static ReadCharacteristicResponse _defaultInstance;
static void $checkItem(ReadCharacteristicResponse v) {
if (v is! ReadCharacteristicResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
BluetoothCharacteristic get characteristic => $_getN(1);
set characteristic(BluetoothCharacteristic v) { setField(2, v); }
bool hasCharacteristic() => $_has(1);
void clearCharacteristic() => clearField(2);
}
class ReadDescriptorRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReadDescriptorRequest')
..aOS(1, 'remoteId')
..aOS(2, 'descriptorUuid')
..aOS(3, 'serviceUuid')
..aOS(4, 'secondaryServiceUuid')
..aOS(5, 'characteristicUuid')
..hasRequiredFields = false
;
ReadDescriptorRequest() : super();
ReadDescriptorRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReadDescriptorRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReadDescriptorRequest clone() => new ReadDescriptorRequest()..mergeFromMessage(this);
ReadDescriptorRequest copyWith(void Function(ReadDescriptorRequest) updates) => super.copyWith((message) => updates(message as ReadDescriptorRequest));
$pb.BuilderInfo get info_ => _i;
static ReadDescriptorRequest create() => new ReadDescriptorRequest();
static $pb.PbList<ReadDescriptorRequest> createRepeated() => new $pb.PbList<ReadDescriptorRequest>();
static ReadDescriptorRequest getDefault() => _defaultInstance ??= create()..freeze();
static ReadDescriptorRequest _defaultInstance;
static void $checkItem(ReadDescriptorRequest v) {
if (v is! ReadDescriptorRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get descriptorUuid => $_getS(1, '');
set descriptorUuid(String v) { $_setString(1, v); }
bool hasDescriptorUuid() => $_has(1);
void clearDescriptorUuid() => clearField(2);
String get serviceUuid => $_getS(2, '');
set serviceUuid(String v) { $_setString(2, v); }
bool hasServiceUuid() => $_has(2);
void clearServiceUuid() => clearField(3);
String get secondaryServiceUuid => $_getS(3, '');
set secondaryServiceUuid(String v) { $_setString(3, v); }
bool hasSecondaryServiceUuid() => $_has(3);
void clearSecondaryServiceUuid() => clearField(4);
String get characteristicUuid => $_getS(4, '');
set characteristicUuid(String v) { $_setString(4, v); }
bool hasCharacteristicUuid() => $_has(4);
void clearCharacteristicUuid() => clearField(5);
}
class ReadDescriptorResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('ReadDescriptorResponse')
..a<ReadDescriptorRequest>(1, 'request', $pb.PbFieldType.OM, ReadDescriptorRequest.getDefault, ReadDescriptorRequest.create)
..a<List<int>>(2, 'value', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
ReadDescriptorResponse() : super();
ReadDescriptorResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
ReadDescriptorResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
ReadDescriptorResponse clone() => new ReadDescriptorResponse()..mergeFromMessage(this);
ReadDescriptorResponse copyWith(void Function(ReadDescriptorResponse) updates) => super.copyWith((message) => updates(message as ReadDescriptorResponse));
$pb.BuilderInfo get info_ => _i;
static ReadDescriptorResponse create() => new ReadDescriptorResponse();
static $pb.PbList<ReadDescriptorResponse> createRepeated() => new $pb.PbList<ReadDescriptorResponse>();
static ReadDescriptorResponse getDefault() => _defaultInstance ??= create()..freeze();
static ReadDescriptorResponse _defaultInstance;
static void $checkItem(ReadDescriptorResponse v) {
if (v is! ReadDescriptorResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
ReadDescriptorRequest get request => $_getN(0);
set request(ReadDescriptorRequest v) { setField(1, v); }
bool hasRequest() => $_has(0);
void clearRequest() => clearField(1);
List<int> get value => $_getN(1);
set value(List<int> v) { $_setBytes(1, v); }
bool hasValue() => $_has(1);
void clearValue() => clearField(2);
}
class WriteCharacteristicRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('WriteCharacteristicRequest')
..aOS(1, 'remoteId')
..aOS(2, 'characteristicUuid')
..aOS(3, 'serviceUuid')
..aOS(4, 'secondaryServiceUuid')
..e<WriteCharacteristicRequest_WriteType>(5, 'writeType', $pb.PbFieldType.OE, WriteCharacteristicRequest_WriteType.WITH_RESPONSE, WriteCharacteristicRequest_WriteType.valueOf, WriteCharacteristicRequest_WriteType.values)
..a<List<int>>(6, 'value', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
WriteCharacteristicRequest() : super();
WriteCharacteristicRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
WriteCharacteristicRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
WriteCharacteristicRequest clone() => new WriteCharacteristicRequest()..mergeFromMessage(this);
WriteCharacteristicRequest copyWith(void Function(WriteCharacteristicRequest) updates) => super.copyWith((message) => updates(message as WriteCharacteristicRequest));
$pb.BuilderInfo get info_ => _i;
static WriteCharacteristicRequest create() => new WriteCharacteristicRequest();
static $pb.PbList<WriteCharacteristicRequest> createRepeated() => new $pb.PbList<WriteCharacteristicRequest>();
static WriteCharacteristicRequest getDefault() => _defaultInstance ??= create()..freeze();
static WriteCharacteristicRequest _defaultInstance;
static void $checkItem(WriteCharacteristicRequest v) {
if (v is! WriteCharacteristicRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get characteristicUuid => $_getS(1, '');
set characteristicUuid(String v) { $_setString(1, v); }
bool hasCharacteristicUuid() => $_has(1);
void clearCharacteristicUuid() => clearField(2);
String get serviceUuid => $_getS(2, '');
set serviceUuid(String v) { $_setString(2, v); }
bool hasServiceUuid() => $_has(2);
void clearServiceUuid() => clearField(3);
String get secondaryServiceUuid => $_getS(3, '');
set secondaryServiceUuid(String v) { $_setString(3, v); }
bool hasSecondaryServiceUuid() => $_has(3);
void clearSecondaryServiceUuid() => clearField(4);
WriteCharacteristicRequest_WriteType get writeType => $_getN(4);
set writeType(WriteCharacteristicRequest_WriteType v) { setField(5, v); }
bool hasWriteType() => $_has(4);
void clearWriteType() => clearField(5);
List<int> get value => $_getN(5);
set value(List<int> v) { $_setBytes(5, v); }
bool hasValue() => $_has(5);
void clearValue() => clearField(6);
}
class WriteCharacteristicResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('WriteCharacteristicResponse')
..a<WriteCharacteristicRequest>(1, 'request', $pb.PbFieldType.OM, WriteCharacteristicRequest.getDefault, WriteCharacteristicRequest.create)
..aOB(2, 'success')
..hasRequiredFields = false
;
WriteCharacteristicResponse() : super();
WriteCharacteristicResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
WriteCharacteristicResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
WriteCharacteristicResponse clone() => new WriteCharacteristicResponse()..mergeFromMessage(this);
WriteCharacteristicResponse copyWith(void Function(WriteCharacteristicResponse) updates) => super.copyWith((message) => updates(message as WriteCharacteristicResponse));
$pb.BuilderInfo get info_ => _i;
static WriteCharacteristicResponse create() => new WriteCharacteristicResponse();
static $pb.PbList<WriteCharacteristicResponse> createRepeated() => new $pb.PbList<WriteCharacteristicResponse>();
static WriteCharacteristicResponse getDefault() => _defaultInstance ??= create()..freeze();
static WriteCharacteristicResponse _defaultInstance;
static void $checkItem(WriteCharacteristicResponse v) {
if (v is! WriteCharacteristicResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
WriteCharacteristicRequest get request => $_getN(0);
set request(WriteCharacteristicRequest v) { setField(1, v); }
bool hasRequest() => $_has(0);
void clearRequest() => clearField(1);
bool get success => $_get(1, false);
set success(bool v) { $_setBool(1, v); }
bool hasSuccess() => $_has(1);
void clearSuccess() => clearField(2);
}
class WriteDescriptorRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('WriteDescriptorRequest')
..aOS(1, 'remoteId')
..aOS(2, 'descriptorUuid')
..aOS(3, 'serviceUuid')
..aOS(4, 'secondaryServiceUuid')
..aOS(5, 'characteristicUuid')
..a<List<int>>(6, 'value', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
WriteDescriptorRequest() : super();
WriteDescriptorRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
WriteDescriptorRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
WriteDescriptorRequest clone() => new WriteDescriptorRequest()..mergeFromMessage(this);
WriteDescriptorRequest copyWith(void Function(WriteDescriptorRequest) updates) => super.copyWith((message) => updates(message as WriteDescriptorRequest));
$pb.BuilderInfo get info_ => _i;
static WriteDescriptorRequest create() => new WriteDescriptorRequest();
static $pb.PbList<WriteDescriptorRequest> createRepeated() => new $pb.PbList<WriteDescriptorRequest>();
static WriteDescriptorRequest getDefault() => _defaultInstance ??= create()..freeze();
static WriteDescriptorRequest _defaultInstance;
static void $checkItem(WriteDescriptorRequest v) {
if (v is! WriteDescriptorRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get descriptorUuid => $_getS(1, '');
set descriptorUuid(String v) { $_setString(1, v); }
bool hasDescriptorUuid() => $_has(1);
void clearDescriptorUuid() => clearField(2);
String get serviceUuid => $_getS(2, '');
set serviceUuid(String v) { $_setString(2, v); }
bool hasServiceUuid() => $_has(2);
void clearServiceUuid() => clearField(3);
String get secondaryServiceUuid => $_getS(3, '');
set secondaryServiceUuid(String v) { $_setString(3, v); }
bool hasSecondaryServiceUuid() => $_has(3);
void clearSecondaryServiceUuid() => clearField(4);
String get characteristicUuid => $_getS(4, '');
set characteristicUuid(String v) { $_setString(4, v); }
bool hasCharacteristicUuid() => $_has(4);
void clearCharacteristicUuid() => clearField(5);
List<int> get value => $_getN(5);
set value(List<int> v) { $_setBytes(5, v); }
bool hasValue() => $_has(5);
void clearValue() => clearField(6);
}
class WriteDescriptorResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('WriteDescriptorResponse')
..a<WriteDescriptorRequest>(1, 'request', $pb.PbFieldType.OM, WriteDescriptorRequest.getDefault, WriteDescriptorRequest.create)
..aOB(2, 'success')
..hasRequiredFields = false
;
WriteDescriptorResponse() : super();
WriteDescriptorResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
WriteDescriptorResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
WriteDescriptorResponse clone() => new WriteDescriptorResponse()..mergeFromMessage(this);
WriteDescriptorResponse copyWith(void Function(WriteDescriptorResponse) updates) => super.copyWith((message) => updates(message as WriteDescriptorResponse));
$pb.BuilderInfo get info_ => _i;
static WriteDescriptorResponse create() => new WriteDescriptorResponse();
static $pb.PbList<WriteDescriptorResponse> createRepeated() => new $pb.PbList<WriteDescriptorResponse>();
static WriteDescriptorResponse getDefault() => _defaultInstance ??= create()..freeze();
static WriteDescriptorResponse _defaultInstance;
static void $checkItem(WriteDescriptorResponse v) {
if (v is! WriteDescriptorResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
WriteDescriptorRequest get request => $_getN(0);
set request(WriteDescriptorRequest v) { setField(1, v); }
bool hasRequest() => $_has(0);
void clearRequest() => clearField(1);
bool get success => $_get(1, false);
set success(bool v) { $_setBool(1, v); }
bool hasSuccess() => $_has(1);
void clearSuccess() => clearField(2);
}
class SetNotificationRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('SetNotificationRequest')
..aOS(1, 'remoteId')
..aOS(2, 'serviceUuid')
..aOS(3, 'secondaryServiceUuid')
..aOS(4, 'characteristicUuid')
..aOB(5, 'enable')
..hasRequiredFields = false
;
SetNotificationRequest() : super();
SetNotificationRequest.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
SetNotificationRequest.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
SetNotificationRequest clone() => new SetNotificationRequest()..mergeFromMessage(this);
SetNotificationRequest copyWith(void Function(SetNotificationRequest) updates) => super.copyWith((message) => updates(message as SetNotificationRequest));
$pb.BuilderInfo get info_ => _i;
static SetNotificationRequest create() => new SetNotificationRequest();
static $pb.PbList<SetNotificationRequest> createRepeated() => new $pb.PbList<SetNotificationRequest>();
static SetNotificationRequest getDefault() => _defaultInstance ??= create()..freeze();
static SetNotificationRequest _defaultInstance;
static void $checkItem(SetNotificationRequest v) {
if (v is! SetNotificationRequest) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
String get serviceUuid => $_getS(1, '');
set serviceUuid(String v) { $_setString(1, v); }
bool hasServiceUuid() => $_has(1);
void clearServiceUuid() => clearField(2);
String get secondaryServiceUuid => $_getS(2, '');
set secondaryServiceUuid(String v) { $_setString(2, v); }
bool hasSecondaryServiceUuid() => $_has(2);
void clearSecondaryServiceUuid() => clearField(3);
String get characteristicUuid => $_getS(3, '');
set characteristicUuid(String v) { $_setString(3, v); }
bool hasCharacteristicUuid() => $_has(3);
void clearCharacteristicUuid() => clearField(4);
bool get enable => $_get(4, false);
set enable(bool v) { $_setBool(4, v); }
bool hasEnable() => $_has(4);
void clearEnable() => clearField(5);
}
class SetNotificationResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('SetNotificationResponse')
..aOS(1, 'remoteId')
..a<BluetoothCharacteristic>(2, 'characteristic', $pb.PbFieldType.OM, BluetoothCharacteristic.getDefault, BluetoothCharacteristic.create)
..aOB(3, 'success')
..hasRequiredFields = false
;
SetNotificationResponse() : super();
SetNotificationResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
SetNotificationResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
SetNotificationResponse clone() => new SetNotificationResponse()..mergeFromMessage(this);
SetNotificationResponse copyWith(void Function(SetNotificationResponse) updates) => super.copyWith((message) => updates(message as SetNotificationResponse));
$pb.BuilderInfo get info_ => _i;
static SetNotificationResponse create() => new SetNotificationResponse();
static $pb.PbList<SetNotificationResponse> createRepeated() => new $pb.PbList<SetNotificationResponse>();
static SetNotificationResponse getDefault() => _defaultInstance ??= create()..freeze();
static SetNotificationResponse _defaultInstance;
static void $checkItem(SetNotificationResponse v) {
if (v is! SetNotificationResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
BluetoothCharacteristic get characteristic => $_getN(1);
set characteristic(BluetoothCharacteristic v) { setField(2, v); }
bool hasCharacteristic() => $_has(1);
void clearCharacteristic() => clearField(2);
bool get success => $_get(2, false);
set success(bool v) { $_setBool(2, v); }
bool hasSuccess() => $_has(2);
void clearSuccess() => clearField(3);
}
class OnNotificationResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('OnNotificationResponse')
..aOS(1, 'remoteId')
..a<BluetoothCharacteristic>(2, 'characteristic', $pb.PbFieldType.OM, BluetoothCharacteristic.getDefault, BluetoothCharacteristic.create)
..hasRequiredFields = false
;
OnNotificationResponse() : super();
OnNotificationResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
OnNotificationResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
OnNotificationResponse clone() => new OnNotificationResponse()..mergeFromMessage(this);
OnNotificationResponse copyWith(void Function(OnNotificationResponse) updates) => super.copyWith((message) => updates(message as OnNotificationResponse));
$pb.BuilderInfo get info_ => _i;
static OnNotificationResponse create() => new OnNotificationResponse();
static $pb.PbList<OnNotificationResponse> createRepeated() => new $pb.PbList<OnNotificationResponse>();
static OnNotificationResponse getDefault() => _defaultInstance ??= create()..freeze();
static OnNotificationResponse _defaultInstance;
static void $checkItem(OnNotificationResponse v) {
if (v is! OnNotificationResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
BluetoothCharacteristic get characteristic => $_getN(1);
set characteristic(BluetoothCharacteristic v) { setField(2, v); }
bool hasCharacteristic() => $_has(1);
void clearCharacteristic() => clearField(2);
}
class DeviceStateResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = new $pb.BuilderInfo('DeviceStateResponse')
..aOS(1, 'remoteId')
..e<DeviceStateResponse_BluetoothDeviceState>(2, 'state', $pb.PbFieldType.OE, DeviceStateResponse_BluetoothDeviceState.DISCONNECTED, DeviceStateResponse_BluetoothDeviceState.valueOf, DeviceStateResponse_BluetoothDeviceState.values)
..hasRequiredFields = false
;
DeviceStateResponse() : super();
DeviceStateResponse.fromBuffer(List<int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r);
DeviceStateResponse.fromJson(String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) : super.fromJson(i, r);
DeviceStateResponse clone() => new DeviceStateResponse()..mergeFromMessage(this);
DeviceStateResponse copyWith(void Function(DeviceStateResponse) updates) => super.copyWith((message) => updates(message as DeviceStateResponse));
$pb.BuilderInfo get info_ => _i;
static DeviceStateResponse create() => new DeviceStateResponse();
static $pb.PbList<DeviceStateResponse> createRepeated() => new $pb.PbList<DeviceStateResponse>();
static DeviceStateResponse getDefault() => _defaultInstance ??= create()..freeze();
static DeviceStateResponse _defaultInstance;
static void $checkItem(DeviceStateResponse v) {
if (v is! DeviceStateResponse) $pb.checkItemFailed(v, _i.qualifiedMessageName);
}
String get remoteId => $_getS(0, '');
set remoteId(String v) { $_setString(0, v); }
bool hasRemoteId() => $_has(0);
void clearRemoteId() => clearField(1);
DeviceStateResponse_BluetoothDeviceState get state => $_getN(1);
set state(DeviceStateResponse_BluetoothDeviceState v) { setField(2, v); }
bool hasState() => $_has(1);
void clearState() => clearField(2);
}
@@ -0,0 +1,100 @@
///
// Generated code. Do not modify.
// source: flutterblue.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
// ignore_for_file: UNDEFINED_SHOWN_NAME,UNUSED_SHOWN_NAME
import 'dart:core' show int, dynamic, String, List, Map;
import 'package:protobuf/protobuf.dart' as $pb;
class BluetoothState_State extends $pb.ProtobufEnum {
static const BluetoothState_State UNKNOWN = const BluetoothState_State._(0, 'UNKNOWN');
static const BluetoothState_State UNAVAILABLE = const BluetoothState_State._(1, 'UNAVAILABLE');
static const BluetoothState_State UNAUTHORIZED = const BluetoothState_State._(2, 'UNAUTHORIZED');
static const BluetoothState_State TURNING_ON = const BluetoothState_State._(3, 'TURNING_ON');
static const BluetoothState_State ON = const BluetoothState_State._(4, 'ON');
static const BluetoothState_State TURNING_OFF = const BluetoothState_State._(5, 'TURNING_OFF');
static const BluetoothState_State OFF = const BluetoothState_State._(6, 'OFF');
static const List<BluetoothState_State> values = const <BluetoothState_State> [
UNKNOWN,
UNAVAILABLE,
UNAUTHORIZED,
TURNING_ON,
ON,
TURNING_OFF,
OFF,
];
static final Map<int, BluetoothState_State> _byValue = $pb.ProtobufEnum.initByValue(values);
static BluetoothState_State valueOf(int value) => _byValue[value];
static void $checkItem(BluetoothState_State v) {
if (v is! BluetoothState_State) $pb.checkItemFailed(v, 'BluetoothState_State');
}
const BluetoothState_State._(int v, String n) : super(v, n);
}
class BluetoothDevice_Type extends $pb.ProtobufEnum {
static const BluetoothDevice_Type UNKNOWN = const BluetoothDevice_Type._(0, 'UNKNOWN');
static const BluetoothDevice_Type CLASSIC = const BluetoothDevice_Type._(1, 'CLASSIC');
static const BluetoothDevice_Type LE = const BluetoothDevice_Type._(2, 'LE');
static const BluetoothDevice_Type DUAL = const BluetoothDevice_Type._(3, 'DUAL');
static const List<BluetoothDevice_Type> values = const <BluetoothDevice_Type> [
UNKNOWN,
CLASSIC,
LE,
DUAL,
];
static final Map<int, BluetoothDevice_Type> _byValue = $pb.ProtobufEnum.initByValue(values);
static BluetoothDevice_Type valueOf(int value) => _byValue[value];
static void $checkItem(BluetoothDevice_Type v) {
if (v is! BluetoothDevice_Type) $pb.checkItemFailed(v, 'BluetoothDevice_Type');
}
const BluetoothDevice_Type._(int v, String n) : super(v, n);
}
class WriteCharacteristicRequest_WriteType extends $pb.ProtobufEnum {
static const WriteCharacteristicRequest_WriteType WITH_RESPONSE = const WriteCharacteristicRequest_WriteType._(0, 'WITH_RESPONSE');
static const WriteCharacteristicRequest_WriteType WITHOUT_RESPONSE = const WriteCharacteristicRequest_WriteType._(1, 'WITHOUT_RESPONSE');
static const List<WriteCharacteristicRequest_WriteType> values = const <WriteCharacteristicRequest_WriteType> [
WITH_RESPONSE,
WITHOUT_RESPONSE,
];
static final Map<int, WriteCharacteristicRequest_WriteType> _byValue = $pb.ProtobufEnum.initByValue(values);
static WriteCharacteristicRequest_WriteType valueOf(int value) => _byValue[value];
static void $checkItem(WriteCharacteristicRequest_WriteType v) {
if (v is! WriteCharacteristicRequest_WriteType) $pb.checkItemFailed(v, 'WriteCharacteristicRequest_WriteType');
}
const WriteCharacteristicRequest_WriteType._(int v, String n) : super(v, n);
}
class DeviceStateResponse_BluetoothDeviceState extends $pb.ProtobufEnum {
static const DeviceStateResponse_BluetoothDeviceState DISCONNECTED = const DeviceStateResponse_BluetoothDeviceState._(0, 'DISCONNECTED');
static const DeviceStateResponse_BluetoothDeviceState CONNECTING = const DeviceStateResponse_BluetoothDeviceState._(1, 'CONNECTING');
static const DeviceStateResponse_BluetoothDeviceState CONNECTED = const DeviceStateResponse_BluetoothDeviceState._(2, 'CONNECTED');
static const DeviceStateResponse_BluetoothDeviceState DISCONNECTING = const DeviceStateResponse_BluetoothDeviceState._(3, 'DISCONNECTING');
static const List<DeviceStateResponse_BluetoothDeviceState> values = const <DeviceStateResponse_BluetoothDeviceState> [
DISCONNECTED,
CONNECTING,
CONNECTED,
DISCONNECTING,
];
static final Map<int, DeviceStateResponse_BluetoothDeviceState> _byValue = $pb.ProtobufEnum.initByValue(values);
static DeviceStateResponse_BluetoothDeviceState valueOf(int value) => _byValue[value];
static void $checkItem(DeviceStateResponse_BluetoothDeviceState v) {
if (v is! DeviceStateResponse_BluetoothDeviceState) $pb.checkItemFailed(v, 'DeviceStateResponse_BluetoothDeviceState');
}
const DeviceStateResponse_BluetoothDeviceState._(int v, String n) : super(v, n);
}
@@ -0,0 +1,300 @@
///
// Generated code. Do not modify.
// source: flutterblue.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
const Int32Value$json = const {
'1': 'Int32Value',
'2': const [
const {'1': 'value', '3': 1, '4': 1, '5': 5, '10': 'value'},
],
};
const BluetoothState$json = const {
'1': 'BluetoothState',
'2': const [
const {'1': 'state', '3': 1, '4': 1, '5': 14, '6': '.BluetoothState.State', '10': 'state'},
],
'4': const [BluetoothState_State$json],
};
const BluetoothState_State$json = const {
'1': 'State',
'2': const [
const {'1': 'UNKNOWN', '2': 0},
const {'1': 'UNAVAILABLE', '2': 1},
const {'1': 'UNAUTHORIZED', '2': 2},
const {'1': 'TURNING_ON', '2': 3},
const {'1': 'ON', '2': 4},
const {'1': 'TURNING_OFF', '2': 5},
const {'1': 'OFF', '2': 6},
],
};
const AdvertisementData$json = const {
'1': 'AdvertisementData',
'2': const [
const {'1': 'local_name', '3': 1, '4': 1, '5': 9, '10': 'localName'},
const {'1': 'tx_power_level', '3': 2, '4': 1, '5': 11, '6': '.Int32Value', '10': 'txPowerLevel'},
const {'1': 'connectable', '3': 3, '4': 1, '5': 8, '10': 'connectable'},
const {'1': 'manufacturer_data', '3': 4, '4': 3, '5': 11, '6': '.AdvertisementData.ManufacturerDataEntry', '10': 'manufacturerData'},
const {'1': 'service_data', '3': 5, '4': 3, '5': 11, '6': '.AdvertisementData.ServiceDataEntry', '10': 'serviceData'},
const {'1': 'service_uuids', '3': 6, '4': 3, '5': 9, '10': 'serviceUuids'},
],
'3': const [AdvertisementData_ManufacturerDataEntry$json, AdvertisementData_ServiceDataEntry$json],
};
const AdvertisementData_ManufacturerDataEntry$json = const {
'1': 'ManufacturerDataEntry',
'2': const [
const {'1': 'key', '3': 1, '4': 1, '5': 5, '10': 'key'},
const {'1': 'value', '3': 2, '4': 1, '5': 12, '10': 'value'},
],
'7': const {'7': true},
};
const AdvertisementData_ServiceDataEntry$json = const {
'1': 'ServiceDataEntry',
'2': const [
const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
const {'1': 'value', '3': 2, '4': 1, '5': 12, '10': 'value'},
],
'7': const {'7': true},
};
const ScanSettings$json = const {
'1': 'ScanSettings',
'2': const [
const {'1': 'android_scan_mode', '3': 1, '4': 1, '5': 5, '10': 'androidScanMode'},
const {'1': 'service_uuids', '3': 2, '4': 3, '5': 9, '10': 'serviceUuids'},
],
};
const ScanResult$json = const {
'1': 'ScanResult',
'2': const [
const {'1': 'device', '3': 1, '4': 1, '5': 11, '6': '.BluetoothDevice', '10': 'device'},
const {'1': 'advertisement_data', '3': 2, '4': 1, '5': 11, '6': '.AdvertisementData', '10': 'advertisementData'},
const {'1': 'rssi', '3': 3, '4': 1, '5': 5, '10': 'rssi'},
],
};
const ConnectRequest$json = const {
'1': 'ConnectRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'android_auto_connect', '3': 2, '4': 1, '5': 8, '10': 'androidAutoConnect'},
],
};
const BluetoothDevice$json = const {
'1': 'BluetoothDevice',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
const {'1': 'type', '3': 3, '4': 1, '5': 14, '6': '.BluetoothDevice.Type', '10': 'type'},
],
'4': const [BluetoothDevice_Type$json],
};
const BluetoothDevice_Type$json = const {
'1': 'Type',
'2': const [
const {'1': 'UNKNOWN', '2': 0},
const {'1': 'CLASSIC', '2': 1},
const {'1': 'LE', '2': 2},
const {'1': 'DUAL', '2': 3},
],
};
const BluetoothService$json = const {
'1': 'BluetoothService',
'2': const [
const {'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
const {'1': 'remote_id', '3': 2, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'is_primary', '3': 3, '4': 1, '5': 8, '10': 'isPrimary'},
const {'1': 'characteristics', '3': 4, '4': 3, '5': 11, '6': '.BluetoothCharacteristic', '10': 'characteristics'},
const {'1': 'included_services', '3': 5, '4': 3, '5': 11, '6': '.BluetoothService', '10': 'includedServices'},
],
};
const BluetoothCharacteristic$json = const {
'1': 'BluetoothCharacteristic',
'2': const [
const {'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
const {'1': 'serviceUuid', '3': 2, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondaryServiceUuid', '3': 3, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
const {'1': 'descriptors', '3': 4, '4': 3, '5': 11, '6': '.BluetoothDescriptor', '10': 'descriptors'},
const {'1': 'properties', '3': 5, '4': 1, '5': 11, '6': '.CharacteristicProperties', '10': 'properties'},
const {'1': 'value', '3': 6, '4': 1, '5': 12, '10': 'value'},
],
};
const BluetoothDescriptor$json = const {
'1': 'BluetoothDescriptor',
'2': const [
const {'1': 'uuid', '3': 1, '4': 1, '5': 9, '10': 'uuid'},
const {'1': 'serviceUuid', '3': 2, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'characteristicUuid', '3': 3, '4': 1, '5': 9, '10': 'characteristicUuid'},
const {'1': 'value', '3': 4, '4': 1, '5': 12, '10': 'value'},
],
};
const CharacteristicProperties$json = const {
'1': 'CharacteristicProperties',
'2': const [
const {'1': 'broadcast', '3': 1, '4': 1, '5': 8, '10': 'broadcast'},
const {'1': 'read', '3': 2, '4': 1, '5': 8, '10': 'read'},
const {'1': 'write_without_response', '3': 3, '4': 1, '5': 8, '10': 'writeWithoutResponse'},
const {'1': 'write', '3': 4, '4': 1, '5': 8, '10': 'write'},
const {'1': 'notify', '3': 5, '4': 1, '5': 8, '10': 'notify'},
const {'1': 'indicate', '3': 6, '4': 1, '5': 8, '10': 'indicate'},
const {'1': 'authenticated_signed_writes', '3': 7, '4': 1, '5': 8, '10': 'authenticatedSignedWrites'},
const {'1': 'extended_properties', '3': 8, '4': 1, '5': 8, '10': 'extendedProperties'},
const {'1': 'notify_encryption_required', '3': 9, '4': 1, '5': 8, '10': 'notifyEncryptionRequired'},
const {'1': 'indicate_encryption_required', '3': 10, '4': 1, '5': 8, '10': 'indicateEncryptionRequired'},
],
};
const DiscoverServicesResult$json = const {
'1': 'DiscoverServicesResult',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'services', '3': 2, '4': 3, '5': 11, '6': '.BluetoothService', '10': 'services'},
],
};
const ReadCharacteristicRequest$json = const {
'1': 'ReadCharacteristicRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'characteristic_uuid', '3': 2, '4': 1, '5': 9, '10': 'characteristicUuid'},
const {'1': 'service_uuid', '3': 3, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondary_service_uuid', '3': 4, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
],
};
const ReadCharacteristicResponse$json = const {
'1': 'ReadCharacteristicResponse',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'characteristic', '3': 2, '4': 1, '5': 11, '6': '.BluetoothCharacteristic', '10': 'characteristic'},
],
};
const ReadDescriptorRequest$json = const {
'1': 'ReadDescriptorRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'descriptor_uuid', '3': 2, '4': 1, '5': 9, '10': 'descriptorUuid'},
const {'1': 'service_uuid', '3': 3, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondary_service_uuid', '3': 4, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
const {'1': 'characteristic_uuid', '3': 5, '4': 1, '5': 9, '10': 'characteristicUuid'},
],
};
const ReadDescriptorResponse$json = const {
'1': 'ReadDescriptorResponse',
'2': const [
const {'1': 'request', '3': 1, '4': 1, '5': 11, '6': '.ReadDescriptorRequest', '10': 'request'},
const {'1': 'value', '3': 2, '4': 1, '5': 12, '10': 'value'},
],
};
const WriteCharacteristicRequest$json = const {
'1': 'WriteCharacteristicRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'characteristic_uuid', '3': 2, '4': 1, '5': 9, '10': 'characteristicUuid'},
const {'1': 'service_uuid', '3': 3, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondary_service_uuid', '3': 4, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
const {'1': 'write_type', '3': 5, '4': 1, '5': 14, '6': '.WriteCharacteristicRequest.WriteType', '10': 'writeType'},
const {'1': 'value', '3': 6, '4': 1, '5': 12, '10': 'value'},
],
'4': const [WriteCharacteristicRequest_WriteType$json],
};
const WriteCharacteristicRequest_WriteType$json = const {
'1': 'WriteType',
'2': const [
const {'1': 'WITH_RESPONSE', '2': 0},
const {'1': 'WITHOUT_RESPONSE', '2': 1},
],
};
const WriteCharacteristicResponse$json = const {
'1': 'WriteCharacteristicResponse',
'2': const [
const {'1': 'request', '3': 1, '4': 1, '5': 11, '6': '.WriteCharacteristicRequest', '10': 'request'},
const {'1': 'success', '3': 2, '4': 1, '5': 8, '10': 'success'},
],
};
const WriteDescriptorRequest$json = const {
'1': 'WriteDescriptorRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'descriptor_uuid', '3': 2, '4': 1, '5': 9, '10': 'descriptorUuid'},
const {'1': 'service_uuid', '3': 3, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondary_service_uuid', '3': 4, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
const {'1': 'characteristic_uuid', '3': 5, '4': 1, '5': 9, '10': 'characteristicUuid'},
const {'1': 'value', '3': 6, '4': 1, '5': 12, '10': 'value'},
],
};
const WriteDescriptorResponse$json = const {
'1': 'WriteDescriptorResponse',
'2': const [
const {'1': 'request', '3': 1, '4': 1, '5': 11, '6': '.WriteDescriptorRequest', '10': 'request'},
const {'1': 'success', '3': 2, '4': 1, '5': 8, '10': 'success'},
],
};
const SetNotificationRequest$json = const {
'1': 'SetNotificationRequest',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'service_uuid', '3': 2, '4': 1, '5': 9, '10': 'serviceUuid'},
const {'1': 'secondary_service_uuid', '3': 3, '4': 1, '5': 9, '10': 'secondaryServiceUuid'},
const {'1': 'characteristic_uuid', '3': 4, '4': 1, '5': 9, '10': 'characteristicUuid'},
const {'1': 'enable', '3': 5, '4': 1, '5': 8, '10': 'enable'},
],
};
const SetNotificationResponse$json = const {
'1': 'SetNotificationResponse',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'characteristic', '3': 2, '4': 1, '5': 11, '6': '.BluetoothCharacteristic', '10': 'characteristic'},
const {'1': 'success', '3': 3, '4': 1, '5': 8, '10': 'success'},
],
};
const OnNotificationResponse$json = const {
'1': 'OnNotificationResponse',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'characteristic', '3': 2, '4': 1, '5': 11, '6': '.BluetoothCharacteristic', '10': 'characteristic'},
],
};
const DeviceStateResponse$json = const {
'1': 'DeviceStateResponse',
'2': const [
const {'1': 'remote_id', '3': 1, '4': 1, '5': 9, '10': 'remoteId'},
const {'1': 'state', '3': 2, '4': 1, '5': 14, '6': '.DeviceStateResponse.BluetoothDeviceState', '10': 'state'},
],
'4': const [DeviceStateResponse_BluetoothDeviceState$json],
};
const DeviceStateResponse_BluetoothDeviceState$json = const {
'1': 'BluetoothDeviceState',
'2': const [
const {'1': 'DISCONNECTED', '2': 0},
const {'1': 'CONNECTING', '2': 1},
const {'1': 'CONNECTED', '2': 2},
const {'1': 'DISCONNECTING', '2': 3},
],
};
@@ -0,0 +1,8 @@
///
// Generated code. Do not modify.
// source: flutterblue.proto
///
// ignore_for_file: non_constant_identifier_names,library_prefixes,unused_import
export 'flutterblue.pb.dart';
@@ -0,0 +1,93 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class BluetoothCharacteristic {
final Guid uuid;
final Guid serviceUuid; // The service that this characteristic belongs to.
final Guid
secondaryServiceUuid; // The nested service that this characteristic belongs to.
final CharacteristicProperties properties;
final List<BluetoothDescriptor> descriptors;
bool get isNotifying {
try {
var cccd =
descriptors.singleWhere((d) => d.uuid == BluetoothDescriptor.CCCD);
return ((cccd.value[0] & 0x01) > 0 || (cccd.value[0] & 0x02) > 0);
} catch (e) {
return false;
}
}
List<int> value;
BluetoothCharacteristic(
{@required this.uuid,
@required this.serviceUuid,
this.secondaryServiceUuid,
@required this.descriptors,
@required this.properties});
BluetoothCharacteristic.fromProto(protos.BluetoothCharacteristic p)
: uuid = new Guid(p.uuid),
serviceUuid = new Guid(p.serviceUuid),
secondaryServiceUuid = (p.secondaryServiceUuid.length > 0)
? new Guid(p.secondaryServiceUuid)
: null,
descriptors = p.descriptors
.map((d) => new BluetoothDescriptor.fromProto(d))
.toList(),
properties = new CharacteristicProperties.fromProto(p.properties),
value = p.value;
void updateDescriptors(List<BluetoothDescriptor> newDescriptors) {
for (var d in descriptors) {
for (var newD in newDescriptors) {
if (d.uuid == newD.uuid) {
d.value = newD.value;
}
}
}
}
}
enum CharacteristicWriteType { withResponse, withoutResponse }
class CharacteristicProperties {
final bool broadcast;
final bool read;
final bool writeWithoutResponse;
final bool write;
final bool notify;
final bool indicate;
final bool authenticatedSignedWrites;
final bool extendedProperties;
final bool notifyEncryptionRequired;
final bool indicateEncryptionRequired;
CharacteristicProperties(
{this.broadcast = false,
this.read = false,
this.writeWithoutResponse = false,
this.write = false,
this.notify = false,
this.indicate = false,
this.authenticatedSignedWrites = false,
this.extendedProperties = false,
this.notifyEncryptionRequired = false,
this.indicateEncryptionRequired = false});
CharacteristicProperties.fromProto(protos.CharacteristicProperties p)
: broadcast = p.broadcast,
read = p.read,
writeWithoutResponse = p.writeWithoutResponse,
write = p.write,
notify = p.notify,
indicate = p.indicate,
authenticatedSignedWrites = p.authenticatedSignedWrites,
extendedProperties = p.extendedProperties,
notifyEncryptionRequired = p.notifyEncryptionRequired,
indicateEncryptionRequired = p.indicateEncryptionRequired;
}
@@ -0,0 +1,26 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class BluetoothDescriptor {
static final Guid CCCD = new Guid("00002902-0000-1000-8000-00805f9b34fb");
final Guid uuid;
final Guid serviceUuid; // The service that this descriptor belongs to.
final Guid
characteristicUuid; // The characteristic that this descriptor belongs to.
List<int> value;
BluetoothDescriptor(
{@required this.uuid,
@required this.serviceUuid,
@required this.characteristicUuid});
BluetoothDescriptor.fromProto(protos.BluetoothDescriptor p)
: uuid = new Guid(p.uuid),
serviceUuid = new Guid(p.serviceUuid),
characteristicUuid = new Guid(p.characteristicUuid),
value = p.value;
}
@@ -0,0 +1,238 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class BluetoothDevice {
final DeviceIdentifier id;
final String name;
final BluetoothDeviceType type;
BluetoothDevice(
{@required this.id, this.name, this.type = BluetoothDeviceType.unknown});
BluetoothDevice.fromProto(protos.BluetoothDevice p)
: id = new DeviceIdentifier(p.remoteId),
name = p.name,
type = BluetoothDeviceType.values[p.type.value];
/// Discovers services offered by the remote device as well as their characteristics and descriptors
Future<List<BluetoothService>> discoverServices() async {
var response = FlutterBlue.instance._servicesDiscoveredChannel
.receiveBroadcastStream()
.map((buffer) => new protos.DiscoverServicesResult.fromBuffer(buffer))
.where((p) => p.remoteId == id.toString())
.map((p) => p.services)
.map((s) => s.map((p) => new BluetoothService.fromProto(p)).toList())
.first;
await FlutterBlue.instance._channel
.invokeMethod('discoverServices', id.toString());
return response;
}
/// Returns a list of Bluetooth GATT services offered by the remote device
/// This function requires that discoverServices has been completed for this device
Future<List<BluetoothService>> get services {
return FlutterBlue.instance._channel
.invokeMethod('services', id.toString())
.then((buffer) =>
new protos.DiscoverServicesResult.fromBuffer(buffer).services)
.then((i) => i.map((s) => new BluetoothService.fromProto(s)).toList());
}
/// Retrieves the value of a specified characteristic
Future<List<int>> readCharacteristic(
BluetoothCharacteristic characteristic) async {
var request = protos.ReadCharacteristicRequest.create()
..remoteId = id.toString()
..characteristicUuid = characteristic.uuid.toString()
..serviceUuid = characteristic.serviceUuid.toString();
FlutterBlue.instance._log(LogLevel.info,
'remoteId: ${id.toString()} characteristicUuid: ${characteristic.uuid.toString()} serviceUuid: ${characteristic.serviceUuid.toString()}');
await FlutterBlue.instance._channel
.invokeMethod('readCharacteristic', request.writeToBuffer());
return await FlutterBlue.instance._characteristicReadChannel
.receiveBroadcastStream()
.map((buffer) =>
new protos.ReadCharacteristicResponse.fromBuffer(buffer))
.where((p) =>
(p.remoteId == request.remoteId) &&
(p.characteristic.uuid == request.characteristicUuid) &&
(p.characteristic.serviceUuid == request.serviceUuid))
.map((p) => p.characteristic.value)
.first
.then((d) => characteristic.value = d);
}
/// Retrieves the value of a specified descriptor
Future<List<int>> readDescriptor(BluetoothDescriptor descriptor) async {
var request = protos.ReadDescriptorRequest.create()
..remoteId = id.toString()
..descriptorUuid = descriptor.uuid.toString()
..characteristicUuid = descriptor.characteristicUuid.toString()
..serviceUuid = descriptor.serviceUuid.toString();
await FlutterBlue.instance._channel
.invokeMethod('readDescriptor', request.writeToBuffer());
return await FlutterBlue.instance._descriptorReadChannel
.receiveBroadcastStream()
.map((buffer) => new protos.ReadDescriptorResponse.fromBuffer(buffer))
.where((p) =>
(p.request.remoteId == request.remoteId) &&
(p.request.descriptorUuid == request.descriptorUuid) &&
(p.request.characteristicUuid == request.characteristicUuid) &&
(p.request.serviceUuid == request.serviceUuid))
.map((d) => d.value)
.first
.then((d) => descriptor.value = d);
}
/// Writes the value of a characteristic.
/// [CharacteristicWriteType.withoutResponse]: the write is not
/// guaranteed and will return immediately with success.
/// [CharacteristicWriteType.withResponse]: the method will return after the
/// write operation has either passed or failed.
Future<Null> writeCharacteristic(
BluetoothCharacteristic characteristic, List<int> value,
{CharacteristicWriteType type =
CharacteristicWriteType.withoutResponse}) async {
var request = protos.WriteCharacteristicRequest.create()
..remoteId = id.toString()
..characteristicUuid = characteristic.uuid.toString()
..serviceUuid = characteristic.serviceUuid.toString()
..writeType =
protos.WriteCharacteristicRequest_WriteType.valueOf(type.index)
..value = value;
var result = await FlutterBlue.instance._channel
.invokeMethod('writeCharacteristic', request.writeToBuffer());
if (type == CharacteristicWriteType.withoutResponse) {
return result;
}
return await FlutterBlue.instance._methodStream
.where((m) => m.method == "WriteCharacteristicResponse")
.map((m) => m.arguments)
.map((buffer) =>
new protos.WriteCharacteristicResponse.fromBuffer(buffer))
.where((p) =>
(p.request.remoteId == request.remoteId) &&
(p.request.characteristicUuid == request.characteristicUuid) &&
(p.request.serviceUuid == request.serviceUuid))
.first
.then((w) => w.success)
.then((success) => (!success)
? throw new Exception('Failed to write the characteristic')
: null)
.then((_) => characteristic.value = value)
.then((_) => null);
}
/// Writes the value of a descriptor
Future<Null> writeDescriptor(
BluetoothDescriptor descriptor, List<int> value) async {
var request = protos.WriteDescriptorRequest.create()
..remoteId = id.toString()
..descriptorUuid = descriptor.uuid.toString()
..characteristicUuid = descriptor.characteristicUuid.toString()
..serviceUuid = descriptor.serviceUuid.toString()
..value = value;
await FlutterBlue.instance._channel
.invokeMethod('writeDescriptor', request.writeToBuffer());
return await FlutterBlue.instance._methodStream
.where((m) => m.method == "WriteDescriptorResponse")
.map((m) => m.arguments)
.map((buffer) => new protos.WriteDescriptorResponse.fromBuffer(buffer))
.where((p) =>
(p.request.remoteId == request.remoteId) &&
(p.request.descriptorUuid == request.descriptorUuid) &&
(p.request.characteristicUuid == request.characteristicUuid) &&
(p.request.serviceUuid == request.serviceUuid))
.first
.then((w) => w.success)
.then((success) => (!success)
? throw new Exception('Failed to write the descriptor')
: null)
.then((_) => descriptor.value = value)
.then((_) => null);
}
/// Sets notifications or indications for the value of a specified characteristic
Future<bool> setNotifyValue(
BluetoothCharacteristic characteristic, bool notify) async {
var request = protos.SetNotificationRequest.create()
..remoteId = id.toString()
..serviceUuid = characteristic.serviceUuid.toString()
..characteristicUuid = characteristic.uuid.toString()
..enable = notify;
await FlutterBlue.instance._channel
.invokeMethod('setNotification', request.writeToBuffer());
return await FlutterBlue.instance._methodStream
.where((m) => m.method == "SetNotificationResponse")
.map((m) => m.arguments)
.map((buffer) => new protos.SetNotificationResponse.fromBuffer(buffer))
.where((p) =>
(p.remoteId == request.remoteId) &&
(p.characteristic.uuid == request.characteristicUuid) &&
(p.characteristic.serviceUuid == request.serviceUuid))
.first
.then((p) => new BluetoothCharacteristic.fromProto(p.characteristic))
.then((c) {
characteristic.updateDescriptors(c.descriptors);
characteristic.value = c.value;
return (c.isNotifying == notify);
});
}
/// Notifies when the characteristic's value has changed.
/// setNotification() should be run first to enable them on the peripheral
Stream<List<int>> onValueChanged(BluetoothCharacteristic characteristic) {
return FlutterBlue.instance._methodStream
.where((m) => m.method == "OnValueChanged")
.map((m) => m.arguments)
.map((buffer) => new protos.OnNotificationResponse.fromBuffer(buffer))
.where((p) => p.remoteId == id.toString())
.map((p) => new BluetoothCharacteristic.fromProto(p.characteristic))
.where((c) => c.uuid == characteristic.uuid)
.map((c) {
characteristic.updateDescriptors(c.descriptors);
characteristic.value = c.value;
return c.value;
});
}
/// The current connection state of the device
Future<BluetoothDeviceState> get state => FlutterBlue.instance._channel
.invokeMethod('deviceState', id.toString())
.then((buffer) => new protos.DeviceStateResponse.fromBuffer(buffer))
.then((p) => BluetoothDeviceState.values[p.state.value]);
/// Notifies when the device connection state has changed
Stream<BluetoothDeviceState> onStateChanged() {
return FlutterBlue.instance._methodStream
.where((m) => m.method == "DeviceState")
.map((m) => m.arguments)
.map((buffer) => new protos.DeviceStateResponse.fromBuffer(buffer))
.where((p) => p.remoteId == id.toString())
.map((p) => BluetoothDeviceState.values[p.state.value]);
}
/// Indicates whether the Bluetooth Device can send a write without response
Future<bool> get canSendWriteWithoutResponse =>
new Future.error(new UnimplementedError());
}
enum BluetoothDeviceType { unknown, classic, le, dual }
enum BluetoothDeviceState { disconnected, connecting, connected, disconnecting }
@@ -0,0 +1,31 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class BluetoothService {
final Guid uuid;
final DeviceIdentifier deviceId;
final bool isPrimary;
final List<BluetoothCharacteristic> characteristics;
final List<BluetoothService> includedServices;
BluetoothService(
{@required this.uuid,
@required this.deviceId,
@required this.isPrimary,
@required this.characteristics,
@required this.includedServices});
BluetoothService.fromProto(protos.BluetoothService p)
: uuid = new Guid(p.uuid),
deviceId = new DeviceIdentifier(p.remoteId),
isPrimary = p.isPrimary,
characteristics = p.characteristics
.map((c) => new BluetoothCharacteristic.fromProto(c))
.toList(),
includedServices = p.includedServices
.map((s) => new BluetoothService.fromProto(s))
.toList();
}
@@ -0,0 +1,7 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
const NAMESPACE = 'plugins.pauldemarco.com/flutter_blue';
@@ -0,0 +1,252 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class FlutterBlue {
final MethodChannel _channel = const MethodChannel('$NAMESPACE/methods');
final EventChannel _stateChannel = const EventChannel('$NAMESPACE/state');
final EventChannel _scanResultChannel =
const EventChannel('$NAMESPACE/scanResult');
final EventChannel _servicesDiscoveredChannel =
const EventChannel('$NAMESPACE/servicesDiscovered');
final EventChannel _characteristicReadChannel =
const EventChannel('$NAMESPACE/characteristicRead');
final EventChannel _descriptorReadChannel =
const EventChannel('$NAMESPACE/descriptorRead');
final StreamController<MethodCall> _methodStreamController =
new StreamController.broadcast(); // ignore: close_sinks
Stream<MethodCall> get _methodStream => _methodStreamController
.stream; // Used internally to dispatch methods from platform.
/// Singleton boilerplate
FlutterBlue._() {
_channel.setMethodCallHandler((MethodCall call) {
_methodStreamController.add(call);
});
// Send the log level to the underlying platforms.
setLogLevel(logLevel);
}
static FlutterBlue _instance = new FlutterBlue._();
static FlutterBlue get instance => _instance;
/// Log level of the instance, default is all messages (debug).
LogLevel _logLevel = LogLevel.debug;
LogLevel get logLevel => _logLevel;
/// Checks whether the device supports Bluetooth
Future<bool> get isAvailable =>
_channel.invokeMethod('isAvailable').then<bool>((d) => d);
/// Checks if Bluetooth functionality is turned on
Future<bool> get isOn => _channel.invokeMethod('isOn').then<bool>((d) => d);
/// Gets the current state of the Bluetooth module
Future<BluetoothState> get state {
return _channel
.invokeMethod('state')
.then((buffer) => new protos.BluetoothState.fromBuffer(buffer))
.then((s) => BluetoothState.values[s.state.value]);
}
/// Occurs when the bluetooth state has changed
Stream<BluetoothState> onStateChanged() {
return _stateChannel
.receiveBroadcastStream()
.map((buffer) => new protos.BluetoothState.fromBuffer(buffer))
.map((s) => BluetoothState.values[s.state.value]);
}
/// Starts a scan for Bluetooth Low Energy devices
/// Timeout closes the stream after a specified [Duration]
Stream<ScanResult> scan({
ScanMode scanMode = ScanMode.lowLatency,
List<Guid> withServices = const [],
List<Guid> withDevices = const [],
Duration timeout,
}) async* {
var settings = protos.ScanSettings.create()
..androidScanMode = scanMode.value
..serviceUuids.addAll(withServices.map((g) => g.toString()).toList());
StreamSubscription subscription;
StreamController controller;
controller = new StreamController(
onListen: () {
if (timeout != null) {
new Future.delayed(timeout, () => controller.close());
}
},
onCancel: () {
_stopScan();
subscription.cancel();
},
);
await _channel.invokeMethod('startScan', settings.writeToBuffer());
subscription = _scanResultChannel.receiveBroadcastStream().listen(
controller.add,
onError: controller.addError,
onDone: controller.close,
);
yield* controller.stream
.map((buffer) => new protos.ScanResult.fromBuffer(buffer))
.map((p) => new ScanResult.fromProto(p));
}
/// Stops a scan for Bluetooth Low Energy devices
Future _stopScan() => _channel.invokeMethod('stopScan');
/// Establishes a connection to the Bluetooth Device.
/// Returns a stream of [BluetoothDeviceState]
/// Timeout closes the stream after a specified [Duration]
/// To cancel connection to device, simply cancel() the stream subscription
Stream<BluetoothDeviceState> connect(
BluetoothDevice device, {
Duration timeout,
bool autoConnect = true,
}) async* {
var request = protos.ConnectRequest.create()
..remoteId = device.id.toString()
..androidAutoConnect = autoConnect;
var connected = false;
StreamSubscription subscription;
StreamController controller;
controller = new StreamController<BluetoothDeviceState>(
onListen: () {
if (timeout != null) {
new Future.delayed(
timeout, () => (!connected) ? controller.close() : null);
}
},
onCancel: () {
_cancelConnection(device);
subscription.cancel();
},
);
await _channel.invokeMethod('connect', request.writeToBuffer());
subscription = device.onStateChanged().listen(
(data) {
if (data == BluetoothDeviceState.connected) {
_log(LogLevel.info, 'connected!');
connected = true;
}
controller.add(data);
},
onError: controller.addError,
onDone: controller.close,
);
yield* controller.stream;
}
/// Cancels connection to the Bluetooth Device
Future _cancelConnection(BluetoothDevice device) =>
_channel.invokeMethod('disconnect', device.id.toString());
/// Sets the log level of the FlutterBlue instance
/// Messages equal or below the log level specified are stored/forwarded,
/// messages above are dropped.
void setLogLevel(LogLevel level) async {
await _channel.invokeMethod('setLogLevel', level.index);
_logLevel = level;
}
void _log(LogLevel level, String message) {
if (level.index <= _logLevel.index) {
print(message);
}
}
}
/// Log levels for FlutterBlue
enum LogLevel {
emergency,
alert,
critical,
error,
warning,
notice,
info,
debug,
}
/// State of the bluetooth adapter.
enum BluetoothState {
unknown,
unavailable,
unauthorized,
turningOn,
on,
turningOff,
off
}
class ScanMode {
const ScanMode(this.value);
static const lowPower = const ScanMode(0);
static const balanced = const ScanMode(1);
static const lowLatency = const ScanMode(2);
static const opportunistic = const ScanMode(-1);
final int value;
}
class DeviceIdentifier {
final String id;
const DeviceIdentifier(this.id);
@override
String toString() => id;
@override
int get hashCode => id.hashCode;
@override
bool operator ==(other) =>
other is DeviceIdentifier && compareAsciiLowerCase(id, other.id) == 0;
}
class ScanResult {
const ScanResult({this.device, this.advertisementData, this.rssi});
ScanResult.fromProto(protos.ScanResult p)
: device = new BluetoothDevice.fromProto(p.device),
advertisementData =
new AdvertisementData.fromProto(p.advertisementData),
rssi = p.rssi;
final BluetoothDevice device;
final AdvertisementData advertisementData;
final int rssi;
}
class AdvertisementData {
final String localName;
final int txPowerLevel;
final bool connectable;
final Map<int, List<int>> manufacturerData;
final Map<String, List<int>> serviceData;
final List<String> serviceUuids;
AdvertisementData(
{this.localName,
this.txPowerLevel,
this.connectable,
this.manufacturerData,
this.serviceData,
this.serviceUuids});
AdvertisementData.fromProto(protos.AdvertisementData p)
: localName = p.localName,
txPowerLevel =
(p.txPowerLevel.hasValue()) ? p.txPowerLevel.value : null,
connectable = p.connectable,
manufacturerData = p.manufacturerData,
serviceData = p.serviceData,
serviceUuids = p.serviceUuids;
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of flutter_blue;
class Guid {
final List<int> _bytes;
final int _hashCode;
Guid._internal(List<int> bytes)
: _bytes = bytes,
_hashCode = _calcHashCode(bytes);
Guid(String input) : this._internal(_fromString(input));
Guid.fromMac(String input) : this._internal(_fromMacString(input));
Guid.empty() : this._internal(new List.filled(16, 0));
static List<int> _fromMacString(input) {
var bytes = new List<int>.filled(16, 0);
if (input == null) {
throw new ArgumentError("Input was null");
}
input = input.toLowerCase();
final RegExp regex = new RegExp('[0-9a-f]{2}');
Iterable<Match> matches = regex.allMatches(input);
if (matches.length != 6) {
throw new FormatException("The format is invalid: " + input);
}
int i = 0;
for (Match match in matches) {
var hexString = input.substring(match.start, match.end);
bytes[i] = hex.decode(hexString)[0];
i++;
}
return bytes;
}
static List<int> _fromString(input) {
var bytes = new List<int>.filled(16, 0);
if (input == null) {
throw new ArgumentError("Input was null");
}
if (input.length < 32) {
throw new FormatException("The format is invalid");
}
input = input.toLowerCase();
final RegExp regex = new RegExp('[0-9a-f]{2}');
Iterable<Match> matches = regex.allMatches(input);
if (matches.length != 16) {
throw new FormatException("The format is invalid");
}
int i = 0;
for (Match match in matches) {
var hexString = input.substring(match.start, match.end);
bytes[i] = hex.decode(hexString)[0];
i++;
}
return bytes;
}
static int _calcHashCode(List<int> bytes) {
const equality = const ListEquality<int>();
return equality.hash(bytes);
}
@override
String toString() {
String one = hex.encode(_bytes.sublist(0, 4));
String two = hex.encode(_bytes.sublist(4, 6));
String three = hex.encode(_bytes.sublist(6, 8));
String four = hex.encode(_bytes.sublist(8, 10));
String five = hex.encode(_bytes.sublist(10, 16));
return "$one-$two-$three-$four-$five";
}
String toMac() {
String one = hex.encode(_bytes.sublist(0, 1));
String two = hex.encode(_bytes.sublist(1, 2));
String three = hex.encode(_bytes.sublist(2, 3));
String four = hex.encode(_bytes.sublist(3, 4));
String five = hex.encode(_bytes.sublist(4, 5));
String six = hex.encode(_bytes.sublist(5, 6));
return "$one:$two:$three:$four:$five:$six".toUpperCase();
}
List<int> toByteArray() {
return _bytes;
}
operator ==(other) => other is Guid && this.hashCode == other.hashCode;
int get hashCode => _hashCode;
}
+197
View File
@@ -0,0 +1,197 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
syntax = "proto3";
option java_package = "com.pauldemarco.flutterblue";
option java_outer_classname = "Protos";
option objc_class_prefix = "Protos";
// Wrapper message for `int32`.
//
// Allows for nullability of fields in messages
message Int32Value {
// The int32 value.
int32 value = 1;
}
message BluetoothState {
enum State {
UNKNOWN = 0;
UNAVAILABLE = 1;
UNAUTHORIZED = 2;
TURNING_ON = 3;
ON = 4;
TURNING_OFF = 5;
OFF = 6;
};
State state = 1;
}
message AdvertisementData {
string local_name = 1;
Int32Value tx_power_level = 2;
bool connectable = 3;
map<int32, bytes> manufacturer_data = 4; // Map of manufacturers to their data
map<string, bytes> service_data = 5; // Map of service UUIDs to their data.
repeated string service_uuids = 6;
}
message ScanSettings {
int32 android_scan_mode = 1;
repeated string service_uuids = 2;
}
message ScanResult {
BluetoothDevice device = 1; // The received peer's ID.
AdvertisementData advertisement_data = 2;
int32 rssi = 3;
}
message ConnectRequest {
string remote_id = 1;
bool android_auto_connect = 2;
}
message BluetoothDevice {
enum Type {
UNKNOWN = 0;
CLASSIC = 1;
LE = 2;
DUAL = 3;
};
string remote_id = 1;
string name = 2;
Type type = 3;
}
message BluetoothService {
string uuid = 1;
string remote_id = 2;
bool is_primary = 3; // Indicates whether the type of service is primary or secondary.
repeated BluetoothCharacteristic characteristics = 4; // A list of characteristics that have been discovered in this service.
repeated BluetoothService included_services = 5; // A list of included services that have been discovered in this service.
}
message BluetoothCharacteristic {
string uuid = 1;
string serviceUuid = 2; // The service that this characteristic belongs to.
string secondaryServiceUuid = 3; // The secondary service if nested
repeated BluetoothDescriptor descriptors = 4; // A list of descriptors that have been discovered in this characteristic.
CharacteristicProperties properties = 5; // The properties of the characteristic.
bytes value = 6;
}
message BluetoothDescriptor {
string uuid = 1;
string serviceUuid = 2; // The service that this descriptor belongs to.
string characteristicUuid = 3; // The characteristic that this descriptor belongs to.
bytes value = 4;
}
message CharacteristicProperties {
bool broadcast = 1;
bool read = 2;
bool write_without_response = 3;
bool write = 4;
bool notify = 5;
bool indicate = 6;
bool authenticated_signed_writes = 7;
bool extended_properties = 8;
bool notify_encryption_required = 9;
bool indicate_encryption_required = 10;
}
message DiscoverServicesResult {
string remote_id = 1;
repeated BluetoothService services = 2;
}
message ReadCharacteristicRequest {
string remote_id = 1;
string characteristic_uuid = 2;
string service_uuid = 3;
string secondary_service_uuid = 4;
}
message ReadCharacteristicResponse {
string remote_id = 1;
BluetoothCharacteristic characteristic = 2;
}
message ReadDescriptorRequest {
string remote_id = 1;
string descriptor_uuid = 2;
string service_uuid = 3;
string secondary_service_uuid = 4;
string characteristic_uuid = 5;
}
message ReadDescriptorResponse {
ReadDescriptorRequest request = 1;
bytes value = 2;
}
message WriteCharacteristicRequest {
enum WriteType {
WITH_RESPONSE = 0;
WITHOUT_RESPONSE = 1;
}
string remote_id = 1;
string characteristic_uuid = 2;
string service_uuid = 3;
string secondary_service_uuid = 4;
WriteType write_type = 5;
bytes value = 6;
}
message WriteCharacteristicResponse {
WriteCharacteristicRequest request = 1;
bool success = 2;
}
message WriteDescriptorRequest {
string remote_id = 1;
string descriptor_uuid = 2;
string service_uuid = 3;
string secondary_service_uuid = 4;
string characteristic_uuid = 5;
bytes value = 6;
}
message WriteDescriptorResponse {
WriteDescriptorRequest request = 1;
bool success = 2;
}
message SetNotificationRequest {
string remote_id = 1;
string service_uuid = 2;
string secondary_service_uuid = 3;
string characteristic_uuid = 4;
bool enable = 5;
}
message SetNotificationResponse {
string remote_id = 1;
BluetoothCharacteristic characteristic = 2;
bool success = 3;
}
message OnNotificationResponse {
string remote_id = 1;
BluetoothCharacteristic characteristic = 2;
}
message DeviceStateResponse {
enum BluetoothDeviceState {
DISCONNECTED = 0;
CONNECTING = 1;
CONNECTED = 2;
DISCONNECTING = 3;
}
string remote_id = 1;
BluetoothDeviceState state = 2;
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2017, Paul DeMarco.\
// All rights reserved. Use of this source code is governed by a\
// BSD-style license that can be found in the LICENSE file.
# Generate protobuf files in Dart
1. If upgrading, delete all proto files from /home/.pub-cache/bin
1. Clone the latest dart-protoc-plugin from https://github.com/dart-lang/dart-protoc-plugin
1. Run `pub install` inside dart-protoc-plugin
1. Run `pub global activate protoc_plugin` to get .dart files into /home/.pub-cache/bin/
1. Get the latest linux protoc compiler from https://github.com/google/protobuf/releases/ (protoc-X.X.X-linux-x86_64.zip)
1. Copy /bin/protoc into /home/.pub-cache/bin/
1. Run the following commands from the protos folder
```protoc --dart_out=../lib/gen ./flutterblue.proto```
```protoc --objc_out=../ios/gen ./flutterblue.proto```
+23
View File
@@ -0,0 +1,23 @@
name: flutter_blue
description: Bluetooth plugin for Flutter
version: 0.5.0
author: Paul DeMarco <paulmdemarco@gmail.com>
homepage: https://github.com/pauldemarco/flutter_blue
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
convert: '^2.1.1'
protobuf: '^0.10.5'
flutter:
plugin:
androidPackage: com.pauldemarco.flutterblue
pluginClass: FlutterBluePlugin
dev_dependencies:
flutter_test:
sdk: flutter
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

+62
View File
@@ -0,0 +1,62 @@
// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:flutter_blue/flutter_blue.dart';
import 'package:flutter_test/flutter_test.dart';
main() {
group("Guid", () {
test('equality', () {
var guid = new Guid("{00002a43-0000-1000-8000-00805f9b34fb}");
var guid2 = new Guid("00002a43-0000-1000-8000-00805f9b34fb");
expect(guid, guid2);
var mac = new Guid.fromMac("01:02:03:04:05:06");
var mac2 = new Guid.fromMac("01:02:03:04:05:06");
expect(mac, mac2);
});
test('empty()', () {
var guid = new Guid.empty();
expect("[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]",
guid.toByteArray().toString());
});
test('toByteArray()', () {
var guid = new Guid("{00002a43-0000-1000-8000-00805f9b34fb}");
expect("[0, 0, 42, 67, 0, 0, 16, 0, 128, 0, 0, 128, 95, 155, 52, 251]",
guid.toByteArray().toString());
});
test('toString()', () {
var guid = new Guid("{00002a43-0000-1000-8000-00805f9b34fb}");
expect("00002a43-0000-1000-8000-00805f9b34fb", guid.toString());
});
test('fromMac()', () {
var guid = new Guid.fromMac("24:0A:64:50:A4:67");
expect("[36, 10, 100, 80, 164, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]",
guid.toByteArray().toString());
});
test('fromMac()', () {
var guid = new Guid.fromMac("24:0A:64:50:A4:67");
expect("24:0A:64:50:A4:67", guid.toMac());
});
test('hashCode', () {
var guid = new Guid.fromMac("24:0A:64:50:A4:67");
var guid2 = new Guid.fromMac("24:0A:64:50:A4:67");
expect(guid.hashCode, guid2.hashCode);
});
test('empty() equality', () {
var guid = new Guid.empty();
var guid2 = new Guid.empty();
var guid3 = new Guid.fromMac("24:0A:64:50:A4:67");
expect(guid == guid2, true);
expect(guid == guid3, false);
});
});
}