今天写好了项目准备交给测试人员去测试,但是问题来了,我平时运行的都是自己的手机,sdk版本是5.0(21)的,但是测试组给我的手机是安卓4.4的,结果搜都搜不到Ble设备,苦逼了好久,我拿了一个demo对比,发现demo可以搜索的到,然后我就对着代码看,看完了也没发现个所以然,最后我决定自己写个demo,很简单,只要实现搜索功能就可以了,结果并没什么卵用,依然搜不到,我是知道adapter只提供了两个搜索方法的,但是鉴于在每个公司的产品都不同,最好设定uuid去搜索。于是换了个方法,然后我去掉了uuid,结果Log就打印出来了,好吧,这都不是问题,反正在android 5.0版本是可以秒杀扫出的,于是做个版本判断吧。希望能帮到此时还在烦恼的你。

 

    --------------------------分割线--------------------------

绕回来了,今天在android6.0设备上搜索蓝牙,结果又是搜索不到,百度搜了一下,重要在stackoverflow上找到了答案。  

   虽然android快要发布7.0了,可是我们好像还没用上6.0,可是如果发布了7.0,我们离用上6.0还会久吗?

   先说一下,虽然下面这个方法已经在5.0给抛弃了,但是还是可以用,因为android在5.0以后可以让手机作为BLE设备端,

   估计整合了一下方法吧,所以下面的方法被废弃了。


boolean

startLeScan(BluetoothAdapter.LeScanCallback callback)


Starts a scan for Bluetooth LE devices.

boolean

startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback)


Starts a scan for Bluetooth LE devices, looking for devices that advertise given services.

 

我试过新方法也是可以搜索的,就是参数设置比较麻烦,有兴趣的朋友自己去试试。下面说下我是怎么解决在6.0上搜索蓝牙

  因为在android6.0对安全权限做了很大的改变,同时搜索蓝牙是需要在AndroidManifest.xml上添加

uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION

  如果在studio上设置目标版本是6.0的话,则需要请求上面这个权限,代码如下

// 判断蓝牙是否开启    
 if(mBluetoothAdapter.isEnabled()){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("This app needs location access");
                    builder.setMessage("Please grant location access so this app can detect Bluetooth.");
                    builder.setPositiveButton(android.R.string.ok, null);
                    builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                        @Override
                        public void onDismiss(DialogInterface dialog) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
                            }
                        }
                    });
                    builder.show();
                }
            }
        }

  /***
     *对授权做处理,0代表授权,-1拒绝授权
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_COARSE_LOCATION: {
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                   // Log.d(TAG, "coarse location permission granted");
                    finish();
                } else {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("Functionality limited");
                    builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
                  builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                        @Override
                        public void onDismiss(DialogInterface dialog) {
                        }
                    });
                    builder.show();
                }
                return;
            }
        }
    }

以上工作只是打开权限而已,或许你会发现设置了上面代码要求了位置权限是可以搜索蓝牙,为什么呢,因为会在Location打开GPS,这时候试试关闭GPS,而这个权限请求是完成的,你会发现根本搜索不到蓝牙,为什么呢?能所有蓝牙的关键原因是打开了GPS,soga,那知道问题就好办了,我们只要打开GPS就行了,下面是判断GPS是否打开的代码:

// Gps是否可用
    public static final boolean isGpsEnable(final Context context) {
        LocationManager locationManager
                = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        if (gps || network) {
            return true;
        }
        return false;
    }

以上可以用于在点击搜索对GPS判断,打开的话直接搜索,没有打开的话就........那就打开呗。

我们可以通过startactivityforresult(activity,requestcode)这个方法来跳转到setting的Location界面,

Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        activity.startActivityForResult(intent,requestCode);


打开GPS,然后返回就可以收到Ble设备了!

其实我并没有用上面那么的权限代码,只要设置目标版本不是6.0,设为5.0,同时打开GPS,同样可以实现Ble设备在6.0上的搜索功能!

至此,已经解决了搜索蓝牙这个问题

下面贴一下我写的代码

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if(isGpsEnable(this)){
                       // gps 已开,接下来请求定位权限,已授权则开始搜索,未授权则提示权限通知
                       requestLocationPermission()
                    }else {
                         // 通过Intent 进入GPS设置界面,这里建议用startActivityForResult()进入GPS设置界面,
                         // 并在onActivityResult()方法做处理,判断gps是否打开,未打开给出提醒,打开了进入定位权限流程
                        liteble.enableLocation(this,PERMISSION_REQUEST_COARSE_LOCATION);
                        Toast.makeText(this,R.string.openGps,Toast.LENGTH_LONG).show();
                    }
                    return;
                }
                showListView();

在点击按钮的时候,先判断android版本,如果是6.0就判断GPS有没有打开,打开了再判断权限是否已申请,申请了直接去搜索,没有打开就跳转到打开GPS界面,6.0版本一下就直接搜索了,是不是发现很简单?


------------------------------------------------------------------------------

更新于 2017/1/22

关于权限问题,不推荐大家使用我上面的方法,在这给大家推荐一个权限的库,

谷歌自己出品的 EasyPermission ,具体用法大家可以去github一下。

然后建议会RxJava的可以试一下 Rxpermission, 不过我是没有尝试,没有太多时间,很多人都再使用。

新出的手机基本都是6.0,有的还是7.0了,国内6.0慢慢的会全部普及,所以大家写程序的时候要适配好权限,基本权限库也是必备了。

------------------------------------------------------------------------------

更新于 2018/4/27

权限库还是建议使用RxPermission,相比EasyPermission 还是具有很大的优势的,不用写那么多接口注解,而且权限请求操作本就是观察者行为,天然符合Rx这种异步库,反正我推荐使用。

然后分享一下关于搜索很慢的问题
亲测手机蓝牙模块比较差的是ovb系列,不是我黑它,除了蓝牙模块还有WiFi模块也做的很烂,相比其它品牌手机,简直不止差一个档次,比较快的是华为,三星,小米魅族也还不错,所以对于有搜索时间限制的应用来说,需要给这三个品牌的手机开个后门,留有足够的时间