IOException: gagal membaca, soket mungkin tertutup - Bluetooth di Android 4.3

100

Saat ini saya mencoba menangani Pengecualian yang aneh saat membuka BluetoothSocket di Nexus 7 (2012) saya, dengan Android 4.3 (Build JWR66Y, saya kira pembaruan 4.3 kedua). Saya telah melihat beberapa posting terkait (misalnya /programming/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), tetapi tampaknya tidak ada yang memberikan solusi untuk masalah ini. Selain itu, seperti yang disarankan dalam utas ini, memasangkan ulang tidak membantu, dan terus mencoba untuk terhubung (melalui loop bodoh) juga tidak berpengaruh.

Saya berurusan dengan perangkat tertanam (adaptor mobil OBD-II noname, mirip dengan http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LAMPU-DENGAN-TELEPON-ANDA-Oceanside.jpg ). Ponsel Android 2.3.7 saya tidak memiliki masalah koneksi, dan Xperia rekan kerja (Android 4.1.2) juga berfungsi. Google Nexus lain (saya tidak tahu apakah 'One' atau 'S', tetapi bukan '4') juga gagal dengan Android 4.3.

Berikut adalah Cuplikan pembentukan koneksi. Ini berjalan di Thread-nya sendiri, dibuat dalam Layanan.

private class ConnectThread extends Thread {

    private static final UUID EMBEDDED_BOARD_SPP = UUID
        .fromString("00001101-0000-1000-8000-00805F9B34FB");

    private BluetoothAdapter adapter;
    private boolean secure;
    private BluetoothDevice device;
    private List<UUID> uuidCandidates;
    private int candidate;
    protected boolean started;

    public ConnectThread(BluetoothDevice device, boolean secure) {
        logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
        adapter = BluetoothAdapter.getDefaultAdapter();
        this.secure = secure;
        this.device = device;

        setName("BluetoothConnectThread");

        if (!startQueryingForUUIDs()) {
            this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
            this.start();
        } else{
            logger.info("Using UUID discovery mechanism.");
        }
        /*
         * it will start upon the broadcast receive otherwise
         */
    }

    private boolean startQueryingForUUIDs() {
        Class<?> cl = BluetoothDevice.class;

        Class<?>[] par = {};
        Method fetchUuidsWithSdpMethod;
        try {
            fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
        } catch (NoSuchMethodException e) {
            logger.warn(e.getMessage());
            return false;
        }

        Object[] args = {};
        try {
            BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
                    Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");

                    uuidCandidates = new ArrayList<UUID>();
                    for (Parcelable uuid : uuidExtra) {
                        uuidCandidates.add(UUID.fromString(uuid.toString()));
                    }

                    synchronized (ConnectThread.this) {
                        if (!ConnectThread.this.started) {
                            ConnectThread.this.start();
                            ConnectThread.this.started = true;
                            unregisterReceiver(this);
                        }

                    }
                }

            };
            registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
            registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));

            fetchUuidsWithSdpMethod.invoke(device, args);
        } catch (IllegalArgumentException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (IllegalAccessException e) {
            logger.warn(e.getMessage());
            return false;
        } catch (InvocationTargetException e) {
            logger.warn(e.getMessage());
            return false;
        }           

        return true;
    }

    public void run() {
        boolean success = false;
        while (selectSocket()) {

            if (bluetoothSocket == null) {
                logger.warn("Socket is null! Cancelling!");
                deviceDisconnected();
                openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
            }

            // Always cancel discovery because it will slow down a connection
            adapter.cancelDiscovery();

            // Make a connection to the BluetoothSocket
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                bluetoothSocket.connect();
                success = true;
                break;

            } catch (IOException e) {
                // Close the socket
                try {
                    shutdownSocket();
                } catch (IOException e2) {
                    logger.warn(e2.getMessage(), e2);
                }
            }
        }

        if (success) {
            deviceConnected();
        } else {
            deviceDisconnected();
            openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
        }
    }

    private boolean selectSocket() {
        if (candidate >= uuidCandidates.size()) {
            return false;
        }

        BluetoothSocket tmp;
        UUID uuid = uuidCandidates.get(candidate++);
        logger.info("Attempting to connect to SDP "+ uuid);
        try {
            if (secure) {
                tmp = device.createRfcommSocketToServiceRecord(
                        uuid);
            } else {
                tmp = device.createInsecureRfcommSocketToServiceRecord(
                        uuid);
            }
            bluetoothSocket = tmp;
            return true;
        } catch (IOException e) {
            logger.warn(e.getMessage() ,e);
        }

        return false;
    }

}

