android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

android 从4.3系统开始可以连接BLE设备,这个大家都知道了。iOS是从7.0版本开始支持BLE。

android 进入5.0时代时,开放了一个新功能,手机可以模拟设备发出BLE广播, 这个新功能其实是 对标于 iOS系统的手机模拟iBeacon设备。

先介绍一下BLE的广播, BLE设备之所以能被手机扫描到,是因为 BLE设备一直在每隔 一段时间广播一次,这个广播里面包含很多数据。

手机扫描BLE设备代码如下:

        public void startScan(){
            bluetoothAdapter.startLeScan(leScanCallback);
        }

    public void stopScan(){
        bluetoothAdapter.stopLeScan(leScanCallback);
    }
    private LeScanCallback leScanCallback=new LeScanCallback() {

        @Override
        public void onLeScan(BluetoothDevice bluetoothdeivce, int rssi, byte[] scandata) {
            //把byte数组转成16进制字符串,方便查看
            Log.e("TAG","scandata:"+ CYUtils.Bytes2HexString(scandata));
        }
    };
ok,这段代码大家在做连接BLE设备进行通讯的时候,已经很熟悉了。其中的 byte数组 scandata就是 BLE设备的广播数据。

那么接下来,我们开始使用 手机1 模拟成BLE设备来发送广播,然后用手机2 来进行扫描查看广播数据 scandata

首先获取 BluetoothAdapter, 熟悉的代码:

BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);

bluetoothAdapter = bluetoothManager.getAdapter();

进行广播的时候需要用到BluetoothLeAdvertiser,进行实例化:

mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
实例化好之后就可以进行广播数据了,开启广播方法是:

BluetoothLeAdvertiser:
public void startAdvertising(AdvertiseSettings settings,
            AdvertiseData advertiseData, final AdvertiseCallback callback)
其中, AdvertiseSettings 是广播的一些设置,比如,广播间隔,是否可以连接等等; AdvertiseData 就是广播数据了, AdvertiseCallback是广播回调,会告诉你广播成功还是失败。

先给一段完整广播代码如下:

    public void startAction(View v){
        byte[] broadcastData ={0x34,0x56};
        mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(broadcastData), mAdvertiseCallback);
    }
    public void stopAction(View v) {
        mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
    }

    public AdvertiseSettings createAdvSettings(boolean connectable, int timeoutMillis) {
        AdvertiseSettings.Builder mSettingsbuilder = new AdvertiseSettings.Builder();
        mSettingsbuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        mSettingsbuilder.setConnectable(connectable);
        mSettingsbuilder.setTimeout(timeoutMillis);
        AdvertiseSettings mAdvertiseSettings = mSettingsbuilder.build();
        return mAdvertiseSettings;
    }

    public AdvertiseData createAdvertiseData(byte[] data) {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
        mDataBuilder.addManufacturerData(0x01AC, data);
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        return mAdvertiseData;
    }
    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);

            ToastUtils.showToast(MainActivity.this, "开启广播成功", 2000);
        }

        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            ToastUtils.showToast(MainActivity.this, "开启广播失败 errorCode:" + errorCode, 2000);
        }
    };

其中,广播数据broadcastData 我暂时直接先定死为2个字节 0x3456,同样在createAdvertiseData里面

也有定死的数据 0x01AC . 开启成功之后

我们使用手机2 来扫描看下广播的数据是什么:

E/TAG: scandata:02011A05FFAC0134560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
log打印出来的scandata 有效数据是 02011A05FFAC013456 .  给大家解释一下这个数据的意思

为了看清楚,我分段如下: 02011A  05  FF AC01 3456   (注,这里的都是16进制数字)

02011A这3个字节,02表示后面一段数据长度为2字节,01表示数据类型是flag ,1A就是flag的数据了

05 表示后面的一段数据长度为 5个字节, FF一个字节,AC01 两个字节,3456两个字节,加起来一共5个字节,老铁没毛病

FF,是一个数据类型,这是我们通过代码mDataBuilder.addManufacturerData(0x01AC, data); 添加广播数据时候设置的

ManufacturerData 是指设备厂商自定义数据,FF 就是代表下面的数据实体是厂商数据.

第一个参数0x01AC,是厂商id,id长度为2个字节,不足2个字节系统会补0,可以看到log打印出来的是 AC01,顺序是倒过来的,这点要注意!

如果我代码是这样写的 :

mDataBuilder.addManufacturerData(0xAC, data); //只写了一个字节的id
那么使用手机2 扫描出的scandata是:

 E/TAG: scandata:02011A05FFAC0034560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以看到,AC后面系统自动补了00

