Android手機(jī)藍(lán)牙總結(jié)之低功耗藍(lán)牙

低功耗藍(lán)牙也就是藍(lán)牙4.0以后的版本登刺,在android手機(jī)是4.3以后才支持卢厂。在項(xiàng)目中,開始使用了傳統(tǒng)藍(lán)牙去進(jìn)行連接河劝,發(fā)現(xiàn)失敗了壁榕,始終沒辦法連接上。后來發(fā)現(xiàn)藍(lán)牙硬件是4.0后的藍(lán)牙版本丧裁,所以下面記錄下android4.3版本后的藍(lán)牙使用护桦。

首先,需要明白一些專業(yè)的術(shù)語煎娇,GATT二庵,characteristics,Properties缓呛,Descriptor催享,Service,UUID哟绊。

GATT

GATT是藍(lán)牙連接后讀寫藍(lán)牙數(shù)據(jù)的通用規(guī)范因妙。它基于ATT通訊協(xié)議(Attribute Protocol),目的是在傳輸信息過程中使用盡量少的數(shù)據(jù)票髓。在傳輸時(shí)攀涵,信息將以特征值(characteristics)和服務(wù)(services)的信息傳輸。這些信息都具有唯一的UUID洽沟。下面分別介紹一些基本概念以故。

characteristics

特征值●刹伲可以理解為一個(gè)數(shù)據(jù)類型怒详。包括一個(gè)值(Value),一個(gè)屬性(Property)和0至多個(gè)對值的描述(Descriptor)。

Properties

定義了characteristic的Value如何被使用踪区,以及characteristic的Descriptor如何被訪問昆烁。

Descriptor

是與Characteristic值相關(guān)的描述,例如范圍缎岗、計(jì)量單位等静尼。

Service

是Characteristic的集合。一個(gè)Service一般包含多個(gè)Characteristic。

UUID

唯一標(biāo)示符鼠渺,每個(gè)Service蜗元,Characteristic,Descriptor系冗,都一個(gè)唯一的UUID。以后在對它們操作時(shí)薪鹦,可以通過它們的UUID查找到對應(yīng)的Service掌敬,Characteristic或者Descriptor

判斷是否支持藍(lán)牙

 public boolean checkIfSupportBle() {
  return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);}

開啟藍(lán)牙

這里有兩種方式:

public void enableBluetooth(Activity activity) {
        if (bleAdapter == null || !bleAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }
    }
public void enableBluetooth() {
       if (bleAdapter == null || !bleAdapter.isEnabled()) {
         bleAdapter.enable();
      }
  }

掃描廣播包

有兩種方式獲得BluetoothAdapter
第一種通過先獲取BluetoothManager,然后獲得BlueAdapter

private BluetoothManager bleManager;
private BluetoothAdapter bleAdapter;
bleManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
bleAdapter = bleManager.getAdapter();

第二種是直接獲取BluetoothAdapter

BluetoothAdapter bleAdapter = BluetoothAdapter.getDefaultAdapter();

獲取藍(lán)牙匹配設(shè)備

public List<BluetoothDevice> getBoundDevices() {
        List<BluetoothDevice> devices = new ArrayList<>();
        Set<BluetoothDevice> boundDevices = bleAdapter.getBondedDevices();
        for (BluetoothDevice device : boundDevices) {
            //對device進(jìn)行其他操作池磁,比如連接等奔害。
            devices.add(device);
        }
        return devices;
    }

開始掃描

public void startLeScan(BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.startLeScan(leScanCallback);
    }
//加入藍(lán)牙過濾
public void startLeScan(UUID[] uuids, BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.startLeScan(uuids, leScanCallback);
    }

關(guān)閉藍(lán)牙搜索

 public void stopLeScan(BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.stopLeScan(leScanCallback);
    }

實(shí)現(xiàn)BluetoothAdapter.LeScanCallback接口

public class MyLeScanCallback implements BluetoothAdapter.LeScanCallback {
    private String mac;
    private Context mContext;
    private LeScanInterface leScanInterface;
    public MyLeScanCallback(Context mContext, String mac) {
        this.mac = mac;
        this.mContext = mContext;
    }

    public MyLeScanCallback(Context mContext) {
        this.mContext = mContext;
    }

