蓝牙开发

* 前几天售前拿来个电子秤,扔地上说,明天要拿这个取招商,功能就是称完之后在app显示重量...
* 内心一万个cnm,没有需求,没有原型,没有评估。还明天就要!大写的服。
* 抱怨太多也没用。问了下是什么通信协议,--->蓝牙发送数据。
*
* 不多说了,撸起袖子干吧。
* 问了生产商,没有sdk,没有文档。只有说明书,靠。等等...说明书上有解析协议。
* 然后开始。。。翻了下git.不太理想。自己撸吧。

都有注释。。

​

package com.basexhgx.xhgx.bthutils;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;

/**
 * Create: 2018/9/20 14:14
 *
 * @author: Winstronzeng [email protected]
 * Description:  扫描蓝牙工具类,扫描设置
 * Version: 1.0
 **/

public class SearchBluetooth {
    BluetoothAdapter mBluetootadapter;


    //TODO  静态单例内部类
    private SearchBluetooth() {
        mBluetootadapter = BluetoothAdapter.getDefaultAdapter();
    }

    public static SearchBluetooth getInstance() {
        return SearchBluetooth2.t;
    }

    private static class SearchBluetooth2 {
        private static SearchBluetooth t = new SearchBluetooth();
    }

    /**
     * 扫描蓝牙设备
     * <p>
     * mBluetootadapter.cancelDiscovery();//停止扫描
     * mBluetootadapter.startDiscovery();//开始扫描附件蓝牙
     * 通过广播接收扫描到的蓝牙设备。并通过配对后进行 socket连接传输数据
     */
    public void doSearchBluetooth() {

        if (null == mBluetootadapter) {
            mBluetootadapter = BluetoothAdapter.getDefaultAdapter();
        }
        if (!mBluetootadapter.isEnabled()) {
            //TODO 校验蓝牙是否打开
            //不做提示,强行打开,此方法需要权限&lt;uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" /&gt;
            boolean enable = mBluetootadapter.enable();
            if (enable) {
                //TODO 扫描蓝牙设备
                mBluetootadapter.cancelDiscovery();
                mBluetootadapter.startDiscovery();
            }
        } else {
            //TODO 扫描蓝牙设备
            mBluetootadapter.cancelDiscovery();//停止扫描
            mBluetootadapter.startDiscovery();//开始扫描附件蓝牙

        }

    }

    public void stopSearchBluetooth() {
        //TODO  停止扫描蓝牙
        if (null != mBluetootadapter) {
            mBluetootadapter.cancelDiscovery();
        }
    }

