1. 程式人生 > >App 和裝置通過藍芽連線收發資料

App 和裝置通過藍芽連線收發資料

一、Android 中進行藍芽開發需要用到的類和執行過程

        1,使用BluetoothAdapter.startLeScance來掃描裝置

     2,在掃描到裝置的回撥函式中的得到BluetoothDevice 物件,並使用Bluetooth.stopLeScan停止掃描

     3,使用BluetoothDevice.connectGatt來獲取到BluetoothGatt物件

     4,執行BluetoothGatt.discoverServices,這個方法是非同步操作,在回撥函式onServicesDiscovered中得到status,通過判斷status是否等於BluetoothGatt.GATT_SUCCESS來            判斷查詢Service是否成功

     5,如果成功了,則通過BluetoothGatt.getService來獲取BluetoothGattService

     6,接著通過BluetoothGattService.getCharacteristic獲取BluetoothGattCharacteristic

     7,然後通過BluetoothGattCharacteristic.getDescriptor獲取BluetoothGattDescriptor

二、收發資料

      收發資料是通過GATT,GATT是通過藍芽收發資料的一種協議,包含Characteristic,Descriptor,Service 三個屬性值,BLE 分為三個部分Service , Characteristic ,Descriptor  這三個部分都是由UUID做為唯一的識別符號,一個藍芽終端可以包含多個Service ,一個Service 可以包含多個Characteristic ,一個Characteristic 包含一個Value 和多個Descriptor,一個Descriptor包含一個Value

三、上程式碼(有些工具類是在其他檔案裡面,我這裡沒有在改了,直接複製上來了)

MainActivice.java:

BluetoothManager bluetoothManager;
BluetoothAdapter mBluetoothAdapter;
Intent intentBluetoothLeService = new Intent();
//低功耗藍芽的檔名
public static String BLUETOOTHSERVICE = "com.boe.navapp.remote.BluetoothLeService";

bluetoothManager = (BluetoothManager) MainActivity.this
.getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { if (!(CommonUtil.isServiceRunning(MainActivity.this, Constants.BLUETOOTHSERVICE))) { intentBluetoothLeService = new Intent(MainActivity.this, BluetoothLeService.class); startService(intentBluetoothLeService); } }
// 判斷當前服務是否啟動
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(70);
    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;
}


BluetoothLeService.java:(這裡我講下主要程式碼,檔案我會傳上去)

public final static String REMOTE_CONNECT_STATUS = "REMOTE_CONNECT_STATUS";// 當前選擇的遙控器連線狀態
public final static String REMOTE_CONNECTED_DEVICES = "REMOTECONNECTEDDEVICES";// 儲存已經連線的裝置列表
public final static String REMOTE_DEVICE_INFO = "REMOTEDEVICEINFO";
public final static String REMOTE_CURR_ADDR = "REMOTECURRADDR";// 當前連線裝置的地址
public final static String ACTION_GATT_REMOTESEVEN_DISCONNECTED = "com.infisight.hudprojector.bluetooth.le.ACTION_GATT_REMOTESEVEN_DISCONNECTED";
private static final String SP_NAME = "address";
@Override
public void onCreate() {
    super.onCreate();
    LogTools.i(TAG, "BluetoothLeService onCreate");
    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    telMgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    prefs.edit().putBoolean(Constants.REMOTE_CONNECT_STATUS, false)
            .commit();
    LogTools.i(TAG, "BluetoothLeService before SaveUtils.loadArray");
    addressList = SaveUtils.loadArray(this, SP_NAME);  //存放連線的地址
GetDeviceInfo();
    LogTools.i(TAG, "BluetoothLeService GetDeviceInfo");
}

/**
 * 獲取裝置資訊 lstNeedConnectDevices
 */
private void GetDeviceInfo() {
    String connectedinfo = prefs.getString(
            Constants.REMOTE_CONNECTED_DEVICES, "");
    if (!connectedinfo.equals("")) {
        Gson gson = new Gson();
        try {
            lstNeedConnectDevices = gson.fromJson(connectedinfo,
                    new TypeToken<List<BleConnectDevice>>() {
                    }.getType());
            for (BleConnectDevice bleconnectdevice : lstNeedConnectDevices) {
                if (!lstNeedConnectAddress.contains(bleconnectdevice
                        .getAddress()))
                    lstNeedConnectAddress
.add(bleconnectdevice.getAddress());
            }
        } catch (Exception e) {
        }
    }
}

public boolean initialize() {
    // 獲取藍芽管理
if (mBluetoothManager == null) {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            return false;
        }
    }
    // 獲取介面卡
