2022年2月19日 星期六

Android Studio - Bluetooth 即時通訊用戶端(Client)程式(四十五)

Android Studio - Bluetooth 即時通訊用戶端(Client)程式(四十五):

雖然 IM / Instant Messaging(即時通訊)互連程式可以使用行業上的協定規範,但需要更多的設置和編程,所以筆者現在是利用 Bluetooth(藍牙) 來使到兩部手機互相直接溝通,不用架構服務器或線上代理,祇是利用 Bluetooth(藍牙)直接互相傳輸資料,使用到 Socket 通訊協定,直接實現點對點傳輸。程式是 IM / Instant Messaging(即時通訊)用戶端(Client)程式。

Android Studio Bluetooth 即時通訊用戶端(Client)程式
  • 操作系統:Windows 7 64-bit 版本
  • 開發環境:Android Studio 4.0.1 版本
  • 原程式:C:\Development\Development_Android\Android_Project\DIY-Android-010-01E Bluetooth IM Client
  • 程式:C:\Development\Development_Android\Android_Project\DIY-Android-010-01E Bluetooth IM Client
Bluetooth 即時通訊用戶端(Client)程式編程步驟:
  • 設定 Bluetooth 許可權限後
  • 設定手機藍牙
  • 啟動手機藍牙
  • 掃描周邊的藍牙設備
  • 顯示周邊藍牙設備資料
  • 選擇藍牙設備作綁定
  • 配對成功,連接設備
  • 在手機設備之間設定傳輸資料

當連接兩台設備設備時,要在兩台設備間創建連接,必須同時實現服務端(Server)和用戶端(Client)機制,其中一台設備(可檢測到的設備)需將自身設置為可接收傳入的連接請求。首先是要配對(配對意味著兩台設備知曉彼此的存在),然後連接完成綁定過程,因此其中一台設備必須開放的服務端,而另一台設備必須發起連接,具有可用於身份驗證的共用鏈路金鑰,並且能夠與彼此建立加密連接。當服務端和用戶端在同一 RFCOMM 通道上分別擁有已連接的 BluetoothSocket 時,二者將被視為彼此連接。藍牙通訊介面與 TCP Socket 相似。可以允許通過 InputStream 和 OutputStream 與其他藍牙設備交換資料,使用 read(byte[]) 和 write(byte[]) 讀取資料並寫入到資料流。

MainActivity.java:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

import android.content.Intent;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.TextView;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Set;

import java.util.UUID;

 

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothSocket;

 

public class MainActivity extends AppCompatActivity {

 

    Button mbtn_server, mbtn_send, mbtn_scan;

    ListView mlv_device;

    TextView mtv_msg, mtv_status, mtv_mode;

    EditText met_msg;

    BluetoothAdapter bluetoothAdapter;

 

    // BluetoothDevice Array Definition

    BluetoothDevice [] bluetoothDevices;

 

    // SendReceive variable

    SendReceive sendReceive;

 

    // Fixed value

    static final int STATE_LISTENING = 1;

    static final int STATE_CONNECTING = 2;

    static final int STATE_CONNECTED = 3;

    static final int STATE_CONNECTION_FAILED = 4;

    static final int STATE_MESSAGE_RECEIVED = 5;

 

    int REQUEST_ENABLE_BLUETOOTH = 1;

    int mStatus;

 

    private static final String APP_NAME = "BluetoothIMApp";

    private static final UUID MY_UUID = UUID.fromString("318c6089-985c-4773-b7ca-4c6130e4209e");

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

 

        mbtn_server = findViewById(R.id.btn_server);

        mbtn_send = findViewById(R.id.btn_send);

        mbtn_scan = findViewById(R.id.btn_scan);

        mlv_device = findViewById(R.id.lv_device);

        mtv_status = findViewById(R.id.tv_status);

        mtv_msg = findViewById(R.id.tv_msg);

        met_msg = findViewById(R.id.et_msg);

        mtv_mode = findViewById(R.id.tv_mode);

 

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

 

        mtv_status.setText("Disconnect");

        mtv_mode.setText("Mode ?");

        mStatus = 0;

 

        if (!bluetoothAdapter.isEnabled()){

            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

            startActivityForResult(enableIntent,REQUEST_ENABLE_BLUETOOTH);

        }

