簡體   English   中英

將 BLE 與 Unity 連接不起作用。 (掃描有效。)

[英]connecting BLE with Unity doesn't work. (scan works.)

將 BLE 設備與 Unity 連接時遇到問題。

實際上,掃描是成功的。 但是連接根本不起作用。

為了在 Unity 中使用 BLE,我使用 Android Studio 制作了一個插件。

我不知道為什么 device.connectGatt(current_activity, false, gattClientCallback); 即使它正確返回 BluetoothGATT 也不會使我的 BLE 外圍設備(Arduino Nano 33 BLE)連接。 當我調用 BLE.bleControllerObj.Call("connect", address); 時顯示文本“set ble_gatt: true”; 在統一。 (這調用了plugin/的connect function) 但是,連接沒有發生,即根本沒有調用回調onConnectionStateChange。 (我知道是因為“連接成功。”沒有出現。)奇怪的是,在設備,connectGatt(current_activity,false; gattClientCallback)執行之后,ble外圍設備停止廣告而不連接。 所以在終止 Unity 應用程序之前,我無法通過其他應用程序掃描 ble 設備。 我猜連接請求被發送到 ble 外圍設備。

(這里,BLE 是 Unity 腳本的名稱,bleControllerObj 是 Unity 中的 AndroidJavaObject 實例。)

此外,我檢查了我的設備和外圍設備可以與現有的 nRF Connect 應用程序連接。

請讓我知道我錯過了什么。 還是我也應該上傳我的 Unity 腳本?

這是我使用的 java 插件的完整代碼。

package com.example.ble;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.Log;
import android.widget.Toast;


public class BLEcontroller {

    public static Activity current_activity;
    public static Context context;
    public static BLEcontroller instance;

    public BluetoothAdapter ble_adapter;
    public BluetoothLeScanner leScanner;
    public List<BluetoothDevice> scanned_devices = new ArrayList<BluetoothDevice>();
    public boolean connected_ = false;
    public BluetoothGatt ble_gatt;
    public BluetoothManager ble_manager;

    private void showText(String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }


    public static BLEcontroller getInstance() {
        if (instance == null) {
            instance = new BLEcontroller();
            current_activity = UnityPlayer.currentActivity;
            context = UnityPlayer.currentActivity.getApplicationContext();
        }

        instance.scanned_devices= new ArrayList<BluetoothDevice>();

        return instance;
    }

    public void setContext(Activity _activity, Context _context){
        current_activity=_activity;
        context=_context;
    }

    public void init() {
        Log.e("Unity", "init start!!!" );
        ble_manager = (BluetoothManager) current_activity.getSystemService(Context.BLUETOOTH_SERVICE);
        ble_adapter = ble_manager.getAdapter();

        Toast.makeText(context, "init start and scanner : "+(leScanner!=null), Toast.LENGTH_SHORT).show();
        Log.e("Unity", "init start and scanner : "+(leScanner!=null) );
        checkBLEAvailable();

        leScanner = ble_adapter.getBluetoothLeScanner();

        if (!current_activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(context, "BlE isn't supported.", Toast.LENGTH_SHORT).show();
            return;
        }

        if (leScanner == null) {
            Toast.makeText(context, "scanner is null", Toast.LENGTH_SHORT).show();
        }
    }




    private void checkBLEAvailable() {

        if (ble_adapter == null || !ble_adapter.isEnabled()) {
            showText("ble is disabled");
            requestEnableBle();
        }

        requestPermissions();
    }

    @SuppressLint("MissingPermission")
    public void startScan() {
        showText("There were " + scanned_devices.size() + " devices");
        scanned_devices.clear();
        Log.e("Unity", "clear devices");
        if (leScanner == null) {
            showText("leScanner was null!");
            Log.e("Unity", "leScanner is null!");
        }
        Log.e("Unity", "startScan in java.");
        leScanner.startScan(mScanCallback);
        showText("start scan");

    }


    public int getScanned_devicesNum(){
        return scanned_devices.size();
    }

    public boolean isConnected(){
        return connected_;
    }

    public BluetoothDevice getScanned_device(int i){
        return scanned_devices.get(i);
    }


