Android 蓝牙 Bluetooth 自动回连 取消pin码校验弹出框

蓝牙深层次的也不太懂,主要是使用了 BluetoothAdapter 和 BluetoothDevice 这两类,一个表示本地蓝牙设备,一个表示远程蓝牙设备
相关说明:https://blog.csdn.net/weixin_44128558/article/details/124835947

连接设备和断开设备

名称介绍
A2dp音频
Gatt低功耗
Headset蓝牙耳机(通话)
Health健康
Hid人机接口设备
Hfp免提
Sap会话通知
HearingAid助听器
Socket面向连接,套接字,基于RFCOMM

等等一些设备

只贴了出主要的代码

	public static final String CONNECT = "connect";
    public static final String DISCONNECT = "disconnect";
	private String currentStatus = "";
	private BluetoothDevice currentDevice = null;
	
	//some code

	// 监听回调
	private BluetoothProfile.ServiceListener mListener = new BluetoothProfile.ServiceListener() {
        @SuppressLint("MissingPermission")
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            Log.d("zwt", "connected profile = " + profile);
            if (profile == BluetoothProfile.A2DP) {
                BluetoothA2dp mA2dp = (BluetoothA2dp) proxy; //转换
                if (mA2dp == null || currentDevice == null){
					Log.d("zwt", "a2dp 初始化失败 或 currentDevice = null ");
					return;
				}
                Log.d("zwt", "a2dp 初始化完成 = "+(mA2dp == null)+":::::");

				if (DISCONNECT.equals(currentStatus)){     // 连接
					//获得所有通过A2DP代理管理连接的蓝牙设备,如果不是A2DP协议代理的设备无法断开连接
					@SuppressLint("MissingPermission") List<BluetoothDevice> deviceList=mA2dp.getConnectedDevices();
					if (deviceList!=null && deviceList.size()>0 && deviceList.contains(currentDevice)){
						disConnectA2dpAndHeadSet(BluetoothA2dp.class, mA2dp, currentDevice);
					}

                /****取消所有蓝牙设备(音箱)连接****/

//                @SuppressLint("MissingPermission") List<BluetoothDevice> deviceList=mA2dp.getConnectedDevices();
//                if(deviceList!=null&&deviceList.size()>0){
//                    Log.d("zwt", "有连接的设备");
//                    for (BluetoothDevice device : deviceList){
//                        disConnectA2dpAndHeadSet(BluetoothA2dp.class, mA2dp, device);
//                    }
//                }else {
//                    Log.d("zwt", "没有连接设备");
//                }
                /*********************************/
	
	
				}else if(CONNECT.equals(currentStatus)){  //断开连接
					connectA2dpAndHeadSet(BluetoothA2dp.class, mA2dp, currentDevice);
				}
                currentDevice = null;

            }
        }
		@Override
        public void onServiceDisconnected(int profile) {
            Log.d(TAG, "close connect profile = " + profile);
            if (profile == BluetoothProfile.A2DP)   {
                mA2dp = null;
            }
        }
    };


	// 连接蓝牙 服务
    private boolean connectA2dpAndHeadSet(Class<?> btClass, BluetoothProfile bluetoothProfile, BluetoothDevice device) {
        Log.d("zwt", "connectA2dpAndHeadSet连接设备");
        Boolean isConnect = false;
        try {
            Method connectMethod = btClass.getMethod("connect", BluetoothDevice.class);
            connectMethod.setAccessible(true);
            isConnect = (boolean) connectMethod.invoke(bluetoothProfile, device);
            Log.d("zwt", "是否连接设备成功:::"+isConnect);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            Log.d("zwt", "连接设备异常");
            e.printStackTrace();
        }
        return isConnect;
    }
    //断开连接蓝牙 服务
    private boolean disConnectA2dpAndHeadSet(Class<?> btClass, BluetoothProfile bluetoothProfile, BluetoothDevice device){
        Log.d("zwt", "disConnectA2dpAndHeadSet断开连接设备");
        Boolean isDisConnect = false;
        try {
            Method disconnectMethod = btClass.getDeclaredMethod("disconnect", BluetoothDevice.class);
            disconnectMethod.setAccessible(true);
            isDisConnect = (boolean) disconnectMethod.invoke(bluetoothProfile, device);
            Log.d("zwt", "是否断开设备成功:::"+isDisConnect);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            Log.d("zwt", "断开设备异常");
            e.printStackTrace();
        }
        return isDisConnect;
    }
	
	/**
     *  连接蓝牙设备
     * @param device 要连接的设备
     * @param bluetoothProfile 代理对象
     */
    public void connect(BluetoothDevice device, int bluetoothProfile){
        currentStatus = CONNECT;
        currentDevice = device;
        bluetoothAdapter.getProfileProxy(context, mListener, bluetoothProfile); //会回调到BluetoothProfile.ServiceListener中

    }
    /**
     *  断开连接蓝牙设备
     * @param device 要断开连接的设备
     * @param bluetoothProfile 代理对象
     */
    public void disConnect(BluetoothDevice device, int bluetoothProfile){
        currentStatus = DISCONNECT;
        currentDevice = device;
        bluetoothAdapter.getProfileProxy(context, mListener, bluetoothProfile);

    } 

