Android:经典蓝牙开发

来源:互联网 发布:c语言编译器安卓中文版 编辑:程序博客网 时间:2024/06/09 20:38

前言:

参加工作也有两年了,一直没什么机会接触蓝牙这一块的开发,特地找时间实践了一下。一开始本来是想尝试BLE的(毕竟是主流了),但是用了两台手机发现都不支持,只好先转战经典蓝牙。


关于API这里就不赘述了,网上已经总结的很好。这里简单实现一个小功能,给出源码大家共同学习。

1)使用前要确保蓝牙的打开等,这里的处理可能有bug,而且先前连接过的要到系统设置里取消配对才能搜索得出来。

2)SDK和系统的版本差异这个没特别的去试验,不一定能运行,这一点相信大家是很有经验的了。

 


一.服务端

1)服务端的话就是等待链接,链接成功之后点击发送图片会调用摄像头拍照之后将图像发送给客户端。

2)连接监听,输入流读数据都是阻塞的,这里都是开一个线程操作。

3)IO流在读取文件的时候一般我们都是判断是否读到-1为结束标志,但是socket的有所不同,输入流并不知道什么时候读到尾了(试过在最后写一个换行符,但是没用)。这里采 取的方法是客户端写入的时候在头四个字节写入图片的byte[]数组长度,那么服务端先读头四个字节得到文件的长度,再根据接受数据的总长度判断是否结束,基于这一点,   我们也可以很容易写出一个进度条的效果。

public class MainActivity extends AppCompatActivity {    private final String MYUUID = "00001101-0000-1000-8000-00805F9B34FB";    private final String TAG = "Bluetooth";    private BluetoothAdapter blueAdapter;    private BluetoothSocket socket;    private InputStream is;    private OutputStream os;    private ReadThread readThread;    private Button btnSendPic;    private ImageView imgView;    private byte[] bitmapBuffer;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        blueAdapter = BluetoothAdapter.getDefaultAdapter();        if (blueAdapter == null)            return;        btnSendPic = (Button) findViewById(R.id.button_send_pic);        imgView = (ImageView) findViewById(R.id.pic);        if (btnSendPic != null) {            btnSendPic.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                    startActivityForResult(intent,                            100);                }            });        }        Thread t = new Thread(new Runnable() {            @Override            public void run() {                try {                    BluetoothServerSocket serverSocket = blueAdapter.listenUsingRfcommWithServiceRecord("my socket", UUID.fromString(MYUUID));                    socket = serverSocket.accept();                    if (socket.isConnected()) {                        is = socket.getInputStream();                        os = socket.getOutputStream();                        readThread = new ReadThread();                        readThread.start();                    }                } catch (IOException e) {                    e.printStackTrace();                }            }        });        t.start();    }    public static byte[] readStream(InputStream inStream) throws Exception {        if (inStream.available() <= 0)            return null;        byte[] head = new byte[4];        byte[] buffer = new byte[1024];        int len = -1;        int length = 0;        inStream.read(head);        int scrLength = bytesToInt(head, 0);        ByteArrayOutputStream outStream = new ByteArrayOutputStream();        while ((len = inStream.read(buffer)) != -1) {            length = length + len;            outStream.write(buffer, 0, len);            if (length >= scrLength)                break;        }        byte[] data = outStream.toByteArray();        outStream.close();        return data;    }    public static byte[] intToBytes(int value) {        byte[] src = new byte[4];        src[3] = (byte) ((value >> 24) & 0xFF);        src[2] = (byte) ((value >> 16) & 0xFF);        src[1] = (byte) ((value >> 8) & 0xFF);        src[0] = (byte) (value & 0xFF);        return src;    }    public static int bytesToInt(byte[] src, int offset) {        int value;        value = (int) ((src[offset] & 0xFF)                | ((src[offset + 1] & 0xFF) << 8)                | ((src[offset + 2] & 0xFF) << 16)                | ((src[offset + 3] & 0xFF) << 24));        return value;    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == 100                && resultCode == Activity.RESULT_OK) {            Bundle bundle = data.getExtras();            Bitmap map = (Bitmap) bundle.get("data");            ByteArrayOutputStream baos = new ByteArrayOutputStream();            map.compress(Bitmap.CompressFormat.JPEG, 10, baos);            byte[] picData = baos.toByteArray();            if (socket.isConnected() && os != null) {                try {                    os.write(intToBytes(picData.length));                    os.write(picData);                    os.flush();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    private class ReadThread extends Thread {        @Override        public void run() {            super.run();            while (true) {                if (socket != null && is != null) {                    try {                        final byte[] bitmapBuffer = readStream(is);                        if (bitmapBuffer != null && bitmapBuffer.length > 0) {                            runOnUiThread(new Runnable() {                                @Override                                public void run() {                                    if (imgView != null) {                                        imgView.setImageBitmap(BitmapFactory.decodeByteArray(bitmapBuffer, 0, bitmapBuffer.length));                                    }                                }                            });                        }                    } catch (Exception e) {                    }                }            }        }    }}

二.客户端

1)点击扫面之后会把结果放到一个列表里,再点击列表项就能连接配对了,这里配对用的还是系统的。

2)其他逻辑和服务端的差不多了


