首先是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());
// }
//};
}
然后是unity代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using UnityEngine;
public class Link2Android : MonoBehaviour
{
public static Link2Android instance;
private void Awake()
{
instance = this;
}
private AndroidJavaObject jo;
private AnalysisRecData analysisRecData = new AnalysisRecData();
private Action<bool> actionConnectCallback;
private Action<BleDevice> actionScanCallback;
public BleDevice curDevice;
public Queue<string> queueRecData = new Queue<string>();
private readonly string bleFilter = "Test";
public float scanPeriod { get; } = 8;
void Start()
{
jo = new AndroidJavaObject("com.miyan.lib4unity.Link2Unity");
bool isSupport = jo.Call<bool>("checkBleSupport");
if (isSupport == false)
{
UIPanelMgr.instance.ToPanelQuit(LanguageMgr.instance.localizeLanguage.deviceDontSupportBle);
}
bool isOpen = jo.Call<bool>("askToOpenBluetooth");
if (isOpen == false)
{
UIPanelMgr.instance.ToPanelQuit(LanguageMgr.instance.localizeLanguage.failedToOpenBle);
}
jo.Call("setBleNameHeader", bleFilter);//过滤头
jo.Call("setScanPeriod", (int)scanPeriod);//设置扫描超时
//jo.Call("setServiceUUID", "0000ff00-0000-1000-8000-00805f9b34fb");
//jo.Call("setChracteristicWriteUUID", "0000ff02-0000-1000-8000-00805f9b34fb");
//jo.Call("setCharacteristicReadUUID", "0000ff02-0000-1000-8000-00805f9b34fb");
}
public void ScanBleDevice(Action<BleDevice> scanCallback)
{
actionScanCallback = scanCallback;
jo.Call("scanLeDevice", true);
}
public void GetDevice(string device)
{
UIPanelMgr.instance.DisplayWarnings("get device: " + device);
try
{
string[] deviceMsg = device.Split('&');
if (deviceMsg[0].StartsWith(bleFilter))
{
BleDevice cbs = new BleDevice
{
nameBle = deviceMsg[0],
mac = deviceMsg[1]
};
actionScanCallback?.Invoke(cbs);
}
else
{
return;
}
}
catch (Exception e)
{
print(e.Message);
}
}
public void ConnectBleDevice(BleDevice device, Action<bool> connectCallback)
{
actionConnectCallback = connectCallback;
StopAllCoroutines();
StartCoroutine(ConnectBleDevice(device));
}
IEnumerator ConnectBleDevice(BleDevice device)
{
jo.Call("stopScan");
yield return new WaitForSeconds(0.15f);
jo.Call("disconnectBle", "before connect new");
yield return new WaitForSeconds(0.3f);
jo.Call("connectBleDevice", device.nameBle);
curDevice = device;
yield return new WaitForSeconds(10);//10s连接超时
actionConnectCallback?.Invoke(false);
jo.Call("disconnectBle", "timer out");
}
public void DisconnectBle()
{
if (curDevice != null)
{
jo.Call("disconnectBle", "quit");
}
}
public void IsConnectSuccess(string torf)
{
bool isSuccess = bool.Parse(torf);
UIPanelMgr.instance.SetOtherDeviceState(curDevice.nameBle);
actionConnectCallback?.Invoke(isSuccess);
StopAllCoroutines();
//ui的变化
UIPanelMgr.instance.RefreshBleState(isSuccess);
}
public void GetMsgFromAndroid(string msg)
{
//UIPanelMgr.instance.DisplayWarnings("get msg: " + msg);
//将数据放入队列
queueRecData.Enqueue(msg);
}
public void GetWarningsFromAndroid(string warning)
{
UIPanelMgr.instance.DisplayWarnings("android warning: " + warning);
}
private void OnApplicationPause(bool pause)
{
if (jo != null)
jo.Call("setAppStopped", pause);
}
private void Update()
{
if (queueRecData.Count > 0)
{
string msg = "";
for (int i = 0; i < queueRecData.Count; i++)
{
msg = queueRecData.Dequeue();
}
curDevice = analysisRecData.DealBleData(msg, curDevice);
//刷新ui
UIPanelMgr.instance.RefreshPanelDevice(curDevice);
}
}
}