    @Override
    public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
        String bleMac = bluetoothDevice.getAddress();
        if (TextUtils.equals(mac, bleMac)) {
            BleManager manager = BleManager.getInstance(mContext);
            manager.setDevice(bluetoothDevice);
        }
        if (leScanInterface != null) {
            leScanInterface.onMyLeScan(bluetoothDevice, i, bytes);
        }

    }

    public void setOnLeScan(LeScanInterface leScanInterface) {
        this.leScanInterface = leScanInterface;
    }

    /**
     * 藍(lán)牙掃描回調(diào)接口
     */
    public interface LeScanInterface {
        /**
         * 藍(lán)牙掃描回調(diào)
         * @param bluetoothDevice
         * @param i
         * @param bytes
         */
        void onMyLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes);
    }
}

Android5.0以后將藍(lán)牙搜索封裝成獨(dú)立的對象,新的寫法

BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); 
bluetoothLeScanner.startScan(mScanCallback);
private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult results) {
            super.onScanResult(callbackType, results);
            BluetoothDevice device = results.getDevice();
            if (!devices.contains(device)) {  //判斷是否已經(jīng)添加
                devices.add(device);//也可以添加devices.getName()到列表,這里省略            }
            // callbackType:回調(diào)類型
            // result:掃描的結(jié)果地熄,不包括傳統(tǒng)藍(lán)牙        }
    };

支持不同版本的寫法

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        ...
        //定義的低于android5.0掃描方法
        startScan()
    } else {
        ...
        //定義的高于android5.0掃描方法
        startLeScan()
    }

建立藍(lán)牙連接

/**
     * 連接藍(lán)牙設(shè)備
     *
     * @param auto
     * @param mGattCallback
     * @return
     */
    public BluetoothGatt connectDevice(boolean auto, BluetoothGattCallback mGattCallback) {
        bleGatt = device.connectGatt(mContext, auto, mGattCallback);
        Log.e(TAG, "生成BluetoothGatt----->" + this.bleGatt);
        return bleGatt;
    }

獲取device

/**
     * 通過mac地址直接得到BluetoothDevice
     *
     * @param mac
     * @return
     */
    public BluetoothDevice getRemoteDevice(String mac) {
        device = bleAdapter.getRemoteDevice(mac);
        return device;
    }

繼承BluetoothGattCallback類华临,復(fù)寫相關(guān)的方法

public class BleGattCallback extends BluetoothGattCallback {
    private static final String TAG = BleGattCallback.class.getName();
    private Context mContext;
    private CharacterInterface characterInterface;
    private BleStateInterface bleStateInterface;

    public BleGattCallback(Context mContext) {
        this.mContext = mContext;
    }

    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            Log.e(TAG, "成功建立藍(lán)牙通道");
            if (newState == BluetoothProfile.STATE_CONNECTED) {
            //發(fā)現(xiàn)服務(wù)
                gatt.discoverServices();
                Log.e(TAG, "藍(lán)牙連接成功!");
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.e(TAG, "藍(lán)牙連接斷開!");
            }
            if (bleStateInterface != null) {
                bleStateInterface.onConnectedChange(newState);
            }
        } else {
            Log.e(TAG, "建立藍(lán)牙通道失敗");
            if (bleStateInterface != null) {
                bleStateInterface.onBleGattStatus(status);
            }

        }

    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            BleManager.getInstance(mContext).enableNotification(gatt, true);
        }
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
            characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        BleManager.getInstance(mContext).writeData();
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
            characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        if (characterInterface != null) {
            characterInterface.notifyChanged(gatt, characteristic);
        }
    }


    public void setOnCharacterInterface(CharacterInterface characterInterface) {
        this.characterInterface = characterInterface;
    }

    public void setOnConnectedChange(BleStateInterface bleStateInterface) {
        this.bleStateInterface = bleStateInterface;
    }

    public interface CharacterInterface {
        /**
         * 特征值改變通知
         *
         * @param gatt
         * @param characteristic
         */
        void notifyChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic);
    }

    public interface BleStateInterface {
        /**
         * 藍(lán)牙連接狀態(tài),注意回調(diào)方法不在主線程
         *
         * @param newState
         */
        void onConnectedChange(int newState);

        /**
         * 藍(lán)牙通道建立狀態(tài)回調(diào)端考,失敗的話需要關(guān)閉BlueToothGatt和BlueToothService,然后重新調(diào)用藍(lán)牙重連
         *
         * @param status
         */
        void onBleGattStatus(int status);


    }
}