mBluetoothAdapter = mBluetoothManager.getAdapter();
    return mBluetoothAdapter != null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    LogTools.d(TAG, "onStartCommand:flags=" + flags + ",startId=" + startId);
    if (mBluetoothManager == null) {
        if (!initialize()) {
            LogTools.i(TAG, "Unable to initialize Bluetooth");
        }
    }
    if (isFirstRun) {
        try {
            handler.postDelayed(runnable, 2000);
        } catch (Exception e) {
        }
    } else {
        LogTools.i(TAG, "Constants.REMOTE_DEVICE_INFO:");
        String address = getSharedPreferences(Constants.REMOTE_DEVICE_INFO,
                0).getString(Constants.REMOTE_CURR_ADDR, "0");
        connect(address);
    }
    isFirstRun = false;
    return START_STICKY;
}

/**
 * 啟動連線執行緒
 */
Runnable runnable = new Runnable() {
    @Override
public void run() {
        // 在這裡啟動連線,如果連線失敗,就再重新試圖連線
LogTools.i(TAG, "try connect runnable");
        try {
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
            mBluetoothAdapter.startLeScan(mLeScanCallback); //掃描低功耗藍芽裝置
} catch (Exception e) {
            // TODO Auto-generated catch block
LogTools.i(TAG, "try connect runnable failed:" + e.getMessage());
            e.printStackTrace();
        }
        handler.postDelayed(this, 10000);
    }

};

// 裝置查找回調得到BluetoothDevice物件
LeScanCallback mLeScanCallback = new LeScanCallback() {

    @Override
public void onLeScan(final BluetoothDevice device, int rssi,
                         byte[] scanRecord) {
        LogTools.d(TAG, "device.getName:" + device.getName() + ",device.address:" + device.getAddress());
        if ("KeyCtrl".equals(device.getName())) {
            close(mGattMap.get(device.getAddress()));

            //獲取BluetoothGatt 物件
BluetoothGatt mBluetoothGatt = device.connectGatt(
                    BluetoothLeService.this, false, mGattCallback);
            mGattMap.put(device.getAddress(), mBluetoothGatt);
        } else if ("infisight_r".equals(device.getName()))//對藍芽OBD功能進行連線
{
            try {
                close(mGattMap.get(device.getAddress()));
                BluetoothGatt mBluetoothGatt = device.connectGatt(
                        BluetoothLeService.this, false, mGattCallback);
                mGattMap.put(device.getAddress(), mBluetoothGatt);
            } catch (Exception e) {
                LogTools.e(TAG, "mBluetoothGatt failed:" + e.getMessage());
            }
        }

    }
};

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        @Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                            int newState) {
            // 連線狀態發生變更
String intentAction = Constants.ACTION_GATT_REMOTESEVEN_DISCONNECTED;
            LogTools.e(TAG, "onConnectionStateChange:name:" + gatt.getDevice().getName() + "Addr:" + gatt.getDevice().getAddress() + ",newState:" + newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                hmIsConnected.put(gatt.getDevice().getAddress(), true);
                SaveUtils.saveArray(BluetoothLeService.this, SP_NAME,
                        addressList);
                if ("KeyCtrl".equals(gatt.getDevice().getName())) {
                    intentAction = Constants.ACTION_GATT_REMOTE_CONNECTED;
                } else if ("infisight_r".equals(gatt.getDevice().getName())) {
                    LogTools.e(TAG, "ble ACTION_GATT_REMOTE_CONNECTED");
                    intentAction = Constants.ACTION_GATT_REMOTESEVEN_CONNECTED;
                }
                prefs.edit().putBoolean(Constants.REMOTE_CONNECT_STATUS, true)
                        .commit();
                broadcastUpdate(intentAction);
                LogTools.e(TAG, "ble gatt.discoverServices");
                gatt.discoverServices();
                SaveDeviceInfo(gatt.getDevice());
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                LogTools.d(TAG, "BluetoothProfile.STATE_DISCONNECTED");
                // 開啟執行緒,不斷時的試圖連線裝置
hmIsConnected.put(gatt.getDevice().getAddress(), false);
                if ("KeyCtrl".equals(gatt.getDevice().getName())) {
                    intentAction = Constants.ACTION_GATT_REMOTE_DISCONNECTED;
                } else if ("infisight_r".equals(gatt.getDevice().getName())) {
                    LogTools.d(TAG, "BLE BluetoothProfile.STATE_DISCONNECTED");
                    intentAction = Constants.ACTION_GATT_REMOTESEVEN_DISCONNECTED;
                }
                prefs.edit().putBoolean(Constants.REMOTE_CONNECT_STATUS, false)
                        .commit();
//                close(gatt);
disconnect(gatt);
                broadcastUpdate(intentAction);
            }
        }

        //通過status 是否等於BluetoothGatt.GATT_SUCCESS來判斷查詢Service是否成功
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            // 發現服務的廣播
LogTools.e(TAG, "onServicesDiscovered:" + gatt.getDevice().getAddress());
            if (status == BluetoothGatt.GATT_SUCCESS) {
                displayGattServices(getSupportedGattServices(gatt), gatt);
                broadcastUpdate(Constants.ACTION_GATT_SERVICES_DISCOVERED);

            }
        }

        @Override
