继续上篇提到的 我们开始进入蓝牙开发的代码的开发工作。首先权限问题 :
1.在Android6.0之前我们我们只要申请下面的两个权限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
2.在Android6.0之后我们还需要申请一个精确定位的权限(这个时候有个比较恶心的问题需要说明下 按常规我们只要把目标的sdk写成23以下应该就不会出现需要申请权限的问题 但是部分机品牌的部分手机会出现这个问题也是没有搞懂 底层怎么兼容的)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
6.0以后还要一个动态权限的获取,这个就没有什么可以多说的了.
以上就是权限,虽然比较啰嗦 但是希望一开始和我一样的蓝牙小白能够更好的理解.
其实我们还可以通过 PackageManager.hasSystemFeature() 来判断是否支持BLE蓝牙但是貌似一般的手机现在都支持了。
接下来就是过去蓝牙的状态
首先需要获取到肯定是蓝牙服务对象 :
BluetoothManager bluetoothManager =
(BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
再获取到蓝牙适配器,这个地方有个小点需要注意一下 ,也是部分品牌部分手机存在的问题 必须加下下面一个判空操作 和一个赋值操作 不然应该是5.0以下是获取不到相关适配器 所以你就会发现 代码都没有问题 就是接受不到相关蓝牙广播数据
这个时候可以直接打开也可以直接给用户一个蓝牙状态的提. 代码如下:
1、直接打开如下
BluetoothManager bluetoothManager =(BluetoothManager) this.mContext.getSystemService(Context.BLUETOOTH_SERVICE);
mBleAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null)
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBleAdapter != null)
mBleAdapter.enable();
2、向用户请求打开蓝牙
BluetoothManager bluetoothManager =(BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null)
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
场景是这样的,每次打开应用 我就判断蓝牙是否打开。其实这个逻辑判断已经能够满足大部分的基本需求了 但是也只是满足大部分需求 这个其实更完美的做法是注册一个广播监听蓝牙状态 代码如下:
//蓝牙的开启关闭的广播监听
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
switch (state) {
case BluetoothAdapter.STATE_ON:
Log.d(TAG, "蓝牙开启");
TelinkLightService.Instance().idleMode(true);
autoConnect();
break;
case BluetoothAdapter.STATE_OFF:
Log.d(TAG, "蓝牙关闭");
break;
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1);
registerReceiver(mReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
接下来就可以启动扫描的了。
这个时候开始你要注意的是所以得接口都是有两个版本 (5.0以上 5.0以下)除了通信那些回调方法
5.0以下的版本:
//Starts a scan for Bluetooth LE devices.
public boolean startLeScan(LeScanCallback callback) {
return startLeScan(null, callback);
}
5.0以上的版本:
ScanSettings.Builder builder = new ScanSettings.Builder();
builder.setReportDelay(0);
builder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.i(TAG, "Scan bluetooth-LE devices using new api(6.0+)!");
builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
builder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE);
builder.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT);
}
ScanSettings ss = builder.build();
BluetoothLeScanner scanner = adapter.getBluetoothLeScanner();
if (scanner != null) {
scanner.startScan(null, ss, LeScannerCB());
Log.i(TAG, "Success start scan bluetooth-LE devices!");
} else
Log.v(TAG, "Scanner is null, start failed, maybe bluetooth not opened/ready.");
}
其中的ScanSeting.Buidler是扫描的设置参数。
这是google给出官方的参数解释,比较容易看懂,我就不翻译了。
前面的相关操作之后。一直需要传入一个参数。这个参数就是广播数据接收器了。也分为两个版本
5.0以下的版本:
scanCB = (BluetoothDevice device, int rssi,
byte[] scanRecord) -> {
};
BluetoothDevice 蓝牙设备对象。其中含有设备的地址,scanRecord这是广播数据信息。
5.0以上的版本:
leScannerCB = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
});
}
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult r : results) {
onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, r);
}
}
public void onScanFailed(int errorCode) {}
}
其中callbackType** 就是ScanSetting设置过去的参数,ScanResult是Android对4.3数据的封装,其中包含了设备的对象BluetoothDevice 信号rssi 广播数据包scanRecord 还有一个参数是设备最后一次发现的时间戳 **mTimestampNanos****
上面就是一个比较简单蓝牙比较简单的相关处理了
下一篇:开始关于数据解析。http://www.jianshu.com/p/d0c9e3c5e30a
下面是完整的源码:
/**
* Created by zxd on 2016/10/24.
*/
public class BleScaner {
private static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4;
//上下文设置
private Context mContext;
//Ble管理器
private BluetoothManager mBleManger;
//是否在扫描
private boolean mScaning;
//本类
private static BleScaner mBleScaner;
//回调接口
private BleScanCallBack mBleScanCallBack;
//5.0一下扫描的接口
private BluetoothAdapter.LeScanCallback mLeScanCallback;
//5.0以上接口
private ScanCallback mScanCallback;
//BLE适配器
private BluetoothAdapter mBleAdapter;
//Ble扫描接口
private BluetoothLeScanner mScanner;
/*
* BlE is Supports
*/
public boolean isBleSupport() {
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
}
/*
* BLE is Open
*/
public boolean isBleOpen() {
mBleManger = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
mBleAdapter = mBleManger.getAdapter();
if (mBleAdapter == null) {
mBleAdapter = BluetoothAdapter.getDefaultAdapter();
}
return mBleAdapter != null && mBleAdapter.enable();
}
//构造方法
public BleScaner(Context context) {
mContext = context;
}
//单例
public static BleScaner core(Context context) {
if (mBleScaner == null) {
synchronized (BleScaner.class) {
if (mBleScaner == null) {
mBleScaner = new BleScaner(context);
}
}
}
return mBleScaner;
}
/*
* 获取手机品牌
* */
public String getPhoneBrand() {
return android.os.Build.BRAND;
}
/*
* 5.0以上
*/
public boolean isSupportLollipop() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
public void setLeScanCallback(BleScanCallBack callback) {
mBleScanCallBack = callback;
Log.i("device", "OKcallback");
if (mBleScanCallBack == null) return;
if (getPhoneBrand().contains("Xiaomi")) {
this.mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (mBleScanCallBack != null)
mBleScanCallBack.onBleScan(device, rssi, scanRecord);
}
};
} else {
if (isSupportLollipop()) {
mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
if (isSupportLollipop()) {
byte[] scanRecord = null;
Log.i(result.getDevice().getAddress(), "收到");
if (result.getScanRecord() != null)
scanRecord = result.getScanRecord().getBytes();
if (mBleScanCallBack != null)
mBleScanCallBack.onBleScan(result.getDevice(), result.getRssi(), scanRecord);
}
}
@Override
public void onScanFailed(int errorCode) {
if (errorCode != ScanCallback.SCAN_FAILED_ALREADY_STARTED)
if (mBleScanCallBack != null)
mBleScanCallBack.onScanFail(errorCode);
}
};
} else {
this.mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (mBleScanCallBack != null)
mBleScanCallBack.onBleScan(device, rssi, scanRecord);
}
};
}
}
}
public interface BleScanCallBack {
void onBleScan(BluetoothDevice device, int rssi, byte[] scanResult);
void onScanFail(int errorCode);
void onStartScan();
void onStopScan();
}
synchronized public void startScan() {
synchronized (this) {
if (mScaning) {
return;
}
if (isBleSupport() && !isBleOpen()) {
return;
}
mScaning = true;
if (getPhoneBrand().contains("Xiaomi")) {
if (!mBleAdapter.startLeScan(
mLeScanCallback)) {
synchronized (this) {
mScaning = false;
}
if (mBleScanCallBack != null)
mBleScanCallBack.onScanFail(SCAN_FAILED_FEATURE_UNSUPPORTED);
} else {
synchronized (this) {
mScaning = true;
}
mBleScanCallBack.onStartScan();
}
} else {
if (isSupportLollipop()) {
mScanner = mBleAdapter.getBluetoothLeScanner();
if (mScanner == null) {
synchronized (this) {
mScaning = false;
}
if (mBleScanCallBack != null)
mBleScanCallBack.onScanFail(SCAN_FAILED_FEATURE_UNSUPPORTED);
} else {
mScanner.startScan(mScanCallback);
synchronized (this) {
mScaning = true;
}
mBleScanCallBack.onStartScan();
}
} else {
if (!mBleAdapter.startLeScan(
mLeScanCallback)) {
synchronized (this) {
mScaning = false;
}
if (mBleScanCallBack != null)
mBleScanCallBack.onScanFail(SCAN_FAILED_FEATURE_UNSUPPORTED);
} else {
synchronized (this) {
mScaning = true;
}
mBleScanCallBack.onStartScan();
}
}
}
}
}
synchronized public void stopScan() {
synchronized (this) {
if (!mScaning)
return;
}
try {
if (isSupportLollipop()) {
if (mScanner != null)
mScanner.stopScan(mScanCallback);
} else {
if (mBleAdapter != null)
mBleAdapter.stopLeScan(mLeScanCallback);
}
} catch (Exception e) {
}
synchronized (this) {
mScaning = false;
}
if (mBleScanCallBack != null)
mBleScanCallBack.onStopScan();
}
}