    public void doConnetBluetooth(int states, BluetoothDevice btDevice, BluetoothAsyncTask bluetoothAsyncTask) {
        if (states == BluetoothDevice.BOND_NONE || states == BluetoothDevice.BOND_BONDED) {
            //TODO  没有配对
            try {
                //通过工具类ClsUtils,调用createBond方法
                boolean bond = BluetoothClsUtils.createBond(btDevice.getClass(), btDevice);
                if (bond) {
                    //创建连接
                    mBluetootadapter.cancelDiscovery();//创建连接前,最好关闭扫描。否则会导致连接上的蓝牙断开。
                    bluetoothAsyncTask.execute("98:D3:32:30:95:B4");
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (states == BluetoothDevice.BOND_BONDED) {
                //TODO  已经配对直接链接

                mBluetootadapter.cancelDiscovery();//创建连接前,最好关闭扫描。否则会导致连接上的蓝牙断开。
                new BluetoothAsyncTask().execute("98:D3:32:30:95:B4");
            }
        }
    }
}

[点击并拖拽以移动]
​
 

有个特别重要的事:

记得添加权限,你不添加as也会提示你的
 

<uses-permission android:name="android.permission.BLUETOOTH" />

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

扫描完,就到接收扫描到的设备了,系统通过广播接收

我们自己写个广播类接收

package com.basexhgx.xhgx.bthutils;


import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.basexhgx.xhgx.bthutils.Obsever.LeaderCenter;

/**
 * Create: 2018/9/20 14:16
 *
 * @author: Winstronzeng [email protected]
 * Description: 接受蓝牙广播
 * Version: 1.0
 **/


public class AcceptBluetoothReceiver extends BroadcastReceiver {
    BluetoothDevice device = null;
    String pin = "1234";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // 发现设备
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            //TODO  从Intent中获取设备对象
            device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //TODO 发现蓝牙设备
            getBluetoothDevice(device);
        } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
            //TODO  扫描结束

        } else if (action.equals("android.bluetooth.device.action.PAIRING_REQUEST")) {
            //再次得到的action,会等于PAIRING_REQUEST
            if (device == null) {
                return;
            }
            try {
                //1.确认配对
                BluetoothClsUtils.setPairingConfirmation(device.getClass(), device, true);
                //2.终止有序广播
                Log.i("info","提示信息" + "isOrderedBroadcast:" + isOrderedBroadcast() + ",isInitialStickyBroadcast:" + isInitialStickyBroadcast());
                abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
                //3.调用setPin方法进行配对...
                boolean ret = BluetoothClsUtils.setPin(device.getClass(), device, pin);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
                Log.i("info","--------------连接断开了-----------");
            }
            // Bluetooth is disconnected, do handling here
        } else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {

            Log.i("info","正在断开蓝牙连接。。。");

        } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
            Log.i("info","已断开蓝牙连接。。。");

        } else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {

            Log.i("info","---------连接了蓝牙成功-----");
        }

    }


    /**
     * 发现蓝牙设备
     *
     * @param device
     */
    public void getBluetoothDevice(BluetoothDevice device) {
        Log.i("info","------->发现目标");
        // 将设备名称和地址放入array adapter,以便在ListView中显示
        LeaderCenter.getInstance().notifyObserver("bluetooth", device);
    }


}

接收到广播数据通过观察者向外传递。也可以通过接口回调或者EventBus传递

通过Activity展示扫描到的蓝牙设备

package com.basexhgx.xhgx.bluetooth;

import android.bluetooth.BluetoothDevice;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.basexhgx.xhgx.bthutils.BluetoothAsyncTask;
import com.basexhgx.xhgx.bthutils.Obsever.BluetoothObserver;
import com.basexhgx.xhgx.bthutils.Obsever.LeaderCenter;
import com.basexhgx.xhgx.bthutils.SearchBluetooth;
import com.basexhgx.xhgx.modle.BluetoothEntity;
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class SearchActivity extends AppCompatActivity implements BluetoothAsyncTask.BluetoothData, BluetoothObserver, AdapterView.OnItemClickListener {
    List<BluetoothDevice> list = new ArrayList<>();
    private Button mSearch;
    private Button sendmsg;
    private ListView mRecyclerview;
    private TextView mPaccept;
    private LinearLayout mLl;
    private EditText editText;
    public static String text;

    private MyBluetoothAdapter mybluetoothAdapter;
    private BluetoothAsyncTask bluetoothAsyncTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        mSearch = (Button) findViewById(R.id.search);
        sendmsg = (Button) findViewById(R.id.sendmsg);
        mRecyclerview = (ListView) findViewById(R.id.recyclerview);
        mPaccept = (TextView) findViewById(R.id.paccept);
        mLl = (LinearLayout) findViewById(R.id.ll);
        editText = findViewById(R.id.edt);
        LeaderCenter.getInstance().registerObserver(this);
        mSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SearchBluetooth.getInstance().doSearchBluetooth();
            }
        });
        sendmsg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                text = editText.getText().toString();
                editText.setText("");
            }
        });
    }

    @Override
    public void bluetoothData(String s, byte[] data) {
        mPaccept.setText("收到=" + s);
    }

    @Override
    public void connetState(String result) {
        mPaccept.setText("收到=" + result);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    @Override
    public void acceptSubjectState(Object obj) {
        //TODO  扫描到的蓝牙设备
        BluetoothDevice btDevice = (BluetoothDevice) obj;

        list.add(btDevice);
        if (mybluetoothAdapter == null) {
            mybluetoothAdapter = new MyBluetoothAdapter(SearchActivity.this, list);
        }
        //列表展示
        mRecyclerview.setAdapter(mybluetoothAdapter);
        mRecyclerview.setOnItemClickListener(this);
        mybluetoothAdapter.notifyDataSetChanged();


    }

    @Override
    public String getTag() {
        return "bluetooth";
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        SearchBluetooth.getInstance().stopSearchBluetooth();
        bluetoothAsyncTask = new BluetoothAsyncTask();
        bluetoothAsyncTask.setBluetoothData(this);
        //TODO 选择蓝牙进行配对链接。如果没有配对过则先进行配对。配对过了直接进行socket链接
        SearchBluetooth.getInstance().doConnetBluetooth(list.get(position).getBondState(), list.get(position), bluetoothAsyncTask);
    }
}

