android5.0 BLE 藍牙4.0+淺析demo搜索(一)


作者:Bgwan
鏈接:https://zhuanlan.zhihu.com/p/23341414
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

作者:Bgwan 蒔蘿花
鏈接:android BLE 藍牙4.0+淺析(一) - Android開發 - 知乎專欄
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。

android BLE 藍牙4.0+淺析(一)

Android 4.3 (API Level 18) introduces built-in platform support for Bluetooth Low Energy in the central roleand provides APIs that apps can use to discover devices, query for services, and read/write characteristics.

+代表藍牙更高版本,

本文介紹Android ble 藍牙4.0,也就是說API level >= 18,且支持藍牙4.0的手機才可以使用,如果手機系統版本API level < 18,是用不了藍牙4.0的,我們通常可以加一個判斷。

首先:操作藍牙,我們需要在AndroidMainfest.xml中配置,如下權限,

<!--藍牙權限-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="true"></uses-feature>

說明:hardware是,在底判斷是否支持,藍牙,admin是超級權限,根據用戶需求不同加入不同的權限,

藍牙SDK版本判斷,如下代碼:

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
    Toast.makeText(this, "當前版本SDK" + Build.VERSION.SDK_INT + "< Android5.0不支持藍牙", Toast.LENGTH_SHORT).show();
mText.setText("當前版本" + Build.VERSION.SDK_INT + "< Android5.0不支持藍牙");
return;
}

1,打開藍牙,藍牙狀態等操作,以及是否支持藍牙BLE

// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
mText.setText(R.string.ble_not_supported);
return;
}
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//需要時再初始化
mHandler = new Handler();
mProgress = new ProgressDialog(NewActivity.this);

2,如果藍牙沒有打開,我們需要打開藍牙,打開藍牙有兩種方式,但是建議給用戶顯示的方式打開,因為用戶需要知道這些權限,不然你這個就是牛氓行為。隱式打開為:

mBluetoothAdapter.enable();

,下面的代碼為顯示的打開方式。

/ Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    Toast.makeText(this, "藍牙正在打開,建議允許應用操作", Toast.LENGTH_SHORT).show();
}

3,搜索藍牙操作。

如果藍牙都已經打開正常,則可以進行搜索周圍藍牙設備的操作,這里記住,不只是手機中的藍牙,任何外設都可以。順帶,我們查看android SDK會發現bluetooth包下面多了le.這是android 藍牙4.2以后新加入的操作藍牙的包,但是谷歌為了兼容以前的版本

mBluetoothAdapter.startLeScan(mLeScanCallback);