public class MainActivity extends AppCompatActivity {    private final String MYUUID = "00001101-0000-1000-8000-00805F9B34FB";    private final String TAG = "Bluetooth";    private BluetoothAdapter blueAdapter;    private ContentAdapter contentAdapter;    private ArrayList<BluetoothDevice> array;    private BluetoothSocket clientSocket;    private InputStream is;    private OutputStream os;    private Button btScan;    private Button btSendPic;    private ImageView imgView;    private ListView listView;    private byte[] bitmapBuffer;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        blueAdapter = BluetoothAdapter.getDefaultAdapter();        if (blueAdapter == null) {            return;        }        array = new ArrayList<BluetoothDevice>();        contentAdapter = new ContentAdapter();        imgView = (ImageView) findViewById(R.id.pic);        btSendPic = (Button) findViewById(R.id.button_send_pic);        if (btSendPic != null) {            btSendPic.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                    startActivityForResult(intent,                            100);                }            });        }        BlueReceiver receiver = new BlueReceiver();        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);        registerReceiver(receiver, filter);        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);        registerReceiver(receiver, filter);        btScan = (Button) findViewById(R.id.btScan);        btScan.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                blueAdapter.startDiscovery();            }        });        listView = (ListView) findViewById(R.id.listview);        if (listView != null) {            listView.setAdapter(contentAdapter);        }    }    public static byte[] intToBytes(int value) {        byte[] src = new byte[4];        src[3] = (byte) ((value >> 24) & 0xFF);        src[2] = (byte) ((value >> 16) & 0xFF);        src[1] = (byte) ((value >> 8) & 0xFF);        src[0] = (byte) (value & 0xFF);        return src;    }    public static int bytesToInt(byte[] src, int offset) {        int value;        value = (int) ((src[offset] & 0xFF)                | ((src[offset + 1] & 0xFF) << 8)                | ((src[offset + 2] & 0xFF) << 16)                | ((src[offset + 3] & 0xFF) << 24));        return value;    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (requestCode == 100                && resultCode == Activity.RESULT_OK) {            Bundle bundle = data.getExtras();            Bitmap map = (Bitmap) bundle.get("data");            ByteArrayOutputStream baos = new ByteArrayOutputStream();            map.compress(Bitmap.CompressFormat.JPEG, 10, baos);            byte[] picData = baos.toByteArray();            if (clientSocket.isConnected() && os != null) {                try {                    os.write(intToBytes(picData.length));                    os.write(picData);                    os.flush();                } catch (IOException e) {                    e.printStackTrace();                } finally {                }            }        }    }    public static byte[] readStream(InputStream inStream) throws Exception {        if (inStream.available() <= 0)            return null;        byte[] head = new byte[4];        byte[] buffer = new byte[1024];        int len = -1;        int length = 0;        inStream.read(head);        int scrLength = bytesToInt(head, 0);        ByteArrayOutputStream outStream = new ByteArrayOutputStream();        while ((len = inStream.read(buffer)) != -1) {            length = length + len;            outStream.write(buffer, 0, len);            if (length >= scrLength)                break;        }        byte[] data = outStream.toByteArray();        outStream.close();        return data;    }    private class ReadThread extends Thread {        @Override        public void run() {            super.run();            while (true) {                if (clientSocket.isConnected() && is != null) {                    try {                        final byte[] bitmapBuffer = readStream(is);                        if (bitmapBuffer != null && bitmapBuffer.length > 0) {                            runOnUiThread(new Runnable() {                                @Override                                public void run() {                                    if (imgView != null) {                                        imgView.setImageBitmap(BitmapFactory.decodeByteArray(bitmapBuffer, 0, bitmapBuffer.length));                                    }                                }                            });                        }                    } catch (Exception e) {                    }                }            }        }    }    private class ContentAdapter extends BaseAdapter {        @Override        public int getCount() {            return array.size();        }        @Override        public Object getItem(int i) {            return null;        }        @Override        public long getItemId(int i) {            return 0;        }        @Override        public View getView(final int i, View view, ViewGroup viewGroup) {            View v = getLayoutInflater().inflate(R.layout.list_item, null);            Button bt = (Button) v.findViewById(R.id.button1);            if (bt != null) {                bt.setText(array.get(i).getName() + "," + array.get(i).getAddress());                bt.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View view) {                        Thread t = new Thread(new Runnable() {                            @Override                            public void run() {                                try {                                    blueAdapter.cancelDiscovery();                                    clientSocket = array.get(i).createRfcommSocketToServiceRecord(UUID.fromString(MYUUID));                                    clientSocket.connect();                                    if (clientSocket.isConnected()) {                                        os = clientSocket.getOutputStream();                                        is = clientSocket.getInputStream();                                        ReadThread thread = new ReadThread();                                        thread.start();                                    }                                } catch (IOException e) {                                    e.printStackTrace();                                }                            }                        });                        t.start();                    }                });            }            return v;        }    }    private class BlueReceiver extends BroadcastReceiver {        @Override        public void onReceive(android.content.Context context, Intent intent) {            String action = intent.getAction();            if (BluetoothDevice.ACTION_FOUND.equals(action)) {                BluetoothDevice device = intent                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {                    array.add(device);                    contentAdapter.notifyDataSetChanged();                    Log.v(TAG, "find device:" + device.getName() + "," +                            device.getAddress() + device.getUuids());                }            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED                    .equals(action)) {                Log.v(TAG, "find over");            }        }    }}

源码下载,这里只给出主要的类和布局,大家最好自己构建项目,就不会有这么多编译上的问题。

https://github.com/SingleInstance/classic-bluetooth-for-Android


原创粉丝点击