Androidble4.0藍芽開發相容2.0藍芽應用(針對arduino藍芽控制小車開發應用HC-08,06藍芽模組的連線)
阿新 • • 發佈:2019-01-31
1.嗯有段時間沒更新部落格啦,給廣大CSDN友上點幹活
2.android藍芽即智慧穿戴裝置火起來之後藍芽的普及也是有點猛,今天我們部落格的主題就是圍繞arduino開發藍芽控制小車寫的測試demo,連線的藍芽模組是HC-08,06型號,所以出廠的硬體UUID是廠商提供的,增對該demo用的範圍也是有限的,當前藍芽的開發功能和庫的使用基本都是一樣的,不一樣的只是硬體藍芽模組的UUID,假如想做智慧手環什麼的換成手環的藍芽UUID就可以用,嗯,就是這麼簡單
3.下面先上個gif圖爽爽看看效果先,本人基本都是先看效果再決定是否下載該demo
由於我的網路不是很好用的遠端投屏至電腦才錄製的gif所以看起來搜尋藍芽有點卡,實際效果是不卡的,中間出現的警告框是樓主的手機後臺記憶體只有600+M所以有一個實時監測手機記憶體的,防止記憶體不足demo崩了,嗯,個人感覺還是不錯的
4.下面上主要程式碼截圖:MainActivity
package com.example.androidbluetooch; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import com.baoyz.swipemenulistview.SwipeMenu; import com.baoyz.swipemenulistview.SwipeMenuCreator; import com.baoyz.swipemenulistview.SwipeMenuItem; import com.baoyz.swipemenulistview.SwipeMenuListView; import com.baoyz.swipemenulistview.SwipeMenuListView.OnMenuItemClickListener; import android.app.Activity; import android.app.ActivityManager; import android.app.Dialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class MainActivity extends Activity implements OnClickListener, OnItemClickListener { protected static final String TAG = "MainActivity"; // 掃描、斷開、傳送藍芽button private Button btn_scan_device, btn_disconnect, btn_send; // 未配對藍芽的listview private ListView lv_disconnect, listview_msgxianshi; // 已配對藍芽的listview,自定義的listview帶滑動刪除 private SwipeMenuListView lv_connect; // 輸入資料的edittext private EditText ed_inout; private int REQUEST_ENABLE_BT = 1; private List<String> list = new ArrayList<String>(); private ConnectThread mConnectThread; public ConnectedThread mConnectedThread; private Dialog progressDialog; private TextView msg; // 藍芽介面卡 private BluetoothAdapter mBluetoothAdapter; // 已經配對的藍芽ArrayList private ArrayList<BluetoothDevice> data_connect = new ArrayList<BluetoothDevice>(); // 未配對的藍芽ArrayList private ArrayList<BluetoothDevice> data_disconnect = new ArrayList<BluetoothDevice>(); // 自定義的adapater,已經配對的藍芽,未配對的藍芽 private LeDeviceListAdapter connectListAdapter, disconnectListAdapter; // HC-08藍芽連線狀態 private boolean mConnected = false; // HC-06藍芽連線狀態 private boolean mhc06Connected = false; // 連線成功的藍芽名字 private String connect_string; // 未配對的HC-06,08點選的標記位 private int data_onitemclick, datahc06_onitemclick; // HC-06:判斷是已經配對的藍芽還是未配對的藍芽,斷開連線的檢視更新 private boolean disconnect_flag = false; // HC-08藍芽地址 private String mDeviceAddress; // 藍芽裝置 private BluetoothDevice dataconnectBean; // 藍芽service,負責後臺的藍芽服務 private static BluetoothLeService mBluetoothLeService; // 藍芽的連線狀態 private String status = "disconnected"; // 藍芽特徵值 private static BluetoothGattCharacteristic target_chara = null; private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); // 藍芽4.0的UUID,其中0000ffe1-0000-1000-8000-00805f9b34fb是廣州匯承資訊科技有限公司08藍芽模組的UUID public static String HEART_RATE_MEASUREMENT = "0000ffe1-0000-1000-8000-00805f9b34fb"; // HC-06藍芽UUID private static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB"; private List<Integer> mBuffer = new ArrayList<Integer>(); private List<ChatMsgEntity> mDataArrays = new ArrayList<ChatMsgEntity>(); private ChatMsgViewAdapter mAdapter; private SelfDialog selfDialog; private Handler mhandler = new Handler(); private Handler myHandler = new Handler() { // 2.重寫訊息處理函式 public void handleMessage(Message msg) { switch (msg.what) { // 判斷髮送的訊息 case 1: { // 更新View if (mConnected == true) { String state = msg.getData().getString("connect_state"); setTitle(connect_string + ":" + state); } else { String state = msg.getData().getString("connect_state"); setTitle(state); } break; } case 2: { // 更新View if (mhc06Connected == true) { String state = msg.getData().getString("connect_state"); setTitle(connect_string + ":" + state); data_connect.add(data_disconnect.get(datahc06_onitemclick)); data_disconnect.remove(datahc06_onitemclick); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); disconnectListAdapter.notifyDataSetChanged(); connectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_connect); // 為listview指定介面卡 lv_connect.setAdapter(connectListAdapter); connectListAdapter.notifyDataSetChanged(); } else { String state = msg.getData().getString("connect_state"); setTitle(state); } break; } case 3: { // 更新View if (mhc06Connected == true) { String state = msg.getData().getString("connect_state"); setTitle(connect_string + ":" + state); } else { String state = msg.getData().getString("connect_state"); setTitle(state); } break; } case 4: { String state = msg.getData().getString("updata_msg"); listview_msg_stringReceiver(new String(state)); break; } } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_scan_device = (Button) findViewById(R.id.btn_scandevice); btn_disconnect = (Button) findViewById(R.id.btn_disconnectdevice); ed_inout = (EditText) findViewById(R.id.ed_inout); btn_send = (Button) findViewById(R.id.btn_send); lv_connect = (SwipeMenuListView) findViewById(R.id.lv_connect); lv_disconnect = (ListView) findViewById(R.id.lv_disconnect); listview_msgxianshi = (ListView) findViewById(R.id.listView1); btn_scan_device.setOnClickListener(this); btn_disconnect.setOnClickListener(this); btn_send.setOnClickListener(this); lv_disconnect.setOnItemClickListener(this); lv_connect.setOnItemClickListener(this); // mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // 開啟藍芽許可權 if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { // DeviceBean bean = new DeviceBean(); // bean.setAddress(device.getAddress()); // bean.setName(device.getName()); data_connect.add(device); // unpairDevice(device); } } else { Toast.makeText(MainActivity.this, "沒有已配對的裝置", Toast.LENGTH_SHORT).show(); } 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); if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { msgDialog("您的手機系統低於4.3,不支援ble4.0藍芽"); } else { msgDialog("您的手機系統高於4.3,支援ble4.0藍芽"); } connectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_connect); // 為listview指定介面卡 lv_connect.setAdapter(connectListAdapter); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); /* 啟動藍芽service */ Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); // 繫結廣播接收器 registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); progressDialog = new Dialog(MainActivity.this, R.style.progress_dialog); progressDialog.setContentView(R.layout.dialog); progressDialog.setCancelable(true); progressDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); msg = (TextView) progressDialog.findViewById(R.id.id_tv_loadingmsg); progressDialog.setCanceledOnTouchOutside(false); SwipeMenuCreator creator = new SwipeMenuCreator() { @Override public void create(SwipeMenu menu) { // create "open" item SwipeMenuItem openItem = new SwipeMenuItem(getApplicationContext()); // set item background openItem.setBackground(new ColorDrawable(Color.rgb(0xC9, 0xC9, 0xCE))); // set item width openItem.setWidth(dp2px(90)); // set item title openItem.setTitle("取消配對"); // set item title fontsize openItem.setTitleSize(14); // set item title font color openItem.setTitleColor(Color.WHITE); // add to menu menu.addMenuItem(openItem); } }; // set creator lv_connect.setMenuCreator(creator); // step 2. listener item click event lv_connect.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public void onMenuItemClick(int position, SwipeMenu menu, int index) { if (data_connect.get(position).getName().equals("HC-06")) { if_or_notPair(); unpairDevice(data_connect.get(position)); data_connect.remove(position); connectListAdapter.notifyDataSetChanged(); } else { Toast.makeText(MainActivity.this, "HC-06支援取消配對,別的藍芽裝置無法消配對", Toast.LENGTH_SHORT).show(); } } }); mAdapter = new ChatMsgViewAdapter(getApplicationContext(), mDataArrays); listview_msgxianshi.setAdapter(mAdapter); listview_msgxianshi.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow( getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); return false; } }); } // 取消已經配對的藍芽(HC-06) private void unpairDevice(BluetoothDevice device) { try { Method m = device.getClass().getMethod("removeBond", (Class[]) null); m.invoke(device, (Object[]) null); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } private void msgDialog(String string) { selfDialog = new SelfDialog(MainActivity.this); selfDialog.setTitle("提示"); selfDialog.setMessage(string); selfDialog.setYesOnclickListener("確定", new SelfDialog.onYesOnclickListener() { @Override public void onYesClick() { // Toast.makeText(MainActivity.this,"點選了--確定--按鈕",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); selfDialog.setNoOnclickListener("取消", new SelfDialog.onNoOnclickListener() { @Override public void onNoClick() { // Toast.makeText(MainActivity.this,"點選了--取消--按鈕",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); selfDialog.show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_scandevice: btn_scan_device.setEnabled(false); msg.setText("賣力載入中"); progressDialog.show(); doDiscovery(); break; case R.id.btn_disconnectdevice: if (mConnected == true) { mBluetoothLeService.disconnect(); for (int i = 0; i < data_connect.size(); i++) { if (data_connect.get(i).equals(dataconnectBean)) { data_disconnect.add(data_connect.get(i)); data_connect.remove(i); } } connectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_connect); // 為listview指定介面卡 lv_connect.setAdapter(connectListAdapter); connectListAdapter.notifyDataSetChanged(); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); disconnectListAdapter.notifyDataSetChanged(); } if_or_notPair(); break; case R.id.btn_send: if (mConnected == false) { } else { if (ed_inout.getText().toString().equals("")) { Log.d(TAG, "111111"); } else { if(isServiceRunning(getApplicationContext(), "com.example.androidbluetooch.BluetoothLeService")==true){ // Toast.makeText(getApplicationContext(), "存在", Toast.LENGTH_SHORT).show(); if(target_chara==null){ }else{ Log.d(TAG, "222222"); target_chara.setValue(ed_inout.getText().toString()); // 呼叫藍芽服務的寫特徵值方法實現傳送資料 mBluetoothLeService.writeCharacteristic(target_chara); listview_msg_stringSend(); } }else{ msgDialog("運行當前所需的服務沒有起來,請至應用管理釋放點記憶體,以保證當前APP所需的執行記憶體"); } } } if (mhc06Connected == true) { if (ed_inout != null && !"".equals(ed_inout)) { try { mConnectedThread.write(ed_inout.getText().toString().getBytes()); listview_msg_stringSend(); } catch (Exception e) { } } } if(mConnected==false||mhc06Connected==false){ listview_msg_stringSend(); } ed_inout.setText(""); break; default: break; } } private String getDate() { Calendar c = Calendar.getInstance(); String year = String.valueOf(c.get(Calendar.YEAR)); String month = String.valueOf(c.get(Calendar.MONTH)+ 1); String day = String.valueOf(c.get(Calendar.DAY_OF_MONTH)); String hour = String.valueOf(c.get(Calendar.HOUR_OF_DAY)); String mins = String.valueOf(c.get(Calendar.MINUTE)); StringBuffer sbBuffer = new StringBuffer(); sbBuffer.append(year + "-" + month + "-" + day + " " + hour + ":" + mins); return sbBuffer.toString(); } private void listview_msg_stringSend() { /** * 傳送訊息跟新View */ ChatMsgEntity entity = new ChatMsgEntity(); entity.setDate(getDate()); entity.setName("user"); entity.setMsgType(false); entity.setText(ed_inout.getText().toString()); mDataArrays.add(entity); mAdapter.notifyDataSetChanged(); ed_inout.setText(""); listview_msgxianshi.setSelection(listview_msgxianshi.getCount() - 1); } private void listview_msg_stringReceiver(String string) { /** * 接收訊息跟新View */ ChatMsgEntity entity = new ChatMsgEntity(); entity.setDate(getDate()); entity.setName("裝置"); entity.setMsgType(true); entity.setText(string); mDataArrays.add(entity); mAdapter.notifyDataSetChanged(); listview_msgxianshi.setSelection(listview_msgxianshi.getCount() - 1); } private void if_or_notPair() { if (disconnect_flag == true) { if (mhc06Connected == true) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } mhc06Connected = false; status = "disconnected"; // 更新連線狀態 Message msg1 = new Message(); msg1.what = 3; Bundle b = new Bundle(); b.putString("connect_state", status); msg1.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg1); } } else { if (mhc06Connected == true) { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } mhc06Connected = false; status = "disconnected"; // 更新連線狀態 Message msg2 = new Message(); msg2.what = 2; Bundle b = new Bundle(); b.putString("connect_state", status); msg2.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg2); } } } // 搜尋藍芽 private void doDiscovery() { setTitle(R.string.scanning); if (mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.cancelDiscovery(); } mBluetoothAdapter.startDiscovery(); } // 搜尋藍芽的廣播 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() + "\n" + // device.getAddress()); if (list.indexOf(device.getAddress().toString()) == -1) { Map<String, Object> listem = new HashMap<String, Object>(); listem.put("dName", device.getName()); listem.put("dAddress", device.getAddress().toString()); Log.d("searchBtDevices==", list.toString()); list.add(device.getAddress()); Log.d("searchBtDevices==", list.toString()); Log.d("Devices==", device.getAddress()); Log.d("==", "not"); // DeviceBean bean = new DeviceBean(); // bean.setAddress(device.getAddress()); // bean.setName(device.getName()); data_disconnect.add(device); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); disconnectListAdapter.notifyDataSetChanged(); } else { Log.d("==", "have"); } } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { btn_scan_device.setEnabled(true); progressDialog.dismiss(); setTitle(R.string.select_device); } } }; /* BluetoothLeService繫結的回撥函式 */ private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (!mBluetoothLeService.initialize()) { Log.e("MainActivity.this", "Unable to initialize Bluetooth"); finish(); } // Automatically connects to the device upon successful start-up // initialization. // 根據藍芽地址,連線裝置 // 每次連線之前關閉上一次連線,這樣在第二次連線藍芽的時候速度快 // 部落格參考http://bbs.eeworld.com.cn/thread-438571-1-1.html mBluetoothLeService.close(); mBluetoothLeService.connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } }; /** * 廣播接收器,負責接收BluetoothLeService類傳送的資料 */ private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))// Gatt連線成功 { progressDialog.dismiss(); mConnected = true; status = "connected"; // 更新連線狀態 updateConnectionState(status); System.out.println("BroadcastReceiver :" + "device connected"); data_connect.add(data_disconnect.get(data_onitemclick)); data_disconnect.remove(data_onitemclick); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); disconnectListAdapter.notifyDataSetChanged(); connectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_connect); // 為listview指定介面卡 lv_connect.setAdapter(connectListAdapter); connectListAdapter.notifyDataSetChanged(); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED// Gatt連線失敗 .equals(action)) { progressDialog.dismiss(); mConnected = false; status = "disconnected"; // 更新連線狀態 updateConnectionState(status); System.out.println("BroadcastReceiver :" + "device disconnected"); for (int i = 0; i < data_connect.size(); i++) { if (data_connect.get(i).equals(dataconnectBean)) { data_disconnect.add(data_connect.get(i)); data_connect.remove(i); } } connectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_connect); // 為listview指定介面卡 lv_connect.setAdapter(connectListAdapter); connectListAdapter.notifyDataSetChanged(); disconnectListAdapter = new LeDeviceListAdapter(MainActivity.this, data_disconnect); // 為listview指定介面卡 lv_disconnect.setAdapter(disconnectListAdapter); disconnectListAdapter.notifyDataSetChanged(); } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED// 發現GATT伺服器 .equals(action)) { // Show all the supported services and characteristics on the // user interface. // 獲取裝置的所有藍芽服務 displayGattServices(mBluetoothLeService.getSupportedGattServices()); System.out.println("BroadcastReceiver :" + "device SERVICES_DISCOVERED"); } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {// 有效資料 // 處理髮送過來的資料 Log.d(TAG, intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); listview_msg_stringReceiver(intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); } } }; /* 更新連線狀態 */ private void updateConnectionState(String status) { Message msg = new Message(); msg.what = 1; Bundle b = new Bundle(); b.putString("connect_state", status); msg.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg); System.out.println("connect_state:" + status); } /** * @Title: displayGattServices @Description: TODO(處理藍芽服務) @param 無 @return * void @throws */ private void displayGattServices(List<BluetoothGattService> gattServices) { if (gattServices == null) return; String uuid = null; // 服務資料,可擴充套件下拉列表的第一級資料 ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>(); // 特徵資料(隸屬於某一級服務下面的特徵值集合) ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>(); // 部分層次,所有特徵值集合 mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); // Loops through available GATT Services. for (BluetoothGattService gattService : gattServices) { // 獲取服務列表 HashMap<String, String> currentServiceData = new HashMap<String, String>(); uuid = gattService.getUuid().toString(); // 查表,根據該uuid獲取對應的服務名稱。SampleGattAttributes這個表需要自定義。 gattServiceData.add(currentServiceData); System.out.println("Service uuid:" + uuid); ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>(); // 從當前迴圈所指向的服務中讀取特徵值列表 List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>(); // Loops through available Characteristics. // 對於當前迴圈所指向的服務中的每一個特徵值 for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { charas.add(gattCharacteristic); HashMap<String, String> currentCharaData = new HashMap<String, String>(); uuid = gattCharacteristic.getUuid().toString(); if (gattCharacteristic.getUuid().toString().equals(HEART_RATE_MEASUREMENT)) { // 測試讀取當前Characteristic資料,會觸發mOnDataAvailable.onCharacteristicRead() mhandler.postDelayed(new Runnable() { @Override public void run() { mBluetoothLeService.readCharacteristic(gattCharacteristic); } }, 200); // 接受Characteristic被寫的通知,收到藍芽模組的資料後會觸發mOnDataAvailable.onCharacteristicWrite() mBluetoothLeService.setCharacteristicNotification(gattCharacteristic, true); target_chara = gattCharacteristic; // 設定資料內容 // 往藍芽模組寫入資料 // mBluetoothLeService.writeCharacteristic(gattCharacteristic); } List<BluetoothGattDescriptor> descriptors = gattCharacteristic.getDescriptors(); for (BluetoothGattDescriptor descriptor : descriptors) { System.out.println("---descriptor UUID:" + descriptor.getUuid()); // 獲取特徵值的描述 mBluetoothLeService.getCharacteristicDescriptor(descriptor); // mBluetoothLeService.setCharacteristicNotification(gattCharacteristic, // true); } gattCharacteristicGroupData.add(currentCharaData); } // 按先後順序,分層次放入特徵值集合中,只有特徵值 mGattCharacteristics.add(charas); // 構件第二級擴充套件列表(服務下面的特徵值) gattCharacteristicData.add(gattCharacteristicGroupData); } } /* 意圖過濾器 */ private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); return intentFilter; } // HC-06藍芽的連線方法 public void connect(BluetoothDevice device) { Log.d(TAG, "connect to: " + device); // Start the thread to connect with the given device mConnectThread = new ConnectThread(device); mConnectThread.start(); } /** * This thread runs while attempting to make an outgoing connection with a * device. It runs straight through; the connection either succeeds or * fails. */ // HC-06藍芽的連線方法 private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; public ConnectThread(BluetoothDevice device) { BluetoothSocket tmp = null; // Get a BluetoothSocket for a connection with the // given BluetoothDevice try { tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID)); } catch (IOException e) { Log.e(TAG, "create() failed", e); } mmSocket = tmp; } public void run() { Log.i(TAG, "BEGIN mConnectThread"); setName("ConnectThread"); // Always cancel discovery because it will slow down a connection mBluetoothAdapter.cancelDiscovery(); // Make a connection to the BluetoothSocket try { // This is a blocking call and will only return on a // successful connection or an exception mmSocket.connect(); } catch (IOException e) { progressDialog.dismiss(); Log.e(TAG, "unable to connect() socket", e); // Close the socket try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() socket during connection failure", e2); } return; } mConnectThread = null; progressDialog.dismiss(); if (disconnect_flag == true) { mhc06Connected = true; status = "connected"; // 更新連線狀態 Message msg = new Message(); msg.what = 3; Bundle b = new Bundle(); b.putString("connect_state", status); msg.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg); } else { mhc06Connected = true; status = "connected"; // 更新連線狀態 Message msg = new Message(); msg.what = 2; Bundle b = new Bundle(); b.putString("connect_state", status); msg.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg); } // Start the connected thread // Start the thread to manage the connection and perform // transmissions mConnectedThread = new ConnectedThread(mmSocket); mConnectedThread.start(); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } /** * This thread runs during a connection with a remote device. It handles all * incoming and outgoing transmissions. */ // HC-06藍芽的連線方法 private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[256]; int bytes; // Keep listening to the InputStream while connected while (true) { try { // //HC-06藍芽的讀資料方法 bytes = mmInStream.read(buffer); Log.d(TAG, "" + new String(buffer)); Message msg1 = new Message(); msg1.what = 4; Bundle b = new Bundle(); b.putString("updata_msg", new String(buffer)); msg1.setData(b); // 將連線狀態更新的UI的textview上 myHandler.sendMessage(msg1); synchronized (mBuffer) { for (int i = 0; i < bytes; i++) { mBuffer.add(buffer[i] & 0xFF); } } // mHandler.sendEmptyMessage(MSG_NEW_DATA); } catch (IOException e) { Log.e(TAG, "disconnected", e); break; } } } /** * Write to the connected OutStream. * * @param buffer * The bytes to write */ // HC-06藍芽的寫資料方法 public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { switch (arg0.getId()) { // 已經配對的藍芽點選事件 case R.id.lv_connect: if (mConnected == true || mhc06Connected == true) { Toast.makeText(MainActivity.this, "請先斷開當前連線", Toast.LENGTH_SHORT).show(); } else { if (data_connect.get(position).getName().equals("HC-06")) { msg.setText("連線藍芽中"); progressDialog.show(); BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(data_connect.get(position).getAddress()); // Attempt to connect to the device connect(device); connect_string = data_connect.get(position).getName(); datahc06_onitemclick = position; disconnect_flag = true; } else { Toast.makeText(getApplicationContext(), "該功能只支援連線HC-06,08藍芽模組", Toast.LENGTH_SHORT).show(); } } break; // 未配對的藍芽點選事件 case R.id.lv_disconnect: if (mConnected == true || mhc06Connected == true) { Toast.makeText(MainActivity.this, "請先斷開當前連線", Toast.LENGTH_SHORT).show(); } else { if (data_disconnect.get(position).getName().equals("HC-08")) { msg.setText("連線藍芽中"); progressDialog.show(); data_onitemclick = position; dataconnectBean = data_disconnect.get(position); mDeviceAddress = data_disconnect.get(position).getAddress(); Log.d(TAG, "111" + data_disconnect.get(position).getAddress()); if (mBluetoothLeService != null) { // 每次連線之前關閉上一次連線,這樣在第二次連線藍芽的時候速度快 // 部落格參考http://bbs.eeworld.com.cn/thread-438571-1-1.html mBluetoothLeService.close(); final boolean result = mBluetoothLeService.connect(mDeviceAddress); connect_string = data_disconnect.get(position).getName(); Log.d(TAG, "Connect request result=" + result); } } else if (data_disconnect.get(position).getName().equals("HC-06")) { msg.setText("連線藍芽中"); progressDialog.show(); BluetoothDevice device = mBluetoothAdapter .getRemoteDevice(data_disconnect.get(position).getAddress()); // Attempt to connect to the device connect(device); connect_string = data_disconnect.get(position).getName(); datahc06_onitemclick = position; } else { Toast.makeText(getApplicationContext(), "該功能只支援連線HC-06,08藍芽模組", Toast.LENGTH_SHORT).show(); } } break; default: break; } } //判斷com.hf.tabhost.BluetoothLeService是否被系統殺死 public static boolean isServiceRunning(Context mContext, String className) { boolean isRunning = false; ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(30); if (!(serviceList.size() > 0)) { return false; } for (int i = 0; i < serviceList.size(); i++) { if (serviceList.get(i).service.getClassName().equals(className) == true) { isRunning = true; break; } } return isRunning; } @Override protected void onDestroy() { super.onDestroy(); // Make sure we're not doing discovery anymore if (mBluetoothAdapter != null) { mBluetoothAdapter.cancelDiscovery(); } // Unregister broadcast listeners this.unregisterReceiver(mReceiver); // 解除廣播接收器 unregisterReceiver(mGattUpdateReceiver); mBluetoothLeService = null; } }
5.程式碼下載地址:CSDN:http://download.csdn.net/download/qq_31546677/10151400
CSDN上傳下載分不能為0了所以我選擇了最少的2分,資源分不多的可以去我github下載,喜歡的可以點個star哦,謝謝了!
6.還有一個樓主寫了一個專門用於arduino控制藍芽小車的APP喜歡的和需要的可以去應用寶下載下來爽爽哦,個人感覺比SPP功能強太多哦,歡迎下載,搜尋HFEasyControl!
6.插播幾張APP的截圖給大家爽爽