注意connectA2dpAndHeadSet 方法,由于 BluetoothA2dp#connect() 和 BluetoothA2dp#disconnect() 方法声明了不能被外部app使用,所以只能用反射的方式调用,这里只实现了 A2DP 协议的连接方式,主要是用于蓝牙音箱,蓝牙耳机等设备的连接,要是想使用蓝牙电话功能,需要使用 BluetoothProfile.HEADSET 协议,实现方法与 A2DP 相同

在这里插入图片描述
调用

BTServiceManager.getInstance().disConnect(currentDevice, BluetoothProfile.A2DP);
BTServiceManager.getInstance().connect(currentDevice, BluetoothProfile.A2DP);

回连设备

上面的方法可以去连接,断开蓝牙音箱等设备,但是奇怪的是无法连接或断开连接手机设备,问题在于,设备连接蓝牙音箱的时候为声音的提供端(即主模式 source端),而连接手机的时候为声音的接收端(即从模式 sink端)两种为不一样的模式,而手机厂商可能做了处理,手机不能作为声音的接收端进行连接,所以会连接失败,如果上面的方法连接成功了状态也不对,变成了设备的声音通过手机的喇叭播放出来

最后查api发现了一个A2DP_SINK模式,所以试试用这个模式进行连接:

在这里插入图片描述
如上图所示,这种模式只能是系统级的应用才能使用,Android studio中直接使用会报错无法编译,要在系统中编译才能通过
在这里插入图片描述

移植项目到系统:https://blog.csdn.net/weixin_44128558/article/details/125278463

	// 蓝牙服务回调监听
    private BluetoothProfile.ServiceListener mListener = new BluetoothProfile.ServiceListener() {
        @SuppressLint("MissingPermission")
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            Log.d(TAG, "connected profile = " + profile);
            if (profile == BluetoothProfile.A2DP) { //蓝牙音箱
				// some code 与上面相同
            }
            
            if (profile == BluetoothProfile.A2DP_SINK){ //作为声音接收端连接手机
                BluetoothA2dpSink mA2dpSinkProfile = (BluetoothA2dpSink) proxy;
                if (mA2dpSinkProfile == null || currentDevice == null){
					Log.d("zwt", "A2dpSink 初始化失败 或 currentDevice = null ");
					return;
				}
                Log.d("zwt", "A2DP_SINK 初始化完成::::"+(mA2dpSinkProfile == null));

                if (CONNECT.equals(currentStatus)){     // 连接手机
                    try{
                        Thread.sleep(300);
                    }catch (InterruptedException e) { e.printStackTrace(); }
                    
                    mA2dpSinkProfile.connect(currentDevice);
                    Log.d("zwt", "连接手机::"+currentDevice.getName());
                    // must set PRIORITY_AUTO_CONNECT or auto-connection will not
                    // occur, however this setting does not appear to be sticky
                    // across a reboot
                    mA2dpSinkProfile.setPriority(currentDevice, BluetoothProfile.PRIORITY_AUTO_CONNECT);
                    
                }else if (DISCONNECT.equals(currentStatus)){    //断开连接手机
                    try{
                        Thread.sleep(300);
                    }catch (InterruptedException e) { e.printStackTrace(); }

                    Log.d(TAG, "断开手机连接::"+currentDevice.getName());
                    mA2dpSinkProfile.disconnect(currentDevice); 
                }

            }
        }

// connect方法与disConnect 方法与上面相同无需更改
	public void connect(BluetoothDevice device, int bluetoothProfile){
        currentStatus = CONNECT;
        currentDevice = device;
        bluetoothAdapter.getProfileProxy(context, mListener, bluetoothProfile);

    }
    public void disConnect(BluetoothDevice device, int bluetoothProfile){
        currentStatus = DISCONNECT;
        currentDevice = device;
        bluetoothAdapter.getProfileProxy(context, mListener, bluetoothProfile);
    } 

调用:主要实现进入app时,断开所有的蓝牙音箱设备,并回连最后一次连接的手机设备,并在退出app时断开与手机的连接

BTServiceManager.getInstance().disConnect(currentDevice, BluetoothProfile.A2DP_SINK);
BTServiceManager.getInstance().connect(currentDevice, BluetoothProfile.A2DP_SINK);