這個方法還是可以使用,這里我們使用le。包下面最新的搜索藍牙的功能,如下:

 //最新寫法。藍牙打開才執行
    if (mBluetoothAdapter.isEnabled()) {
mProgress.setMessage("正在搜索周圍設備...");
mProgress.setCancelable(false);
mProgress.show();
newtext.setText("藍牙已經打開,關閉藍牙請在設置中設置");
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Initializes list view adapter.
        mLeDeviceListAdapter = new LeDeviceListAdapter();
listView.setAdapter(mLeDeviceListAdapter);
//顯示dialog
        new Thread(new Runnable() {
@Override
            public void run() {
try {
                    Thread.sleep(3000);
if (mProgress != null) {
mProgress.dismiss();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
mLeDeviceListAdapter.clearDevice();
        scanLeDevice(true);
    }
}

scanLeDevice是對方法的封裝,這里主要是調用bluetoothlescanner的starscan方法,該方法可以傳遞兩個參數,這里先討論傳遞mScanCallback這是一個掃描結果的回掉接口;當然這里操作也應該放到子線程中去處理。

mBluetoothLeScanner.startScan(mScanCallback);//新

具體的scanLeDevice()方法如下:

private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
        mHandler.postDelayed(new Runnable() {
@Override
            public void run() {
mScanning = false;
mBluetoothLeScanner.stopScan(mScanCallback);
                invalidateOptionsMenu();
            }
        }, SCAN_PERIOD);
mScanning = true;
mBluetoothLeScanner.startScan(mScanCallback);//新
    } else {
mScanning = false;
mBluetoothLeScanner.stopScan(mScanCallback);
    }
    invalidateOptionsMenu();
}

4,以上我們就開啟了藍牙的搜索,功能,然后會觸發mScanCallback進行結果的監聽。主要監聽里面的三個方法,onScanResult,onBatchScanResults,onScanFailed,搜索到結果以后,我們需要對它進行解析,代碼里面都注釋得很清楚


// Device scan callback.
    private ScanCallback mScanCallback = new ScanCallback() {
@Override
        public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result == null || result.getDevice() == null
                    || TextUtils.isEmpty(result.getDevice().getName())) {
mText.setText("沒有搜索到藍牙設備");
//                return;
            }
//如果是外設則可能存在沒有ServiceUuids
//            builder.append("/n").append(
//                    new String(result.getScanRecord().getServiceData(
//                            result.getScanRecord().getServiceUuids().get(0)),
//                            Charset.forName("UTF-8")));

            BluetoothDevice device = result.getDevice();
            Log.d(TAG, "Device name: " + device.getName());
            Log.d(TAG, "Device address: " + device.getAddress());
            Log.d(TAG, "Device service UUIDs: " + device.getUuids());
if (builder.toString().contains(device.getName())) {
            } else {
builder.append("\n" + device.getName() + "&" + device.getAddress() + "\n");
            }
            ScanRecord record = result.getScanRecord();
            Log.d(TAG, "Record advertise flags: 0x" + Integer.toHexString(record.getAdvertiseFlags()));
            Log.d(TAG, "Record Tx power level: " + record.getTxPowerLevel());
            Log.d(TAG, "Record device name: " + record.getDeviceName());
            Log.d(TAG, "Record service UUIDs: " + record.getServiceUuids());
            Log.d(TAG, "Record service data: " + record.getServiceData());

mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();

mText.setText("搜索結果,builder:" + builder.toString());
        }

@Override
        public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
for (ScanResult result : results) {
                Toast.makeText(getApplicationContext(), "result:" + result.getDevice().getAddress(), Toast.LENGTH_SHORT).show();
            }
        }

@Override
        public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
mText.setText("搜索藍牙失敗 errorCode:" + errorCode);

        }
    };

這里我自己對搜索的結果操作為,

mLeDeviceListAdapter.addDevice(device);

加入到mLeDeviceListAdapter中去,這是一個listview的適配器,

5,藍牙列表,結果顯示的適配器代碼,很簡單,如下面。

// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;

public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = NewActivity.this.getLayoutInflater();
    }

public void addDevice(BluetoothDevice device) {
if (!mLeDevices.contains(device)) {
mLeDevices.add(device);
        }
    }

public void clearDevice() {
if (mLeDevices.size() > 0) {
mLeDevices.clear();
        }
    }

public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
    }

public void clear() {
mLeDevices.clear();
    }

@Override
    public int getCount() {
return mLeDevices.size();
    }

@Override
    public Object getItem(int i) {
return mLeDevices.get(i);
    }

@Override
    public long getItemId(int i) {
return i;
    }

@Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        DeviceScanActivity.ViewHolder viewHolder;
// General ListView optimization code.
        if (view == null) {
            view = mInflator.inflate(R.layout.listitem_device, null);
            viewHolder = new DeviceScanActivity.ViewHolder();
            viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
            viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
            view.setTag(viewHolder);
        } else {
            viewHolder = (DeviceScanActivity.ViewHolder) view.getTag();
        }

        BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
            viewHolder.deviceName.setText(deviceName);
else
            viewHolder.deviceName.setText(R.string.unknown_device);
        viewHolder.deviceAddress.setText(device.getAddress());

return view;
    }
}

以上就是全部代碼,下面文章,會從源碼的角度分析,最新的開啟,藍牙和以前版本的對比,方便理解,在以后的文章會講解如何連接嵌入式的藍牙設備進行數據的傳送。當然這里會由淺到深的體現出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM