杰瑞科技汇

Java蓝牙如何实现设备连接通信?

Of course! Java Bluetooth development is a topic that has evolved significantly over the years. Here’s a comprehensive guide covering the history, modern approaches, and code examples.

The Two Main Approaches in Java

When people talk about "Java Bluetooth," they are usually referring to one of two things:

  1. Java ME (Micro Edition) / Embedded Java: This was the original way to handle Bluetooth on resource-constrained devices like older mobile phones (feature phones). The primary API was the JSR-82 (Java API for Bluetooth (JAB)). This API is now largely obsolete for new mobile development.
  2. Standard Java (SE / EE): This is the approach for desktop, server, or Android applications. It involves using a wrapper library that communicates with the native Bluetooth stack of the operating system (e.g., BlueZ on Linux, Bluetooth Stack on Windows).

The Modern Approach for Desktop & Server: BlueCove

For standard Java applications (not Android), the most common and well-maintained library is BlueCove.

  • What it is: A Java library that implements the JSR-82 specification. It acts as a bridge, allowing your Java code to talk to the operating system's native Bluetooth drivers.
  • Platform Support: It works on Windows, macOS, and Linux (with BlueZ).
  • Key Features:
    • Device Discovery (Scanning)
    • RFCOMM (Serial Port Profile - SPP) for creating simple, reliable data channels.
    • L2CAP for lower-level communication.
    • OBEX (Object Exchange) for file transfers.

Getting Started with BlueCove

  1. Add Dependency (Maven):

    <dependency>
        <groupId>net.sf.bluecove</groupId>
        <artifactId>bluecove</artifactId>
        <version>2.1.1</version>
    </dependency>

    (Note: You might also need bluecove-gpl for Linux, which has fewer licensing restrictions).

  2. Bluetooth Permissions (Crucial on Linux): On Linux, your application needs permissions to access the Bluetooth hardware. You must run your Java application with sudo or add your user to the netdev and bluetooth groups and set appropriate udev rules.


Code Examples with BlueCove

Here are practical examples for common Bluetooth tasks.

Example 1: Discovering Nearby Devices

This code scans for other Bluetooth devices in range and prints their names and addresses.

import javax.bluetooth.*;
import java.util.Vector;
public class BluetoothDeviceDiscovery {
    public static void main(String[] args) {
        // Get the local Bluetooth adapter
        LocalDevice localDevice = null;
        try {
            localDevice = LocalDevice.getLocalDevice();
        } catch (BluetoothStateException e) {
            System.err.println("Bluetooth is not available or not turned on.");
            e.printStackTrace();
            return;
        }
        System.out.println("Local Device: " + localDevice.getBluetoothAddress());
        System.out.println("Local Device Name: " + localDevice.getFriendlyName());
        // Start device discovery
        DiscoveryListener discoveryListener = new MyDiscoveryListener();
        try {
            System.out.println("\nStarting device discovery...");
            localDevice.getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, discoveryListener);
        } catch (BluetoothStateException e) {
            System.err.println("Could not start inquiry.");
            e.printStackTrace();
        }
    }
    // Custom DiscoveryListener to handle discovery events
    static class MyDiscoveryListener implements DiscoveryListener {
        @Override
        public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
            try {
                System.out.println("Device Found: " + btDevice.getFriendlyName(false) + " [" + btDevice.getBluetoothAddress() + "]");
            } catch (IOException e) {
                System.out.println("Device Found: [Unknown Name] [" + btDevice.getBluetoothAddress() + "]");
            }
        }
        @Override
        public void inquiryCompleted(int discType) {
            System.out.println("\nDevice Inquiry Completed.");
            if (discType == DiscoveryListener.INQUIRY_COMPLETED) {
                System.out.println("Successfully completed.");
            } else if (discType == DiscoveryListener.INQUIRY_TERMINATED) {
                System.out.println("Terminated.");
            } else if (discType == DiscoveryListener.INQUIRY_ERROR) {
                System.out.println("Error occurred.");
            }
            System.exit(0); // Exit after discovery is done
        }
        @Override
        public void serviceSearchCompleted(int transID, int respCode) {}
        @Override
        public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {}
    }
}

Example 2: Acting as a Server (SPP)

This code creates a server that listens for incoming Bluetooth connections on the Serial Port Profile (SPP). When a client connects, it reads data from the input stream and prints it.

import javax.bluetooth.*;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.StreamConnectionNotifier;
import java.io.IOException;
import java.io.InputStream;
public class BluetoothServer {
    // The UUID for the Serial Port Profile (SPP)
    // You can generate your own UUID using an online generator.
    private static final String SPP_UUID = "0000110100001000800000805F9B34FB";
    public static void main(String[] args) throws IOException {
        // Get the local Bluetooth adapter
        LocalDevice localDevice = LocalDevice.getLocalDevice();
        localDevice.setDiscoverable(DiscoveryAgent.GIAC); // Make the device discoverable
        System.out.println("Server started. Waiting for clients...");
        // Create the connection URL for the SPP service
        String connectionString = "btspp://localhost:" + SPP_UUID + ";name=Sample SPP Server";
        // Create a notifier and open the connection
        try (StreamConnectionNotifier streamConnNotifier = (StreamConnectionNotifier) Connector.open(connectionString)) {
            // Wait for a client connection
            StreamConnection connection = streamConnNotifier.acceptAndOpen();
            System.out.println("Client connected.");
            // Open an input stream to read data from the client
            try (InputStream inputStream = connection.openInputStream()) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    String receivedData = new String(buffer, 0, bytesRead);
                    System.out.println("Received: " + receivedData);
                }
            }
        }
    }
}

