天天看點

Android通過藍牙與PC通信Android通過藍牙與PC通信

Android通過藍牙與PC通信

在程式設計模型上,這裡把電腦設計成伺服器端,用Java實作一個Windows電腦上的藍牙伺服器,名為:

PCBluetoothServer

Java SE

本身并沒有實作藍牙功能子產品,如果在Windows通過Java實作藍牙功能,需要額外的導入兩個jar(64位):

<dependencies>
    <!-- https://mvnrepository.com/ -->
    <dependency>
        <groupId>io.ultreia</groupId>
        <artifactId>bluecove</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>

</dependencies>
           

部署在Windows PC電腦上的藍牙伺服器端代碼

PCBluetoothServer.java

服務端接收到用戶端資訊後,會主動給用戶端回複資訊

public class PCBluetoothServer {
    private String UUID = "0000110100001000800000805F9B34FB";

    public static void main(String[] args) {
        new PCBluetoothServer();
    }

    public PCBluetoothServer() {
        try {
            /**
             * 開啟一個連接配接,等待通路
             */
            String url = "btspp://localhost:" + UUID;
            StreamConnectionNotifier notifier = (StreamConnectionNotifier) Connector
                    .open(url);
            serverLoop(notifier);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void serverLoop(StreamConnectionNotifier notifier) {
        try {
            // infinite loop to accept connections.
            while (true) {
                System.out.println("等待連接配接");
                /**
                 * 阻塞方法acceptAndOpen(),一直等待
                 */
                handleConnection(notifier.acceptAndOpen());
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * 處理連接配接請求,使用線程異步處理,避免一直等待處理完成
     * 先要接收到用戶端資訊,才可以繼續執行
     * @param conn
     * @throws IOException
     */
    private void handleConnection(StreamConnection conn) throws IOException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OutputStream out = conn.openOutputStream();
                    InputStream in = conn.openInputStream();
                    DataOutputStream dos = new DataOutputStream(out);
                    DataInputStream dis = new DataInputStream(in);
                    // 阻塞方法
                    String read = dis.readUTF();
                    System.out.println("接收到Client:" + read);
					//給用戶端回複資訊
                    dos.writeUTF("Server receive you Msg,Thank you!");
                    dos.close();
                    dis.close();
                    conn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
           

Android用戶端

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
/**
 * Android手機用戶端通過藍牙發送資料到部署在Windows PC電腦上。
 * 如果運作失敗,請打開手機的設定,檢查是否賦予該App權限:
 *
 * <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 * <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 *
 * <uses-permission android:name="android.permission.BLUETOOTH" />
 * <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
 *
 * Android手機的藍牙用戶端。
 * 代碼啟動後檢查目前手機是否已經和藍牙名稱為  TARGET_DEVICE_NAME 的配對成功。
 * 本程式為測試程式,需要先手動使藍牙與PC進行配對
 * TARGET_DEVICE_NAME 為PC端配對的藍牙裝置名
 * MY_UUID 與PC端應該保持一緻
 *
 */
public class MainActivity extends AppCompatActivity {

    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothServerSocket serverSocket;

    //要連接配接的目标藍牙裝置。
    private final String TARGET_DEVICE_NAME = "DELL-PC";

    private final String TAG = "藍牙調試";
    private final String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";


    /**
     * @param
     * @return
     * @description 獲得和目前Android已經配對的藍牙裝置
     * @date: 2020/4/5 10:05
     * @author: lxf
     */
    private BluetoothDevice getPairedDevices() {

        // 獲得和目前Android已經配對的藍牙裝置。
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
        for (BluetoothDevice pairedDevice : pairedDevices) {
            // 把已經取得配對的藍牙裝置名字和位址列印出來。
            Log.d(TAG, pairedDevice.getName() + " : " + pairedDevice.getAddress());
            if (TextUtils.equals(TARGET_DEVICE_NAME, pairedDevice.getName())) {
                Log.d(TAG, "已配對目标裝置 -> " + TARGET_DEVICE_NAME);
                return pairedDevice;
            }
        }
        return null;
    }


    /**
     * 開啟藍牙
     */
    private void openBluetooth() {
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothDevice device = getPairedDevices();
        if (device == null) {
            // 注冊廣播接收器。
            // 接收藍牙發現訊息。
//            IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
//            registerReceiver(mBroadcastReceiver, filter);
//            if (mBluetoothAdapter.startDiscovery()) {
//                Log.d(TAG, "啟動藍牙掃描裝置...");
//            }
        } else {
            try {
                connectService(device, MY_UUID);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


    private void connectService(BluetoothDevice device, String uuid) throws IOException {

        try (BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));) {
            Log.d(TAG, "連接配接服務端...");
            socket.connect();
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            /**
             * 阻塞方法
             */
            dos.writeUTF("hello server, I am client");
            dos.flush();

            DataInputStream dis = new DataInputStream(socket.getInputStream());
            /**
             * 阻塞方法
             */
            String readUTF = dis.readUTF();
            System.out.println("接收到服務端資訊:" + readUTF);
            TextView textView = findViewById(R.id.textView);
            textView.setText(readUTF);
            textView.setTextColor(Color.RED);

            dos.close();
            dis.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button myBtn = findViewById(R.id.myBtn);
        myBtn.setOnClickListener(v -> {
            Toast.makeText(MainActivity.this, "開啟藍牙", Toast.LENGTH_SHORT).show();
            openBluetooth();
        });
    }
}
           

用戶端運作結果

Android通過藍牙與PC通信Android通過藍牙與PC通信

服務端運作結果

Android通過藍牙與PC通信Android通過藍牙與PC通信