精华内容
下载资源
问答
  • android蓝牙连接

    2016-09-25 15:10:46
    android蓝牙设备连接,提取系统核心代码,
  • 通过蓝牙功能与设备进行连接以及获取设备传输过来的数据
  • 此demo实现了android ble4.0蓝牙跟设备的连接通讯功能,可以同时连接多台并且同时发送数据。
  • 主要介绍了Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇),具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • AndPrinter Android 蓝牙连接便携式热敏打印机 打印Demo (测试设备 佳博 ZH-380) 打印效果
  • 主要是搜索蓝牙、得到蓝牙列表、点击item之后、连接点击的蓝牙、进入第二个界面接收数据;别人写的,我改造了一下
  • android 蓝牙连接通信

    2018-09-10 16:17:44
    android端,实现连接蓝牙硬件,通过SN唯一标识连接,写入指令字符,Service相应回调查看结果
  • 主要介绍了Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇),具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • Android 蓝牙连接

    千次阅读 2019-05-01 18:06:32
    最多可以同时和7个其它蓝牙设备建立连接,进行通信。蓝牙可分为两大类:传统蓝牙蓝牙3.0规范之前),低功耗蓝牙蓝牙4.0规范之后)。 Android 从4.3版本(API Level 18)开始支持低功耗蓝牙Bluetooth Low Energy...

    一、概述

    蓝牙是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换。最多可以同时和7个其它蓝牙设备建立连接,进行通信。蓝牙可分为两大类:传统蓝牙(蓝牙3.0规范之前),低功耗蓝牙(蓝牙4.0规范之后)。

    Android 从4.3版本(API Level 18)开始支持低功耗蓝牙Bluetooth Low Energy(BLE)通信。Android提供了相应的 API, 应用程序通过这些 API 可以实现 蓝牙设备扫描、配对、连接、传输数据等功能。

    二、Android BLE API几个重要类

    1、BluetoothAdapter

    本地的蓝牙适配器。是所有蓝牙交互操作的入口点。通过这个类可以发现其他蓝牙设备,查询已配对的设备列表,使用一个已知的MAC地址来实例化一个BluetoothDevice,以及创建一个BluetoothServerSocket来为监听与其他设备的通信。

    2、BluetoothDevice

    远程蓝牙设备。使用这个类来请求一个与远程设备的BluetoothSocket连接,或者查询关于设备名称、地址、类和连接状态等设备信息。

    3、BluetoothSocket

    代表一个蓝牙socket的接口(和TCP Socket类似)。这是一个连接点,它允许一个应用与其他蓝牙设备通过InputStream和OutputStream交换数据。

    4、BluetoothServerSocket

    代表一个开放的服务器socket,它监听接受的请求(与TCP ServerSocket类似)。为了连接两台Android设备,一个设备必须使用这个类开启一个服务器socket。当一个远程蓝牙设备开始一个和该设备的连接请求,BluetoothServerSocket将会返回一个已连接的BluetoothSocket,接受该连接。

    三、蓝牙开发

    1、流程

    2、开启权限

    <uses-permission android:name="android.permission.BLUETOOTH"/> 
    //开启蓝牙时,mBluetoothAdapter.enable()需要以下权限
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    3、开启蓝牙

    public void isBluetoothEnable() {
            //获取蓝牙适配器
    	mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    	if (mBluetoothAdapter != null){
    		// 蓝牙已打开
    		if (mBluetoothAdapter.isEnabled()){			
    		}else{//未打开则开启,此处可以通过弹框提示来提示用户开启
                mBluetoothAdapter.enable()
            }
        }	
    }

    4、搜索附近蓝牙设备

    /**
     * 注册搜索蓝牙设备的广播
     */
    private void startDiscovery() {
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        registerReceiver(receiver, filter);
        IntentFilter filter1 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        registerReceiver(receiver, filter1);
        startScanBluetooth();
    }
    
    private void startScanBluetooth() {
        // 判断是否在搜索,如果在搜索,就取消搜索
        if (bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
        }
        // 开始搜索
        bluetoothAdapter.startDiscovery();
    }
    
    /**
     * 蓝牙广播接收
     */
    private final BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
        public void onReceive(Context context, Intent intent) {
    
           String action = intent.getAction();
           if (BluetoothDevice.ACTION_FOUND.equals(action)) {
               BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    
               //蓝牙rssi参数,代表蓝牙强度
               short rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);
               //蓝牙设备名称
               String name = device.getName();
               //蓝牙设备连接状态
               int status = device.getBondState();
               ...
            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
               ...
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
               Toast.makeText(context, "蓝牙设备搜索完成", Toast.LENGTH_SHORT).show();
            }
        }
    };

    关于蓝牙连接状态:

    BluetoothDevice.BOND_BONDED:已配对

    BluetoothDevice.BOND_BONDING:配对中

    BluetoothDevice.BOND_NONE:未配对或取消配对

    关于蓝牙强度rssi:

    单位是dbm,蓝牙信号的强度RSSI = 10*log P,P代表接收到的信号功率。蓝牙会发送广播,距离大小会影响信号功率强弱。假设发射功率取最大值为1mw,那么RSSI的值为0,也就是说你的距离离蓝牙最近时在理想状态下所获取的RSSI的值为0,但在实际中基本不会存在这个理想状态,因此RSSI的值基本都为负数。

    一般说来,在BLE中,假设信号强度按强、中、弱、差4个等级划分,rssi范围依次是:-60 ~ 0 、-70 ~ -60、-80 ~ -70、<-80。

    5、配对

    //获取已配对设备信息
    public List<BluetoothDevice> getPairedBluetoothDevices() {
    	List deviceList = new ArrayList<>();
    	Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    	if (pairedDevices.size() > 0) {
    		for (BluetoothDevice device : pairedDevices) {
    			deviceList.add(device);
    		}
    	}
    	return deviceList;
    }
    //若已配对设备数为0,跳转到手机系统蓝牙设置界面
    Intent enableBtIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
    mContext.startActivity(enableBtIntent);
    //手动配对,完成配对后重新扫描即可
    Method method = BluetoothDevice.class.getMethod("createBond");
    method.invoke(itemlist.get(position).getDevice());
    

    6、连接

    蓝牙连接需要在子线程中完成

    public class BluetoothConnectThread extends Thread {
    
        private static final UUID BluetoothUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
        BluetoothSocket bluetoothSocket;
        BluetoothDevice bluetoothDevice;
    
        private boolean connected = false;
        private Object lock = new Object();
    
        //蓝牙连接回调接口
        private BluetoothConnectCallback connectCallback;
    
        public BluetoothConnectThread(BluetoothDevice device,
                                      BluetoothConnectCallback callback) {
            try {
                bluetoothDevice = device;
                bluetoothSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(BluetoothUUID);
                connectCallback = callback;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            if (bluetoothSocket != null) {
                if (connected) {
                    cancel2();
                    connected = false;
                }
            }
    
            new Thread() {
                @Override
                public void run() {
                    connect();
                    if (connected) {
                        if (connectCallback != null){
                            connectCallback.connectSuccess(bluetoothSocket);
                        }
                    }
                }
            }.start();
    
        }
    
        public void connect() {
            try {
                synchronized (lock) {
                    bluetoothSocket.connect();
                    connected = true;
                }
            } catch (Exception connectException) {
                connectException.printStackTrace();
                cancel();
                try {
                    Method m;
                    m = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                    bluetoothSocket = (BluetoothSocket) m.invoke(bluetoothDevice, Integer.valueOf(1));
                    bluetoothSocket.connect();
                    connected = true;
                } catch (Exception ex) {
                    ex.printStackTrace();
                    if (connectCallback != null){
                        connectCallback.connectFailed(ex.getMessage());
                    }
                }
            }
        }
    
        public void cancel() {
            try {
                synchronized (lock) {
                    if (connected) {
                        bluetoothSocket.close();
                        connected = false;
                    }
                }
            } catch (IOException e) {
            }
        }
    
        public void cancel2() {
            try {
                synchronized (lock) {
                    bluetoothSocket.close();
                    connected = false;
                }
            } catch (IOException e) {
            }
        }
    
    }
    public interface BluetoothConnectCallback {
    
        void connectSuccess(BluetoothSocket socket);
    
        void connectFailed(String errorMsg);
    
        void connectCancel();
    }

    注意以上,BluetoothUUID一般为固定的,connect()放在子线程中可以提高连接成功率(不明所以),注意connect失败需要通过反射createRfcommSocket该方法完成,自验目前连接成功率较高。

    7、传输数据

    //获取BluetoothSocket输出流
    OutputStream outputStream = bluesocket.getOutputStream();
    //之后将数据写入输出流完成传输
    outputStream.write(data);
    outputStream.flush();

     

    展开全文
  • 实现的主要功能(蓝牙配对成功如何与远程设备一直连接) 1.当蓝牙配对成功连接时,非主动断开会自动...这个类中蓝牙连接状态 void sendConnectionStateChange(BluetoothDevice device, int profile, int state, int prevS
  • java实现电脑和Android蓝牙连接源代码
  • 1.安卓平台实现蓝牙连接,可以与全站仪蓝牙直接连接 2.支持同时连接多个蓝牙设备,自定义最大连接数 3.支持同时做蓝牙主机和从机,发起连接或者等待连接
  • 无论是WIFI还是4G网络,建立网络连接后都是访问...Android蓝牙技术提供了4个工具类,分别是蓝牙适配器BluetoothAdapter、蓝牙设备BluetoothDevice、蓝牙服务端套接字BluetoothServerSocket和蓝牙客户端套接字Blueto
  • 对于手机用蓝牙连接打印机进行打印小票、打印图片、打印二维码,条形码 对手机连接蓝牙进行了处理,蓝牙连接成功进行打印,失败提示用户进行蓝牙列表选择 只需要连接一次,后面打印无需再次连接
  • Android蓝牙连接相关

    2017-10-13 20:24:21
    自定义实现 Android 蓝牙连接 、接收 、发送数据,
  • Android代码:蓝牙连接51单片机LED代码
  • 上一篇文章介绍了“蓝牙扫描”,今天来说一下android蓝牙连接过程中133的问题: 我们经常在网上看到一些答案说需要释放gatt资源,这种方式可以在一定程度上减少出现133的概率。个人发现的一个规律是:一般出现蓝牙...

    上一篇文章介绍了“蓝牙扫描”,今天来说一下android蓝牙连接过程中133的问题:

    我们经常在网上看到一些答案说需要释放gatt资源,这种方式可以在一定程度上减少出现133的概率。个人发现的一个规律是:一般出现蓝牙连接133的问题,大多是android低配机型(虽然上层调用了gatt.close()方法,但手机底层蓝牙服务可能仍与设备保持连接状态,其所占用蓝牙资源不能及时释放,所以导致了我们连接一直出现133的问题)。

    这里先说一下常规操作:我们在蓝牙连接失败或者断开连接时,一定要及时的进行gatt.disconnect()和gatt.close()操作;但是在实际的开发过程中,我们可能会进入一种死循环:即如果一旦出现连接133的情况下,如果不断开蓝牙开关一次或设备重新上电一次,可能会一直出现133的情况。这种情况显然不是我们想看到的,所以个人总结出一套亲测有效的方法(此方法无法100%规避出现133的问题,但可以提高出现133情况之后再去连接的成功率),下面看一段刚刚写的一段demo,但实际项目仍会有很有需要优化的地方,仅供参考:

    /**
     * 连接设备(为了给客官们更详尽的展示,所以把很多变量都写在了方法内,实际项目中很多变量不会在方法内初始化)
     * 入参:设备mac地址
     * @param mac
     */
    private  void  connectDevice(final String mac){
        // 获取蓝牙适配器
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter == null){
            Log.d("connectDevice","bluetoothAdapter is null");
            return;
        }
        // 根据mac地址获取蓝牙设备实例对象,当然此处的bluetoothDevice也可以通过蓝牙扫描得到
        BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(mac);
        if(bluetoothDevice == null){
            Log.d("connectDevice","this device is not exist");
            return;
        }
        // 由于今天只讨论蓝牙连接问题,所以这里仅重写了"监测连接状态变化"的方法
        gattCallback = new BluetoothGattCallback() {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                if(status == 0){ //表示gatt服务成功
                    if(newState == BluetoothProfile.STATE_CONNECTED){  // 连接成功状态
                          //连接成功之后的操作
                    }else if(newState == BluetoothProfile.STATE_DISCONNECTED){ // 断开连接状态
                          //断开连接之后的操作
                    }
                }else {
                    gatt.disconnect();
                    gatt.close();
                    if(status == 133){ //经典错误:133
                       //提示:此处我们可以根据全局的一个flag,去重试连接一次,以增大连接成功率
                        if(!isRetry){
                            isRetry = true;
                            connectDevice(mac);
                        }
                    }
                }
            }
        };
        // gatt为全局变量,获取当前gatt服务下连接的设备
        if(gatt != null && gatt.getConnectedDevices() != null){
            for(BluetoothDevice device:gatt.getConnectedDevices()){
                if(device.getAddress().equals(mac)){  // 如果当前遍历出的连接设备与我们需要连得设备是同一设备
                    gatt.disconnect(); //先去断开之前未正常断开的连接,解决连接133的问题
                }
            }
            gatt.close(); //释放gatt服务
            gatt = null;
        }
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            gatt = bluetoothDevice.connectGatt(MainActivity.this,
                    false, gattCallback, TRANSPORT_LE);  //
        } else {
            gatt = bluetoothDevice.connectGatt(MainActivity.this,
                    false, gattCallback);
        }
    }

    关于蓝牙连接的问题先告一段落了,后面有时间会继续分享BluetoothGattCallback内的其他方法的作用。也欢迎大家指正以及提出宝贵的意见,互相进步。谢谢~

     

    展开全文
  • 手机通过蓝牙连接打印机,从BluetoothSocket中getOutputStream()获取outputStream, 然后设置一下即可
  • Android蓝牙连接状态检测

    千次阅读 2020-09-14 10:45:38
    目前Android Bluetooth API's要求设备在建立RFCOMM信道前必须配对(配对是在使用Bluetooth API初始化一个加密连接时自动完成的)。 检测蓝牙历史配对设备: private void getDevices() { Bluetooth

    配对和连接是两个不同的概念:
    配对意思是两个设备相互意识到对方的存在,共享一个用来鉴别身份的链路键(link-key),能够与对方建立一个加密的连接。
    连接意思是两个设备现在共享一个RFCOMM信道,能够相互传输数据。

    目前Android Bluetooth API's要求设备在建立RFCOMM信道前必须配对(配对是在使用Bluetooth API初始化一个加密连接时自动完成的)。

    检测蓝牙历史配对设备:

        private void getDevices() {
            BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
            for (BluetoothDevice bluetoothDevice : bondedDevices) {
                Log.i(TAG, "name is : " + bluetoothDevice.getName() + " state is:" + bluetoothDevice.getBondState());
            }
            Log.i(TAG, "size:" + bondedDevices.size());
        }

    检测蓝牙已经连接设备使用反射方式:

        private void checkLinkState1() {
            ArrayList<BluetoothDevice> deviceList = new ArrayList<>();
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象
            try {
                //得到连接状态的方法
                Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);
                //打开权限
                method.setAccessible(true);
                int state = (int) method.invoke(adapter, (Object[]) null);
                if (state == BluetoothAdapter.STATE_CONNECTED) {
                    Log.i(TAG, "BluetoothAdapter.STATE_CONNECTED");
                    Set<BluetoothDevice> devices = adapter.getBondedDevices();
                    Log.i(TAG, "devices:" + devices.size());
    
                    for (BluetoothDevice device : devices) {
                        Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                        method.setAccessible(true);
                        boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);
                        if (isConnected) {
                            Log.i(TAG, "connected:" + device.getName());
                            deviceList.add(device);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    检测蓝牙已经连接设备使用配置文件方式:

        private void checkLinkState() {
            BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            int flag = -1;
    
            int a2dp = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
            int headset = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            int health = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
            int health1 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT);
            int health2 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT_SERVER);
            int health3 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            int health4 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEARING_AID);
            int health5 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HID_DEVICE);
            int health6 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.SAP);
    
            if (a2dp == BluetoothProfile.STATE_CONNECTED) {
                flag = a2dp;
            } else if (headset == BluetoothProfile.STATE_CONNECTED) {
                flag = headset;
            } else if (health == BluetoothProfile.STATE_CONNECTED) {
                flag = health;
            } else if (health1 == BluetoothProfile.STATE_CONNECTED) {
                flag = health1;
            } else if (health2 == BluetoothProfile.STATE_CONNECTED) {
                flag = health2;
            } else if (health3 == BluetoothProfile.STATE_CONNECTED) {
                flag = health3;
            } else if (health4 == BluetoothProfile.STATE_CONNECTED) {
                flag = health4;
            } else if (health5 == BluetoothProfile.STATE_CONNECTED) {
                flag = health5;
            } else if (health6 == BluetoothProfile.STATE_CONNECTED) {
                flag = health6;
            }
            Log.e(TAG, "flag is " + flag);
    
            if (flag != -1) {
                bluetoothAdapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
    
                    @Override
                    public void onServiceDisconnected(int profile) {
                        // TODO Auto-generated method stub
                        Log.i(TAG, "onServiceDisconnected");
    
                    }
    
                    @Override
                    public void onServiceConnected(int profile, BluetoothProfile proxy) {
                        // TODO Auto-generated method stub
                        List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                        if (mDevices != null && mDevices.size() > 0) {
                            for (BluetoothDevice device : mDevices) {
                                Log.i(TAG, "device name: " + device.getName());
                            }
                        } else {
                            Log.i(TAG, "mDevices is null");
                        }
                    }
                }, flag);
            }
    
        }

    当然使用前需要注册监听,下面是完整activity:

    import androidx.appcompat.app.AppCompatActivity;
    
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothProfile;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import com.example.jumptest.R;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    
    public class BluetoothActivity extends AppCompatActivity {
    
        private static final String TAG = "BluetoothActivity";
    
        public static void goToBluetoothTest(Context context) {
            Intent intent = new Intent(context, BluetoothActivity.class);
            context.startActivity(intent);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            Log.e(TAG, "BluetoothActivity onCreate");
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_bluetooth);
    
            registerBroadcastReveiver();
            findViewById(R.id.blue_btn).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    //获取已经配对的蓝牙信息
                    getDevices();
    
                    //方式一:不用反射,个别设备无法检测到
                    checkLinkState();
    
                    //方式二:使用系统API反射,没有问题
                    checkLinkState1();//OK test
    
                }
            });
    
        }
    
        private void checkLinkState1() {
            ArrayList<BluetoothDevice> deviceList = new ArrayList<>();
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象
            try {
                //得到连接状态的方法
                Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);
                //打开权限
                method.setAccessible(true);
                int state = (int) method.invoke(adapter, (Object[]) null);
                if (state == BluetoothAdapter.STATE_CONNECTED) {
                    Log.i(TAG, "BluetoothAdapter.STATE_CONNECTED");
                    Set<BluetoothDevice> devices = adapter.getBondedDevices();
                    Log.i(TAG, "devices:" + devices.size());
    
                    for (BluetoothDevice device : devices) {
                        Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                        method.setAccessible(true);
                        boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);
                        if (isConnected) {
                            Log.i(TAG, "connected:" + device.getName());
                            deviceList.add(device);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private void checkLinkState() {
            BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            int flag = -1;
    
            int a2dp = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
            int headset = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            int health = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);
            int health1 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT);
            int health2 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT_SERVER);
            int health3 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            int health4 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEARING_AID);
            int health5 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HID_DEVICE);
            int health6 = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.SAP);
    
            if (a2dp == BluetoothProfile.STATE_CONNECTED) {
                flag = a2dp;
            } else if (headset == BluetoothProfile.STATE_CONNECTED) {
                flag = headset;
            } else if (health == BluetoothProfile.STATE_CONNECTED) {
                flag = health;
            } else if (health1 == BluetoothProfile.STATE_CONNECTED) {
                flag = health1;
            } else if (health2 == BluetoothProfile.STATE_CONNECTED) {
                flag = health2;
            } else if (health3 == BluetoothProfile.STATE_CONNECTED) {
                flag = health3;
            } else if (health4 == BluetoothProfile.STATE_CONNECTED) {
                flag = health4;
            } else if (health5 == BluetoothProfile.STATE_CONNECTED) {
                flag = health5;
            } else if (health6 == BluetoothProfile.STATE_CONNECTED) {
                flag = health6;
            }
            Log.e(TAG, "flag is " + flag);
    
            if (flag != -1) {
                bluetoothAdapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
    
                    @Override
                    public void onServiceDisconnected(int profile) {
                        // TODO Auto-generated method stub
                        Log.i(TAG, "onServiceDisconnected");
    
                    }
    
                    @Override
                    public void onServiceConnected(int profile, BluetoothProfile proxy) {
                        // TODO Auto-generated method stub
                        List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                        if (mDevices != null && mDevices.size() > 0) {
                            for (BluetoothDevice device : mDevices) {
                                Log.i(TAG, "device name: " + device.getName());
                            }
                        } else {
                            Log.i(TAG, "mDevices is null");
                        }
                    }
                }, flag);
            }
    
        }
    
        private void getDevices() {
            BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
            for (BluetoothDevice bluetoothDevice : bondedDevices) {
                Log.i(TAG, "name is : " + bluetoothDevice.getName() + " state is:" + bluetoothDevice.getBondState());
            }
            Log.i(TAG, "size:" + bondedDevices.size());
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unRegisterBroadcastReceiver();
        }
    
        private void registerBroadcastReveiver() {
            IntentFilter connectStateChangeFilter = new IntentFilter(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
            IntentFilter stateChangeFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
            IntentFilter connectFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
            IntentFilter disConnectFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    
            registerReceiver(stateChangeReceiver, connectStateChangeFilter);
            registerReceiver(stateChangeReceiver, stateChangeFilter);
            registerReceiver(stateChangeReceiver, connectFilter);
            registerReceiver(stateChangeReceiver, disConnectFilter);
        }
    
        private void unRegisterBroadcastReceiver() {
            unregisterReceiver(stateChangeReceiver);
        }
    
        private BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
    //            Log.i(TAG, "bluetooth, stateChangeReceiver, action: " + action);
    
                if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
                    Log.e(TAG, "connect");
                }
                if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
                    Log.e(TAG, "disconnect");
                }
    
                if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
                    Log.e(TAG, "ACTION_CONNECTION_STATE_CHANGED");
                }
    
                if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                    Log.e(TAG, "ACTION_STATE_CHANGED");
                }
            }
        };
    }

    相关参考:

    https://blog.csdn.net/mapeifan/article/details/50683956

    https://blog.csdn.net/gh8609123/article/details/66969006

    https://www.jianshu.com/p/332050b327b7

    展开全文
  • Android 蓝牙连接 蓝牙搜索 bluetooth 连接配对,如果需要请下载。
  • Android蓝牙连接问题总结

    万次阅读 2017-12-07 10:42:04
    最近开始接触Android蓝牙设备问题,严格意义上来说,也算是第二次接触蓝牙机制了,之前对于蓝牙设备的整个过程,也不是太了解,只是接触了一些自己需要的部分。而这次应该算是比较深入的了解了蓝牙机制的部分吧,...

    最近开始接触Android的蓝牙设备问题,严格意义上来说,也算是第二次接触蓝牙机制了,之前对于蓝牙设备的整个过程,也不是太了解,只是接触了一些自己需要的部分。而这次应该算是比较深入的了解了蓝牙机制的部分吧,所以就总结一下这段时间对蓝牙的个人认识吧


    (此图片转自http://blog.csdn.net/l331258747/article/details/55261386)

    基本上关于蓝牙的流程,这张图片就说明的差不多了,检测用户是否开启了蓝牙——开启蓝牙——扫描蓝牙设备——选择设备连接——发现服务——注册特征码——断开连接,我们就参考这张图,按照响应的顺序来说一下整个蓝牙设备流程的流程方法吧

    一:蓝牙检测

    我们在启用蓝牙模块的时候,还要先声明一下相关的权限问题

      <!-- 步骤(1)设置Google Map API v2 Key,其中com.wei.android.beginning为package的名字 -->
        <permission
            android:name="com.example.administrator.bluetoothdevice.permission.MAPS_RECEIVE"
            android:protectionLevel="signature" />
        <uses-permission android:name="com.example.administrator.bluetoothdevice.permission.MAPS_RECEIVE" />
        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
        <uses-permission android:name="no.nordicsemi.android.LOG" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <!-- 获取位置权限才可以搜索到设备-->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <!-- 蓝牙分享所需的权限 -->
        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    蓝牙通信之前,需要先确定设备是否支持蓝牙功能,先初始化一个BluetoothAdapter的实例,

    BluetoothAdapter提供了一个静态方法getDefaultAdapter()来获得BluetoothAdapter的实例

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    然后检测蓝牙是否开启并打开蓝牙:

    第一种方法:

    if(mBluetoothAdapter!=null){

    if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }

    }

    第二种方法:

    if(mBluetoothAdapter!=null){

    if (!mBluetoothAdapter.isEnabled()) {

    mBluetoothAdapter.enable();

    }

    }

    而两种方法,都会提示用户开启蓝牙权限。

    二:扫描蓝牙设备

    在扫描这里,要多添加一个点,就是关于蓝牙连接状态的广播监听,方便在蓝牙是否连接,断开的时候去做相关的逻辑处理,所以还是有必要了解一下的。

    if (mCommonBroadcastReceiver != null) {
        LocalBroadcastManager.getInstance(this).registerReceiver(
                mCommonBroadcastReceiver, makeIntentFilter());
        //注册蓝牙监听状态改变
        BleProfileServiceReadyActivity.this.registerReceiver(mCommonBroadcastReceiver, makeIntentFilter2());
    }
    private static IntentFilter makeIntentFilter2() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return intentFilter;
    }
    注册相关的蓝牙广播监听之后,在监听中做对应的逻辑处理
    private BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String action = intent.getAction();
            if (BleProfileService.BROADCAST_CONNECTION_STATE.equals(action)) {
    
                final int state = intent.getIntExtra(
                        BleProfileService.EXTRA_CONNECTION_STATE,
                        BleProfileService.STATE_DISCONNECTED);
                switch (state) {
                    case BleProfileService.STATE_CONNECTED:
                     
                        break;
                    case BleProfileService.STATE_DISCONNECTED:
                      
                        break;
    
                    case BleProfileService.STATE_LINK_LOSS:
    
                       
                        break;
    
                    case BleProfileService.STATE_CONNECTING:
    
                        break;
                    case BleProfileService.STATE_DISCONNECTING:
    
                       
                        break;
                    default:
                        // there should be no other actions
                        break;
                }
            }
    这里解释一下相关的状态含义:

    STATE_DISCONNECTED 状态为断开
    STATE_CONNECTING 状态为连接"
    STATE_DISCONNECTING 状态为断中
    STATE_CONNECTED 状态为连接中

    简单的说一下监听方法后,我们在回到主题,关于扫描蓝牙设备的方法:

    1. //搜索附近所有的外围设备  
    2. mBluetoothAdapter.startLeScan(mLeScanCallback);  
    3. //搜索某些uuid的外围设备。  
    4. mBluetoothAdapter.startLeScan(uuid[] ,mLeScanCallback);  
    1. 停止扫描  
    2. mBluetoothAdapter.stopLeScan(mLeScanCallback);  


    /*
     * 扫描结果回调
     */
    private LeScanCallback mLeScanCallback= new LeScanCallback() {
    
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi,
                             final byte[] scanRecord) {
            if (mLeScanCallback== null) {
                return;
            }
            try {
               //这里写逻辑代码
            } catch (Exception e) {
                Log.e("", e.toString());
            }
            return;
        }
    };

    解释一下其中的几个参数,当你扫描回调后,基本就可以搜索到周围的蓝牙设备了(前提是蓝牙开启的状态下),在回调的结果中,分别以后三个参数

    BluetoothDevice 表示你搜索的设备对象,一般获取设备的mac地址就是从这个对象获取,方法是
    getAddress()
    rssi 表示的则是设备距离的远近,信号强弱值,有需要这个值可以用数组缓存下来显示
    
    
    scanRecord 表示的则是蓝牙设备的一些属性值,比如
    serviceUUIDs;serviceData;localName等  
    在这里要补充说明一点的是,手机扫描设备回调,可能会无法调用,需要手机将位置权限也打开给应用,如果禁掉了应用的位置权限,也会导致扫描设备回调方法无法执行。

    三、蓝牙设备连接

    关于蓝牙的连接问题,先要说明几个相关类的含义

    BluetoothGatt:中央使用和处理数据;
    BluetoothGattCallback:中央的回调。

    BluetoothGattServer:周边提供数据;

    BluetoothGattServerCallback:周边的回调

    BluetoothGattService:Gatt服务

    BluetoothGattCharacteristic:Gatt特性

    BluetoothGattDescriptor:Gatt描述

    (转自http://blog.csdn.net/vnanyesheshou/article/details/51943870)

    我们要做的连接操作,就是用其中一个对象来处理的:

    BluetoothDevicedevice=mBluetoothAdapter.getRemoteDevice(new_mac);

    蓝牙设备对象,由BluetoothAdapter根据设备的mac地址来获取

    这里需要注意的一个坑是,mac地址必须是FF:FF:FF:FF这样的形式,这点不同于IOS的适配,如果使用其他的设备地址,会出现异常IllegalArgumentException,所以在连接的时候建议处理好此类异常问题:

    if (BluetoothManager.BluetoothState()) {
        try {
            BluetoothDevice device = getBluetoothAdapter().getRemoteDevice(DeviceAddress);
            Logger.i(TAG, "connectionHandler() " + DeviceAddress);
            if (null != device) {
                BluetoothGatt gatt = device.connectGatt(getContext(), false, this);
                if (gatt.connect()) {
                    createControl(gatt);
                    return true;
                }
            }
        } catch (IllegalArgumentException e) {
            Toast.makeText(getContext(), getContext().getString(R.string.error_device), Toast.LENGTH_SHORT).show();
            return false;
        } catch (Exception e) {
            Toast.makeText(getContext(), getContext().getString(R.string.error_device), Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    BluetoothGatt mBluetoothGatt =device.connectGatt(mContext, false,mGattCallback);

    这里的三个参数,分别对应的是<1>上下文对象<2>是否自动连接<3>连接回调和连接结果返回。这里重点解释一下第二个参数,个人建议最好是设置为false,如果设置自动连接,则安卓底层会不停的跟对应Mac地址的设备反复连接,连接效率会变得很慢,而且容易发送阻塞,导致后边的设备一直在等前一个设备连接成功的回调,蓝牙设备的连接一定要分开逐个连接,尽量不要形成线程阻碍。

    private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
        @Override
        //获取连接状态方法,BLE设备连接上或断开时,会调用到此方
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (DEBUG) Log.d(TAG, "onConnectionStateChange");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    showMessage("Bluetooth LE connected");
                }
                else if (status == BluetoothProfile.STATE_DISCONNECTED) {
                    showMessage("Bluetooth LE disconnected");
                }
            }
        }
    
        //成功发现设备的services时,调用此方法
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if ((status == BluetoothGatt.GATT_SUCCESS) &&
                    (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
                showMessage("Discover service Successful !!!");
            }
        }
    
        //读写characteristic时会调用到以下方法
        @Override
        public void onCharacteristicRead(BluetoothGatt gattBluetoothGattCharacteristic characteristic, int status) {
            if ((status == BluetoothGatt.GATT_SUCCESS) &&
                    (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) {
                showMessage(characteristic.getStringValue(0));
            }
        }
    
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            BluetoothGattCharacteristic mCharacteristic =
                    getCharacteristic(CHARACTERISTIC_UUID);
            if ((status == BluetoothGatt.GATT_SUCCESS) &&
                    (characteristic.getStringValue(0).equals(mCharacteristic.getStringValue(0)))) {
                showMessage("CharacteristicWrite Successful !!!");
            }
        }
    };
    (代码内容转自http://blog.csdn.net/l331258747/article/details/55261386,也可以参考文章最后留的Demo中的处理方法)
    连接是否成功,以及通知的处理,是声明在OnConnectionStateChange,看名字也应该可以看的出来,当设备的蓝牙连接状态发生改变的时候调用的方法。这里也是整个蓝牙最容易出现问题的地方,就是超过了手机连接设备的上限,导致反复连接无法连接上的133状态码问题。(133状态码一般出现在连接设备的数量超过了最大上限值)所以我们要针对这种问题,做相应的处理,尽可能在不使用的蓝牙连接的时候就及时回收掉BlueToothGatt。
         @Override
        publicvoid onConnectionStateChange(BluetoothGatt gatt, intstatus, intnewState) {
            String intentAction;
            if(status == BluetoothGatt.GATT_SUCCESS) {
                if(newState == BluetoothProfile.STATE_CONNECTED) {
                    intentAction = BluetoothConstants.ACTION_GATT_CONNECTED;
                    mBLEConnectionState = BluetoothConstants.BLE_STATE_CONNECTED;
                    broadcastUpdate(intentAction);
                    Log.i(TAG, "Connected to GATT server.");
                    Log.i(TAG, "Attempting to start service discovery:"  + mBluetoothGatt.discoverServices());
                elseif (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    intentAction = BluetoothConstants.ACTION_GATT_DISCONNECTED;
                    mBLEConnectionState = BluetoothConstants.BLE_STATE_DISCONNECTED;
                    close(); // 防止出现status 133
                    Log.i(TAG, "Disconnected from GATT server.");
                    broadcastUpdate(intentAction);
                }
            else{
                Log.d(TAG, "onConnectionStateChange received: "  + status);
                intentAction = BluetoothConstants.GATT_STATUS_133;
                mBLEConnectionState = BluetoothConstants.BLE_STATE_DISCONNECTED;
                close(); // 防止出现status 133
                broadcastUpdate(intentAction);
                connect(reConnectAddress);
            }
        }
     

    (转自http://blog.csdn.net/baidu_26352053/article/details/54571688)

    四、发现服务,注册特征码

    onServiceAdded需要注意我们的特征码一定不能在别的地方注册,因为蓝牙连接是一个耗时操作,如果你提前注册了特征码,很可能注册不成功,一定放在onServiceAdded方法下去注册,否则你会发现根本无法操作蓝牙设备
       private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
            @Override
            //获取连接状态方法,BLE设备连接上或断开时,会调用到此方
            public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
                if (DEBUG) Log.d(TAG, "onConnectionStateChange: newState=" + newState);
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                        mDevice = device;
                        String devicename = device.getName();
                        String address = device.getAddress();
                        notifyConnected(devicename);
                        beginNotification();
                    } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
                        stopNotification();
                        notifyDisconnected();
                        mDevice = null;
                    }
                }
            }
    
            //service添加成功会调用此方
            @Override
            public void onServiceAdded(int status, BluetoothGattService service) {
                if (DEBUG) Log.d(TAG, "onServiceAdded()");
                if (status == BluetoothGatt.GATT_SUCCESS) notifyServiceAdded();
            }
    
            //读写Characteristic,在此获得客户端发来的消息
            @Override
            public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,BluetoothGattCharacteristic characteristic,
                                                     boolean preparedWrite, boolean responseNeeded,int offset, byte[] value) {
                if (DEBUG) Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
                try{
                    mCharacteristicString = new String(value); //客户端发来的消息
                }catch(Exception e){
                }
                notifyCharacteristicWriteRequest(mCharacteristicString);
            }
        }
    
        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
                                                int offset, BluetoothGattCharacteristic characteristic) {
            if (DEBUG) Log.d(TAG, "onCharacteristicReadRequest()");
            notifyCharacteristicReadRequest();
        }
    };
    关于其他的蓝牙设备回调,接收发送数据包给蓝牙设备等操作,就要放在回调的其他几个方法了,具体都有相关的说明和标注,就不一一列出了。

    五:蓝牙设备断开问题

    在这里一定要说明的是,close一定要放在disconnect后调用,如果看过安卓蓝牙的底层源码的,一定有看到close中其实是有调用到disconnect方法的。很多时候设备断开后无法再重新连接,都是因为已经达到了手机蓝牙可连接设备的上限值,基本上手机可缓存的蓝牙设备都是在6个或者6个以上的,但是超过这个数量之后,就会发现始终连接不上设备的问题,类似蓝牙连接中常见的133问题,大多数时候我们在断开设备或者不需要蓝牙连接的时候,最好是调用close来回收掉BluetoothGatt,下次在重新创建一个连接对象。

    mBluetoothGatt.disconnect();
    mBluetoothGatt.close();
    mBluetoothGatt = null;

    五:关于蓝牙设备中出现的133问题

    1、就是建立及时回收蓝牙连接断开方法

    // 断开连接
    public boolean disConnect() {
        if (mBluetoothGatt != null) {
            System.out.println("断开连接");
            Log.d("TAG", "连接失败,已断开连接" + mBluetoothGatt);
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
            mBluetoothGatt = null;
            connect_flag = false;
            setConnectionState(BluetoothProfile.STATE_DISCONNECTED);
            cleanControl();
            return true;
        }
        return false;
    }

    2、安卓底层还有一个回收刷新蓝牙缓存的方法,不过是无法调用的。在android.bluetooth.BluetoothGatt

    android.bluetooth.BluetoothGatt类中有一个refresh方法是隐藏性质的方法,所以要通过java反射机制来调用此方法。


    清理方法如下,一般建议放在最后清理缓存的时候调用,否则你会发现由于清理了缓存,反复都连接不上设备

    /**
     * 清理蓝牙缓存
     */
    public boolean refreshDeviceCache() {
        if (mBluetoothGatt != null) {
            try {
                Method localMethod = mBluetoothGatt.getClass().getMethod(
                        "refresh", new Class[0]);
                if (localMethod != null) {
                    boolean bool = ((Boolean) localMethod.invoke(
                            mBluetoothGatt, new Object[0])).booleanValue();
                    return bool;
                }
            } catch (Exception localException) {
                L.i(TAG, "An exception occured while refreshing device");
            }
        }
        return false;
    }

    大致流程就说完了,其中还有很多坑,比如特征码注册问题了,无法正常断开设备问题了,重启蓝牙后无法正常连接设备等,以后再找时间对此单独在写一篇文章吧,另外附上gothub上发布的蓝牙设备连接搜索整的Demo地址

    https://github.com/wangyetongsss/BluetoothDevice

    展开全文
  • 程序实现功能:开启、关闭、连接蓝牙,SCAN周围蓝牙并获得蓝牙名字,地址,信号强度RSSI,连接状态,因为当时是为了做一个蓝牙定位,所以按照需求还添加了一个是否是自己买的蓝牙基站的Textview。 当判断SCAN到的...
  • 安卓Android源码——android蓝牙连接打印机.rar

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,481
精华内容 10,592
关键字:

android蓝牙连接