Android 经典蓝牙开发(二)

本文章经典蓝牙开发目录:

1、权限申请
2、开启蓝牙
3、扫描蓝牙
4、配对蓝牙
5、连接蓝牙
6、通信(实现双向通信)(我用的两个手机通过蓝牙进行通信的~)
7、关闭各种通信
Android 蓝牙开发 经典蓝牙和低功耗蓝牙(一)
Android 低功耗蓝牙开发(三)

先看一串效果图
小米LTE作为客户端,小米5作为服务端
双方配对

小米lte配对.png

小米5配对.png

客户端向服务端发送数据
小米lte发送数据.png

小米5接收数据.png

服务端向客户端回传数据
小米5发送数据.png

小米lte接收数据.png

==================开始正文==============

哈哈哈哈

第一步,权限申请

1、Android6.0搜索周围的蓝牙设备,需要位置权限 ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION 其中的一个,并且将手机的位置服务(定位 GPS)打开。
清单文件:

  <!-- 使用蓝牙的权限 -->
   <uses-permission android:name="android.permission.BLUETOOTH" />
   <!-- 扫描蓝牙设备或者操作蓝牙设置 -->
   <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
   <!--模糊定位权限,仅作用于6.0+-->
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
   <!--精准定位权限,仅作用于6.0+-->
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

权限申请工具类:LocalUtils.java
1、这个类用来检查GPS和定位权限,回调在Activity里面。

public class LocalUtils {

    //申请权限
    public static final int permission_LocationCode = 101;
    //打开gps定位
    public static final int open_GPSCode = 102;
    static String[] permissionsIndex;
    /**
     * 此方法用来检查gps和定位权限,先检查gps是否打开,在检查是否有定位权限
     * @param activity 上下文对象
     * @param permissions 权限的名称
     * @return
     */
    public static boolean checkLocalPermissiion(Activity activity, String[] permissions) {
        permissionsIndex = permissions;
        if (checkGPSIsOpen(activity)) {
            return checkPermissions(activity);
        } else {
            Toast.makeText(activity, "需要打开GPS", Toast.LENGTH_SHORT).show();
            goToOpenGPS(activity);
        }
        return false;
    }

    /**
     * 检查GPS是否打开
     *
     */
    public static boolean checkGPSIsOpen(Activity activity) {
        LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
        if (locationManager == null)
            return false;
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }


    /**
     * 检查权限并申请权限
     */
    public static boolean checkPermissions(final Activity activity) {
        List<String> permissionDeniedList = new ArrayList<>();
        for (String permission : permissionsIndex) {
            int permissionCheck = ContextCompat.checkSelfPermission(activity, permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                return true;
            } else {
                permissionDeniedList.add(permission);
            }
        }
        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
            ActivityCompat.requestPermissions(activity, deniedPermissions, permission_LocationCode);
        }
        return false;
    }


    /**
     * 去手机设置打开GPS
     *
     * @param activity
     */
    public static void goToOpenGPS(Activity activity) {
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        activity.startActivityForResult(intent, open_GPSCode);

    }
}

在Activity里面回调:


    //GPS
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case LocalUtils.open_GPSCode://检查是否手机打开定位
                if (LocalUtils.checkGPSIsOpen(this)) {
                    LocalUtils.checkLocalPermissiion(this, permissions);//检查定位权限
                } else {
                    LocalUtils.goToOpenGPS(this);//打开GPS
                }
                break;
        }
    }

    /**
     * 权限回调
     */
    @Override
    public final void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case LocalUtils.permission_LocationCode://是否打开允许定位权限
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            initClassica();//初始化经典蓝牙
                        }
                    }
                }
                break;
        }
    }
哈哈哈.gif

ps:第一步是比较简单的哦~~看看就明白了

第二步,开启蓝牙

1、获取BluetoothAdapter
 获取BluetoothAdapter两种方式:
方式一:

  BluetoothManager systemService = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
  BluetoothAdapter bluetoothAdapter = systemService.getAdapter();

方式二:

 BluetoothAdapter bluetoothAdapter =BluetoothAdapter.getDefaultAdapter();

2、判断设备是否支持蓝牙
 如果 BluetoothAdapter.getDefaultAdapter()==null,不支持,否则支持。
3、开启蓝牙

 /**
    * 自动打开蓝牙(同步)
    * 这个方法打开蓝牙会弹出提示
    * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功
    */
   public void openBlueSync(Activity activity, int requestCode) {
       Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
       activity.startActivityForResult(intent, requestCode);
   }
哈哈哈.jpg

ps:第二步,嗯嗯嗯....我就开始百度了~~~

第三步,扫描蓝牙

1、扫描蓝牙

/**
        * 扫描的方法 返回true 扫描成功
        * 通过接收广播获取扫描到的设备
        * @return
        */
       public boolean scanBlueTooth() {
           //当前是否在扫描,如果是就取消当前的扫描,重新扫描
           if (bluetoothAdapter.isDiscovering()) {
               bluetoothAdapter.cancelDiscovery();
           }
           //此方法是个异步操作,一般搜索12秒
           return bluetoothAdapter.startDiscovery();
       }

2、取消扫描

      /**
         * 取消扫描蓝牙
         * @return true 为取消成功
         */
        public boolean cancelScanBule() {
            return bluetoothAdapter.cancelDiscovery();
        }

3、广播接收扫描的结果
  系统自动回发送广播,告诉我们,扫描出来的蓝牙设备。
先定义接口,来回调广播中的结果(在activity接收结果的哦~~~)
ClientCallBack.java

public interface ClientCallBack {
    //开始扫描
    void onScanStarted();

    //扫描结束
    void onScanFinished();

    //扫描中
    void onScanning(BluetoothDevice device);

    //配对请求
    void onBondRequest();

    //配对成功
    void onBondSuccess(BluetoothDevice device);

    //正在配对
    void onBonding(BluetoothDevice device);

    //配对失败
    void onBondFail(BluetoothDevice device);

    //连接成功
    void onConnectSuccess();

    //连接失败
    void onConnectFail(String errorMsg);

    //连接关闭
    void onConnectClose();
}

BlueReceiver.java

public class BlueReceiver extends BroadcastReceiver {
  private String pin = "0000";  //此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
  private static final String TAG = "mcy_Receiver";
  private ClientCallBack callBack;

  public BlueReceiver(ClientCallBack callBack) {
      this.callBack = callBack;
  }

  public void setCallBack(ClientCallBack callBack){
      this.callBack=callBack;
  }

  //广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行
  @Override
  public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      Log.d(TAG, "action:" + action);
      BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
      if(callBack==null){
          return;
      }
      switch (action) {
          case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
              callBack.onScanStarted();
              break;
          case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
              callBack.onScanFinished();
              break;
          case BluetoothDevice.ACTION_FOUND:
              callBack.onScanning(device);
              break;
          case BluetoothDevice.ACTION_PAIRING_REQUEST:
                  callBack.onBondRequest();
              break;
          case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
              switch (device.getBondState()) {
                  case BluetoothDevice.BOND_NONE:
                      callBack.onBondFail(device);
                      break;
                  case BluetoothDevice.BOND_BONDING:
                      callBack.onBonding(device);
                      break;
                  case BluetoothDevice.BOND_BONDED:
                      callBack.onBondSuccess(device);
                      break;
              }
              break;
      }
  }

}

为了方便统一管理,把蓝牙的操作写在服务里面,ClassicsBlueToothService.java,因此,把广播注册在服务里面,生命周期跟着服务走~~

public class ClassicsBlueToothService extends Service {
    private IntentFilter filter;
    private BlueReceiver pinBlueReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        //获取蓝牙适配器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //注册广播
        //蓝牙广播,系统自动发送广播,只要设置制定的 action 即可
        filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//结束扫描
        filter.addAction(BluetoothDevice.ACTION_FOUND);//发现设备
        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//发起配对请求
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//配对状态
        pinBlueReceiver = new BlueReceiver(blueCallBack);

        registerReceiver(pinBlueReceiver, filter);//注册广播
    }

   @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(pinBlueReceiver);
    }
       ........还有很多代码,就不全部拿出来了,去github上看吧
}
委屈.png

ps:第三步的广播和服务的结合使用搬出来了,好久没用了,又从头过一遍,才写出来的~~~

第四步,配对蓝牙