    @SuppressLint("MissingPermission")
    public void stopScan(){
        leScanner.stopScan(mScanCallback);
        showText("scan stop.");
    }

    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            processResult(result);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult result : results) {
                processResult(result);
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            showText("scanFailed with "+errorCode);
        }

        @SuppressLint("MissingPermission")
        private void processResult(final ScanResult result) {
            boolean add_result=true;
            if(result.getDevice().getName()==null) {
                Log.e("Unity", "No device name");
                add_result = false;
            }
            for (BluetoothDevice device : scanned_devices){
                if (device.getAddress()==result.getDevice().getAddress()){
                    Log.e("Unity", "Already exists : " +device.getName());
                    add_result=false;
                }
            }
            if (add_result){
                scanned_devices.add(result.getDevice());
            }
            tidyUpScanned_devices();
        }
    };

    public void tidyUpScanned_devices(){
        ArrayList<BluetoothDevice> arrayList=new ArrayList<>();

        for (int i=0; i<scanned_devices.size(); i++){
            if (getDeviceIndex(arrayList, scanned_devices.get(i))==-1){
                arrayList.add(scanned_devices.get(i));
            }
        }
        scanned_devices.clear();
        scanned_devices=arrayList;
    }

    private int getDeviceIndex(List<BluetoothDevice> list, BluetoothDevice device){
        for (int i=0; i<list.size(); i++){
            if (device.getAddress().equalsIgnoreCase(list.get(i).getAddress())){
                return i;
            }
        }
        return -1;
    }

    @SuppressLint("MissingPermission")
    public void connect(String address) {
        if (!ble_adapter.isEnabled()) {
            showText("Turn on BLE");
            return;
        }

        for (BluetoothDevice device : scanned_devices) {
            if (device.getAddress().equals(address)) {
                showText(("try connecting device : " + address));
                disconnectGattServer();
                ble_gatt = device.connectGatt(current_activity, false, gattClientCallback);
                showText("set ble_gatt : " + (ble_gatt != null));
            }
        }
    }

    @SuppressLint("MissingPermission")
    public void connect() {
        if (!ble_adapter.isEnabled()) {
            showText("Turn on BLE");
            return;
        }

        for (BluetoothDevice device : scanned_devices) {
            showText(("try connecting device : " + device.getAddress()));
            disconnectGattServer();
            ble_gatt = device.connectGatt(current_activity, false, gattClientCallback);
            showText("set ble_gatt : " + (ble_gatt != null));
            return;
        }
    }

    @SuppressLint("MissingPermission")
    public void disconnectGattServer() {
        /*showText("Closing Gatt connection");
        // reset the connection flag
        connected_ = false;
        // disconnect and close the gatt
        if (ble_gatt != null) {
            ble_gatt.disconnect();
            ble_gatt.close();
        }*/
    }

    @SuppressLint("MissingPermission")
    // Gatt Client Callback class
    private BluetoothGattCallback gattClientCallback=new BluetoothGattCallback() {

        @Override
        public void onConnectionStateChange(BluetoothGatt _gatt, int _status, int _new_state) {
            super.onConnectionStateChange(_gatt, _status, _new_state);
            showText("Connection Success!");
            if (_status != BluetoothGatt.GATT_SUCCESS) {
                showText("failed connecting");
                disconnectGattServer();
                return;
            }
            if (_new_state == BluetoothProfile.STATE_CONNECTED) {
                // set the connection flag
                connected_ = true;
                showText("Connected to the GATT server");
                _gatt.discoverServices();
            } else if (_new_state == BluetoothProfile.STATE_DISCONNECTED) {
                disconnectGattServer();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt _gatt, int _status) {
            super.onServicesDiscovered(_gatt, _status);
            // check if the discovery failed
            if (_status != BluetoothGatt.GATT_SUCCESS) {
                showText("Device service discovery failed, status: " + _status);
                return;
            }
            showText("service discovered : "+_gatt.getServices().get(0).getUuid());
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt _gatt, BluetoothGattCharacteristic _characteristic) {
            super.onCharacteristicChanged(_gatt, _characteristic);

            showText( "characteristic changed: " + _characteristic.getValue().toString());

        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt _gatt, BluetoothGattCharacteristic _characteristic, int _status) {
            super.onCharacteristicWrite(_gatt, _characteristic, _status);
            if (_status == BluetoothGatt.GATT_SUCCESS) {
                showText("Characteristic written successfully");
            } else {
                showText("Characteristic write unsuccessful, status: " + _status);
                disconnectGattServer();
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                showText("Characteristic read successfully");
            } else {
                showText("Characteristic read unsuccessful, status: " + status);
            }
        }

        // Log the value of the characteristic
        // @param characteristic
        private void readCharacteristic(BluetoothGattCharacteristic _characteristic) {
            byte[] msg = _characteristic.getValue();
            showText( "read: " + msg.toString());
        }
    };


    @SuppressLint("MissingPermission")
    private void requestEnableBle() {
        Intent ble_enable_intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        current_activity.startActivityForResult(ble_enable_intent, 1);

    }

    private void requestPermissions(){
        current_activity.requestPermissions(
                new String[] {Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT}, 2);
    }

}

我找到了解決方案!

問題是我嘗試使用應該在 UI 線程中使用的 Toast 方法,但實際上回調是在 binder 線程中調用的,因此在啟動 discoverServices 之前線程已終止。

另外,請確保 connectGatt、disconnect、close 應該在主線程中運行,可能在某些設備中,因此建議使用 new Handler(Looper.getMainLooper()).post。

ConnectGatt 必須在某些手機的 ui 線程中調用。在 Android-BLE-Library 中,BleManagerHandler::enqueue 可以在 worker 線程中調用,BluetoothGattCallback::onConnectionStateChange 也可以在 binder 線程中調用。 所以這兩個條件可能會導致這個問題!

https://github.com/NordicSemiconductor/Android-BLE-Library/issues/159

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM