실리의 프로그램 사이트

유니티로 핸드폰과 컴퓨터간의 블루투스 통신을 해보자(3차 작업) 본문

Unity 강좌

유니티로 핸드폰과 컴퓨터간의 블루투스 통신을 해보자(3차 작업)

sillyknight 2017. 3. 8. 17:16


다른 작업을 하느라 글 쓰는게 늦어졌네요.


그럼 이제 저번 강좌 뒷부분을 시작해보겠습니다.


이제 build 방법을 jar 파일 생성으로 바꿀 겁니다.


아래의 build.gradle을 수정할 겁니다.

apply plugin: 'com.android.application' --> apply plugin: 'com.android.library'


android {
compileSdkVersion 24
buildToolsVersion "24.0.3"
defaultConfig {           applicationId "com.sillyent.unitybluetoothcode"    --> 삭제
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1                                        --> 삭제
        versionName "1.0"                                    --> 삭제
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" --> 삭제
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}


dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
-------------------------------------------------------------삭제 시작------------------------------
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
-------------------------------------------------------------삭제 완료------------------------------
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    compile files('libs/classes.jar')
-------------------------------------------------------------추가 시작------------------------------
}


task deleteObjectJar(type: Delete){
    delete 'release/UnityBluetoothCode.jar'
}


task exportJar(type: Copy){
    from('build/intermediates/bundles/release/')
    into('release/')
    include('classes.jar')
    rename('classes.jar', 'UnityBluetoothCode.jar')
}

exportJar.dependsOn(deleteObjectJar, build)
-------------------------------------------------------------추가 완료------------------------------


위와 같이 변경 하면 아래와 같은 완성본이 나옵니다.



apply plugin: 'com.android.library'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.3"
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 24
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    compile files('libs/classes.jar')
}

task deleteObjectJar(type: Delete){
    delete 'release/UnityBluetoothCode.jar'
}


task exportJar(type: Copy){
    from('build/intermediates/bundles/release/')
    into('release/')
    include('classes.jar')
    rename('classes.jar', 'UnityBluetoothCode.jar')
}

exportJar.dependsOn(deleteObjectJar, build)


위와 같은 작업을 다 끝내고 나면 이제 싱크를 맞춰야 합니다. Sync Now를 클릭해줍니다.





이제부터 실제로 유니티에서 통신을 할 수 있도록 프로그래밍을 할 겁니다.



1. 자바 클래스를 생성해줍니다.







2. AndroidManifest 부분을 수정해줍니다.



<수정 전>

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sillyent.unitybluetoothcode">
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".BluetoothActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

------------------------------------------------------------추가 시작 -------------------------------------

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

<uses-permission android:name="android.permission.BLUETOOTH"/>

------------------------------------------------------------추가 완료 -------------------------------------
</manifest>



<수정 후>

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sillyent.unitybluetoothcode">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".BluetoothActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
</manifest>



3. BluetoothService 클래스를 작성합니다.


public class BluetoothService {


private static final String TAG = "Silly :: BluetoothService :: ";
private BluetoothAdapter bluetoothAdapter;

OutputStream outputStream;
InputStream inputStream;
BluetoothDevice selectDevice;

public BluetoothService()
{
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}

public boolean CheckBluetoothAvailable()
{
if(bluetoothAdapter == null)
{
Log.d(TAG, "Bluetooth is not available");
return false;
}
else
{
Log.d(TAG, "Bluetooth is available");
return true;
}
}

Set<BluetoothDevice> pairDevices;
public String SearchDevice()
{
Log.d(TAG,"SearchDevice");
String connetedDeviceInfo = "";
if(bluetoothAdapter.isEnabled())
{
Log.d(TAG, "Bluetooth On");
bluetoothAdapter.startDiscovery();

pairDevices = bluetoothAdapter.getBondedDevices();

if(pairDevices.size() > 0)
{
for(BluetoothDevice device : pairDevices)
{
Log.d(TAG, device.getName().toString());
Log.d(TAG, device.getAddress().toString());

connetedDeviceInfo += device.getName().toString() + "/";
connetedDeviceInfo += device.getAddress().toString() + ",";
}
}
}
else
{
Log.d(TAG, "Bluetooth Off");
connetedDeviceInfo += "Bluetooth Off";
}
return connetedDeviceInfo;
}

public void ConnectedDevice(String DeviceName)
{
Log.d(TAG, DeviceName);
if(pairDevices.size() > 0)
{
for(BluetoothDevice device : pairDevices)
{
if(device.getName().equals(DeviceName)) {
selectDevice = device;
}
}
}
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
String Data ="";
try {
BluetoothSocket mSocket = selectDevice.createRfcommSocketToServiceRecord(uuid);
mSocket.connect();

outputStream = mSocket.getOutputStream();
inputStream = mSocket.getInputStream();

// 데이터 수신 준비
ReceiveData();
}catch(Exception e) {
Log.d(TAG, e.toString());
// 블루투스 연결 중 오류 발생

}
}

byte[] readBuffer = new byte[1024];
Thread thread;
boolean stopThread = false;

void ReceiveData()
{
readBuffer = new byte[1024];

thread = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted() && !stopThread)
{
try
{
int receiveBytes = inputStream.available();
if(receiveBytes >0)
{
byte[] packetBytes =new byte[receiveBytes];
inputStream.read(packetBytes);
String buffer = new String(packetBytes,0,receiveBytes);
UnityPlayer.UnitySendMessage("BluetoothControl", "ReceiveData", buffer);
}
} catch (IOException e) {
Log.d(TAG,e.toString());
stopThread = true;
}
}
}
});
thread.start();
}
}



4. BluetoothActivity를 작성합니다.


 public class BluetoothActivity extends UnityPlayerActivity {


private static final String TAG = "Silly :: BluetoothActivity :: ";

private static BluetoothService bluetoothService = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

public void BluetoothInit()
{
Log.d(TAG, "BluetoothInit");

if(bluetoothService == null)
{
bluetoothService = new BluetoothService();

if(!bluetoothService.CheckBluetoothAvailable())
{
UnityPlayer.UnitySendMessage("BluetoothControl","ErrorMessage", "Bluetooth is not available");
}
else
{
UnityPlayer.UnitySendMessage("BluetoothControl", "SearchDevice", bluetoothService.SearchDevice());
}
}
}

public void ConnectedDevice(String deviceName)
{
bluetoothService.ConnectedDevice(deviceName);
}

public void StopThread()
{
bluetoothService.stopThread = true;
}

}



5. jar 파일을 익스포트 한다.(exportJar)




여기까지 하시면 이제 유니티에서 쓸수 있는 네이티브 코드가 만들어진 겁니다.


코드는 복사해서 쓰셔도 되지만 이해가 안되는 부분이 많을 텐데요. 


아래 부분에서 설명을 드리겠습니다.




1. build.gradle 부분입니다.


1) apply plugin: 'com.android.application' --> apply plugin: 'com.android.application'


:: 어플리케이션 빌드가 아닌 라이브러리 빌드를 하겠다는 뜻입니다.


2) task deleteObjectJar(type: Delete){

delete 'release/UnityBluetoothCode.jar'


}


:: 파일을 삭제하는 테스크를 생성합니다. release 폴더에 있는 UnityBluetoothCode.jar 파일을 삭제합니다.


3)task exportJar(type: Copy){

    from('build/intermediates/bundles/release/')
    into('release/')
    include('classes.jar')
    rename('classes.jar', 'UnityBluetoothCode.jar')
}


:: 파일을 복사(생성)하는 테스크를 생성합니다. release 폴더에 classes.jar 파일을 생성하는데 이름을          UnityBlutoothCode.jar로 변경합니다.


4) exportJar.dependsOn(deleteObjectJar, build)


:: 파일을 복사(생성)하는 테스크는 deleteObjectJar 테스크와 빌드에 의존성을 가집니다.


결론적으로 빌드를 하는 데 빌드를 파일 생성으로 해서 최종적으로 UnityBluetoothCode.jar 파일로 만들겠다는 겁니다.





2. AndroidManifest 부분입니다.


 1)<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

  <uses-permission android:name="android.permission.BLUETOOTH"/>


:: 블루투스에 대한 권한을 요청합니다.




3. BluetoothService 클래스 부분입니다.

 1) public BluetoothService()

  {
      bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  }


:: 블루투스 서비스 클래스를 생성할때 블루투스 어댑터를 받아옵니다.


2) public boolean CheckBluetoothAvailable()
   {
        if(bluetoothAdapter == null)
        {
            Log.d(TAG, "Bluetooth is not available");
            return false;
        }
        else
        {
            Log.d(TAG, "Bluetooth is available");
            return true;        
        }
    }


:: 블루투스 어댑터를 확인하여 블루투스가 사용가능한 기기인지 확인합니다.


2) public String SearchDevice()
    {
        Log.d(TAG,"SearchDevice");
        String connetedDeviceInfo = "";


        if(bluetoothAdapter.isEnabled())

        {
            Log.d(TAG, "Bluetooth On");
            bluetoothAdapter.startDiscovery();


            :: 블루투스 검색을 시작합니다.

         

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


    :: 페어링된 디바이스들을 불러옵니다.

   if(pairDevices.size() > 0)
   {

   for(BluetoothDevice device : pairDevices)

   {
        Log.d(TAG, device.getName().toString());
        Log.d(TAG, device.getAddress().toString());
        connetedDeviceInfo += device.getName().toString() + "/";  


        :: 페어링된 디바이스 이름을 받아옵니다.


        connetedDeviceInfo += device.getAdress().toString() + ",";   


        :: 페어링된 디바이스 주소를 받아옵니다.

    }

}

}
else
{
    Log.d(TAG, "Bluetooth Off");
    connetedDeviceInfo += "Bluetooth Off";


    :: 블루투스가 꺼져 있는 경우 꺼져 있다는 문자열을 저장합니다.


}


return connetedDeviceInfo;                           

}


:: 블루투스가 켜져 있는지 확인해서 페어링된 디바이스들을 찾아냅니다.



3) public void ConnectedDevice(String DeviceName)
    {
        UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");


        :: UUID입니다. 고유값을 가집니다.


        String Data ="";

try {
BluetoothSocket mSocket = selectDevice.createRfcommSocketToServiceRecord(uuid);


:: 소켓을 생성합니다.


mSocket.connect();


         :: 소켓을 연결합니다.


outputStream = mSocket.getOutputStream();

    :: 소켓의 출력 스트림입니다.


inputStream = mSocket.getInputStream();


      :: 소켓의 입력 스트립니다.


// 데이터 수신 준비
ReceiveData();


            :: 데이터를 받을 함수입니다.


}catch(Exception e) {
Log.d(TAG, e.toString());
// 블루투스 연결 중 오류 발생

}
}


:: 디바이스 이름을 받아서 그 디바이스와 소켓을 연결합니다.



byte[] readBuffer = new byte[1024]; :: 버퍼 사이즈를 지정합니다.
Thread thread;                         :: 스레드를 생성합니다.

boolean stopThread = false; :: 스레드를 멈출 변수를 지정합니다.

void ReceiveData()
{
readBuffer = new byte[1024];

thread = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted() && !stopThread)
{
try
{
int receiveBytes = inputStream.available(); :: 입력스트림을 받아옵니다.
if(receiveBytes >0)
{
byte[] packetBytes =new byte[receiveBytes];


:: 입력 스트림의 크기에 따른 패킷바이트를 생성


inputStream.read(packetBytes);                :: 데이터 읽기

String buffer = new String(packetBytes,0,receiveBytes);


:: 받아온 데이터를 문자열로 변환


// 유니티에서 동작할 작업 실시
UnityPlayer.UnitySendMessage("BluetoothControl", "ReceiveData", buffer);

:: 유니티로 문자열을 전송


}
} catch (IOException e) {
Log.d(TAG,e.toString());
stopThread = true;
}
}
}
});
thread.start();
}

}

:: 스레드를 생성해서 받아온 데이터가 있을 때 유니티로 전송해줍니다.





여기까지 하시면 이제 유니티로 Jar파일을 가져가서 직접 통신을 연결할 차례입니다. 그럼 다음 강의에서 뵙겠습니다.



Comments