封裝成完整的類

public class BleManager {
    private BluetoothAdapter bleAdapter;
    private BluetoothManager bleManager;
    private BluetoothGatt bleGatt;
    private BluetoothGattService gattService;
    private BluetoothDevice device;
    private Context mContext;
    private static volatile BleManager singleton;
    private final int REQUEST_ENABLE_BT = 1;
    private StringBuffer buffer = new StringBuffer();
    private String TAG = getClass().getName();

    private BleManager(Context mContext) {
        this.mContext = mContext;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            bleManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
            bleAdapter = bleManager.getAdapter();
        } else {
            bleAdapter = BluetoothAdapter.getDefaultAdapter();
        }
    }

    /**
     * 獲取藍(lán)牙管理類的單例
     *
     * @param context
     * @return
     */
    public static BleManager getInstance(Context context) {
        if (singleton == null) {
            synchronized (BleManager.class) {
                if (singleton == null) {
                    singleton = new BleManager(context);
                }
            }
        }
        return singleton;
    }

    /**
     * 判斷是否支持藍(lán)牙設(shè)備
     *
     * @return
     */
    public boolean checkIfSupportBle() {
        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
    }

    /**
     * 開啟藍(lán)牙設(shè)備
     */
    public void enableBluetooth(Activity activity) {
        if (bleAdapter == null || !bleAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }
    }


    public void enableBluetooth() {
        if (bleAdapter == null || !bleAdapter.isEnabled()) {
            bleAdapter.enable();
        }
    }


    /**
     * 獲取藍(lán)牙綁定了的列表設(shè)備
     */
    public List<BluetoothDevice> getBoundDevices() {
        List<BluetoothDevice> devices = new ArrayList<>();
        Set<BluetoothDevice> boundDevices = bleAdapter.getBondedDevices();
        for (BluetoothDevice device : boundDevices) {
            //對device進(jìn)行其他操作雅潭,比如連接等。
            devices.add(device);
        }
        return devices;
    }

    /**
     * 通用藍(lán)牙掃描方法却特,持續(xù)時(shí)間大概10s扶供,掃描到藍(lán)牙發(fā)出廣播進(jìn)行接收
     */
    public void startDiscover() {
        bleAdapter.startDiscovery();
    }

    /**
     * 該方法目前穩(wěn)定
     *
     * @param leScanCallback
     */
    public void startLeScan(BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.startLeScan(leScanCallback);
    }

    /**
     * 通過UUID過濾篩選出合適的藍(lán)牙設(shè)備
     *
     * @param uuids
     * @param leScanCallback
     */
    public void startLeScan(UUID[] uuids, BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.startLeScan(uuids, leScanCallback);
    }

    /**
     * 代替果實(shí)的startLeScan(),但是不穩(wěn)定
     *
     * @param scanCallback
     */
    @RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
    public void startBleScan(ScanCallback scanCallback) {
        bleAdapter.getBluetoothLeScanner().startScan(scanCallback);
    }

    /**
     * 關(guān)閉藍(lán)牙搜索
     *
     * @param leScanCallback
     */
    public void stopLeScan(BluetoothAdapter.LeScanCallback leScanCallback) {
        bleAdapter.stopLeScan(leScanCallback);
    }

    /**
     * 藍(lán)牙是否開啟
     *
     * @return
     */
    public boolean isOpen() {
        return bleAdapter.isEnabled();
    }

    /**
     * 關(guān)閉藍(lán)牙設(shè)備
     *
     * @param scanCallback
     */
    @RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
    public void stopBleScan(ScanCallback scanCallback) {
        bleAdapter.getBluetoothLeScanner().stopScan(scanCallback);
    }

    public void setBleGatt(BluetoothGatt bleGatt) {
        this.bleGatt = bleGatt;
    }

    public void setGattService(BluetoothGattService gattService) {
        this.gattService = gattService;
    }

    public BluetoothGatt getBleGatt() {
        return bleGatt;
    }

    public BluetoothGattService getGattService() {
        return gattService;
    }

    public BluetoothDevice getDevice() {
        return device;
    }

    public void setDevice(BluetoothDevice device) {
        this.device = device;
    }

    /**
     * 開啟藍(lán)牙設(shè)備
     */
    public void openBle() {
        bleAdapter.enable();
    }

    /**
     * 關(guān)閉藍(lán)牙設(shè)備
     */
    public void closeBle() {
        bleAdapter.disable();
    }

    /**
     * 通過mac地址直接得到BluetoothDevice
     *
     * @param mac
     * @return
     */
    public BluetoothDevice getRemoteDevice(String mac) {
        device = bleAdapter.getRemoteDevice(mac);
        return device;
    }

    /**
     * 連接藍(lán)牙設(shè)備
     *
     * @param auto
     * @param mGattCallback
     * @return
     */
    public BluetoothGatt connectDevice(boolean auto, BluetoothGattCallback mGattCallback) {
        bleGatt = device.connectGatt(mContext, auto, mGattCallback);
        Log.e(TAG, "生成BluetoothGatt----->" + this.bleGatt);
        return bleGatt;
    }

    /**
     * 獲取對應(yīng)應(yīng)用的服務(wù)
     * @return
     */
    public BluetoothGattService getDefaultGattService() {
        this.gattService = bleGatt.getService(UUID.fromString(UUIDManager.SERVICE_UUID));
        return gattService;
    }


    @SuppressLint ("NewApi")
    public boolean enableNotification(BluetoothGatt bluetoothGatt, boolean enable) {
        if (gattService == null) {
            getDefaultGattService();
        }
        BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID.fromString(UUIDManager.NOTIFY_UUID));
        if (bluetoothGatt == null || characteristic == null) {
            return false;
        }
        if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) {
            return false;
        }
        //獲取到Notify當(dāng)中的Descriptor通道  然后再進(jìn)行注冊
        BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(UUIDManager.NOTIFY_DESCRIPTOR));
        if (clientConfig == null) {
            return false;
        }
        if (enable) {
            clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        } else {
            clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
        }
        return bluetoothGatt.writeDescriptor(clientConfig);
    }

    /**
     * 藍(lán)牙設(shè)備傳數(shù)據(jù)
     *
     * @param data
     * @return
     */
    private boolean writeBluetoothData(String data) {
        BluetoothGattCharacteristic writeCharacter = null;
        if (gattService == null) {
            gattService = getDefaultGattService();
            if (gattService == null) {
                return false;
            }
        }
        writeCharacter = gattService.getCharacteristic(UUID.fromString(UUIDManager.WRITE_UUID));
        // 設(shè)置監(jiān)聽
        this.bleGatt.setCharacteristicNotification(writeCharacter, true);
        // 當(dāng)數(shù)據(jù)傳遞到藍(lán)牙之后
        // 會(huì)回調(diào)BluetoothGattCallback里面的write方法
        writeCharacter.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
        // 將需要傳遞的數(shù)據(jù) 打碎成16進(jìn)制
        try {
            writeCharacter.setValue(CommonUtils.getHexBytes(data));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return this.bleGatt.writeCharacteristic(writeCharacter);
    }

    /**
     * 向藍(lán)牙設(shè)備寫入數(shù)據(jù)
     */
    public void writeData(String content) {
        buffer.append(content);
        writeData();
    }

    public void writeData() {
        int length = buffer.length();
        String writeData = "";
        if (length >= 20) {
            writeData = buffer.substring(0, 20);
        } else {
            writeData = buffer.toString();
        }
        if (writeData.length() > 0) {
            writeBluetoothData(writeData);
        }
        if (writeData.length() > 0) {
            buffer.delete(0, writeData.length());
        }
    }


    /**
     * 關(guān)閉藍(lán)牙連接
     */
    public void closeGatt() {
        if (bleGatt != null) {
            bleGatt.disconnect();
            bleGatt.close();
            Log.e(TAG, "連接藍(lán)牙斷開bleGatt" + this.bleGatt);
            Log.e(TAG, "連接藍(lán)牙斷開gattService" + this.gattService);
            bleGatt = null;
            gattService = null;
        }
    }
}

UUID的獲取

一般而言UUID會(huì)由硬件工程師提供的,但是有時(shí)候硬件工程師也不知道裂明,這時(shí)就需要自己去檢測了椿浓。首先通過尋找服務(wù)Service的UUID,然后通過找出特征值的UUID闽晦,并且判斷特征值的UUID的屬性是讀扳碍,寫還是通知。也可以可以借助引用nRF Connect連接藍(lán)牙得到相應(yīng)的值仙蛉。

/**
     * 展示服務(wù)Services和characteristic對應(yīng)的UUID晋修,以及具備的屬性恩沛。
     *
     * @param gattServices
     */
    public boolean queryGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null) {
            return false;
        }
        for (BluetoothGattService myService : gattServices) {
        //找出服務(wù)的UUID
            String uuId = myService.getUuid().toString();
              List<BluetoothGattCharacteristic> gattCharacteristics =myService.getCharacteristics();  
            for (final BluetoothGattCharacteristic  gattCharacteristic: gattCharacteristics) {  
                Log.e(TAG,"---->char uuid:"+gattCharacteristic.getUuid());  

                int charaProp = gattCharacteristic.getProperties();  
               //所有Characteristics按屬性分類
               if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                     Log.d(TAG, "gattCharacteristic的UUID為:" + gattCharacteristic.getUuid());
                     Log.d(TAG, "gattCharacteristic的屬性為:  可讀");
                    }
               if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {
                            Log.d(TAG, "gattCharacteristic的UUID為:" + gattCharacteristic.getUuid());
                            Log.d(TAG, "gattCharacteristic的屬性為:  可寫");
                        }
               if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                            Log.d(TAG, "gattCharacteristic的UUID為:" + gattCharacteristic.getUuid() + gattCharacteristic);
                            Log.d(TAG, "gattCharacteristic的屬性為:  具備通知屬性");
                        }
                   }
               return false;
        }
    }

這樣就能找到對應(yīng)服務(wù)的UUID和特征值characteristic的UUID,從而進(jìn)行相應(yīng)的讀寫和通知的操作。讀寫通知有可能公用一個(gè)通道苞慢,即特征值UUID有可能相同,但是這不影響通信穗泵。對于外部藍(lán)牙硬件瓮孙,一般通過通知的方式,接收返回的數(shù)據(jù)麸祷,開啟藍(lán)牙通知的方式為BleManager的enableNotification()方法澎怒。
補(bǔ)充藍(lán)牙讀的寫法:

bleGatt.readCharacteristic(characteristic);

如果要使用,放在BluetoothGattCallback復(fù)寫方法onCharacteristicRead()方法下進(jìn)行邏輯操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喷面,一起剝皮案震驚了整個(gè)濱河市星瘾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惧辈,老刑警劉巖琳状,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盒齿,居然都是意外死亡念逞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門边翁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翎承,“玉大人,你說我怎么就攤上這事符匾∵犊В” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵啊胶,是天一觀的道長甸各。 經(jīng)常有香客問我,道長创淡,這世上最難降的妖魔是什么痴晦? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮琳彩,結(jié)果婚禮上誊酌,老公的妹妹穿的比我還像新娘。我一直安慰自己露乏,他們只是感情好碧浊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘟仿,像睡著了一般箱锐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上劳较,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天驹止,我揣著相機(jī)與錄音,去河邊找鬼观蜗。 笑死臊恋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的墓捻。 我是一名探鬼主播抖仅,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了撤卢?” 一聲冷哼從身側(cè)響起环凿,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎放吩,沒想到半個(gè)月后智听,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渡紫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年瞭稼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腻惠。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖欲虚,靈堂內(nèi)的尸體忽然破棺而出集灌,到底是詐尸還是另有隱情,我是刑警寧澤复哆,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布欣喧,位于F島的核電站,受9級(jí)特大地震影響梯找,放射性物質(zhì)發(fā)生泄漏唆阿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一锈锤、第九天 我趴在偏房一處隱蔽的房頂上張望驯鳖。 院中可真熱鬧,春花似錦久免、人聲如沸浅辙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽记舆。三九已至,卻和暖如春呼巴,著一層夾襖步出監(jiān)牢的瞬間泽腮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工衣赶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诊赊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓屑埋,卻偏偏與公主長得像豪筝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容