安卓上使用ble,并和unity通信

首先是java代码
package com.miyan.lib4unity;
import android.Manifest;
import android.app.Activity;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ProviderInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.widget.BaseAdapter;
import android.widget.Toast;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.PortUnreachableException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.UUID;
import java.util.logging.LogRecord;
import java.io.UnsupportedEncodingException;
public class Link2Unity {
private Activity unityActivity;
public Activity getUnityActivity(){
if (unityActivity == null){
try {
Class<?> classType = Class.forName("com.unity3d.player.UnityPlayer");
unityActivity = (Activity)classType.getDeclaredField("currentActivity").get(classType);
}
catch (ClassNotFoundException e){}
catch (IllegalAccessException e){}
catch (NoSuchFieldException e){}
}
return unityActivity;
}
boolean callUnity(String gameobjectName, String functionName, String args){
try {
Class<?> classType = Class.forName("com.unity3d.player.UnityPlayer");
Method method = classType.getMethod("UnitySendMessage", String.class, String.class, String.class);
method.invoke(classType, gameobjectName, functionName, args);
return true;
}
catch (ClassNotFoundException e){}
catch (NoSuchMethodException e){}
catch (IllegalAccessException e){}
catch (InvocationTargetException e){}
return false;
}
public boolean testConnection(String msg){
Toast.makeText(getUnityActivity(), msg, Toast.LENGTH_LONG);
callUnity("Link2Android", "GetMsgFromAndroid", "hello");
return true;
}
/*
private String[] permissions = new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.CAMERA,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
};
public void requestPower(){
callUnity("Link2Android", "GetMsgFromAndroid", String.valueOf(Build.VERSION.SDK_INT));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
callUnity("Link2Android", "GetMsgFromAndroid", String.valueOf(Build.VERSION_CODES.M));
for (int i = 0; i < permissions.length; i++) {
callUnity("Link2Android", "GetMsgFromAndroid", permissions[i]);
if (ActivityCompat.checkSelfPermission(getUnityActivity(), permissions[i]) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(getUnityActivity(), permissions, 1);
callUnity("Link2Android", "GetMsgFromAndroid", permissions[i]);
//Toast.makeText(getUnityActivity(), "request", Toast.LENGTH_SHORT).show();
break;
}
}
}
}
*/
//蓝牙部分
private boolean isAppStopped = false;
public void setAppStopped(boolean msg){
isAppStopped = msg;
callUnity("Link2Android", "GetWarningsFromAndroid", "is stop receiving: " + isAppStopped);
}
private static long scanPeriod = 5000;//10s后停止扫描
public void setScanPeriod(int value){
scanPeriod = value * 1000;
callUnity("Link2Android", "GetWarningsFromAndroid", "scan period: " + scanPeriod);
}
private boolean scanning;
private ArrayList<BluetoothDevice> bluetoothDevices = new ArrayList<BluetoothDevice>();
private BluetoothAdapter bluetoothAdapter;
public BluetoothAdapter getBluetoothAdapter(){
if (bluetoothAdapter == null){
final BluetoothManager bluetoothManager = (BluetoothManager)getUnityActivity().getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
}
return bluetoothAdapter;
}
private PackageManager packageManager;
public PackageManager getPackageManager(){
if (packageManager == null)
packageManager = getUnityActivity().getPackageManager();
return packageManager;
}
public boolean checkBleSupport(){
//callUnity("Link2Android", "GetWarningsFromAndroid", "check ble support");
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
return false;
}
if (getBluetoothAdapter() == null){
return false;
}
return true;
}
public boolean askToOpenBluetooth(){
//callUnity("Link2Android", "GetWarningsFromAndroid", "ask to open ble");
if (!getBluetoothAdapter().isEnabled()){
getBluetoothAdapter().enable();
}
callUnity("Link2Android", "GetWarningsFromAndroid", "ble is enabled: " + String.valueOf(getBluetoothAdapter().isEnabled()));
return getBluetoothAdapter().isEnabled();
}
public void scanLeDevice(final boolean enable){
//callUnity("Link2Android", "GetWarningsFromAndroid", "begin scan");
//bluetoothDevices.clear();
Handler handler = new Handler();
if (enable){
handler.postDelayed(new Runnable() {
@Override
public void run() {
scanning = false;
callUnity("Link2Android", "GetWarningsFromAndroid", "time out stop scan");
try{
getBluetoothAdapter().getBluetoothLeScanner().stopScan(scanCallback);
}
catch (Exception e){
callUnity("Link2Android", "GetWarningsFromAndroid",
"outer scan error: " + e.getMessage() + "\n" + e.getLocalizedMessage());
}
}
}, scanPeriod);
bluetoothDevices.clear();
scanning = true;
callUnity("Link2Android", "GetWarningsFromAndroid", "start scan");
getBluetoothAdapter().getBluetoothLeScanner().startScan(scanCallback);
}
else {
scanning = false;
getBluetoothAdapter().getBluetoothLeScanner().stopScan(scanCallback);
callUnity("Link2Android", "GetWarningsFromAndroid", "order stop scan");
}
}
public void stopScan(){
scanLeDevice(false);
}
private String bleNameHeader = "Test";
public void setBleNameHeader(String header){
bleNameHeader = header;
callUnity("Link2Android", "GetWarningsFromAndroid", "scan filter: " + bleNameHeader);
}
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (!bluetoothDevices.contains(result.getDevice()) && result.getDevice().getName() != null){
callUnity("Link2Android", "GetWarningsFromAndroid", result.getDevice().getName() + " / " + bleNameHeader);
if (result.getDevice().getName().contains(bleNameHeader)){
StringBuilder sb = new StringBuilder();
sb.append(result.getDevice().getName());
sb.append("&");
sb.append(result.getDevice().getAddress());
callUnity("Link2Android", "GetDevice",sb.toString());
bluetoothDevices.add(result.getDevice());
}
}
}
};
private BluetoothDevice curDevice;
private BluetoothGatt bluetoothGatt;
public void connectBleDevice(String deviceName){
callUnity("Link2Android", "GetWarningsFromAndroid", "order name: " + deviceName);
for (int i = 0; i < bluetoothDevices.size(); i++) {
//callUnity("Link2Android", "GetWarningsFromAndroid",
// "is equal: " + String.valueOf(bluetoothDevices.get(i).getName().compareTo(deviceName) == 0) );
if (bluetoothDevices.get(i).getName().compareTo(deviceName) == 0){
curDevice = bluetoothDevices.get(i );
//callUnity("Link2Android", "GetWarningsFromAndroid", "connect name: " + curDevice.getName());
bluetoothGatt = curDevice.connectGatt(getUnityActivity(), true, bluetoothGattCallback);
if (bluetoothGatt.connect()){
//bluetoothGatt.discoverServices();
}
}
}
}
private BluetoothGattService bluetoothGattService;
private BluetoothGattCharacteristic writeCharacter;
private BluetoothGattCharacteristic readCharacter;
//public static String Service_uuid = "0000ffe0-0000-1000-8000-00805f9b34fb";
public static String Service_uuid = "0003CDD0-0000-1000-8000-00805F9B0131";
//public static String Characteristic_uuid_TX = "0000ffe1-0000-1000-8000-00805f9b34fb";
public static String Characteristic_uuid_TX = "0003CDD1-0000-1000-8000-00805F9B0131";
//public static String Characteristic_uuid_RX = "0000ffe3-0000-1000-8000-00805f9b34fb";
public static String Characteristic_uuid_RX = "0003CDD2-0000-1000-8000-00805F9B0131";
public void setServiceUUID(String uuid){
Service_uuid = uuid;
}
public void setChracteristicWriteUUID(String uuid){
Characteristic_uuid_TX = uuid;
}
public void setCharacteristicReadUUID(String uuid){
Characteristic_uuid_RX = uuid;
}
private BluetoothGattCallback bluetoothGattCallback= new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == BluetoothGatt.GATT)
callUnity("Link2Android", "GetWarningsFromAndroid", "gatt success");
if (newState == BluetoothProfile.STATE_CONNECTED){
callUnity("Link2Android", "GetWarningsFromAndroid", "connected");
callUnity("Link2Android", "IsConnectSuccess", "true");
bluetoothGatt.discoverServices();
}
else if (newState == BluetoothProfile.STATE_DISCONNECTED){
callUnity("Link2Android", "GetWarningsFromAndroid", "disconnected");
callUnity("Link2Android", "IsConnectSuccess", "false");
disconnectBle("android");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS){
//callUnity("Link2Android", "GetWarningsFromAndroid", "service uuid: " + Service_uuid);
//callUnity("Link2Android", "GetWarningsFromAndroid", "character read uuid: " + Characteristic_uuid_TX);
//callUnity("Link2Android", "GetWarningsFromAndroid", "character write uuid: " + Characteristic_uuid_RX);
bluetoothGattService = bluetoothGatt.getService(UUID.fromString(Service_uuid));
List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics();
// if (characteristics != null){
//
// for (int i = 0; i < characteristics.size(); i++) {
// callUnity("Link2Android", "GetWarningsFromAndroid", "get uuid: " + characteristics.get(i).getUuid().toString());
// }
// }
writeCharacter = bluetoothGattService.getCharacteristic(UUID.fromString(Characteristic_uuid_RX));
//boolean isSuccess2 = bluetoothGatt.setCharacteristicNotification(readCharcter, true);
/*
List<BluetoothGattDescriptor> descriptors2 = readCharcter.getDescriptors();
for (BluetoothGattDescriptor descriptor : descriptors2){
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
*/
readCharacter = bluetoothGattService.getCharacteristic(UUID.fromString(Characteristic_uuid_TX));
boolean isSucces = bluetoothGatt.setCharacteristicNotification(readCharacter, true);
List<BluetoothGattDescriptor> descriptors = readCharacter.getDescriptors();
for (BluetoothGattDescriptor descriptor : descriptors){
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
//callUnity("Link2Android", "GetWarningsFromAndroid", "read: "+characteristic.getStringValue(0));
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
//callUnity("Link2Android", "GetWarningsFromAndroid", "write: "+ Characteristic_uuid_RX + " "+characteristic.getStringValue(0));
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//callUnity("Link2Android", "GetWarningsFromAndroid", "change: "+ characteristic.getUuid());
if (isAppStopped == false){
byte[] buffer = characteristic.getValue();
checkBuffer(buffer);
}
}
};
private String bytesToString(byte[] buffer){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buffer.length; i++) {
sb.append(buffer[i] + " ");
}
return sb.toString();
}
private int mark;
private LinkedList<Byte> list = new LinkedList<Byte>();
private byte space = 0x20;
private void checkBuffer(byte[] buffer){
for (int i = 0; i < buffer.length; i++) {
if (mark == 0){
if (buffer[i] == 0x24){
mark = 1;
list.clear();
list.add(buffer[i]);
}
}
else if (mark == 1){
list.add(buffer[i]);
if (buffer[i] == 0x0D){
mark = 0;
//这里将所有字节处理后发给unity
if (isAppStopped == false)
callUnity("Link2Android", "GetMsgFromAndroid", list.toString());
}
else{
//这里都是有效数据
//if (buffer[i] != 0x0d)
// list.add(buffer[i]);
//else
// list.add(space);
}
}
}
}
public void disconnectBle(String caller){
callUnity("Link2Android", "GetWarningsFromAndroid", "get " + caller + " disconnect order");
try{
if (curDevice == null || bluetoothGatt == null)
return;
callUnity("Link2Android", "GetWarningsFromAndroid", "disconnect: " + bluetoothGatt.getDevice().getName());
bluetoothGatt.disconnect();
bluetoothGatt.close();
bluetoothGatt = null;
}
catch (Exception e){
callUnity("Link2Android", "GetWarningsFromAndroid", "disconnect error: " + e.getMessage());
}
}
public void writeToBle(String msg){
//readCharacter.setValue(msg);
//bluetoothGatt.writeCharacteristic(readCharacter);
writeCharacter.setValue(msg);
bluetoothGatt.writeCharacteristic(writeCharacter);
}
//private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
// @Override
// public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
// callUnity("Link2Android", "GetWarningsFromAndroid", device.getName());
// }
/