        implementListeners();

    }

 

    private void implementListeners() {

        mbtn_scan.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();

                String[] strings = new String[devices.size()];

                bluetoothDevices =new BluetoothDevice[devices.size()];

                int index=0;

                if (devices.size()>0){

                    for (BluetoothDevice device : devices){

                        bluetoothDevices[index] = device;

                        strings[index] = device.getName();

                        index++;

                    }

 

                    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getApplicationContext(),android.R.layout.simple_list_item_1,strings);

                    mlv_device.setAdapter(arrayAdapter);

                }

            }

        });

 

        mlv_device.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override

            public void onItemClick(AdapterView<?> parent, View view, int i, long id) {

                mtv_mode.setText("Client Mode");

                ClientClass clientClass = new ClientClass(bluetoothDevices[i]);

                clientClass.start();

                mtv_status.setText("Connecting");

            }

        });

 

        mbtn_send.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                String string = String.valueOf(met_msg.getText());

                if (mStatus == 3) {

                    sendReceive.write(string.getBytes());

                }

            }

        });

    }

 

    Handler handler = new Handler(new Handler.Callback() {

        @Override

        public boolean handleMessage(Message msg) {

 

            // Handler : UI Thread is enable communication

            switch (msg.what){

                case STATE_LISTENING:

                    mtv_status.setText("Listening");

                    mStatus = 1;

                    break;

 

                case STATE_CONNECTING:

                    mtv_status.setText("Connecting");

                    mStatus = 2;

                    break;

 

                case STATE_CONNECTED:

                    mtv_status.setText("Connected");

                    mStatus = 3;

                    break;

 

                case STATE_CONNECTION_FAILED:

                    mtv_status.setText("Connection Failed");

                    mStatus = 0;

                    break;

 

                case STATE_MESSAGE_RECEIVED:

                    byte[] readBuffer = (byte[]) msg.obj;

                    String tempMessage = new String(readBuffer,0,msg.arg1);

                    mtv_msg.setText(tempMessage);

                    break;

            }

            return true;

        }

    });

 

 

    // SendReceive

    private class SendReceive extends Thread{

 

        private final BluetoothSocket bluetoothSocket;

        private final InputStream inputStream;

        private final OutputStream outputStream;

 

        public SendReceive(BluetoothSocket socket){

            bluetoothSocket = socket;

            InputStream tempInput = null;

            OutputStream tempOutput = null;

            try {

                tempInput = bluetoothSocket.getInputStream();

                tempOutput = bluetoothSocket.getOutputStream();

            } catch (IOException e) {

                e.printStackTrace();

            }

            inputStream = tempInput;

            outputStream = tempOutput;

        }

 

        public void run(){

            byte [] buffer = new byte[1024];

            int bytes;

            while (true){

                try {

                    bytes = inputStream.read(buffer);

                    handler.obtainMessage(STATE_MESSAGE_RECEIVED,bytes,-1,buffer).sendToTarget();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

 

        // write

        public void write (byte[] bytes){

            try {

                outputStream.write(bytes);

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

}


MainActivity.java - Client Class:

    // Client Class

    private class ClientClass extends Thread{

        private BluetoothDevice device;

        private BluetoothSocket socket;

 

        public ClientClass(BluetoothDevice device1){

            device = device1;

            try{

                socket = device.createRfcommSocketToServiceRecord(MY_UUID);

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

 

        public void run(){

            try {

                socket.connect();

                Message message = Message.obtain();

                message.what = STATE_CONNECTED;

                handler.sendMessage(message);

                sendReceive = new SendReceive(socket);

                sendReceive.start();

 

            } catch (IOException e) {

                e.printStackTrace();

                Message message = Message.obtain();

                message.what = STATE_CONNECTION_FAILED;

                handler.sendMessage(message);

            }

        }

    }


activity¬main.xml:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity">

 

    <TextView

        android:id="@+id/tv_status"

        android:layout_width="120dp"

        android:layout_height="wrap_content"

        android:layout_alignParentTop="true"

        android:layout_alignParentEnd="true"

        android:layout_alignParentRight="true"

        android:layout_marginTop="6dp"

        android:layout_marginEnd="31dp"

        android:layout_marginRight="31dp"

        android:text="STATUS" />

 

    <Button

        android:id="@+id/btn_server"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentStart="true"

        android:layout_alignParentLeft="true"

        android:layout_alignParentTop="true"

        android:layout_marginStart="12dp"

        android:layout_marginLeft="12dp"

        android:layout_marginTop="5dp"

        android:text="SERVER" />

 

    <Button

        android:id="@+id/btn_scan"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentTop="true"

        android:layout_marginStart="19dp"

        android:layout_marginLeft="19dp"

        android:layout_marginTop="5dp"

        android:layout_toEndOf="@+id/btn_server"

        android:layout_toRightOf="@+id/btn_server"

        android:text="DEVICE" />

 

    <ListView

        android:id="@+id/lv_device"

        android:layout_width="358dp"

        android:layout_height="110dp"

        android:layout_alignParentBottom="true"

        android:layout_centerInParent="true"

        android:layout_marginStart="16dp"

        android:layout_marginLeft="16dp"

        android:layout_marginBottom="11dp"

        android:background="@android:color/holo_green_dark" />

 

    <Button

        android:id="@+id/btn_send"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentTop="true"

        android:layout_marginStart="37dp"

        android:layout_marginLeft="37dp"

        android:layout_marginTop="57dp"

        android:background="@android:color/black"

        android:textColor="@android:color/white"

        android:layout_toEndOf="@+id/et_msg"

        android:layout_toRightOf="@+id/et_msg"

        android:text="Send" />

 

    <TextView

        android:id="@+id/tv_msg"

        android:layout_width="390dp"

        android:layout_height="494dp"

        android:layout_below="@+id/et_msg"

        android:layout_alignParentStart="true"

        android:layout_alignParentLeft="true"

        android:layout_centerHorizontal="true"

        android:layout_marginStart="15dp"

        android:layout_marginLeft="15dp"

        android:layout_marginTop="-17dp"

        android:text="Message" />

 

    <EditText

        android:id="@+id/et_msg"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@+id/btn_server"

        android:layout_marginStart="16dp"

        android:layout_marginLeft="16dp"

        android:layout_marginTop="5dp"

        android:layout_marginBottom="28dp"

        android:ems="10"

        android:inputType="textPersonName"

        android:textColor="@android:color/black"

        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintStart_toStartOf="parent" />

 

    <TextView

        android:id="@+id/tv_mode"

        android:layout_width="120dp"

        android:layout_height="wrap_content"

        android:layout_below="@+id/tv_status"

        android:layout_alignParentEnd="true"

        android:layout_alignParentRight="true"

        android:layout_marginTop="5dp"

        android:layout_marginEnd="29dp"

        android:layout_marginRight="29dp"

        android:text="MODE" />

</RelativeLayout>


Android Studio Bluetooth 即時通訊程式
2022年 2月 19日(Sat)天氣報告
氣溫:40.0°F / 4.0°C @ 07:00
風速:每小時 14公里
降雨機會:9%
相對濕度:百分之 87%
天氣:多雲

沒有留言:

張貼留言