配对:

  /**
         * 配对(配对成功与失败通过广播返回)
         * !!!弹出配对框
         *
         * @param device
         */
        public void pinBlueTooth(BluetoothDevice device) {
            if (device == null) {
                Log.e("mcy", "设备不可以为空");
                return;
            }
            //配对之前把扫描关闭
            if (bluetoothAdapter.isDiscovering()) {
                bluetoothAdapter.cancelDiscovery();
            }
            //判断设备是否配对,没有配对在配,配对了就不需要配了
            if (device.getBondState() == BluetoothDevice.BOND_NONE) {//BOND_NONE 没有配对状态
                Log.d("mcy", "attemp to bond:" + device.getName());
                try {
                    boolean returnValue = device.createBond();
                    Log.e("是否配对成功:", "" + returnValue);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "配对失败");

                }
            }
        }

取消配对:


        /**
         * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
         *
         * @param device
         */
        public void cancelPinBuleTooth(BluetoothDevice device) {
            if (device == null) {
                Log.d("mcy", "设备不可以为空");
                return;
            }
            //判断设备是否配对,没有配对就不用取消了
            if (device.getBondState() != BluetoothDevice.BOND_NONE) {
                Log.d("mcy", "配对--" + device.getName());
                try {
                    Method removeBondMethod = device.getClass().getMethod("removeBond");
                    Boolean returnValue = (Boolean) removeBondMethod.invoke(device);
                    returnValue.booleanValue();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "取消配对失败");
                }
            }
        }
开心.jpg

ps:第四步,嗯嗯嗯,还是比较好看的,只是操作蓝牙

第五步,连接蓝牙

这里说一下 uuid 的问题,要想进行通信,客户端和服务端必须一致,否则连接失败,因为我用的手机进行的通讯,所有,我写了双向通信,既可以写也可以读。
连接蓝牙
注意:在连接蓝牙的同时,开启一个子线程,用来写入数据!!!!

  /**
         * @param uuid   用户指定的 uuid ,可随意写,只要格式对就行
         * @param device 连接的设备
         */
        public void connectionBlueTooth(String uuid, BluetoothDevice device) {
            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
                if (bluetoothSocket != null && !bluetoothSocket.isConnected()) {
                    sendDataThread = new ClientThread(bluetoothSocket, blueCallBack);
                    sendDataThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

ClientThread.java

public class ClientThread extends Thread {

    private static final String TAG = "mcy";
    private ClientCallBack callBack;
    private BluetoothSocket bluetoothSocket = null;
    private Handler handler;
    private OutputStream outputStream;

    public ClientThread(BluetoothSocket bluetoothSocket, ClientCallBack callBack) {
        this.callBack = callBack;
        this.bluetoothSocket = bluetoothSocket;
    }

    /**
     * 写数据
     *
     * @param data
     */

    public void write(byte[] data) {
        Message message = new Message();
        message.obj = data;
        handler.sendMessage(message);
    }

    /**
     * 关闭各种连接连接
     */
    public void closeSocket() {
        try {
            outputStream.close();
            bluetoothSocket.close();
            callBack.onConnectClose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            bluetoothSocket.connect();
            outputStream = bluetoothSocket.getOutputStream();//读取需要发送的的数据
            Looper.prepare();
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    try {
                        byte[] data = (byte[]) msg.obj;
                        outputStream.write(data);
                        outputStream.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            callBack.onConnectSuccess();
            Looper.loop();
        } catch (IOException e) {
            callBack.onConnectFail(e.getMessage());
        }
    }
}
变少

ps:第五步,有难度,光这个uuid,我就研究了好久,到底是个什么玩意,哼、、、头大日渐变少了~~

第六步,通信(实现双向通信)

1、客户端发送数据

 /**
         * 写数据
         */
        public void sendData(byte[] data) {
            if (sendDataThread != null) {
                sendDataThread.write(data);
            }
        }

2、客户端接收数据

/**
         * 读数据
         */
        public void readListern(String name, String uuid, ServiceCallback callBack) {
            acceptThread = new AcceptThread(name, uuid, bluetoothAdapter, callBack);
            acceptThread.start();
        }

定义一个接口,来监听,收到数据的状态

public interface ServiceCallback {
    //连接成功
    void onConnectSuccess();

    //连接失败
    void onConnectFail(String errorMsg);

    //连接关闭
    void onConnectClose();

    //接收到的数据
    void onResultMessage(byte[] data);
}

开启一个子线程,用来监听服务端发过来的数据

public class AcceptThread extends Thread {
    private static final String TAG = "mcy";
    private ServiceCallback callBack;
    private BluetoothServerSocket serverSocket = null;
    private InputStream inputStream;
    private BufferedInputStream bufferedInputStream;
    private byte[] data;

    public AcceptThread(String name, String uuid, BluetoothAdapter bluetoothAdapter, ServiceCallback callBack) {
        this.callBack = callBack;
        try {
            serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(name, UUID.fromString(uuid));

        } catch (IOException e) {
            e.printStackTrace();
            callBack.onConnectFail(e.getMessage());
        }
    }

    /**
     * 关闭各种流和通信的socket
     */
    public void closeSocket() {
        try {
            inputStream.close();
            bufferedInputStream.close();
            serverSocket.close();
            callBack.onConnectClose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            final BluetoothSocket bluetoothSocket = serverSocket.accept();
            callBack.onConnectSuccess();
            inputStream = bluetoothSocket.getInputStream();//获取服务端发来的消息
            bufferedInputStream = new BufferedInputStream(inputStream);
            while (true) {
                int available =0;
                wh:
lable==0){
                    available=inputStream.available();
                }
                data = new byte[available];
                bufferedInputStream.read(data);
                callBack.onResultMessage(data);//回传数据
            }
        } catch (IOException e) {
            callBack.onConnectFail(e.getMessage());
            e.printStackTrace();
        }
    }
}
哈哈哈.jpeg

ps:第六步,昨晚这一步,基本上做完了~~头发没了、、、

第七步,关闭各种通信

在第五步和第六步的子线程里均有关闭通信的方法

      /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleConnecion() {
            sendDataThread.closeSocket();
        }
        /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleServiceConnecion() {
            acceptThread.closeSocket();
        }

好了,放大招,请看activity和service

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "mcy";
    private TextView textView;
    private TextView textView2;
    private TextView textView3;
    private EditText editTxt;
    String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
    private final int openBTCode = 100;
    // ----------------经典蓝牙------------------
    private ClassicsBlueToothService.ClassicaBlueToothBind classicaBTBind;
    private ServiceConnection classicaConnection;
    private List<BluetoothDevice> devicesList = new ArrayList<>();
    private ClientCallBack blueCallBack;
    private String text = "";


    private String uuid = "6db14d27-04f1-4df8-98ca-356dfc16ee43";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //检查权限   >6.0以上版本需要动态的申请定位权限,< 6.0 清单文件声明了即可
        if (LocalUtils.checkLocalPermissiion(this, permissions)) {
            initClassica();
        }

    }


    private void initView() {
        textView = findViewById(R.id.textView);
        textView2 = findViewById(R.id.textView2);
        textView3 = findViewById(R.id.textView3);
        editTxt = findViewById(R.id.editTxt);
        findViewById(R.id.button5).setOnClickListener(this);
        findViewById(R.id.button11).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button5://经典--写数据
                text = editTxt.getText().toString();
                classicaBTBind.sendData(text.getBytes());
                break;
            case R.id.button11://低功耗--发送数据
                break;

        }
    }

   
    private void initClassica() {
        blueCallBack = new ClientCallBack() {
            @Override
            public void onScanStarted() {
                Log.e("mcy", "开始扫描");

            }

            @Override
            public void onScanFinished() {
                Log.e("mcy", "结束扫描");
            }

            @Override
            public void onScanning(BluetoothDevice device) {
                Log.e("mcy", "扫描到设备-->" + device.getName());
                if (!devicesList.contains(device)) {
                    //将设备加入列表数据中
                    devicesList.add(device);
                }
                textView.setText(textView.getText() + "\n" + device.getName());
                Log.e(TAG, "" + device.getName());
                //已配对的蓝牙
                if (device.getBondState() == BluetoothDevice.BOND_BONDED) {//BOND_BONDED 已经配对状态
                    textView2.setText(textView2.getText() + "\n" + device.getName());
                } else {
                    classicaBTBind.pinBlueTooth(devicesList.get(0));
                }

            }

            @Override
            public void onBondRequest() {
                Log.e("mcy", "开始配对");

            }

            @Override
            public void onBondFail(BluetoothDevice device) {
                Log.e("mcy", "取消配对");
            }

            @Override
            public void onBonding(BluetoothDevice device) {
                Log.e("mcy", "配对中");
            }

            @Override
            public void onBondSuccess(BluetoothDevice device) {
                Log.e("mcy", "配对成功");
                classicaBTBind.connectionBlueTooth(uuid, device);
                //registReadListener(); //测试使用,双端通讯

            }

            @Override
            public void onConnectSuccess() {
                Log.e("mcy", "连接成功");
            }

            @Override
            public void onConnectFail(String errorMsg) {
                Log.e("mcy", "连接失败" + errorMsg);
            }

            @Override
            public void onConnectClose() {
                Log.e("mcy", "连接关闭");

            }
        };
        classicaConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                classicaBTBind = ((ClassicsBlueToothService.ClassicaBlueToothBind) service);
                if (blueCallBack != null) {
                    classicaBTBind.setBlueCallback(blueCallBack);//设置广播监听
                }
                if (classicaBTBind.getAdapter() != null) {
                    //判断蓝牙是否开启
                    if (!classicaBTBind.getAdapter().isEnabled()) {
                        //打开蓝牙
                        openBlueSync(MainActivity.this, openBTCode);
                    } else {
                        //========================开始执行工作=============================
                        classicaBTBind.scanBlueTooth();//扫描蓝牙
                        registReadListener();//注册读数据事件
                    }
                } else {
                    Toast.makeText(MainActivity.this, "此设备不支持蓝牙", Toast.LENGTH_SHORT).show();
                }


            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                classicaBTBind = null;

            }
        };
        bindService(new Intent(this, ClassicsBlueToothService.class), classicaConnection, BIND_AUTO_CREATE);
    }

    //经典蓝牙注册读数据事件
    private void registReadListener() {
        classicaBTBind.readListern("Demo", uuid, new ServiceCallback() {

            @Override
            public void onConnectSuccess() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接成功~");
                    }
                });
            }

            @Override
            public void onConnectFail(final String errorMsg) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接失败" + errorMsg);
                    }
                });

            }

            @Override
            public void onConnectClose() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.e("mcy", "读数据连接关闭");

                    }
                });
            }

            @Override
            public void onResultMessage(final byte[] data) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView3.setText(new String(data));
                    }
                });
            }
        });
    }

    /**
     * 自动打开蓝牙(同步)
     * 这个方法打开蓝牙会弹出提示
     * 需要在onActivityResult 方法中判断resultCode == RESULT_OK  true为成功
     */
    public void openBlueSync(Activity activity, int requestCode) {
        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        activity.startActivityForResult(intent, requestCode);
    }


    //GPS
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case LocalUtils.open_GPSCode://检查是否手机打开定位
                if (LocalUtils.checkGPSIsOpen(this)) {
                    LocalUtils.checkLocalPermissiion(this, permissions);
                } else {
                    LocalUtils.goToOpenGPS(this);
                }
                break;
        }
    }

    /**
     * 权限回调
     */
    @Override
    public final void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case LocalUtils.permission_LocationCode://是否打开允许定位权限
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                            initClassica();//初始化经典蓝牙
                        }
                    }
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(classicaConnection);
    }
}

