Skip to content

Commit

Permalink
Merge branch 'feature/new_package'
Browse files Browse the repository at this point in the history
  • Loading branch information
Erhannis committed Jul 1, 2023
2 parents 06a061c + 0c0509c commit 0dba3fd
Show file tree
Hide file tree
Showing 42 changed files with 1,776 additions and 297 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.5.0] - 2023-07-01

Glued in BLE support from https://github.com/kai-morich/SimpleBluetoothLeTerminal

## [0.4.0] - 2021-08-17

Update flutter plugin v2.
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

# `flutter_bluetooth_serial`
# `flutter_bluetooth_serial_ble`

[![pub package](https://img.shields.io/pub/v/flutter_bluetooth_serial.svg)](https://pub.dartlang.org/packages/flutter_bluetooth_serial)
[![pub package](https://img.shields.io/pub/v/flutter_bluetooth_serial_ble.svg)](https://pub.dartlang.org/packages/flutter_bluetooth_serial_ble)

Flutter basic implementation for Classical Bluetooth (only RFCOMM for now).
Flutter basic implementation for Classical Bluetooth (only RFCOMM for now), and now also BLE. I hacked out parts of [SimpleBluetoothLeTerminal](https://github.com/kai-morich/SimpleBluetoothLeTerminal) and glued them to [flutter_bluetooth_serial](https://github.com/edufolly/flutter_bluetooth_serial) and now `BluetoothConnection.toAddress` accepts a second parameter, `type`, defaulting to `AUTO`, giving the behavior of trying to connect with the usual BT Classic mechanism first, then switching to BLE if that fails. (Note this makes the default behavior slow to connect to a BLE device.) It should work out of the box, a drop-in replacement of the previous version, aside from the addition of two "_ble"s to the imports. Hasn't been tested very rigorously yet, sorry. I do note that BLE connection fails the first time I try after installing the app, and is fine after that - probably some permissions thing in the wrong place. Check permissions if you have trouble.


## Features
Expand Down Expand Up @@ -36,7 +36,7 @@ For now there is only Android support.
# Add dependency to `pubspec.yaml` of your project.
dependencies:
# ...
flutter_bluetooth_serial: ^0.3.2
flutter_bluetooth_serial_ble: ^0.5.0
```
#### Installing
Expand All @@ -50,7 +50,7 @@ flutter pub get

#### Importing
```dart
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:flutter_bluetooth_serial_ble/flutter_bluetooth_serial_ble.dart';
```

#### Usage
Expand Down Expand Up @@ -106,6 +106,7 @@ You might also want to check [milestones](https://github.com/edufolly/flutter_bl
- [Eduardo Folly](mailto:[email protected])
- [Martin Mauch](mailto:[email protected])
- [Patryk Ludwikowski](mailto:[email protected])
- https://github.com/kai-morich/SimpleBluetoothLeTerminal for BLE code

After version 0.3.0 we have a lot of collaborators. If you would like to be credited, please send me an [email](mailto:[email protected]).

Expand Down
5 changes: 3 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.0.0'
}
}
rootProject.allprojects {
Expand All @@ -18,7 +18,7 @@ rootProject.allprojects {
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 30
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
Expand All @@ -34,6 +34,7 @@ android {
implementation 'androidx.appcompat:appcompat:1.3.0'
}
buildToolsVersion '30.0.3'
namespace 'io.github.edufolly.flutterbluetoothserial'
}

dependencies {
Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
2 changes: 1 addition & 1 deletion android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'flutter_bluetooth_serial'
rootProject.name = 'flutter_bluetooth_serial_ble'
14 changes: 14 additions & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
package="io.github.edufolly.flutterbluetoothserial">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<!-- From SimpleBluetoothLeTerminal -->
<!-- <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />-->
<!-- &lt;!&ndash; <= 30 + Xiaomi/MIUI &ndash;&gt;-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="32"/>-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>-->
<!-- <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>-->
<!-- >= API 31 -->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" />-->
<!-- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>-->

</manifest>
Original file line number Diff line number Diff line change
@@ -1,186 +1,20 @@
package io.github.edufolly.flutterbluetoothserial;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.util.Arrays;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;

/// Universal Bluetooth serial connection class (for Java)
public abstract class BluetoothConnection
{
protected static final UUID DEFAULT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

protected BluetoothAdapter bluetoothAdapter;

protected ConnectionThread connectionThread = null;

public boolean isConnected() {
return connectionThread != null && connectionThread.requestedClosing != true;
}



public BluetoothConnection(BluetoothAdapter bluetoothAdapter) {
this.bluetoothAdapter = bluetoothAdapter;
}



// @TODO . `connect` could be done perfored on the other thread
// @TODO . `connect` parameter: timeout
// @TODO . `connect` other methods than `createRfcommSocketToServiceRecord`, including hidden one raw `createRfcommSocket` (on channel).
// @TODO ? how about turning it into factoried?
public interface BluetoothConnection {
public boolean isConnected();
/// Connects to given device by hardware address
public void connect(String address, UUID uuid) throws IOException {
if (isConnected()) {
throw new IOException("already connected");
}

BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if (device == null) {
throw new IOException("device not found");
}

BluetoothSocket socket = device.createRfcommSocketToServiceRecord(uuid); // @TODO . introduce ConnectionMethod
if (socket == null) {
throw new IOException("socket connection not established");
}

// Cancel discovery, even though we didn't start it
bluetoothAdapter.cancelDiscovery();

socket.connect();

connectionThread = new ConnectionThread(socket);
connectionThread.start();
}
public void connect(String address, UUID uuid) throws IOException;
/// Connects to given device by hardware address (default UUID used)
public void connect(String address) throws IOException {
connect(address, DEFAULT_UUID);
}

public void connect(String address) throws IOException;
/// Disconnects current session (ignore if not connected)
public void disconnect() {
if (isConnected()) {
connectionThread.cancel();
connectionThread = null;
}
}

/// Writes to connected remote device
public void write(byte[] data) throws IOException {
if (!isConnected()) {
throw new IOException("not connected");
}

connectionThread.write(data);
}

public void disconnect();
/// Writes to connected remote device
public void write(byte[] data) throws IOException;
/// Callback for reading data.
protected abstract void onRead(byte[] data);

public void onRead(byte[] data);
/// Callback for disconnection.
protected abstract void onDisconnected(boolean byRemote);

/// Thread to handle connection I/O
private class ConnectionThread extends Thread {
private final BluetoothSocket socket;
private final InputStream input;
private final OutputStream output;
private boolean requestedClosing = false;

ConnectionThread(BluetoothSocket socket) {
this.socket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;

try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}

this.input = tmpIn;
this.output = tmpOut;
}

/// Thread main code
public void run() {
byte[] buffer = new byte[1024];
int bytes;

while (!requestedClosing) {
try {
bytes = input.read(buffer);

onRead(Arrays.copyOf(buffer, bytes));
} catch (IOException e) {
// `input.read` throws when closed by remote device
break;
}
}

// Make sure output stream is closed
if (output != null) {
try {
output.close();
}
catch (Exception e) {}
}

// Make sure input stream is closed
if (input != null) {
try {
input.close();
}
catch (Exception e) {}
}

// Callback on disconnected, with information which side is closing
onDisconnected(!requestedClosing);

// Just prevent unnecessary `cancel`ing
requestedClosing = true;
}

/// Writes to output stream
public void write(byte[] bytes) {
try {
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}

/// Stops the thread, disconnects
public void cancel() {
if (requestedClosing) {
return;
}
requestedClosing = true;

// Flush output buffers befoce closing
try {
output.flush();
}
catch (Exception e) {}

// Close the connection socket
if (socket != null) {
try {
// Might be useful (see https://stackoverflow.com/a/22769260/4880243)
Thread.sleep(111);

socket.close();
}
catch (Exception e) {}
}
}
}
public void onDisconnected(boolean byRemote);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.github.edufolly.flutterbluetoothserial;

public abstract class BluetoothConnectionBase implements io.github.edufolly.flutterbluetoothserial.BluetoothConnection {
public interface OnReadCallback {
public void onRead(byte[] data);
}
public interface OnDisconnectedCallback {
public void onDisconnected(boolean byRemote);
}

final OnReadCallback onReadCallback;
final OnDisconnectedCallback onDisconnectedCallback;

public BluetoothConnectionBase(OnReadCallback onReadCallback, OnDisconnectedCallback onDisconnectedCallback) {
this.onReadCallback = onReadCallback;
this.onDisconnectedCallback = onDisconnectedCallback;
}

public void onRead(byte[] data) {
onReadCallback.onRead(data);
}

public void onDisconnected(boolean byRemote) {
onDisconnectedCallback.onDisconnected(byRemote);
}
}
Loading

0 comments on commit 0dba3fd

Please sign in to comment.