Example 3: Acting as a Client (SPP)

This code scans for a server with a specific UUID and connects to it to send a message.

import javax.bluetooth.*;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import java.io.IOException;
import java.io.OutputStream;
public class BluetoothClient {
    // The UUID must match the server's UUID
    private static final String SPP_UUID = "0000110100001000800000805F9B34FB";
    public static void main(String[] args) throws IOException, InterruptedException {
        // First, find the server device
        RemoteDevice serverDevice = findDeviceByUuid();
        if (serverDevice == null) {
            System.out.println("Server device not found.");
            return;
        }
        System.out.println("Found server: " + serverDevice.getFriendlyName(false));
        // Create the connection URL to the specific device and service
        String connectionString = "btspp://" + serverDevice.getBluetoothAddress() + ":" + SPP_UUID + ";authenticate=false;encrypt=false";
        // Open the connection
        try (StreamConnection connection = (StreamConnection) Connector.open(connectionString)) {
            System.out.println("Connected to server.");
            // Open an output stream to send data
            try (OutputStream outputStream = connection.openOutputStream()) {
                String message = "Hello from Java Client!";
                outputStream.write(message.getBytes());
                System.out.println("Sent: " + message);
            }
        }
    }
    private static RemoteDevice findDeviceByUuid() throws IOException, InterruptedException {
        // This is a simplified discovery. A real app would cache devices or use a more robust method.
        // We'll just start a discovery and look for a device offering our service.
        DiscoveryListener listener = new DiscoveryListener() {
            private RemoteDevice foundDevice = null;
            @Override
            public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                System.out.println("Checking device: " + btDevice.getBluetoothAddress());
                // In a real app, you'd check if this device offers the service you want.
                // For simplicity, we'll just take the first device and check for services.
                this.foundDevice = btDevice;
            }
            @Override
            public void inquiryCompleted(int discType) {
                System.out.println("Inquiry complete.");
            }
            @Override
            public void serviceSearchCompleted(int transID, int respCode) {
                System.out.println("Service search complete.");
            }
            @Override
            public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
                for (ServiceRecord record : servRecord) {
                    String uuidStr = record.getConnectionURL(0, false);
                    if (uuidStr != null && uuidStr.contains(SPP_UUID)) {
                        System.out.println("Found service with matching UUID!");
                        // We can't get the RemoteDevice from the record directly here,
                        // so we rely on deviceDiscovered to have set it.
                        // This example is simplified.
                    }
                }
            }
        };
        LocalDevice localDevice = LocalDevice.getLocalDevice();
        localDevice.getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, listener);
        // Wait a bit for the discovery to complete
        Thread.sleep(15000); // 15 seconds
        // In a real implementation, you'd have a way to get the found device from the listener.
        // This is a placeholder for a more robust mechanism.
        // For now, let's assume you know the server's address.
        // return RemoteDevice.getDevice("00:11:22:33:44:55");
        return null; // Simplified for this example
    }
}

The Android Approach: Android Bluetooth API

Developing for Android is a completely different experience. You do not use BlueCove or JSR-82. Instead, you use Google's dedicated android.bluetooth package.

Key Differences:

  • Permissions: You must declare BLUETOOTH, BLUETOOTH_ADMIN, and on Android 12+ (API 31), BLUETOOTH_CONNECT and BLUETOOTH_SCAN in your AndroidManifest.xml.
  • Asynchronous Operations: Almost all Bluetooth operations (discovery, connection) are asynchronous and use callbacks.
  • Modern APIs: Google has introduced BluetoothAdapter.LeScanCallback for modern, energy-efficient scanning and BluetoothManager for easier access to the adapter.

High-Level Android Workflow:

  1. Get BluetoothAdapter: The entry point for all Bluetooth interactions.
  2. Check if Bluetooth is enabled: Prompt the user to enable it if not.
  3. Discover Devices: Use startDiscovery() with a BroadcastReceiver or a modern LeScanCallback.
  4. Get BluetoothDevice: Represents a remote device.
  5. Connect: Use device.createRfcommSocketToServiceRecord() to get a BluetoothSocket.
  6. Manage Connection: Connect on a background thread. Use socket.getInputStream() and socket.getOutputStream() for communication.

Summary: Which to Use?

Scenario Recommended Approach Key API / Library
Desktop Java App (Windows, macOS, Linux) BlueCove JSR-82 (via BlueCove)
Android App (Modern) Android Bluetooth API android.bluetooth.* package
Android App (Legacy) Android Bluetooth API android.bluetooth.* package
Java ME / Embedded JSR-82 javax.bluetooth.*
Server-Side Java Not Recommended Bluetooth is a short-range technology; use network sockets (TCP/IP) instead.

For any new Java project running on a standard JVM (desktop, server), BlueCove is your best bet. For any Android project, you must use the native Android Bluetooth APIs.

分享:
扫描分享到社交APP
上一篇
下一篇