Kode gagal bluetoothSocket.connect(). Saya mendapatkan a java.io.IOException: read failed, socket might closed, read ret: -1. Ini adalah sumber yang sesuai di GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Dipanggil melalui readInt (), dipanggil dari https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Beberapa metadata dump dari soket bekas menghasilkan informasi berikut. Ini persis sama di Nexus 7 dan ponsel 2.3.7 saya.

Bluetooth Device 'OBDII'
Address: 11:22:33:DD:EE:FF
Bond state: 12 (bonded)
Type: 1
Class major version: 7936
Class minor version: 7936
Class Contents: 0
Contents: 0

Saya memiliki beberapa adaptor OBD-II lainnya (lebih ekspansif) dan semuanya berfungsi. Apakah ada kemungkinan, bahwa saya melewatkan sesuatu atau mungkinkah ini bug di Android?

matthes
sumber
Saya telah mencoba solusi di atas, dapatkah sombody membantu dalam masalah ini stackoverflow.com/q/52105647/1559331
dileepVikram

Jawaban:

129

Saya akhirnya menemukan solusi. Keajaiban tersembunyi di balik kap BluetoothDevicekelas (lihat https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Sekarang, ketika saya menerima pengecualian itu, saya membuat contoh fallback BluetoothSocket, mirip dengan kode sumber di bawah ini. Seperti yang Anda lihat, memanggil metode tersembunyi createRfcommSocketmelalui refleksi. Saya tidak tahu mengapa metode ini disembunyikan. Kode sumber mendefinisikannya seolah- publicolah ...

Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};

Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};

fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
fallbackSocket.connect();

connect()maka tidak akan gagal lagi. Saya masih mengalami beberapa masalah. Pada dasarnya, ini terkadang memblokir dan gagal. Reboot Perangkat SPP (colok / colokkan) membantu dalam kasus seperti itu. Kadang-kadang saya juga mendapatkan permintaan Penyandingan lain connect()bahkan setelah perangkat sudah diikat.

MEMPERBARUI:

di sini adalah kelas lengkap, berisi beberapa kelas bertingkat. untuk implementasi nyata ini bisa diadakan sebagai kelas terpisah.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;

public class BluetoothConnector {

    private BluetoothSocketWrapper bluetoothSocket;
    private BluetoothDevice device;
    private boolean secure;
    private BluetoothAdapter adapter;
    private List<UUID> uuidCandidates;
    private int candidate;


    /**
     * @param device the device
     * @param secure if connection should be done via a secure socket
     * @param adapter the Android BT adapter
     * @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
     */
    public BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
            List<UUID> uuidCandidates) {
        this.device = device;
        this.secure = secure;
        this.adapter = adapter;
        this.uuidCandidates = uuidCandidates;

        if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
            this.uuidCandidates = new ArrayList<UUID>();
            this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
        }
    }

    public BluetoothSocketWrapper connect() throws IOException {
        boolean success = false;
        while (selectSocket()) {
            adapter.cancelDiscovery();

            try {
                bluetoothSocket.connect();
                success = true;
                break;
            } catch (IOException e) {
                //try the fallback
                try {
                    bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
                    Thread.sleep(500);                  
                    bluetoothSocket.connect();
                    success = true;
                    break;  
                } catch (FallbackException e1) {
                    Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
                } catch (InterruptedException e1) {
                    Log.w("BT", e1.getMessage(), e1);
                } catch (IOException e1) {
                    Log.w("BT", "Fallback failed. Cancelling.", e1);
                }
            }
        }

        if (!success) {
            throw new IOException("Could not connect to device: "+ device.getAddress());
        }

        return bluetoothSocket;
    }

    private boolean selectSocket() throws IOException {
        if (candidate >= uuidCandidates.size()) {
            return false;
        }

        BluetoothSocket tmp;
        UUID uuid = uuidCandidates.get(candidate++);

        Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
        if (secure) {
            tmp = device.createRfcommSocketToServiceRecord(uuid);
        } else {
            tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
        }
        bluetoothSocket = new NativeBluetoothSocket(tmp);

        return true;
    }

    public static interface BluetoothSocketWrapper {

        InputStream getInputStream() throws IOException;

        OutputStream getOutputStream() throws IOException;

        String getRemoteDeviceName();

        void connect() throws IOException;

        String getRemoteDeviceAddress();

        void close() throws IOException;

        BluetoothSocket getUnderlyingSocket();

    }


    public static class NativeBluetoothSocket implements BluetoothSocketWrapper {

        private BluetoothSocket socket;

        public NativeBluetoothSocket(BluetoothSocket tmp) {
            this.socket = tmp;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return socket.getInputStream();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return socket.getOutputStream();
        }

        @Override
        public String getRemoteDeviceName() {
            return socket.getRemoteDevice().getName();
        }

        @Override
        public void connect() throws IOException {
            socket.connect();
        }

        @Override
        public String getRemoteDeviceAddress() {
            return socket.getRemoteDevice().getAddress();
        }

        @Override
        public void close() throws IOException {
            socket.close();
        }

        @Override
        public BluetoothSocket getUnderlyingSocket() {
            return socket;
        }

    }

    public class FallbackBluetoothSocket extends NativeBluetoothSocket {

        private BluetoothSocket fallbackSocket;

        public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
            super(tmp);
            try
            {
              Class<?> clazz = tmp.getRemoteDevice().getClass();
              Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
              Method m = clazz.getMethod("createRfcommSocket", paramTypes);
              Object[] params = new Object[] {Integer.valueOf(1)};
              fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
            }
            catch (Exception e)
            {
                throw new FallbackException(e);
            }
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return fallbackSocket.getInputStream();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return fallbackSocket.getOutputStream();
        }


        @Override
        public void connect() throws IOException {
            fallbackSocket.connect();
        }


        @Override
        public void close() throws IOException {
            fallbackSocket.close();
        }

    }

    public static class FallbackException extends Exception {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        public FallbackException(Exception e) {
            super(e);
        }

    }
}
matthes
sumber
3
Wow! solusi yang bagus!
Bobs
2
@MD saya tidak tahu caranya. Saya baru saja menguji dan ternyata berfungsi.
Bobs
1
Ini tidak berfungsi pada nexus 4. dapatkah Anda memberi tahu cara mengatasi masalah ini. Saya hampir mencoba segalanya. Terima kasih.
Shah
3
@ Matthes Maaf untuk mengatakan tetapi bahkan solusi Anda menggunakan fallback belum Memecahkan masalah saya. Mendapatkan di bawah Kesalahan. Fallback failed. Cancelling. java.io.IOException: Connection refused Tolong bantu.
Tushar Banne
2
@ matthes "SPP-Device (plug off / plug in) membantu dalam kasus seperti itu.". Pernyataan on / off adalah yang paling diremehkan di dunia. Saya hanya menyia-nyiakan 3 jam dan yang harus saya lakukan hanyalah menyalakan dan mematikannya -_-
Adz
98