广播数据出除了可以添加ManufacturerData,还可以添加ServerUUID, 代码如下:

public AdvertiseData createAdvertiseData(byte[] data) {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
        mDataBuilder.addManufacturerData(0x01AC, data);
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        return mAdvertiseData;
    }
代码添加了一个 AE8F的 server uuid, 使用手机2 扫描的scandata 如下:

E/TAG: scandata:02011A05FFAC01345603038FAE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看03038FAE 这一段,第一个03 表示后面的一段数据长度为3个字节  第二个03 表示这个数据类型是 server uuid类型,uuid的数据就是8FAE,顺序是倒过来的!

有人会问: 如果 我把addServiceUuid代码放在 addManufacturerData 前面,扫描的数据顺序是什么样的呢?

答案 还是:

E/TAG: scandata:02011A05FFAC01345603038FAE00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以添加多个 server uuid吗? 可以,代码如下:
    public AdvertiseData createAdvertiseData(byte[] data) {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addManufacturerData(0x01AC, data);
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        return mAdvertiseData;
    }
扫描的结果是:

E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看0503 8FAE E1FF 这一段, 05 表示后面的一段数据长度是5个字节,03表示数据类型是 server uuid, 8FAE是第一个uuid, E1FF是第二个uuid

这个ServerUUID 有什么用呢? 

不知大家在扫描BLE设备的时候,有没有注意到这个方法:

BluetoothAdapter
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)

这个方法也可以用来扫描BLE设备,但是多了一个参数, UUID数组, 这个扫描方法是用来过滤BLE设备用的,比如 你公司开发一个 蓝牙防丢器APP,你使用 startLeScan(callback)这个方法扫描的话,你会发现你扫描到周围的所有的BLE设备,同事戴的小米手环可能也被你扫描到,这样让用户来选择设备进行连接的话可能就比较迷糊,startLeScan(serviceUuids,callback) 这个方法在扫描的时候会过滤广播里的数据,只有符合的BLE设备才会被扫描回调。 所以,你们公司的蓝牙防丢器设备可以在广播字段里加入特定的server uuid, app扫描的时候可以过滤其他设备。

我们来实现一下这个功能, 修改 手机2 的扫描代码:

        public void startScan(){
                UUID[] serviceUuids = new UUID[] { UUID    .fromString("0000ae8f-0000-1000-8000-00805f9b34fb") };
        bluetoothAdapter.startLeScan(serviceUuids, leScanCallback);
    }
    public void stopScan(){
        bluetoothAdapter.stopLeScan(leScanCallback);
    }
    private LeScanCallback leScanCallback=new LeScanCallback() {

        @Override
        public void onLeScan(BluetoothDevice bluetoothdeivce, int rssi, byte[] scandata) {
            //把byte数组转成16进制字符串,方便查看
            Log.e("TAG","scandata:"+ CYUtils.Bytes2HexString(scandata));
        }
    };
扫描结果是这样的:

05-23 16:13:30.522 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.625 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.735 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.847 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:30.955 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.061 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.192 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.283 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.369 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
05-23 16:13:31.480 10197-10197/jiqi.blescandemo E/TAG: scandata:02011A05FFAC01345605038FAEE1FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
可以发现,扫描结果里面只会出现拥有  AE8F 这个uuid的 BLE设备,搜索不到其他设备

注意:部分手机使用startLeScan(serviceUuids,callback)这个方法过滤设备 会扫描不到设备,即使这个设备UUID符合过滤条件,我归结为手机/系统问题,如三星手机

这样,我们知道,广播数据可以添加ManufacturerData,还可以添加ServerUUID, 还有吗? 有,代码如下:

    public AdvertiseData createAdvertiseData(byte[] data) {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x64,0x12});
        mDataBuilder.addManufacturerData(0x01AC, data);
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        return mAdvertiseData;
    }

扫描结果如下:

E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE64120000000000000000000000000000000000000000000000000000000000000000000000000000000000
直接看05168FAE6412 这一段,05依然表示下面一段数据长度为5个字节,16表示数据类型为 server data, 8FAE表示这个数据的uuid是AE8F, 6412就是数据本体了.

那么这个 server data能做什么呢?比如有这样一个 产品:温度计,温度计硬件在广播字段里的server data里面加入它测量的温度,这样APP可以不连接温度计设备 只通过扫描就知道温度了,是不是很方便.

