蓝牙深层次的也不太懂,主要是使用了 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")@Overridepublic 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;}}@Overridepublic 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")@Overridepublic 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 rebootmA2dpSinkProfile.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")@Overrideprotected 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 为当前连接的设备,注意控好状态,不要乱了,本应该是个当前连接设备数组@Overridepublic 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")@Overridepublic 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 REQUESTFor 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);

轻松实现

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

  1. Android开发:利用Activity的Dialog风格完成弹出框设计

    转:http://www.linuxidc.com/Linux/2011-08/41933.htm 在我们使用Dialog时,如果需要用到很多自己设计的控件,虽然可以让弹出框显示出我们需要的界面,但却 ...

  2. 深入了解Android蓝牙Bluetooth——《基础篇》

    深入了解Android蓝牙Bluetooth--<基础篇> 什么是蓝牙?   也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的 ...

  3. android -- 蓝牙 bluetooth解读

    入手一个新的模块或应用,当然首先要知道它都有什么了,与它相关的代码在那里,所以先一起看下蓝牙代码分布吧. 1. 代码分布: packages/apps/Bluetooth/ 看这路径肯定是蓝牙应用方面 ...

  4. ZT android -- 蓝牙 bluetooth (四)OPP文件传输

    android -- 蓝牙 bluetooth (四)OPP文件传输 分类: Android的原生应用分析 2013-06-22 21:51 2599人阅读 评论(19) 收藏 举报 4.2源码AND ...

  5. android -- 蓝牙 bluetooth (四)OPP文件传输

    原址 在前面android -- 蓝牙 bluetooth (一) 入门文章结尾中提到了会按四个方面来写这系列的文章,前面已写了蓝牙打开和蓝牙搜索,这次一起来看下蓝牙文件分享的流程,也就是蓝牙应用op ...

  6. android -- 蓝牙 bluetooth (一) 入门

    android -- 蓝牙 bluetooth (一) 入门 分类: Android的原生应用分析 2013-05-19 21:44 19998人阅读 评论(42) 收藏 举报 bluetooth4. ...

  7. android弹出框自定义按钮,安卓(kotlin)自定义弹出框

    在安卓开发中,我们经常会遇到这种情况,就是可爱的UI们设计了一套属于我们自己风格的弹出框,为了彰显我们自己的风格,使用自动的dialog当然满足不了我们的需求,所以还是得这基础上写出我们自己的提示框, ...

  8. android点击按钮弹出输入框,android 弹出框(输入框和选择框)

    1.输入框: final EditText inputServer = new EditText(this); inputServer.setFilters(new InputFilter[]{new ...

  9. android tv 悬浮窗口,android TV的自定义关机弹出框

    关机的时候会走power的相关部分 首先我们监听power键的文件是在frameworks\base\services\core\java\com\android\server\policy\Phon ...

最新文章

  1. Linux15-SELinux
  2. Customization larbin
  3. 08-Isolation using virtualization in the Secure World_Whitepaper
  4. 外挂学习之路(3)--- 内存遍历工具
  5. verilog 简单module_一个简单的verilog小程序
  6. javaweb 常用jar包_使用javaweb写一个登录案例
  7. Python关于中文字符前面的u(转载)
  8. JVM初学之JVM的运行时数据区
  9. 动态规划____编辑距离
  10. 回顾2006年:网络通信十大事件
  11. 虚拟机(VMware Workstation)的使用方法(转)
  12. 旅游规划 (25 分)(Dijkstra)
  13. 程序应该怎样写比较规范
  14. spring boot集成redis
  15. 【问题解决】seckill-秒杀项目 -- 服务端异常
  16. ValueError X has 2 features, but LogisticRegression is expecting 5 features as input
  17. 你真的知道如何使用Target.Count吗?
  18. domino mysql_IBM domino数据库操作,数据迁移
  19. Google Android EDLA协议及AER认证
  20. sinh函数_sinh()函数以及C ++中的示例

热门文章

  1. SpringBoot集成Minio搭建自己的分布式文件服务器(Minio集成篇)
  2. Java微信公众号开发(附源码!!!)
  3. idea svn IP地址更换方法
  4. MSDC 4.3 接口规范(6)
  5. VC中常见的108个问题
  6. Linux进程池、线程池调研
  7. 为什么需要软件开发报告
  8. html5视频播放器 知乎,6款让人赞不绝口的电脑软件,知乎超10W人推荐,建议悄悄收藏...
  9. 线段树入门之夜空星亮
  10. UITextView内边距设置