public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic, int status) {
            LogTools.d(TAG, "onCharacteristicRead");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(Constants.ACTION_DATA_AVAILABLE, gatt, characteristic);
            }
        }

        @Override
public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            LogTools.d(TAG, "onCharacteristicChanged");
            broadcastUpdate(Constants.ACTION_DATA_AVAILABLE, gatt, characteristic);
        }

        @Override
public void onCharacteristicWrite(BluetoothGatt gatt,
                                          BluetoothGattCharacteristic characteristic, int status) {

        }
    };
 public static boolean saveArray(Context context, String spname, ArrayList<String> list) {
        mySharedPreferences = context.getSharedPreferences(spname, Context.MODE_PRIVATE);
        Editor edit = mySharedPreferences.edit();
        edit.putInt("Status_size", list.size()); /*sKey is an array*/
for (int i = 0; i < list.size(); i++) {
            edit.putString("Status_" + i, list.get(i) + "");
        }
//     LogTools.i("saveArray", list+"");
return edit.commit();
    }
  private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }
/**
     * 儲存裝置資訊
     */
private void SaveDeviceInfo(BluetoothDevice bluetoothdevice) {
        List<BleConnectDevice> lstConnectDevices = new ArrayList<BleConnectDevice>();
        String connectedinfo = prefs.getString(
                Constants.REMOTE_CONNECTED_DEVICES, "");
        Gson gson = new Gson();
        if (!connectedinfo.equals("")) {

            try {
                lstConnectDevices = gson.fromJson(connectedinfo,
                        new TypeToken<List<BleConnectDevice>>() {
                        }.getType());
            } catch (Exception e) {
            }
        }
        if (!lstNeedConnectAddress.contains(bluetoothdevice.getAddress())) {
            lstNeedConnectAddress.add(bluetoothdevice.getAddress());
            BleConnectDevice bledevice = new BleConnectDevice(); //儲存裝置的資訊
bledevice.setAddress(bluetoothdevice.getAddress());
            bledevice.setName(bluetoothdevice.getName());
            lstConnectDevices.add(bledevice);
            try {
                String newaddr = gson.toJson(lstConnectDevices);
                prefs.edit()
                        .putString(Constants.REMOTE_CONNECTED_DEVICES, newaddr)
                        .commit();
            } catch (Exception e) {
            }
        } else if ("KeyCtrl".equals(bluetoothdevice.getName())) {
            mTypeMap.put(bluetoothdevice.getAddress(), "remote");
//        }else  if (bluetoothdevice.getName().contains("BLE"))//對藍芽OBD功能進行連線
} else if ("infisight_r".equals(bluetoothdevice.getName()))//對藍芽OBD功能進行連線
{
            mTypeMap.put(bluetoothdevice.getAddress(), "remote");
        }

    }
  public boolean connect(final String address) {
        // 確認已經獲取到介面卡並且地址不為空
if (mBluetoothAdapter == null || address == null || address.equals("0")) {
            return false;
        }

        final BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
        // 通過裝置地址獲取裝置
if (device == null) {
            LogTools.e(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        // LogTools.i(TAG, "device.connectGatt(this, false, mGattCallback)");
if (mGattMap.keySet().contains(address)) {
            BluetoothGatt mBluetoothGatt = mGattMap.get(address);
            if (mBluetoothGatt != null) {
                // close(mBluetoothGatt);
disconnect(mBluetoothGatt);
            }
        }
        BluetoothGatt mBluetoothGatt = device.connectGatt(this, false,
                mGattCallback);
        mGattMap.put(address, mBluetoothGatt);
        addressList.add(address);
//        mConnectionState = STATE_CONNECTING;
return true;
    }

public void disconnect(BluetoothGatt mBluetoothGatt) {
    // LogTools.i("LIFECYCLE", "disconnect");
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        LogTools.e(TAG, "BluetoothAdapter not initialized disconnect");
        return;
    }
    mBluetoothGatt.disconnect();
    // 斷開連線
}

  // 從特徵中分析返回的資料並表示為action後進行廣播
private void broadcastUpdate(final String action, BluetoothGatt gatt,
                                 final BluetoothGattCharacteristic characteristic) {
        if ("KeyCtrl".equals(gatt.getDevice().getName())) {
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for (byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                if (stringBuilder.toString().trim().equals("01")) {
                    // 上
int operFlag = 1;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
                    LogTools.i(TAG, "keys01");

                } else if (stringBuilder.toString().trim().equals("02")) {
                    LogTools.i(TAG, "isPhoneIng:"+ProcessMsgService.isPhoneIng);
                    if(ProcessMsgService.isPhoneIng == true)
                    {
                        try {
                            PhoneUtils.getITelephony(telMgr)
                                    .answerRingingCall();
                        } catch (RemoteException e) {
                            // TODO Auto-generated catch block
e.printStackTrace();
                        } catch (Exception e) {
                            LogTools.i(TAG, "error:"+e.getMessage());
                            CommonUtil.answerRingingCall(this);
                        }
                        return;
                    }
                    // 確定
int operFlag = 5;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_SINGLETAP);
LogTools.i(TAG, "keys02");
                } else if (stringBuilder.toString().trim().equals("04")) {
                    // 喚醒
MainActivity.svr.controlToWake(true);
                    LogTools.i(TAG, "keys04");
                } else if (stringBuilder.toString().trim().equals("08")) {
                    LogTools.i(TAG, "isPhoneIng:"+ProcessMsgService.isPhoneIng);
                    LogTools.i(TAG, "keys08");
                    if(ProcessMsgService.isPhoneIng == true)
                    {
                        try {
                            PhoneUtils.getITelephony(telMgr).endCall();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        return;
                    }
                    // 返回
int operFlag = 0;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GETSTURE_BACK);
LogTools.i(TAG, "keys08");
                } else if (stringBuilder.toString().trim().equals("10")) {
                    // 下
int operFlag = 2;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_TODOWN);
LogTools.i(TAG, "keys10");
                }
                // intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
                // stringBuilder.toString());
}
//        }else if (gatt.getDevice().getName().contains("BLE"))
} else if ("infisight_r".equals(gatt.getDevice().getName())) {
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for (byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                if (stringBuilder.toString().trim().equals("15")) {
                    // 上
int operFlag = 1;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();

                } else if (stringBuilder.toString().trim().equals("12")) {
                    //如果在通話中,接聽電話
if(ProcessMsgService.isPhoneIng == true)
                    {
                        try {
                            PhoneUtils.getITelephony(telMgr)
                                    .answerRingingCall();
                        } catch (RemoteException e) {
                            // TODO Auto-generated catch block
e.printStackTrace();
                        } catch (Exception e) {
                            CommonUtil.answerRingingCall(this);
                        }
                        return;
                    }
                    // 確定
int operFlag = 5;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_SINGLETAP);
} else if (stringBuilder.toString().trim().equals("14")) {
                    // 喚醒
MainActivity.svr.controlToWake(true);
                } else if (stringBuilder.toString().trim().equals("16")) {
                    //如果已經在通話中,直接結束通話電話
LogTools.i(TAG, "key:16");
                    LogTools.i(TAG, "isPhoneIng:"+ProcessMsgService.isPhoneIng);
                    if(ProcessMsgService.isPhoneIng == true)
                    {
                        try {
                            PhoneUtils.getITelephony(telMgr).endCall();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        return;
                    }
                    // 返回
int operFlag = 0;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GETSTURE_BACK);
} else if (stringBuilder.toString().trim().equals("11")) {
                    // 下
int operFlag = 2;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_TODOWN);
} else if (stringBuilder.toString().trim().equals("13")) {
                    // 左
int operFlag = 3;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_TOLEFT);
} else if (stringBuilder.toString().trim().equals("17")) {
                    // 右
int operFlag = 4;
                    Message msg = sendKeyHandler.obtainMessage(operFlag);
                    msg.what = operFlag;
                    msg.sendToTarget();
//          ProcessBroadcast(Constants.GESTURE_INFO,
//                Constants.GESTURE_TORIGHT);
}
            }
        }

    }

BluetoothService 下載地址http://download.csdn.net/detail/pigseesunset/9690371