贴出主要代码

	@SuppressLint("MissingPermission")
    @Override
	protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
		if (initPairBLEAndConnectBLE(getConnectedDevice())){
            callBackBT();
        }
	}

	/**
     * 获得所有已经连接的设备
     * @return 已连接设备列表
     */
    public Set<BluetoothDevice> getConnectedDevice(){
    	// bluetoothAdapter 自己通过代码获得
        if (bluetoothAdapter != null){
            //得到已配对的设备列表
            @SuppressLint("MissingPermission") Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
            Set<BluetoothDevice> resultConnectedDevice = new HashSet<>();
            for (BluetoothDevice bluetoothDevice : devices) {
                boolean isConnect = false;
                try {
                    isConnect = (boolean) bluetoothDevice.getClass().getMethod("isConnected").invoke(bluetoothDevice);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    e.printStackTrace();
                }
                if (isConnect) {
                    resultConnectedDevice.add(bluetoothDevice);
                }
            }
            return resultConnectedDevice;
        }
        return null;
    }

	/**
     * 初始话蓝牙状态
     * @param devices 已经连接的设备
     * @return 是否回连设备,已经连接了设备返回false,否则返回true
     */
    @SuppressLint("MissingPermission")
    private boolean initPairBLEAndConnectBLE(Set<BluetoothDevice> devices){
        if (devices != null && devices.size()>0){
            for (BluetoothDevice bluetoothDevice : devices) {
                // 经典 1, BLE 2, 双模 3,
                Log.d("zwt", "已连接设别:"+bluetoothDevice.getName()+"::类别::"+bluetoothDevice.getType());
                int styleMajor = bluetoothDevice.getBluetoothClass().getMajorDeviceClass();
                if(styleMajor == BluetoothClass.Device.Major.PHONE){ //手机
                    // TODO 有连接到的手机设备,做些UI的更新提示
                    return false;
                }else if(styleMajor == BluetoothClass.Device.Major.AUDIO_VIDEO){//音频设备
                	//这里是要做打开应用先自动断开所有的蓝牙音箱设备,连接手机
                	//因为在连接音箱设备的同时不能连接手机,跟蓝牙芯片有关(RTL8723DU),即不能同时处在主模式和从模式,一时间只能为一个模式
                    BTServiceManager.getInstance().disConnect(bluetoothDevice, BluetoothProfile.A2DP);
                    continue;
                } else {//其他设备
                    // TODO 其他未适配设备,UI提示先手动断开在连接手机蓝牙
                    return false;
                }
            }
        }
        return true;
    }
	/**
     * 回连蓝牙设备
     */
    @SuppressLint("MissingPermission")
    private void callBackBT(){
        Set<BluetoothDevice> ConnctedDevices = BTChatA2dpServiceManager.getInstance().getBondedDevice();
        for (BluetoothDevice device : ConnctedDevices){
            @SuppressLint("MissingPermission") int styleMajor = device.getBluetoothClass().getMajorDeviceClass();
            Log.d("zwt","callBackBT() 已配对设备::"+device.getName()+":类型(512手机)(1024音频设备)::"+styleMajor);
            if (styleMajor == BluetoothClass.Device.Major.PHONE){
                Log.d("zwt", "手机设备回连中");
                BTServiceManager.getInstance().connect(device, BluetoothProfile.A2DP_SINK);
                //只尝试连接最近连接过的一个手机设备,无论成功与否都不在向下尝试
                break;
            }
        }
    }
	// 这里拦截按键,因为发现在destory中调用断开连接的方法无作用,可能是有些资源被释放了
	// currentDevice 为当前连接的设备,注意控好状态,不要乱了,本应该是个当前连接设备数组
	@Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                Log.d("zwt", "按下返回按键");
                if (currentDevice != null)
                    BTServiceManager.getInstance().disConnect(currentDevice, BluetoothProfile.A2DP_SINK);
                finish();
                return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }

取消pin码验证

比起上面的回连功能可简单太多了网上资料也很多,需要注册个广播,手动设置以下pin码就行了

	@SuppressLint("MissingPermission")
    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        if (action == null) return;
       
        if (action.equals(BluetoothDevice.ACTION_UUID)){
            Log.d("zwt", "ACTION_UUID 唯一码UUID:");
        }

		// 配对请求广播
        if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)){
            Log.d(TAG, "ACTION_PAIRING_REQUEST 配对请求");
            //获得蓝牙设备
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Bundle extras = intent.getExtras();
            //"android.bluetooth.device.extra.PAIRING_KEY"
            Object pairkey = extras.get(BluetoothDevice.EXTRA_PAIRING_KEY);	//配对的pin码

            Log.d("zwt", "device-->"+String.valueOf(btDevice )+":::pairkey-->"+String.valueOf(pairkey));

            btDevice.setPairingConfirmation(true); 
            //消费这个广播,不然这个广播传到底层就会又弹出配对界面,一闪而过
            abortBroadcast(); 
            //ret为true 表示设置成功,fales表示不成功
            boolean ret = btDevice.setPin(pairkey.toString().getBytes());
        }
		//其他广播监听
    }

注册广播

		IntentFilter intentFilter = new IntentFilter();
        
        //添加其他需要监听的广播
        
        intentFilter.addAction(BluetoothDevice.ACTION_UUID);
        intentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
        /**
         Broadcast Action: This intent is used to broadcast PAIRING REQUEST
         For apps targeting Build.VERSION_CODES#R or lower, this requires the Manifest.permission#BLUETOOTH_ADMIN permission which can be gained with a simple <uses-permission> manifest tag.
         */


        //注册广播
        registerReceiver(mBroadcastReceiver, intentFilter);

轻松实现

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值