以下有几个坑请大家注意一下:

  情况1:

    public AdvertiseData createAdvertiseData(byte[] data) {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
       // mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x64,0x12});
        mDataBuilder.addManufacturerData(0x01AC, data);
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        return mAdvertiseData;
    }

     我注释了一句代码,广播字段里我没有 添加 ae8f这个 uuid,而直接添加了 ae8f的data 为 0x6412,那么扫描结果如何?

     使用startLeScan(serviceUuids,callback)过滤 ae8f这个uuid,没有扫描结果;

     使用startLeScan(callback),扫描结果如下:

E/TAG: scandata:02011A05FFAC0134560303E1FF05168FAE641200000000000000000000000000000000000000000000000000000000000000000000000000000000000000

     可以看到是有 ae8f对应的数据 6412,但是server uuid里面是没有 ae8f的.

  情况2:

     代码顺序1:

        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x44});
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x12});

//扫描结果
E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE54120000000000000000000000000000000000000000000000000000000000000000000000000000000000

    代码顺序2:

        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x11});
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x43});

//扫描结果
E/TAG: scandata:02011A05FFAC01345605038FAEE1FF05168FAE54110000000000000000000000000000000000000000000000000000000000000000000000000000000000

    代码顺序3:

        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x1A});
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x47});

//扫描结果
E/TAG: scandata:02011A05FFAC0134560503E1FF8FAE05168FAE541A0000000000000000000000000000000000000000000000000000000000000000000000000000000000

    代码顺序4:

        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceUuid( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"));
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"),new byte[]{0x22,0x48});
        mDataBuilder.addServiceData( ParcelUuid.fromString("0000ae8f-0000-1000-8000-00805f9b34fb"),new byte[]{0x54,0x1B});

//扫描结果
E/TAG: scandata:02011A05FFAC0134560503E1FF8FAE05168FAE541B0000000000000000000000000000000000000000000000000000000000000000000000000000000000

    情况2总结:从上面4个代码顺序的结果来看,总是扫描到 ae8f这个uuid对应的数据,没有第二个 server data,但是为什么每次都是ae8f?我TM也不知道!!

AdvertiseData介绍完毕,下面再稍微介绍一下 AdvertiseSettings

        AdvertiseSettings.Builder mSettingsbuilder = new AdvertiseSettings.Builder();
        mSettingsbuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        mSettingsbuilder.setConnectable(connectable);
        mSettingsbuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
        mSettingsbuilder.setTimeout(0);
        AdvertiseSettings mAdvertiseSettings = mSettingsbuilder.build();

 setAdvertiseMode(int advertiseMode)
         设置广播的模式,低功耗,平衡和低延迟三种模式;
         对应  AdvertiseSettings.ADVERTISE_MODE_LOW_POWER  ,ADVERTISE_MODE_BALANCED ,ADVERTISE_MODE_LOW_LATENCY
         从左右到右,广播的间隔会越来越短 

 setConnectable(boolean connectable)
          设置是否可以连接。
          广播分为可连接广播和不可连接广播,一般不可连接广播应用在iBeacon设备上,这样APP无法连接上iBeacon设备

 setTimeout(int timeoutMillis)
          设置广播的最长时间,最大值为常量AdvertiseSettings.LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000;  180秒
          设为0时,代表无时间限制会一直广播
 setTxPowerLevel(int txPowerLevel)
          设置广播的信号强度
          常量有AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,ADVERTISE_TX_POWER_LOW,ADVERTISE_TX_POWER_MEDIUM,ADVERTISE_TX_POWER_HIGH
          从左到右分别表示强度越来越强.
          举例:当设置为ADVERTISE_TX_POWER_ULTRA_LOW时,
          手机1和手机2放在一起,手机2扫描到的rssi信号强度为-56左右,
          当设置为ADVERTISE_TX_POWER_HIGH  时, 扫描到的信号强度为-33左右,
          信号强度越大,表示手机和设备靠的越近

     好了,关于BluetoothLeAdvertiser 的用法介绍完毕!!!!

可能有人会说,bluetoothAdapter.startLeScan(leScanCallback); 这个方法过时了怎么办,那可以看一下我的另一篇文章

《android BLE 扫描BLE设备 BluetoothLeScanner》

源码附件:

模拟BLE广播源码:http://pan.baidu.com/s/1bptOQyb

手机2扫描打印的源码就不放出了,很简单。

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

原文地址:https://www.cnblogs.com/Free-Thinker/p/9292183.html

时间: 2024-10-12 13:14:53

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser的相关文章

Android之监测手机网络状态的广播

Android之监测手机网络状态的广播 Android 监控网络状态 Android利用广播监听设备网络连接(断网)的变化情况

android BLE Peripheral 做外设模拟设备,供ios、android 连接通讯。

为了能让其它设备可以发现其设备,先启动特定广播.看自己需要什么广播格式. android 对外发出广播,都一样,只是更改其中的方法: android BLE Peripheral 模拟 ibeacon 发出ble 广播 开始广播: 增加使用BluetoothGattServer 1 public void startAdvertising(MockServerCallBack callBack) { 2 //获取BluetoothLeAdvertiser,BLE发送BLE广播用的一个API 3

android L BLE Peripheral牛刀小试

知道Android L对蓝牙对了一些改进,包括添加A2dp sink.HFP client.BLE Peripheral功能等等. 我花了一天多时间对Android L BLE Peripheral SDK进行了研究,网上的资料很少,有一个介绍的还不够清晰,所以就自己写了一个测试应用,希望可以对理解BLE Peripheral有一定的帮助. 此贴主要以讲解代码为主,我会把项目代码也传到CSDN中,帮助大家测试. 首先说明一点,并不是Android L的系统就可以支持BLE Peripheral,

android5.0(Lollipop) BLE Peripheral牛刀小试

转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46468743 知道Android L对蓝牙对了一些改进.包含加入A2dp sink.HFP client.BLE Peripheral功能等等. 我花了一天多时间对Android L BLE Peripheral SDK进行了研究,网上的资料非常少,有一个介绍的还不够清晰,所以就自己写了一个測试应用.希望能够对理解BLE Peripheral有一定的帮助. 此贴主要以解说代

详解BLE 空中包格式—兼BLE Link layer协议解析

BLE有几种空中包格式?常见的PDU命令有哪些?PDU和MTU的区别是什么?DLE又是什么?BLE怎么实现重传的?BLE ACK机制原理是什么?希望这篇文章能帮你回答以上问题. 虽然BLE空中包(packet)涉及BLE协议栈link layer,L2CAP,SMP和ATT等各层次,但link layer跟空中包格式关系最紧密,掌握了BLE packet的格式,就很容易理解BLE link layer协议的工作原理,因此文章取名"详解BLE空中包格式-兼BLE link layer协议解析&qu

Android 进程常驻(5)----开机广播的简单守护以及总结

这是一个轻量级的库,配置几行代码.就能够实如今android上实现进程常驻,也就是在系统强杀下,以及360获取root权限下.clean master获取root权限下都无法杀死进程 支持系统2.3到6.0 支持大部分设备,包含三星.华为.oppo,nexus.魅族等等 能够简单对开机广播进行保护 github地址: https://github.com/Marswin/MarsDaemon 原理分析: Android 进程常驻(0)----MarsDaemon使用说明 Android 进程常驻

Android中通过进程注入技术修改广播接收器的优先级

前言 这个周末又没有吊事,在家研究了如何通过进程的注入技术修改广播接收器的优先级,关于这个应用场景是很多的,而且也很重要,所以就很急的去fixed了. Android中的四大组件中有一个广播:Broadcast 关于它的相关知识可以转战:http://blog.csdn.net/jiangwei0910410003/article/details/19150705 我们这里就不做太多解释了,现在来看一下问题: 知识前提 这篇文章和我之前介绍一篇文章: Andrdoid中对应用程序的行为拦截实现方

Android中怎样做到自己定义的广播仅仅能有指定的app接收

今天没吊事.又去面试了,详细哪家公司就不说了,由于我在之前的blog中注明了那些家公司的名字,结果人家给我私信说我泄露他们的题目.好吧,我错了... 事实上当我们已经在工作的时候.我们能够在空暇的时间去面一面,由于面试有非常多优点的: 第一点:你知道这个公司的详细地址了,以后和朋友说的时候也是有话题的 第二点:这点非常重要.看看其它公司的面试题(如今有的公司还在採用笔试题这个环节.真心无语了.题目全是从网上找的,非常没有意思.所以我仅仅要见到有笔试题的一律pass,个人感觉面到如今,阿里和滴滴还

Android 通过adb shell am broadcast发送广播

Android 通过adb shell am broadcast发送广播 adb shell am broadcast 后面的参数有: [-a <ACTION>][-d <DATA_URI>][-t <MIME_TYPE>] [-c <CATEGORY> [-c <CATEGORY>] ...] [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...] [--ez <EXTRA_K