baik, saya memiliki masalah yang sama dengan kode saya, dan itu karena sejak android 4.2 bluetooth stack telah berubah. jadi kode saya berjalan dengan baik di perangkat dengan android <4.2, di perangkat lain saya mendapatkan pengecualian yang terkenal "gagal baca, soket mungkin tertutup atau batas waktu, baca ret: -1"

Masalahnya ada pada socket.mPortparameternya. Saat Anda membuat soket menggunakan socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);, mPortmendapat nilai integer " -1 ", dan nilai ini tampaknya tidak berfungsi untuk android> = 4.2, jadi Anda perlu menyetelnya ke " 1 ". Kabar buruknya adalah bahwa createRfcommSocketToServiceRecordhanya menerima UUID sebagai parameter dan tidak mPortbegitu kita harus menggunakan pendekatan lain. Jawabannya diposting oleh @matthes juga bekerja untuk saya, tetapi saya disederhanakan: socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);. Kita perlu menggunakan kedua atribut soket, yang kedua sebagai cadangan.

Jadi kodenya adalah (untuk menghubungkan ke SPP di perangkat ELM327):

BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();

    if (btAdapter.isEnabled()) {
        SharedPreferences prefs_btdev = getSharedPreferences("btdev", 0);
        String btdevaddr=prefs_btdev.getString("btdevaddr","?");

        if (btdevaddr != "?")
        {
            BluetoothDevice device = btAdapter.getRemoteDevice(btdevaddr);

            UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); // bluetooth serial port service
            //UUID SERIAL_UUID = device.getUuids()[0].getUuid(); //if you don't know the UUID of the bluetooth device service, you can get it like this from android cache

            BluetoothSocket socket = null;

            try {
                socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID);
            } catch (Exception e) {Log.e("","Error creating socket");}

            try {
                socket.connect();
                Log.e("","Connected");
            } catch (IOException e) {
                Log.e("",e.getMessage());
                try {
                    Log.e("","trying fallback...");

                    socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1);
                    socket.connect();

                    Log.e("","Connected");
                }
             catch (Exception e2) {
                 Log.e("", "Couldn't establish Bluetooth connection!");
              }
            }
        }
        else
        {
            Log.e("","BT device not selected");
        }
    }
George Dima
sumber
57
untuk moderator: karena Anda menghapus jawaban saya sebelumnya tanpa alasan, saya mempostingnya lagi.
George Dima
2
terima kasih George atas wawasan tentang mPortparameter! imho alur kerjanya tetap sama, saya hanya membungkus hal-hal dengan beberapa kelas yang menerapkan antarmuka.
matthes
5
ya, saya sudah mengatakan solusi Anda bagus, tetapi saya ingin membuat orang mengerti mengapa perlu menggunakan pendekatan ini dimulai dengan Android 4.2
George Dima
2
SPP = Profil Port Serial (yang mengemulasi port serial melalui bluetooth) dan ELM327 adalah perangkat bluetooth <-> obd car, google saja.
George Dima
10
Ini berfungsi untuk saya setelah mengubah nilai port dari 1 menjadi 2. Silakan lihat kode ini. socket = (BluetoothSocket) device.getClass (). getMethod ("createRfcommSocket", Class baru [] {int.class}). invoke (device, 2); socket.connect ();
Dinesh IT
16

Pertama, jika Anda perlu berbicara dengan perangkat bluetooth 2.x, dokumentasi ini menyatakan bahwa:

Petunjuk: Jika Anda menghubungkan ke papan serial Bluetooth, coba gunakan SPP UUID yang terkenal 00001101-0000-1000-8000-00805F9B34FB . Namun jika Anda terhubung ke rekan Android, buat UUID unik Anda sendiri.

Saya tidak berpikir itu akan berhasil, tetapi hanya dengan mengganti UUID dengan 00001101-0000-1000-8000-00805F9B34FBitu berfungsi. Namun, kode ini tampaknya menangani masalah versi SDK, dan Anda bisa mengganti fungsinya device.createRfcommSocketToServiceRecord(mMyUuid);dengan tmp = createBluetoothSocket(mmDevice);setelah menentukan metode berikut:

private BluetoothSocket createBluetoothSocket(BluetoothDevice device)
    throws IOException {
    if(Build.VERSION.SDK_INT >= 10){
        try {
            final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
            return (BluetoothSocket) m.invoke(device, mMyUuid);
        } catch (Exception e) {
            Log.e(TAG, "Could not create Insecure RFComm Connection",e);
        }
    }
    return  device.createRfcommSocketToServiceRecord(mMyUuid);
}

Kode sumber bukan milik saya, tetapi berasal dari situs web ini .

tobiasBora
sumber
1
Itu menyelesaikan hampir 2 hari kerja ... desahan syukur ... Tanpa UUID ini soket akan langsung menutup dan gagal tanpa penjelasan lebih lanjut.
David Sinclair
terima kasih banyak atas bantuannya. UUID SAYA adalah alfanumerik dan saya mencoba untuk menghubungkan HC-5 dan koneksi yang menunjukkan bluetooth saya gagal tetapi ketika saya menggunakan solusi ini, masalah saya terpecahkan. terima kasih lagi
Nikhil Shende
8

Saya mengalami gejala yang sama seperti yang dijelaskan di sini. Saya dapat menghubungkan sekali ke printer bluetooth tetapi koneksi berikutnya gagal dengan "soket tertutup" tidak peduli apa yang saya lakukan.

Saya merasa agak aneh bahwa solusi yang dijelaskan di sini diperlukan. Setelah melalui kode saya, saya menemukan bahwa saya lupa menutup InputStream dan OutputSteram soket dan tidak menghentikan ConnectedThreads dengan benar.

ConnectedThread yang saya gunakan sama dengan contoh di sini:

http://developer.android.com/guide/topics/connectivity/bluetooth.html

Perhatikan bahwa ConnectThread dan ConnectedThread adalah dua kelas yang berbeda.

Kelas apa pun yang memulai ConnectedThread harus memanggil interrupt () dan cancel () di thread. Saya menambahkan mmInStream.close () dan mmOutStream.close () dalam metode ConnectedTread.cancel ().

Setelah menutup utas / aliran / soket dengan benar, saya dapat membuat soket baru tanpa masalah.

