iOS BLE 開(kāi)發(fā)小記[3] - 如何實(shí)現(xiàn)一個(gè) Local Peripheral

歡迎訪問(wèn)我的博客 muhlenXi,該文章出自我的博客, 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明來(lái)源: http://muhlenxi.com/2017/05/01/iOS-Bluetooth-Low-Energy-Develop-Chapter3低剔。

導(dǎo)語(yǔ):

在這一節(jié)账蓉,你將會(huì)學(xué)到袱蚓,如何通過(guò) CoreBluetooth 框架來(lái)實(shí)現(xiàn) Local Peripheral 方面的功能和代理方法钞啸。

在 iOS BLE 開(kāi)發(fā)小記[2]中,你已經(jīng)學(xué)到了如何在 Central 方面去調(diào)用 BLE 的常用方法喇潘。在這一節(jié)中体斩,你將學(xué)習(xí)用 CoreBluetooth 框架來(lái)調(diào)用 Peripheral 方面 BLE 的常用方法。通過(guò)本文的示例代碼响蓉,將會(huì)引導(dǎo)你開(kāi)發(fā)一個(gè)將你的 Local 設(shè)備實(shí)現(xiàn)為 Local Peripheral硕勿。你將會(huì)從中學(xué)到:

  • 如何創(chuàng)建一個(gè) Peripheral Manager 對(duì)象
  • 如何為你的 Local Peripheral 設(shè)置 Services 和 Characteristics
  • 如何發(fā)布你的 Services 和 Characteristics 數(shù)據(jù)
  • 如何廣播你的設(shè)備
  • 如何對(duì)連接的 Central 做讀寫請(qǐng)求響應(yīng)
  • 如何發(fā)送更新后的值給訂閱的 Central

或許你發(fā)現(xiàn)示例代碼過(guò)于簡(jiǎn)單和抽象哨毁,你需要在你的 App 中做些恰當(dāng)?shù)木毩?xí)來(lái)掌握這些內(nèi)容。更高級(jí)的技巧和最佳實(shí)踐在后續(xù)的文章中將會(huì)講解。

Peripheral 實(shí)現(xiàn)詳情

創(chuàng)建一個(gè) Peripheral Manager 對(duì)象

在 Local Device(當(dāng)前設(shè)備)實(shí)現(xiàn) Peripheral 規(guī)范的第一步是分配(allocate)和初始化(initialize)一個(gè)周邊管理(Peripheral Manager)民傻,(用 CBPeripheralManager 對(duì)象表示)呀舔,通過(guò)調(diào)用 CBPeripheralManager 的 initWithDelegate:queue:options: 方法來(lái)創(chuàng)建管理對(duì)象,如下所示

myPeripheralManager =
        [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];

在示例代碼中话浇,設(shè)置 Delegate 為 self 是為了接收 Peripheral 的事件響應(yīng)脏毯,將參數(shù) dispatch queue 置為 nil。意味著 Peripheral Manager 將會(huì)在主隊(duì)列中分發(fā)事件幔崖。

當(dāng)你創(chuàng)建一個(gè) Peripheral Manger 對(duì)象時(shí)食店,Peripheral Manager 會(huì)通過(guò) peripheralManagerDidUpdateState: 方法來(lái)代理回調(diào),你必須實(shí)現(xiàn)這個(gè)代理方法來(lái)確保當(dāng)前設(shè)備是否支持 BLE 技術(shù)赏寇,關(guān)于代理方法的詳情可以查閱 CBPeripheralManagerDelegate Protocol Reference.

設(shè)置你的 Services 和 Characteristics

在第一節(jié)中吉嫩,我們了解到,一個(gè) Local Peripheral 采用樹(shù)形結(jié)構(gòu)來(lái)組織 Services 和 Characteristics 的數(shù)據(jù)嗅定。因此必須采用樹(shù)形結(jié)構(gòu)方式來(lái)設(shè)置 Local Peripheral 的 Services 和 Characteristics自娩。你第一步要做的是搞清和理解 Service 和 Characteristic 是如何標(biāo)識(shí)的。

通過(guò) UUID 標(biāo)識(shí) Services 和 Characteristics

Peripheral 的 Service 和 Characteristic 是通過(guò) 128 位的特定藍(lán)牙 UUID(通用唯一識(shí)別碼)來(lái)標(biāo)識(shí)的渠退,在 CoreBluetooth 中是用 CBUUID 對(duì)象來(lái)表示的忙迁。并不是所有的 UUID 都是通過(guò) Bluetooth Special Interest Group (藍(lán)牙特別興趣小組)預(yù)定義的。為了方便起見(jiàn)碎乃,Bluetooth SIG 定義和發(fā)布了許多通用的 16位 UUID姊扔。舉個(gè)例子,Bluetooth SIG 事先定義了一個(gè)16位的 UUID 用來(lái)標(biāo)識(shí)一個(gè)心率 Service梅誓,該 UUID 是 128位 UUID 0000180D-0000-1000-8000-00805F9B34FB 進(jìn)行縮減而來(lái)的恰梢,這是基于藍(lán)牙 4.0 規(guī)范中晨川,第 3 卷 F 部分第 3.2.1 節(jié)定義的藍(lán)牙基礎(chǔ) UUID。

CBUUID 提供了一個(gè)處理比較長(zhǎng)的 UUID 的工廠方法删豺,舉個(gè)例子共虑,生成一個(gè)表示心率 Service 的 UUID,可以調(diào)用 UUIDWithString 方法來(lái)通過(guò)預(yù)定義的 16位 UUID來(lái)創(chuàng)建 CBUUID 對(duì)象呀页。

CBUUID *heartRateServiceUUID = [CBUUID UUIDWithString: @"180D"];

當(dāng)你通過(guò)預(yù)定義的 16位 UUID 來(lái)創(chuàng)建 CBUUID 對(duì)象時(shí)妈拌,CoreBluetooth 會(huì)基于128位Bluetooth Base UUID 填充剩下的的 UUID 位。

為你定制的 Services 和 Characteristics 生成 UUID

你的 Service 和 Characteristic 的UUID也許可能沒(méi)有被 Bluetooth UUIDs 預(yù)定義蓬蝶,如果沒(méi)有被預(yù)定義尘分,你需要手動(dòng)生成你自己的 128位 UUID 來(lái)表示 Service 和 Characteristic。

通過(guò)命令行命令 uuidgen 可以生成 128位的 UUID丸氛,打開(kāi)你的 Terminal(終端)培愁,通過(guò)這種方式依次為你的 Services 和 Characteristics 生成一個(gè) UUID (用連字符連接起來(lái)的字符串)來(lái)標(biāo)識(shí)。舉例如下:

$ uuidgen
71DA3FD1-7E10-41C1-B16F-4430B506CDE7

你可以用上面方法生成的 UUID 調(diào)用 UUIDWithString 方法來(lái)創(chuàng)建一個(gè) CBUUID 對(duì)象缓窜。

 CBUUID *myCustomServiceUUID =
        [CBUUID UUIDWithString:@"71DA3FD1-7E10-41C1-B16F-4430B506CDE7"];
構(gòu)建你的 服務(wù)特征樹(shù)

當(dāng)你為每個(gè) Service 和 Characteristic 創(chuàng)建 CBUUID 對(duì)象后定续,你可以創(chuàng)建 mutable Service(可變服務(wù)) 和 mutable Characteristic(可變特征),然后以樹(shù)形的方式組織它們禾锤。舉個(gè)例子私股,如果你現(xiàn)在有一個(gè) Characteristic 的 UUID,你可以通過(guò)調(diào)用 CBMutableCharacteristic 類的 initWithType:properties:value:permissions: 方法生成一個(gè) mutable Characteristic恩掷。

myCharacteristic =
        [[CBMutableCharacteristic alloc] initWithType:myCharacteristicUUID
         properties:CBCharacteristicPropertyRead
         value:myValue permissions:CBAttributePermissionsReadable];

當(dāng)你創(chuàng)建 mutable Characteristic 的時(shí)候倡鲸,你可以指定它的 properties(屬性)、value(值)和 permissions(權(quán)限許可)黄娘,你指定的 properties 和 permissions 決定這個(gè) Characteristic 的值是否可以讀或者寫峭状,或者連接的 Central 能否訂閱該 Characteristic 的值。下面的示例中逼争,Characteristic 的值是被指定為可讀的优床。關(guān)于 mutable Characteristic 的 properties 和 permissions 詳情可以查閱 CBMutableCharacteristic Class Reference.

提示:如果你指定了 Characteristic 的值,那么該值將被緩存并且該 Characteristic 的 properties 和 permissions 將被設(shè)置為可讀的氮凝。因此羔巢,如果你需要 Characteristic 的值是可寫的,或者你希望在 Service 發(fā)布后罩阵,Characteristic 的值在 lifetime(生命周期)中依然可以更改竿秆,你必須將該 Characteristic 的值指定為 nil。通過(guò)這種方式可以確保 Characteristic 的值,在 Peripheral Manager 收到來(lái)自連接的 Central 的讀或者寫請(qǐng)求的時(shí)候稿壁,能夠被動(dòng)態(tài)處理幽钢。

既然你創(chuàng)建了一個(gè) mutable Characteristic,你也能通過(guò)調(diào)用 CBMutableService 類的 initWithType:primary: 方法創(chuàng)建一個(gè) mutable Service傅是。如下所示:

myService = [[CBMutableService alloc] initWithType:myServiceUUID primary:YES];

在示例代碼中匪燕,第二個(gè)參數(shù)被指定為 YES蕾羊,用來(lái)表明該 Service 是 Primary(主要的),而不是 secondary(次要的)帽驯。一個(gè) Primary Service 用來(lái)描述這個(gè)設(shè)備的主要功能龟再,還可以用來(lái)引用其他的 Service。一個(gè) Secondary Service 用來(lái)描述的是上下文中相關(guān)的或者被引用的 Service尼变。舉個(gè)例子利凑,從心率傳感器中獲取心率的服務(wù)是 primary Service,而獲取傳感器電量的服務(wù)就可以被視為 secondary Service 嫌术。

當(dāng)你創(chuàng)建完 Service 后哀澈。你需要設(shè)置 Service 的 Characteristic 數(shù)組屬性,如下:

myService.characteristics = @[myCharacteristic];

發(fā)送你的 Services 和 Characteristics

當(dāng)你構(gòu)建好服務(wù)特征樹(shù)后度气,下一步就是按照 BLE 的規(guī)范發(fā)布到設(shè)備的服務(wù)特征庫(kù)中割按,用 CoreBluetooth 可以很輕松的完成這一步,只需要調(diào)用 CBPeripheralManager類 的 addService: 方法就可以了磷籍。 示例代碼如下:

[myPeripheralManager addService:myService];

當(dāng)你調(diào)用該方法發(fā)布服務(wù)時(shí)适荣,Peripheral Manager 會(huì)調(diào)用 peripheralManager:didAddService:error: 方法進(jìn)行代理回調(diào),實(shí)現(xiàn)這個(gè)代理方法可以獲取到產(chǎn)生的錯(cuò)誤择示,示例代碼如下:

- (void)peripheralManager:(CBPeripheralManager *)peripheral
            didAddService:(CBService *)service
                    error:(NSError *)error {
    if (error) {
        NSLog(@"Error publishing service: %@", [error localizedDescription]);
    }
    // ...
}

提示:當(dāng)你發(fā)布 Service 和相關(guān)的 Characteristic 到 Peripheral 的數(shù)據(jù)庫(kù)中后束凑,設(shè)備已經(jīng)將數(shù)據(jù)緩存,你不能再改變它了栅盲。

廣播你的 Service

當(dāng)你發(fā)布你的 Service 和 Characteristic 到設(shè)備的服務(wù)特征庫(kù)時(shí),你可以廣播一些服務(wù)給正在監(jiān)聽(tīng)的 Central废恋,你可以通過(guò)調(diào)用 CBPeripheralManager 類的 startAdvertising: 方法來(lái)開(kāi)始廣播谈秫,傳入的字典是要廣播的數(shù)據(jù)。

[myPeripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey :
        @[myFirstService.UUID, mySecondService.UUID] }];

在示例代碼中鱼鼓,傳入的字典中唯一的 key 是 CBAdvertisementDataServiceUUIDsKey,用一個(gè)包含 CBUUID 對(duì)象的數(shù)組來(lái)表示你想要廣播的服務(wù)的 UUID拟烫。你在字典中可以指定的其他 key 在 Advertisement Data Retrieval Keys 中有詳細(xì)說(shuō)明。也就是說(shuō)迄本,僅有 CBAdvertisementDataLocalNameKeyCBAdvertisementDataServiceUUIDsKey 這兩個(gè) key 支持 Peripheral Manager 對(duì)象硕淑。

當(dāng)你在本地設(shè)備中廣播一些數(shù)據(jù)時(shí),Peripheral Manager 會(huì)通過(guò) peripheralManagerDidStartAdvertising:error: 方法來(lái)代理回調(diào)嘉赎。如果你的設(shè)備不能廣播而發(fā)生錯(cuò)誤時(shí)置媳,實(shí)現(xiàn)這個(gè)代理方法可以獲取產(chǎn)生的錯(cuò)誤:

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
                                       error:(NSError *)error {
 
    if (error) {
        NSLog(@"Error advertising: %@", [error localizedDescription]);
    }
    // ...
}

提示:廣播數(shù)據(jù)方法會(huì)被盡力執(zhí)行,因?yàn)榭臻g是有限的和多個(gè) APP 可能同時(shí)需要廣播數(shù)據(jù)公条,更多詳情可以查閱關(guān)于 startAdvertising: 方法的討論拇囊。

當(dāng)你的 APP 在后臺(tái)運(yùn)行時(shí)也會(huì)影響廣播的行為,這一內(nèi)容將會(huì)在下一篇中進(jìn)行討論靶橱。

響應(yīng) Central 的讀寫請(qǐng)求

當(dāng)你連接一個(gè)或多個(gè) Central 后寥袭,你可能會(huì)收到讀或者寫的請(qǐng)求路捧,對(duì)這些請(qǐng)求作出響應(yīng)需要采取恰當(dāng)?shù)姆绞剑旅娴氖纠a將會(huì)描述如何處理這些請(qǐng)求传黄。

當(dāng)一個(gè)連接的 Central 發(fā)送讀取某個(gè) Characteristic 數(shù)據(jù)的請(qǐng)求時(shí)杰扫,Peripheral Manager 會(huì)調(diào)用 peripheralManager:didReceiveReadRequest: 方法進(jìn)行代理回調(diào)。代理方法以 CBATTRequest 對(duì)象的方式來(lái)傳遞請(qǐng)求膘掰,它包含一些請(qǐng)求的屬性涉波。

比如,當(dāng)你收到一個(gè)讀取 Characteristic 值的簡(jiǎn)單請(qǐng)求時(shí)炭序,可以通過(guò)代理方法回調(diào)的 CBATTRequest 對(duì)像來(lái)判斷 Central 指定要讀取的 Characteristic 是否和設(shè)備服務(wù)庫(kù)中的 Characteristic 是否相匹配啤覆。你可以開(kāi)始實(shí)現(xiàn)這個(gè)代理方法,示例代碼如下:

- (void)peripheralManager:(CBPeripheralManager *)peripheral
    didReceiveReadRequest:(CBATTRequest *)request {
 
    if ([request.characteristic.UUID isEqual:myCharacteristic.UUID]) {
        // ...
    }
}

如果 Characteristic 的 UUID 能夠匹配惭聂,下一步就是確保讀取請(qǐng)求的位置沒(méi)有超出 Characteristic 的值的邊界窗声。如下面代碼所示,你可以通過(guò)使用 CBATTRequest 對(duì)象的 offset 屬性來(lái)確保讀取請(qǐng)求沒(méi)有嘗試讀取范圍之外的數(shù)據(jù)辜纲。

if (request.offset > myCharacteristic.value.length) {
    [myPeripheralManager respondToRequest:request
        withResult:CBATTErrorInvalidOffset];
    return;
}

假如讀取請(qǐng)求的 offset(偏移)已經(jīng)確認(rèn)笨觅,現(xiàn)在就可以設(shè)置請(qǐng)求的 Characteristic 的屬性(默認(rèn)值為 nil)為你設(shè)備中的 Characteristic 的值了,你應(yīng)該重視讀取請(qǐng)求的偏移:

request.value = [myCharacteristic.value
        subdataWithRange:NSMakeRange(request.offset,
        myCharacteristic.value.length - request.offset)];

設(shè)置完值后耕腾,通過(guò)調(diào)用 respondToRequest:withResult: 方法并傳入 request(更新值后的)和 請(qǐng)求的結(jié)果參數(shù)來(lái)對(duì) Remote Central 的請(qǐng)求作出響應(yīng)表示請(qǐng)求已經(jīng)被成功處理见剩。示例代碼如下:

[myPeripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
// ...

只要代理方法 peripheralManager:didReceiveReadRequest: 方法被回調(diào),就需要準(zhǔn)確的調(diào)用 respondToRequest:withResult: 方法扫俺。

提示:如果 Characteristic 的 UUID 不匹配苍苞,或者因?yàn)槟撤N原因不能完全讀取,不必去填充請(qǐng)求狼纬,直接調(diào)用 respondToRequest:withResult: 方法并提供一個(gè)表示失敗的結(jié)果即可羹呵。你可能指定的結(jié)果列表見(jiàn) CBATTError Constants 常量枚舉。

處理連接的 Central 寫入請(qǐng)求也比較易懂疗琉。當(dāng) Central 發(fā)送一個(gè)寫入請(qǐng)求給一個(gè)或多個(gè)你的 Characteristic 時(shí)冈欢,Peripheral Manager 會(huì)通過(guò) peripheralManager:didReceiveWriteRequests: 方法來(lái)代理回調(diào)。這是盈简,代理方法會(huì)傳遞一個(gè)包含一個(gè)或多個(gè) CBATTRequest 對(duì)象的數(shù)組給你凑耻,數(shù)組中的每個(gè)對(duì)象都代表一個(gè)寫入請(qǐng)求。當(dāng)你確定寫入請(qǐng)求能夠處理時(shí)柠贤,你可以設(shè)置 Characteristic 的值香浩,示例代碼如下:

myCharacteristic.value = request.value;

雖然上述例子沒(méi)有證明這一點(diǎn),但當(dāng)你給 Characteristic 寫數(shù)據(jù)的時(shí)候种吸,你應(yīng)該確保請(qǐng)求的 offset 屬性的范圍有效弃衍。

就像你響應(yīng)讀取請(qǐng)求一樣,只要代理方法 peripheralManager:didReceiveWriteRequest: 方法被回調(diào)坚俗,就需要準(zhǔn)確無(wú)誤的調(diào)用 respondToRequest:withResult: 方法镜盯。也就是說(shuō)岸裙,respondToRequest:withResult: 方法期望有一個(gè) CBATTRequest 對(duì)象,即使你可能通過(guò) peripheralManager:didReceiveWriteRequests: 代理方法接收到一個(gè)包含 CBATTRequest 對(duì)象的數(shù)組速缆,你也應(yīng)該傳入數(shù)組中的第一個(gè)對(duì)象降允,示例代碼如下:

[myPeripheralManager respondToRequest:[requests objectAtIndex:0]
        withResult:CBATTErrorSuccess];

提示:將多請(qǐng)求視為單一請(qǐng)求來(lái)對(duì)待,如果個(gè)別的請(qǐng)求不能被填充艺糜,你就不必填充其余的請(qǐng)求了剧董,直接調(diào)用 respondToRequest:withResult: 方法并提供一個(gè)表示失敗的結(jié)果即可。

發(fā)送更新 Characteristic 的通知給訂閱的 Central

連接的 Central 經(jīng)常會(huì)訂閱一個(gè)或多個(gè) Characteristic 的值破停,當(dāng)這些值發(fā)生變化時(shí)翅楼,你應(yīng)該發(fā)送通知給訂閱的 Central 。

當(dāng)一個(gè)連接的 Central 訂閱一個(gè)或多個(gè)你的 Characteristic 值時(shí)真慢,Peripheral Manager 會(huì)通過(guò) peripheralManager:central:didSubscribeToCharacteristic: 方法來(lái)代理回調(diào)毅臊。示例代碼如下:

- (void)peripheralManager:(CBPeripheralManager *)peripheral
                  central:(CBCentral *)central
didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
 
    NSLog(@"Central subscribed to characteristic %@", characteristic);
    // ...
}

將上述的代理方法作為一個(gè)線索來(lái)開(kāi)始給 Central 發(fā)送更新后的值。

接著黑界,獲取更新后的 Characteristic 的值管嬉,通過(guò)調(diào)用 CBPeripheralManager類的 updateValue:forCharacteristic:onSubscribedCentrals: 方法來(lái)給 Central 發(fā)送通知。示例代碼如下:

NSData *updatedValue = // fetch the characteristic's new value
BOOL didSendValue = [myPeripheralManager updateValue:updatedValue
    forCharacteristic:characteristic onSubscribedCentrals:nil];

當(dāng)你調(diào)用這個(gè)方法給訂閱的 Central 發(fā)送通知時(shí)朗鸠,你可以通過(guò)最后的那個(gè)參數(shù)來(lái)指定要發(fā)送的 Central蚯撩,示例代碼中的參數(shù)為 nil,表明將會(huì)發(fā)送通知給所有連接且訂閱的 Central烛占,沒(méi)有訂閱的 Central 則會(huì)被忽略胎挎。

updateValue:forCharacteristic:onSubscribedCentrals: 方法會(huì)返回一個(gè) Boolean 類型的值來(lái)表示通知是否成功的發(fā)送給訂閱的 Central 了,如果 base queue (基礎(chǔ)隊(duì)列)滿載扰楼,該方法會(huì)返回 NO呀癣,當(dāng)傳輸隊(duì)列存在更多空間時(shí),Peripheral Manager 則會(huì)調(diào)用 peripheralManagerIsReadyToUpdateSubscribers: 代理方法進(jìn)行回調(diào)弦赖。你可以實(shí)現(xiàn)這個(gè)代理方法,在方法中再次調(diào)用 updateValue:forCharacteristic:onSubscribedCentrals: 方法發(fā)送通知給訂閱的 Central浦辨。

提示:用通知發(fā)送單個(gè)數(shù)據(jù)包給訂閱的 Central蹬竖,就是說(shuō),一旦訂閱的 Central 發(fā)行更新時(shí)流酬,你就應(yīng)該調(diào)用 updateValue:forCharacteristic:onSubscribedCentrals: 方法用單一通知發(fā)送全部的更新值币厕。

并不是所有的數(shù)據(jù)都是通過(guò)通知來(lái)傳輸?shù)模@主要取決于你的 Characteristic 的值的大小芽腾,只有當(dāng) Central 調(diào)用
CBPeripheral類的 readValueForCharacteristic: 方法時(shí)旦装,你可以檢索全部的值。

參考文獻(xiàn)

1摊滔、Performing Common Peripheral Role Tasks

結(jié)束語(yǔ)

歡迎在本文下面留言一起交流心得...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阴绢,一起剝皮案震驚了整個(gè)濱河市店乐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呻袭,老刑警劉巖眨八,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異左电,居然都是意外死亡廉侧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門篓足,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)段誊,“玉大人,你說(shuō)我怎么就攤上這事栈拖×幔” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵辱魁,是天一觀的道長(zhǎng)烟瞧。 經(jīng)常有香客問(wèn)我,道長(zhǎng)染簇,這世上最難降的妖魔是什么参滴? 我笑而不...
    開(kāi)封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮锻弓,結(jié)果婚禮上砾赔,老公的妹妹穿的比我還像新娘。我一直安慰自己青灼,他們只是感情好暴心,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著杂拨,像睡著了一般专普。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弹沽,一...
    開(kāi)封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天檀夹,我揣著相機(jī)與錄音,去河邊找鬼策橘。 笑死炸渡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丽已。 我是一名探鬼主播蚌堵,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了吼畏?” 一聲冷哼從身側(cè)響起督赤,我...
    開(kāi)封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宫仗,沒(méi)想到半個(gè)月后够挂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藕夫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年孽糖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毅贮。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡办悟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滩褥,到底是詐尸還是另有隱情病蛉,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布瑰煎,位于F島的核電站铺然,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏酒甸。R本人自食惡果不足惜魄健,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望插勤。 院中可真熱鬧沽瘦,春花似錦、人聲如沸农尖。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盛卡。三九已至助隧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滑沧,已是汗流浹背喇颁。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚎货,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓蔫浆,卻偏偏與公主長(zhǎng)得像殖属,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓦盛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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