본문 바로가기

Programming/Android

Android<->Mac Bluetooth 연결하기

반응형

Mac 을 Server로 하고 Android를 Client로 하여 서로 데이터를 주고 받도록 하는 것이 1차 목표였다.

둘의 통신은 BLE가 아닌 기본 Bluetooth 이다.

Mac은 IOBluetooth를 사용하지 않고 Python LightBlue library를 사용하여 작성하였다.

아래는 기본 테스트이므로 접속이 완료되면 데이터를 주고 받고 끝난다.


Android Code

package com.yhg.bluetoothclient;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Set;
import java.util.UUID;


public class MyActivity extends ActionBarActivity {
    private final int REQUEST_ENABLE_BT = 10;
    private final String SERVICE_UUID = "00001101-0000-1000-8000-00805F9B34FB";
    private final String TAG = "ChopeTest";
    private BluetoothAdapter mBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "bluetooth not supported", Toast.LENGTH_SHORT).show();
            return;
        }

        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }
        else {
            connectServer();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_OK) {
            connectServer();
        }
    }

    private void connectServer() {
        Set pairedDevices = mBluetoothAdapter.getBondedDevices();
        BluetoothDevice pairedDevice = null;

        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                Log.d(TAG, device.getName() + "\n" + device.getAddress());

                // 테스트를 빠르게 하기 위해...
                pairedDevice = device;
                break;
            }
        }

        if (pairedDevice != null) {
            new ConnectThread(pairedDevice).start();
        }
    }

    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
        public ConnectThread(BluetoothDevice device) {
            // Use a temporary object that is later assigned to mmSocket,
            // because mmSocket is final
            BluetoothSocket tmp = null;
            mmDevice = device;

            // Get a BluetoothSocket to connect with the given BluetoothDevice
            try {
                // MY_UUID is the app's UUID string, also used by the server code
                tmp = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString(SERVICE_UUID));
            } catch (IOException e) { }
            mmSocket = tmp;
        }

        public void run() {
            // Cancel discovery because it will slow down the connection
            mBluetoothAdapter.cancelDiscovery();

            try {
                // Connect the device through the socket. This will block
                // until it succeeds or throws an exception
                mmSocket.connect();
            } catch (IOException connectException) {
                // Unable to connect; close the socket and get out
                connectException.printStackTrace();
                try {
                    mmSocket.close();
                } catch (IOException closeException) { }
                return;
            }

            // Do work to manage the connection (in a separate thread)
            ReaderThread thread = new ReaderThread(mmSocket);
            thread.start();
        }

        /** Will cancel an in-progress connection, and close the socket */
        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) { }
        }
    }

    private class ReaderThread extends Thread {
        private InputStreamReader mReader;

        public ReaderThread(BluetoothSocket socket) {
            try {
                mReader = new InputStreamReader(socket.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            char[] buffer = new char[255];

            try {
                int len = mReader.read(buffer);
                String content = new String(buffer, 0, len);
                Log.d(TAG, "receive data : "+content);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


Python Code

import lightblue

s = lightblue.socket()
s.bind((lightblue.gethostaddr(), 0))  # bind to 0 to bind to dynamically assigned port 
s.listen(1)
lightblue.advertise("00001101-0000-1000-8000-00805F9B34FB", s, lightblue.RFCOMM)
conn, addr = s.accept()
print "Connected by", addr
conn.send("Hi Chope!")
conn.close()
s.close()


처음에 service uuid를 uuidgen으로 생성하니 연결이 안되서 한참을 헤맸다….

기존에 존재하는 service uuid만 사용해야 할것 같다.


실행해 보면 정상적으로 연결되는 것을 확인할 수 있다.


데이터를 계속 주고받는 테스트를 해봐야지 :)



반응형