ClassicsBlueToothService.java:

public class ClassicsBlueToothService extends Service {
    private IntentFilter filter;
    private BlueReceiver pinBlueReceiver;
    private BluetoothAdapter bluetoothAdapter;
    private ClientThread sendDataThread;
    private BluetoothSocket bluetoothSocket;
    private ClientCallBack blueCallBack;
    private AcceptThread acceptThread;

    @Override
    public void onCreate() {
        super.onCreate();
        //获取蓝牙适配器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //注册广播
        //蓝牙广播,系统自动发送广播,只要设置制定的 action 即可
        filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//结束扫描
        filter.addAction(BluetoothDevice.ACTION_FOUND);//发现设备
        filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);//发起配对请求
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//配对状态
        pinBlueReceiver = new BlueReceiver(blueCallBack);

        registerReceiver(pinBlueReceiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(pinBlueReceiver);
    }

    public class ClassicaBlueToothBind extends Binder {

        public BluetoothAdapter getAdapter() {
            return bluetoothAdapter;
        }

        public void setBlueCallback(ClientCallBack callback) {
            ClassicsBlueToothService.this.blueCallBack = callback;
            pinBlueReceiver.setCallBack(callback);
        }

        /**
         * 扫描的方法 返回true 扫描成功
         * 通过接收广播获取扫描到的设备
         *
         * @return
         */
        public boolean scanBlueTooth() {
            //当前是否在扫描,如果是就取消当前的扫描,重新扫描
            if (bluetoothAdapter.isDiscovering()) {
                bluetoothAdapter.cancelDiscovery();
            }
            //此方法是个异步操作,一般搜索12秒
            return bluetoothAdapter.startDiscovery();
        }

