手机BLE蓝牙通讯
Android的藍牙開發(fā),包括藍牙的廣播事件和掃描,藍牙配對連接、數(shù)據(jù)傳輸?shù)葐栴},本文著重講BLE低功耗藍牙4.0開發(fā)
AndroidMainifest權限:
? ? <uses-sdk
? ? ? ? android:minSdkVersion="18"
? ? ? ? android:targetSdkVersion="19" />
? ? <!--藍牙權限-->
?? ?<uses-permission android:name="android.permission.BLUETOOTH"/>
?? ?<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
?? ?<!--Android 5.0以上藍牙好需要位置權限-->
?? ?<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
?? ?<uses-permission android:name="andriod.permission.ACCESS_FINE_LOCATION"/>
?? ?<!--設備支持BLE低功耗藍牙 true -->
?? ?<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"></uses-feature>
△低功耗藍牙4.0開發(fā):源碼
import java.util.ArrayList; import java.util.List; import java.util.UUID; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.pm.PackageManager; public class MainActivity extends Activity {private BluetoothAdapter mBluetoothAdapter;private Handler mHandler=new Handler();private boolean mScanning;private BluetoothGatt mGatt;private BluetoothGattCharacteristic mGattCharacteristic;private ListView mlv;//自定義列表listviewprivate BleAdapter mBleAdapter;//自定義適配器adapterprivate ArrayList<BluetoothDevice> mArray=new ArrayList<BluetoothDevice>();//自定義容器private EditText mEdit;//自定義edittext@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initUI();initBLE();}@Overrideprotected void onDestroy() {if(mGatt!=null){mGatt.close();mGatt=null;}super.onDestroy();}//初始化自定義控件private void initUI(){findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(mGatt!=null){mGatt.close();mGatt=null;}scanLe(true);}});mlv = (ListView) findViewById(R.id.listView1);mBleAdapter = new BleAdapter(MainActivity.this,mArray);mlv.setAdapter(mBleAdapter);mlv.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {if(mGatt==null){mGatt = mArray.get(position).connectGatt(MainActivity.this, false, mGattCallback);}else{mGatt.connect(); }new AlertDialog.Builder(MainActivity.this).setTitle("請輸入內容").setView(mEdit=new EditText(MainActivity.this)).setPositiveButton("確定", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {mGattCharacteristic.setValue(mEdit.getText().toString().trim());mGatt.writeCharacteristic(mGattCharacteristic);}}).show();}});}//初始化藍牙4.0private void initBLE() {//如果不支持BLE則退出程序if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {Toast.makeText(this,"不支持低功耗藍牙", Toast.LENGTH_SHORT).show();finish();}//獲取藍牙適配器打開藍牙m(xù)BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (mBluetoothAdapter!=null&&!mBluetoothAdapter.isEnabled()) {mBluetoothAdapter.enable();//自動打開藍牙}}//開始掃描BLEprivate void scanLe(boolean enable) {if (enable) {if (mBluetoothAdapter.isEnabled()) {if (mScanning){return;}mArray.clear();mScanning = true;mHandler.postDelayed(mScanRunnable, 5000);//5秒后關閉掃描mBluetoothAdapter.startLeScan(mLeScanCallback);} else {Toast.makeText(this,"藍牙檢測中", Toast.LENGTH_SHORT).show();}} else {mBluetoothAdapter.stopLeScan(mLeScanCallback);mHandler.removeCallbacks(mScanRunnable);mScanning = false;}}//停止掃描BLEprivate final Runnable mScanRunnable = new Runnable() {@Overridepublic void run() {scanLe(false);}};//掃描結果private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {/**@param device:識別的遠程設備* @param rssi: 信號值為遠程藍牙設備的報告,0代表沒有藍牙設備* @param scanRecord:遠程設備提供的配對號*/@Overridepublic void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {MainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {//保存到本地:用來展示掃描得到的內容if(!mArray.contains(device)){Log.e("onLeScan","===設備"+device.getName()+"="+device.getAddress()+"="+rssi);mArray.add(device);mBleAdapter.notifyDataSetChanged();}}});}};//通知public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled){mGatt.setCharacteristicNotification(characteristic, enabled);BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));if (enabled){clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);}else{clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);}mGatt.writeDescriptor(clientConfig);}//數(shù)據(jù)通訊監(jiān)聽private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) {if (newState == BluetoothProfile.STATE_CONNECTED) {//啟動服務狀態(tài)Log.e("======", "===開始啟動服務:" + gatt.discoverServices());}};public void onServicesDiscovered(final BluetoothGatt gatt, int status) {if (status == BluetoothGatt.GATT_SUCCESS){//發(fā)現(xiàn)服務狀態(tài)Log.e("======", "===發(fā)現(xiàn)服務");List<BluetoothGattService> services = mGatt.getServices();for(final BluetoothGattService gattService:services) {List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();for (final BluetoothGattCharacteristic gattCharacteristic : characteristics) {if (gattCharacteristic.getUuid().toString().equals("0000ffe1-0000-1000-8000-00805f9b34fb")){mGattCharacteristic=gattCharacteristic;mHandler.postDelayed(new Runnable(){@Overridepublic void run(){gatt.readCharacteristic(gattCharacteristic);}}, 200);setCharacteristicNotification(gattCharacteristic,true);List<BluetoothGattDescriptor> descriptors = gattCharacteristic.getDescriptors();for (BluetoothGattDescriptor descriptor : descriptors){gatt.readDescriptor(descriptor);}}}}}};public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {if (status == BluetoothGatt.GATT_SUCCESS) {//寫入狀態(tài)Log.e("======", "===寫入" +new String(characteristic.getValue()));}};public void onCharacteristicRead(BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic,int status) {if (status == BluetoothGatt.GATT_SUCCESS) {//讀取狀態(tài)Log.e("======","===讀取" +new String(characteristic.getValue()));}}public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {Log.e("======", "===獲取數(shù)據(jù)" +new String(characteristic.getValue()));//獲取數(shù)據(jù)};};} /*** 藍牙限制20字節(jié)需將數(shù)據(jù)分包* **/public int[] dataSeparate(int len){ int[] lens = new int[2];lens[0]=len/20;lens[1]=len-20*lens[0];return lens;}/* * 發(fā)送按鍵的響應事件,主要發(fā)送文本框的數(shù)據(jù)*/@Overridepublic void onClick(View v){// TODO Auto-generated method stubbyte[] buff = send_et.getText().toString().getBytes();int len = buff.length;int[] lens = dataSeparate(len);for(int i =0;i<lens[0];i++){String str = new String(buff, 20*i, 20);mGattCharacteristic.setValue(str);//只能一次發(fā)送20字節(jié),所以這里要分包發(fā)送//調用藍牙服務的寫特征值方法實現(xiàn)發(fā)送數(shù)據(jù)mBluetoothLeService.writeCharacteristic(mGattCharacteristic);}if(lens[1]!=0){String str = new String(buff, 20*lens[0], lens[1]);mGattCharacteristic.setValue(str);//調用藍牙服務的寫特征值方法實現(xiàn)發(fā)送數(shù)據(jù)mBluetoothLeService.writeCharacteristic(mGattCharacteristic);}}傳統(tǒng)藍牙:
1.打開藍牙設備BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.cancelDiscovery(); IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); ? filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); registerReceiver(mReceiver, filter); mBluetoothAdapter.startDiscovery();//搜索附近藍牙private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction(); ?if (BluetoothDevice.ACTION_FOUND.equals(action)){//找到設備時 通過EXTRA_DEVICE附加域來得到一個BluetoothDevice設備 ?BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//信號強度 ?int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);?}else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){//藍牙配對或取消配對時的狀態(tài)}??} }; device.connectGatt(act, false, new BluetoothGattCallback() {public void onConnectionStateChange(android.bluetooth.BluetoothGatt gatt, int status, int newState) {if(status == 0&&newState == 2) {gatt.discoverServices();//搜索藍牙周圍服務}else{//"搜索失敗"}};public void onServicesDiscovered(android.bluetooth.BluetoothGatt gatt, int status) {if(status == BluetoothGatt.GATT_SUCCESS){Iterator var4 = gatt.getServices().iterator();while(var4.hasNext()) {BluetoothGattService var3;BluetoothGattCharacteristic var5;BluetoothGattService next = (BluetoothGattService)var4.next();if((var3 = next).getUuid().equals(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb"))?&& (var5 = var3.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb"))) != null) {gatt.readCharacteristic(var5);//"獲取電量中…"}}}};public void onCharacteristicRead(final android.bluetooth.BluetoothGatt gatt, final android.bluetooth.BluetoothGattCharacteristic characteristic, final in t status) {act.runOnUiThread(new Runnable() {@Overridepublic void run() {if(characteristic!=null&&status == BluetoothGatt.GATT_SUCCESS){//characteristic.getIntValue(17, 0)+"%電量"gatt.close();}}});}; } ); /**?* 根據(jù)Rssi獲得返回的距離,返回數(shù)據(jù)單位為m?* @param rssi?* @return?*/ ? public static double getDistance(int rssi){ ?int iRssi = Math.abs(rssi); ?double power = (iRssi-A_Value)/(10*n_Value); //A_Value=59發(fā)射端和接收端相隔1米時的信號強度,n_Value=2.0環(huán)境衰減因子return Math.pow(10,power); ? }2.藍牙連接有兩種方式,可直接配對
String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB"; UUID uuid = UUID.fromString(SPP_UUID); mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter(); mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress); BluetoothSocket socket= mBluetoothDevice.createRfcommSocketToServiceRecord(uuid);//UUID連接!服務端為listenUsingRfcommWithServiceRecord("name",uuid) mBluetoothAdapter.cancelDiscovery(); socket.connect(); mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter(); mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress); Method m = mBluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class }); BluetoothSocket socket = (BluetoothSocket) m.invoke(mBluetoothDevice, 1);//1-30端口連接! mBluetoothAdapter.cancelDiscovery(); socket.connect(); Method method = mBluetoothDevice.getClass().getMethod("createBond");//配對createBond/取消配對removeBond Boolean returnValue = (Boolean) method.invoke(mBluetoothDevice);3.藍牙數(shù)據(jù)傳輸getInputStream getOutputStream
os = accept.getOutputStream();//輸出流 os.write("連接成功success".getBytes()); is = socket.getInputStream();//輸入流 ? byte[] buffer=new byte[512]; int len=0; ByteArrayBuffer bab = new ByteArrayBuffer(len); while(-1!=(len=is.read(buffer))){ bab.append(buffer, 0, len); } String string = new String(bab.toByteArray(),"utf-8");注意:BluetoothSocket的等耗時操作需要另外開啟線程再進行!!!
總結
- 上一篇: dbm与mysql区别_dbm数据库
- 下一篇: 详细讲解修改allure报告自定义的lo