Add All the files from the touchpad_demonstrator Flutter App which can be build for Android and iOS
@@ -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>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Flutter Plugins" type="FlutterPluginsLibraryType">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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 -> OnCharacteristicChanged. Moved value stream to characteristic. 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	" 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 -> OnCharacteristicChanged. Moved value stream to characteristic. 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>
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,119 @@
|
||||
[](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**.
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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/).
|
||||
@@ -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>
|
||||
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 442 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
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"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
|
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]));
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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```
|
||||
@@ -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
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 35 KiB |
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||