        /**
         * 取消扫描蓝牙
         *
         * @return true 为取消成功
         */
        public boolean cancelScanBule() {
            return bluetoothAdapter.cancelDiscovery();
        }

        /**
         * 配对(配对成功与失败通过广播返回)
         * !!!弹出配对框
         *
         * @param device
         */
        public void pinBlueTooth(BluetoothDevice device) {
            if (device == null) {
                Log.e("mcy", "设备不可以为空");
                return;
            }
            //配对之前把扫描关闭
            if (bluetoothAdapter.isDiscovering()) {
                bluetoothAdapter.cancelDiscovery();
            }
            //判断设备是否配对,没有配对在配,配对了就不需要配了
            if (device.getBondState() == BluetoothDevice.BOND_NONE) {//BOND_NONE 没有配对状态
                Log.d("mcy", "attemp to bond:" + device.getName());
                try {
                    boolean returnValue = device.createBond();
                    Log.e("是否配对成功:", "" + returnValue);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "配对失败");

                }
            }
        }

        /**
         * 取消配对(取消配对成功与失败通过广播返回 也就是配对失败)
         *
         * @param device
         */
        public void cancelPinBuleTooth(BluetoothDevice device) {
            if (device == null) {
                Log.d("mcy", "设备不可以为空");
                return;
            }
            //判断设备是否配对,没有配对就不用取消了
            if (device.getBondState() != BluetoothDevice.BOND_NONE) {
                Log.d("mcy", "配对--" + device.getName());
                try {
                    Method removeBondMethod = device.getClass().getMethod("removeBond");
                    Boolean returnValue = (Boolean) removeBondMethod.invoke(device);
                    returnValue.booleanValue();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.d("mcy", "取消配对失败");
                }
            }
        }

        /**
         * @param uuid   用户指定的 uuid ,可随意写,只要格式对就行,客户端和服务端保持一致即可。
         * @param device 连接的设备
         */



        public void connectionBlueTooth(String uuid, BluetoothDevice device) {
            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
                if (bluetoothSocket != null && !bluetoothSocket.isConnected()) {
                    sendDataThread = new ClientThread(bluetoothSocket, blueCallBack);
                    sendDataThread.start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /**
         * 写数据
         */
        public void sendData(byte[] data) {
            if (sendDataThread != null) {
                sendDataThread.write(data);
            }
        }

        /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleConnecion() {
            sendDataThread.closeSocket();
        }


        /**
         * 读数据
         */
        public void readListern(String name, String uuid, ServiceCallback callBack) {
            acceptThread = new AcceptThread(name, uuid, bluetoothAdapter, callBack);
            acceptThread.start();
        }

        /**
         * 写数据断开连接
         *
         * @return
         */
        public void cancleServiceConnecion() {
            acceptThread.closeSocket();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new ClassicaBlueToothBind();
    }
}

github,地址 : https://github.com/Mchunyan/BlueToothTest

-----------------------The End-----------------

下一篇写,低功耗蓝牙开发~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Guide to BluetoothSecurity原文 本出版物可免费从以下网址获得:https://doi.o...
    公子小水阅读 7,882评论 0 6
  • Android平台支持蓝牙网络协议栈,实现蓝牙设备之间数据的无线传输。本文档描述了怎样利用android平台提供的...
    Camming阅读 3,274评论 0 3
  • 最近项目使用蓝牙,之前并没有接触,还是发现了很多坑,查阅了很多资料,说的迷迷糊糊,今天特查看官方文档。 说下遇到的...
    King9527阅读 1,780评论 0 1
  • 公司的项目最近需要用到蓝牙开发的相关内容,因此特地查阅了Google官方文档的内容并进行二次整理,希望能对需要学习...
    Chuckiefan阅读 32,408评论 44 123
  • 蓝牙 注:本文翻译自https://developer.android.com/guide/topics/conn...
    RxCode阅读 8,613评论 11 99