Android知识点
Service设置为前台服务
Toast消息不重复显示
Android5.0以上隐式启动第三方应用的服务
AIDL的使用
生成二维码方法
ANT build.xml文件详解
service周期性工作
跳转到系统开启GPS
跨进程访问sharepreference
ping方法判断网络是否可用
Android 技术分享 - RTMP直播 和 Camera
设计基类 -- BaseActivity
正则表达式
关机 -- 通过反射机制
gradle配置日志打印信息
Application 多次实例化问题
Gsensor_方向感应实现
Android状态栏微技巧,带你真正理解沉浸式模式
Top Activity的包名获取
校验和
android 拷贝DB数据到内存卡
打开和关闭虚拟按键
Properties读取中文乱码解决方案
如何实现Activity窗口快速变暗
Android判断SD卡
Android 代码执行adb shell 指令
Android 动态添加权限
全局获取Application对象
Android中Hook Instrumentation的一些思考
获取Activity实例
Activity 启动延时加载方案
生成 frameworks/base/preloaded-classes文件
Bluetooth-蓝牙模块
8、BLE蓝牙按键jar包使用说明
Bluetooth 蓝牙 4.x
Bluetooth 蓝牙搜索、配对连接
Android.bluetooth 功能解析
Android4.4 之Bluetooth整理
Framework 层理解 - 框图
Android事件传递机制详解
Android-tools知识点
Android博客
Android 调试宝典
遇到的难点问题
ubuntu
Android Framework
Android 规范和API Doc
开发接口文档
Java 知识点
工具使用
RK3588
MTK
Android Studio 知识
其他知识

Android

个人Android学习总结


Bluetooth 蓝牙搜索、配对连接

<p>[android 蓝牙搜索、配对连接](<a href="http://www.2cto.com/kf/201502/374785.html">http://www.2cto.com/kf/201502/374785.html</a> &quot;android 蓝牙搜索、配对连接&quot;) [ Android中如何实现蓝牙的配对与连接](<a href="http://blog.csdn.net/u012910985/article/details/50387551">http://blog.csdn.net/u012910985/article/details/50387551</a> &quot; Android中如何实现蓝牙的配对与连接&quot;)</p> <h1>android 蓝牙搜索、配对连接</h1> <p>蓝牙协议可以实现一个蓝牙设备和6到8个蓝牙设备进行通信。 1、蓝牙搜索的实现</p> <p>利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备。</p> <p>第一步,获得蓝牙适配器</p> <pre><code>BluetoothAdapter mBtAdapter= BluetoothAdapter.getDefaultAdapter(); // 判断蓝牙是否打开 if (!mAdapter.isEnabled()) { mAdapter.enable(); }</code></pre> <p>第二步动态注册蓝牙搜索广播接收者</p> <pre><code>// Register for broadcasts when a device is discovered IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); // Register for broadcasts when discovery has finished filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter);</code></pre> <p>并且可以利用意图过滤器设置广播的优先级</p> <pre><code>filter.setPriority(Integer.MAX_VALUE);</code></pre> <p>对应的广播接收者:</p> <pre><code>// The BroadcastReceiver that listens for discovered devices and // changes the title when discovery is finished private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // If it's already paired, skip it, because it's been listed already if (device.getBondState() != BluetoothDevice.BOND_BONDED) { mNewDevicesArrayAdapter.add(device.getName() + &amp;quot;\n&amp;quot; + device.getAddress()); } // When discovery is finished, change the Activity title } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); setTitle(R.string.select_device); if (mNewDevicesArrayAdapter.getCount() == 0) { String noDevices = getResources().getText(R.string.none_found).toString(); mNewDevicesArrayAdapter.add(noDevices); } } } };</code></pre> <p>或者利用发现和完成动作定义两个广播接受者,在完成的动作中注销广播接收者。 关键代码如下:</p> <pre><code>/** * 接收器 当搜索蓝牙设备完成时调用 */ private BroadcastReceiver _foundReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 将结果添加到列表中 _devices.add(device); DeviceInfo info = new DeviceInfo(); info.setmDeviceName(device.getName()); info.setmDeviceMacAddr(device.getAddress()); infos.add(info); info = null; // 显示列表 showDevices(); } }; private BroadcastReceiver _discoveryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 卸载注册的接收器 unregisterReceiver(_foundReceiver); unregisterReceiver(this); _discoveryFinished = true; } };</code></pre> <p>这样便完成蓝牙的搜索了。</p> <p>2、蓝牙配对</p> <p>蓝牙要想通信目前是必须要先配对才能连接的。</p> <p>蓝牙配对的api是hide的。但是api19可以直接调用蓝牙设备的配对方法。</p> <p>所以配对都是利用反射的方法。这里有一个强大的工具类可以直接拿来使用,如下:</p> <pre><code>package net.oschina_pdp.app.Utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.util.Log; public class ClsUtils { public ClsUtils() { // TODO Auto-generated constructor stub } /** * 与设备配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean createBond(Class&amp;lt; ? extends BluetoothDevice&amp;gt; btClass, BluetoothDevice btDevice) throws Exception { Method createBondMethod = btClass.getMethod(&amp;quot;createBond&amp;quot;); Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice); return returnValue.booleanValue(); } /** * 与设备解除配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean removeBond(Class&amp;lt;? extends BluetoothDevice&amp;gt; btClass, BluetoothDevice btDevice) throws Exception { Method removeBondMethod = btClass.getMethod(&amp;quot;removeBond&amp;quot;); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice); return returnValue.booleanValue(); } static public boolean setPin(Class btClass, BluetoothDevice btDevice, String str) throws Exception { try { Method removeBondMethod = btClass.getDeclaredMethod(&amp;quot;setPin&amp;quot;, new Class[] {byte[].class}); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[] {str.getBytes()}); Log.e(&amp;quot;returnValue设置密码&amp;quot;, &amp;quot;&amp;quot; + returnValue.booleanValue()); return returnValue.booleanValue(); } catch (SecurityException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } // 取消用户输入 static public boolean cancelPairingUserInput(Class&amp;lt;?&amp;gt; btClass, BluetoothDevice device) throws Exception { Method createBondMethod = btClass.getMethod(&amp;quot;cancelPairingUserInput&amp;quot;); cancelBondProcess(btClass,device) ; Boolean returnValue = (Boolean) createBondMethod.invoke(device); Log.i(&amp;quot;取消对话框&amp;quot;,&amp;quot;cancelPairingUserInput&amp;quot;+returnValue.booleanValue()); return returnValue.booleanValue(); } // 取消配对 static public boolean cancelBondProcess(Class&amp;lt;?&amp;gt; btClass, BluetoothDevice device) throws Exception { Method createBondMethod = btClass.getMethod(&amp;quot;cancelBondProcess&amp;quot;); Boolean returnValue = (Boolean) createBondMethod.invoke(device); return returnValue.booleanValue(); } /** * * @param clsShow */ static public void printAllInform(Class&amp;lt;?&amp;gt; clsShow) { try { // 取得所有方法 Method[] hideMethod = clsShow.getMethods(); int i = 0; for (; i &amp;lt; hideMethod.length; i++) { Log.e(&amp;quot;method name&amp;quot;, hideMethod[i].getName() + &amp;quot;;and the i is:&amp;quot; + i); } // 取得所有常量 Field[] allFields = clsShow.getFields(); for (i = 0; i &amp;lt; allFields.length; i++) { Log.e(&amp;quot;Field name&amp;quot;, allFields[i].getName()); } } catch (SecurityException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } static public boolean pair(String strAddr, String strPsw) { boolean result = false; BluetoothAdapter bluetoothAdapter = BluetoothAdapter .getDefaultAdapter(); bluetoothAdapter.cancelDiscovery(); if (!bluetoothAdapter.isEnabled()) { bluetoothAdapter.enable(); } BluetoothDevice device = bluetoothAdapter.getRemoteDevice(strAddr); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { try { Log.d(&amp;quot;mylog&amp;quot;, &amp;quot;NOT BOND_BONDED&amp;quot;); boolean flag1=ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对 boolean flag2=ClsUtils.createBond(device.getClass(), device); // remoteDevice = device; // 配对完毕就把这个设备对象传给全局的remoteDevice result = true; } catch (Exception e) { // TODO Auto-generated catch block Log.d(&amp;quot;mylog&amp;quot;, &amp;quot;setPiN failed!&amp;quot;); e.printStackTrace(); } // } else { Log.d(&amp;quot;mylog&amp;quot;, &amp;quot;HAS BOND_BONDED&amp;quot;); try { ClsUtils.removeBond(device.getClass(), device); //ClsUtils.createBond(device.getClass(), device); boolean flag1= ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对 boolean flag2=ClsUtils.createBond(device.getClass(), device); // remoteDevice = device; // 如果绑定成功,就直接把这个设备对象传给全局的remoteDevice result = true; } catch (Exception e) { // TODO Auto-generated catch block Log.d(&amp;quot;mylog&amp;quot;, &amp;quot;setPiN failed!&amp;quot;); e.printStackTrace(); } } return result; } }</code></pre> <p>蓝牙配对的关键代码:</p> <pre><code>flag3= ClsUtils.createBond(device.getClass(), device);</code></pre> <p>其中device是蓝牙设备。在配对的时候会有一个配对广播,可以自定义一个广播接受者获取配对广播,然后在这个广播接收者里设置pin值,取消确定对话框,实现自动配对。关键代码如下:</p> <pre><code>mReceiver=new ParingReceiver(device); IntentFilter filter=new IntentFilter(); filter.addAction( BluetoothDevice.ACTION_PAIRING_REQUEST); filter.setPriority(Integer.MAX_VALUE); registerReceiver(mReceiver, filter); private class ParingReceived extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { BluetoothDevice btDevice=mAdapter.getRemoteDevice(&amp;quot;EC:89:F5:98:46:f9&amp;quot;); try { setPin(btDevice.getClass(),btDevice,&amp;quot;000000&amp;quot;); cancelPairingUserInput(btDevice.getClass(), btDevice); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }</code></pre> <p>在我的4.2系统上是没有效果的。找了一个上午的资料;网上给出了两种解决方法:(1)修改setting 系统源码,(2)模拟点击事件。</p> <p>蓝牙配对完成后就可以连接通信了。</p> <p>3、蓝牙通信</p> <p>蓝牙同时的本质是蓝牙套接字,一个主动发起连接的的设备做客户端,一个监听连接的设备做服务端,类似sokcet网络编程,利用多线程,读取数据流就可完成蓝牙通信。</p> <p>如下是蓝牙串口通信的关键代码:</p> <pre><code>/** * 建立连接并通信 * * @param btDev * @return */ private boolean connect(BluetoothDevice btDev) { boolean flag = false; try { /*if(btDev.fetchUuidsWithSdp()){ btDev.getUuids(); }*/ //建立连接 mSocket = btDev .createRfcommSocketToServiceRecord(UUID.fromString(&amp;quot;00001101-0000-1000-8000-00805F9B34FB&amp;quot;)); mSocket.connect(); mOutputStream = mSocket.getOutputStream(); mInputStream = mSocket.getInputStream(); mOutputStream.write(&amp;quot;StartOnNet\n&amp;quot;.getBytes()); mOutputStream.flush(); flag = true; } catch (Exception e) { }</code></pre> <p>蓝牙服务端代码 private class ServerThread implements Runnable {</p> <pre><code> private InputStream mInputStream; private OutputStream mOutputStream; public ServerThread() { } @Override public void run() { try { while (true) { mBluetoothServerSocket = mAdapter .listenUsingRfcommWithServiceRecord( &amp;quot;btspp&amp;quot;, UUID.fromString(&amp;quot;00001101-0000-1000-8000-00805F9B34FB&amp;quot;)); Log.i(&amp;quot;服务端线程运行&amp;quot;, &amp;quot;蓝牙服务端线程开始&amp;quot;); Log.i(&amp;quot;服务端线程运行&amp;quot;, &amp;quot;蓝牙服务端线程阻塞中&amp;quot;); mBluetoothSocket = mBluetoothServerSocket.accept(); if (mBluetoothSocket != null) { break; } } Log.i(&amp;quot;服务端线程运行&amp;quot;, &amp;quot;蓝牙服务端线程&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;quot;); mInputStream = mBluetoothSocket.getInputStream(); mOutputStream = mBluetoothSocket.getOutputStream(); byte[] data = getSocketResult(mInputStream); String tempString = new String(data); Log.i(&amp;quot;蓝牙服务端监听str&amp;quot;, tempString); // 向客户端发送数据 if (tempString.equals(&amp;quot;StartOnNet\n&amp;quot;)) { mOutputStream.write(&amp;quot;haha&amp;quot;.getBytes()); mOutputStream.flush(); if(!isServiceRunning(&amp;quot;com.yqq.endClient3.service.GpsInfoCollectionService&amp;quot;,BluethoothServer.this)){ // 开启GPS收集服务 gpsService= new Intent(BluethoothServer.this, GpsInfoCollectionService.class); Log.i(&amp;quot;蓝牙服务端监听&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;quot;, &amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;quot;); startService(gpsService); } } } catch (Exception e) { // TODO: handle exception } finally { if (mInputStream != null) { try { mInputStream.close(); mInputStream = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mInputStream != null) { try { mOutputStream.close(); mOutputStream = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mBluetoothSocket != null) { try { mBluetoothSocket.close(); mBluetoothSocket = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mBluetoothServerSocket != null) { try { mBluetoothServerSocket.close(); mBluetoothServerSocket = null; Looper.prepare(); Message message = Message.obtain(); message.what = 0x123456; mHandler.sendMessage(message); Looper.loop(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }</code></pre>

页面列表

ITEM_HTML