Daniel T
sumber
Terima kasih, mengalami masalah yang sama, barusan saya pikir saya belum menutup aliran dan koneksi ...
Rafael
mencoba semua skenario di atas, (kecuali untuk menghapus penyebab perangkat berpasangan lain dengan baik yang sebenarnya bukan solusi ditemukan bahwa ya ... ini biasanya hanya terjadi ketika aliran input dan soket tidak ditutup dengan benar ..... !!
Aman Satija
7

Sebenarnya saya telah menemukan masalahnya.

Kebanyakan orang yang mencoba membuat koneksi menggunakan socket.Connect();mendapatkan pengecualian dipanggil Java.IO.IOException: read failed, socket might closed, read ret: -1.

Dalam beberapa kasus juga tergantung pada perangkat Bluetooth Anda, karena terdapat dua jenis Bluetooth yang berbeda, yaitu BLE (hemat energi) dan Klasik.

Jika Anda ingin memeriksa jenis perangkat Bluetooth Anda, berikut kodenya:

        String checkType;
        var listDevices = BluetoothAdapter.BondedDevices;
        if (listDevices.Count > 0)
        {
            foreach (var btDevice in listDevices)
            {
                if(btDevice.Name == "MOCUTE-032_B52-CA7E")
                {
                    checkType = btDevice.Type.ToString();
                    Console.WriteLine(checkType);
                }
            }
        }

Saya sudah mencoba selama berhari-hari untuk memecahkan masalah, tetapi sejak hari ini saya telah menemukan masalahnya. Sayangnya, solusi dari @matthes masih memiliki beberapa masalah seperti yang dia katakan, tetapi inilah solusi saya.

Saat ini saya bekerja di Xamarin Android, tetapi ini juga harus berfungsi untuk platform lain.

LARUTAN

Jika terdapat lebih dari satu perangkat pasangan, maka Anda harus menghapus perangkat pasangan lainnya. Jadi simpan hanya yang ingin Anda hubungkan (lihat gambar di kanan).

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Pada gambar kiri Anda melihat bahwa saya memiliki dua perangkat yang dipasangkan, yaitu "MOCUTE-032_B52-CA7E" dan "Blue Easy". Itulah masalahnya, tetapi saya tidak tahu mengapa masalah itu terjadi. Mungkin protokol Bluetooth mencoba mendapatkan beberapa informasi dari perangkat Bluetooth lain.

Namun, socket.Connect();pekerjaannya bagus sekarang, tanpa masalah. Jadi saya hanya ingin membagikan ini, karena kesalahan itu sangat mengganggu.

Semoga berhasil!

Jamie
sumber
Ini bekerja pada satu perangkat tempat saya mengalami masalah ini, yang hanya terjadi pada saya pada ponsel 5.0, dan bahkan hanya ketika saya pertama kali mengaktifkan BT, kemudian membuka koneksi. Jika BT sudah aktif, tidak ada masalah koneksi! Itu tidak terjadi pada perangkat dengan versi Android yang lebih baru, menunjukkan pengembang memperhatikan bug & memperbaikinya, tetapi halaman Android BT tidak menjelaskan sepatah kata pun tentang itu. Tapi solusi Anda berhasil, terima kasih!
John Perry
7

Pada versi Android yang lebih baru, saya menerima kesalahan ini karena adaptor masih menemukan ketika saya mencoba untuk menyambung ke soket. Meskipun saya memanggil metode cancelDiscovery pada adaptor Bluetooth, saya harus menunggu hingga callback ke metode onReceive () BroadcastReceiver dipanggil dengan tindakan BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Setelah saya menunggu adaptor menghentikan penemuan, maka panggilan hubungkan pada soket berhasil.

kmac.mcfarlane
sumber
6

Anda meletakkan registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); dengan "bluetooth" dieja "bleutooth".

Fizz Binn
sumber
4

Jika seseorang mengalami masalah dengan Kotlin, saya harus mengikuti jawaban yang diterima dengan beberapa variasi:

fun print(view: View, text: String) {
    var adapter = BluetoothAdapter.getDefaultAdapter();
    var pairedDevices = adapter.getBondedDevices()
    var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    if (pairedDevices.size > 0) {
        for (device in pairedDevices) {
            var s = device.name
            if (device.getName().equals(printerName, ignoreCase = true)) {
                Thread {
                    var socket = device.createInsecureRfcommSocketToServiceRecord(uuid)
                    var clazz = socket.remoteDevice.javaClass
                    var paramTypes = arrayOf<Class<*>>(Integer.TYPE)
                    var m = clazz.getMethod("createRfcommSocket", *paramTypes)
                    var fallbackSocket = m.invoke(socket.remoteDevice, Integer.valueOf(1)) as BluetoothSocket
                    try {
                        fallbackSocket.connect()
                        var stream = fallbackSocket.outputStream
                        stream.write(text.toByteArray(Charset.forName("UTF-8")))
                    } catch (e: Exception) {
                        e.printStackTrace()
                        Snackbar.make(view, "An error occurred", Snackbar.LENGTH_SHORT).show()
                    }
                }.start()
            }
        }
    }
}

Semoga membantu

Santiago Martí Olbrich
sumber
3

Perangkat Bluetooth dapat beroperasi dalam mode klasik dan LE secara bersamaan. Terkadang mereka menggunakan alamat MAC yang berbeda tergantung pada cara Anda menghubungkan. Panggilansocket.connect() menggunakan Bluetooth Classic, jadi Anda harus memastikan perangkat yang Anda dapatkan saat memindai benar-benar perangkat klasik.