蓝牙开发

接着开始读设备 穿过来的数据

这里使用异步线程防止主线程阻塞也必须这么干

代码如下:

package com.basexhgx.xhgx.bthutils;

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


import com.basexhgx.xhgx.bluetooth.SearchActivity;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

/**
 * @author: ZengWQ(zwq_em @ 163.com)
 * Date: 2017-10-12
 * Time: 15:18  数据传输  获取,发送数据
 * Verssion: 1.0
 * Describe:
 */


public class BluetoothAsyncTask extends AsyncTask<String, String, String> {

    public BluetoothAsyncTask() {
    }

    BluetoothData bluetoothData;

    public BluetoothData getBluetoothData() {
        return bluetoothData;
    }

    public void setBluetoothData(BluetoothData bluetoothData) {
        this.bluetoothData = bluetoothData;
    }

    private BluetoothSocket btSocket;
    private OutputStream outStream;
    //这条是蓝牙串口通用的UUID,不要更改
    private static final UUID MY_UUID =
            UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    @Override
    protected String doInBackground(String... params) {
        // TODO Auto-generated method stub
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(params[0]);
        try {
            btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
            try {
                btSocket.connect();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("ON RESUME: BT connection established, data transfer link open.");

        } catch (IOException e) {

            try {
                btSocket.close();
                return "3";//Socket 创建失败

            } catch (IOException e2) {

                System.out.println("ON RESUME: Unable to close socket during connection failure");
                return "2";//Socket 关闭失败
            }
        } finally {
            BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
            readData();
            writeData(SearchActivity.text);
            return "0";
        }
    }

    @Override    //这个方法是在主线程中运行的,所以可以更新界面
    protected void onPostExecute(String result) {
        // TODO Auto-generated method stub
        //连接成功则启动监听
        Log.i("info", "bluetooth_connet_state" + result);
        super.onPostExecute(result);
    }

    /**
     * 读取外来蓝牙设备的数据
     */

    public void readData() {
        byte b[] = new byte[30];// 所有的内容都读到此数组之中
        StringBuilder stringBuilder = new StringBuilder();
        try {
            InputStream inputStream = btSocket.getInputStream();
            while (true) {
                if (inputStream.read(b) != -1) {
                    stringBuilder.append(b);
                }
                if (null != bluetoothData)
                    bluetoothData.connetState(new String(b));
                System.out.println("--------size=" + new String(b));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public interface BluetoothData {
        void bluetoothData(String s, byte[] data);

        void connetState(String result);

    }

    /**
     * send 要发送的数据
     *
     * @return 0 soket 创建成功  1失败
     */
    public String writeData(String send) {
        try {
            outStream = btSocket.getOutputStream();

            while (true) {
                byte[] bytes = SearchActivity.text.getBytes();
                if (bytes.length > 0) {
                    outStream.write(bytes);
                    outStream.flush();
                }
            }
        } catch (IOException e) {
            Log.e("error", "ON RESUME: Output stream creation failed.", e);
            return "1";//Socket 流创建失败
        } finally {
            Log.i("info", "----------蓝牙连接正常,Socket 创建成功---");
            return "0";//蓝牙连接正常,Socket 创建成功
        }
    }

}

这段代码的接收方法亲测没问题。向蓝牙设备发送的代码没亲测过。不知道有问题没。

我目前做的是招商投标用的demo,没有仔细优化,读到数据之后的操作代码就不贴了。‘

整个过程大致就是以上的代码,在这里记录一下。比较low,勿喷。