Mudah untuk memfilter hanya untuk perangkat Klasik, namun:

if(BluetoothDevice.DEVICE_TYPE_LE == device.getType()){ //socket.connect() }

Tanpa pemeriksaan ini, ini adalah kondisi balapan, apakah pemindaian hibrid akan memberi Anda perangkat Klasik atau perangkat BLE terlebih dahulu. Ini mungkin tampak sebagai ketidakmampuan intermiten untuk terhubung, atau sebagai perangkat tertentu yang dapat terhubung dengan andal sementara yang lain tampaknya tidak pernah bisa.

kmac.mcfarlane
sumber
1

Saya juga menghadapi masalah ini, Anda bisa menyelesaikannya dengan 2 cara, seperti yang disebutkan sebelumnya menggunakan refleksi untuk membuat soket Kedua adalah, klien mencari server dengan UUID yang diberikan dan jika server Anda tidak berjalan paralel dengan klien maka ini terjadi. Buat server dengan UUID klien tertentu dan kemudian dengarkan dan terima klien dari sisi server. Ini akan berfungsi.

ireshika piyumalie
sumber
1

Saya mengalami masalah ini dan memperbaikinya dengan menutup aliran input dan output sebelum menutup soket. Sekarang saya dapat memutuskan sambungan dan terhubung lagi tanpa masalah.

https://stackoverflow.com/a/3039807/5688612

Di Kotlin:

fun disconnect() {
    bluetoothSocket.inputStream.close()
    bluetoothSocket.outputStream.close()
    bluetoothSocket.close()
}
TheoKanning
sumber
1

Jika bagian lain dari kode Anda telah membuat koneksi dengan soket yang sama dan UUID, Anda mendapatkan kesalahan ini.

pengguna1725145
sumber
0

Bahkan saya memiliki masalah yang sama, akhirnya memahami masalah saya, saya mencoba menyambung dari (di luar jangkauan) jangkauan jangkauan Bluetooth.

krishnamurthy
sumber
0

Saya punya masalah ini dan solusinya adalah menggunakan GUID ajaib khusus.

            val id: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // Any other GUID doesn't work.
            val device: BluetoothDevice = bta!!.bondedDevices.first { z -> z.name == deviceName }

            bts = device.createRfcommSocketToServiceRecord(id) // mPort is -1
            bts?.connect()
            // Start processing thread.

Saya curiga bahwa ini adalah UUID yang berfungsi:

var did: Array<ParcelUuid?> = device.uuids

Namun, saya belum mencoba semuanya.

Richard Barraclough
sumber
Bahkan saya menggunakan UUID yang sama. Tapi tidak membantu saya. Apakah ini hanya mendukung untuk menghubungkan ke perangkat bluetooth Klasik (bukan BLE)? Apa yang harus saya lakukan untuk menyambung ke perangkat BLE menggunakan Xamarin.Forms. Diposting di sini [ stackoverflow.com/questions/62371859/…
Shailesh Bhat
Saya menggunakan Bluetooth klasik; BLE adalah sampah.
Richard Barraclough
-1

Dengan menambahkan tindakan filter, masalah saya teratasi

 // Register for broadcasts when a device is discovered
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
    intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    registerReceiver(mReceiver, intentFilter);
Vinod Ranga
sumber
-3

Saya juga menerima hal yang sama IOException, tetapi saya menemukan demo sistem Android: proyek "BluetoothChat" berhasil. Saya menentukan masalahnya adalah UUID.

Jadi saya mengganti saya UUID.fromString("00001001-0000-1000-8000-00805F9B34FB")ke UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")dan itu berfungsi paling banyak adegan, hanya kadang-kadang perlu me-restart perangkat Bluetooth;

taotao
sumber