iBeacon 應(yīng)用實(shí)例

iBeacon是什么?

??? 蘋果官方對(duì)iBeacon的描述:iBeacon是iOS 7推出的一項(xiàng)技術(shù),可為APP提供新的位置感知功能。利用藍(lán)牙低功耗(BLE)骆莹,具有iBeacon技術(shù)的設(shè)備可用于在對(duì)象周圍建立區(qū)域。這允許iOS設(shè)備確定它何時(shí)進(jìn)入或離開(kāi)該區(qū)域担猛,以及估計(jì)與信標(biāo)的接近度幕垦。在使用iBeacon技術(shù)時(shí)丢氢,需要考慮硬件和軟件組件,本文檔將介紹這兩者先改,以及建議的用途和最佳實(shí)踐疚察,以幫助確保高效部署,從而實(shí)現(xiàn)出色的用戶體驗(yàn)仇奶。

采用iBeacon技術(shù)的設(shè)備

???采用iBeacon技術(shù)的設(shè)備可以使用紐扣電池供電一個(gè)月或更長(zhǎng)時(shí)間貌嫡,或者使用更大的電池一次運(yùn)行數(shù)月,或者可以在外部長(zhǎng)時(shí)間供電该溯。iOS設(shè)備也可以配置為生成iBeacon廣告岛抄,但此功能的范圍有限。iBeacon廣告通過(guò)藍(lán)牙低功耗提供以下信息:

image.png

???UUID狈茉,主要和次要值提供iBeacon的標(biāo)識(shí)信息夫椭。該信息本質(zhì)上是分層的,主要和次要字段允許細(xì)分由UUID建立的身份氯庆〔淝铮可以使用OS X中的uuidgen命令行實(shí)用程序生成UUID,也可以使用NSUUID Foundation類以編程方式生成UUID堤撵。

iBeacon軟件 - 核心位置API

???在iOS 7之前感凤,核心位置使用由地理位置(緯度和經(jīng)度)和半徑定義的區(qū)域,稱為“地理圍欄”粒督。通過(guò)定義具有標(biāo)識(shí)符的區(qū)域,iBeacon實(shí)現(xiàn)了新的靈活性禽翼。這允許將信標(biāo)附加到不綁定到單個(gè)位置的對(duì)象上屠橄。例如,信標(biāo)設(shè)備可用于設(shè)置諸如食物卡車或游輪之類的可移動(dòng)物體周圍的區(qū)域闰挡。此外锐墙,多個(gè)設(shè)備可以使用相同的標(biāo)識(shí)符。這將使零售連鎖店能夠在其所有位置使用信標(biāo)长酗,并允許iOS設(shè)備知道何時(shí)進(jìn)入其中任何一個(gè)溪北。隱私和位置由于iBeacon是Core Location的一部分,因此需要相同的用戶授權(quán)才能使用夺脾。當(dāng)APP嘗試使用iBeacon API時(shí)之拨,用戶將看到相同的位置授權(quán)警報(bào):

image.png

???在CoreLocation中使用信標(biāo)區(qū)域API的APP將顯示在“隱私”>“位置服務(wù)”下的“設(shè)置”APP中,用戶可以隨時(shí)允許或拒絕APP訪問(wèn)iBeacon功能咧叭。此外蚀乔,任何與iBeacon關(guān)聯(lián)的藍(lán)牙數(shù)據(jù)包都將從CoreBluetooth API中排除。
???與地理圍欄區(qū)域監(jiān)控一樣菲茬,當(dāng)處于活動(dòng)狀態(tài)時(shí)吉挣,狀態(tài)欄將顯示空心箭頭派撕。使用測(cè)距時(shí),狀態(tài)欄將顯示實(shí)心位置箭頭睬魂。

iBeacon的準(zhǔn)確性

???當(dāng)iOS設(shè)備檢測(cè)到信標(biāo)的信號(hào)時(shí)终吼,它使用信號(hào)的強(qiáng)度(RSSI或接收信號(hào)強(qiáng)度指示)來(lái)確定信標(biāo)的接近度以及其估計(jì)接近度的準(zhǔn)確性。信號(hào)越強(qiáng)氯哮,iOS對(duì)信標(biāo)的接近程度就越高际跪。信號(hào)越弱,iOS對(duì)信標(biāo)的接近程度越低蛙粘。
???當(dāng)iOS設(shè)備可以清晰地接收GPS信號(hào)時(shí)垫卤,例如當(dāng)設(shè)備處于戶外開(kāi)放狀態(tài)且軌道GPS衛(wèi)星的視線暢通時(shí),你的位置就可以更準(zhǔn)確地確定出牧。

區(qū)域監(jiān)測(cè)

???與現(xiàn)有的地理圍欄區(qū)域監(jiān)視類似穴肘,APP可以在設(shè)備進(jìn)入或離開(kāi)由信標(biāo)定義的區(qū)域時(shí)請(qǐng)求通知。當(dāng)APP使該請(qǐng)求開(kāi)始監(jiān)視信標(biāo)區(qū)域時(shí)舔痕,它必須指定iBeacon廣播包的UUID评抚。雖然APP僅限于20個(gè)受監(jiān)控區(qū)域,但通過(guò)在多個(gè)位置使用單個(gè)UUID伯复,設(shè)備可以輕松地同時(shí)監(jiān)控多個(gè)物理位置慨代。

???除了UUID之外,APP還可以選擇提供主要和次要字段啸如,以進(jìn)一步指定要監(jiān)視的信標(biāo)區(qū)域侍匙。假設(shè)我們指定一塊區(qū)域,如果APP僅為信標(biāo)區(qū)域指定UUID叮雳,則當(dāng)進(jìn)入或離開(kāi)該區(qū)域時(shí)將會(huì)通知它想暗。由于主要字段用于確定特定區(qū)域,如果只是在進(jìn)入該區(qū)域時(shí)得到通知帘不,APP可以使用UUID +主要值來(lái)配置信標(biāo)區(qū)域说莫。如果只想在進(jìn)入該區(qū)域的指定位置時(shí)收到通知,APP可以使用顆粒度更細(xì)的值來(lái)配置信標(biāo)寞焙,即:UUID + major + minor的組合储狭。

應(yīng)用實(shí)例

1.BLE設(shè)備數(shù)據(jù)同步

??? BLE設(shè)備與APP配對(duì)成功之后,為該設(shè)備注冊(cè)IBeacon信標(biāo)捣郊。此時(shí)設(shè)備通過(guò)廣播包把數(shù)據(jù)點(diǎn)傳給APP辽狈,APP再開(kāi)啟HTTP請(qǐng)求上傳數(shù)據(jù)點(diǎn)到云端。當(dāng)iPhone與BLE設(shè)備斷連的時(shí)候模她,數(shù)據(jù)同步中斷稻艰。當(dāng)iPhone再次進(jìn)入設(shè)備藍(lán)牙有效距離內(nèi),設(shè)備發(fā)送IBeacon廣播包侈净,此廣播包與傳輸數(shù)據(jù)點(diǎn)的廣播包不同尊勿,它的作用是用來(lái)喚醒APP僧凤,它必須帶有特定標(biāo)識(shí)的UUID,當(dāng)iPhone監(jiān)聽(tīng)到IBeacon廣播包中的UUID元扔,與注冊(cè)信標(biāo)的UUID相同時(shí)躯保,發(fā)起設(shè)備掃描并恢復(fù)連接狀態(tài),同步數(shù)據(jù)澎语。

??? IBeacon喚醒設(shè)備的能力非常強(qiáng)大途事,鎖屏、后臺(tái)掛起擅羞、kill都能喚醒APP尸变。
代碼示例:

// 初始化 Location
- (CLLocationManager *)locationManager {
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
        _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        _locationManager.distanceFilter = kCLDistanceFilterNone;
//        _locationManager.allowsBackgroundLocationUpdates = YES;
        _locationManager.pausesLocationUpdatesAutomatically = NO;
    }
    return _locationManager;
}

// 注冊(cè)IBeacon監(jiān)聽(tīng)
- (void)startIbeaconMonitorWithUUID:(NSString *)uuid devId:(NSString *)devId {
    
    if (![PHBleUnlockUtil isValidUUID:uuid]) {
        return;
    }
    
    if (![self checkIBeacon:devId]) {
        return;
    }
    NSString *ibeaconIdentifer = [PHBleUnlockUtil ibeaconRegionIdentifierWithDevId:devId];
    CLBeaconRegion *ibeacon = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:[PHBleUnlockUtil generatedStandardUUIDWithDeviceUUID:uuid]] identifier:ibeaconIdentifer];
    ibeacon.notifyOnEntry = YES;
    ibeacon.notifyOnExit = YES;
    ibeacon.notifyEntryStateOnDisplay = YES;
    
    // 系統(tǒng)框架會(huì)根據(jù)identifier和Region類型自動(dòng)替換,不用手動(dòng)先stop stopMonitoringForRegion停止IBeacon監(jiān)聽(tīng)。這是異步完成的减俏,可能不會(huì)立即反映在MonitoredRegions中
    [self.locationManager stopMonitoringForRegion:ibeacon];
    [self.locationManager startMonitoringForRegion:ibeacon];
}

// 移除單個(gè)IBeacon監(jiān)聽(tīng)
- (void)stopIbeaconMonitorWithDevId:(NSString *)devId {
   
 NSSet *monitoredRegions = [self.locationManager monitoredRegions];
    for (CLRegion *rg in monitoredRegions) {
        if ([rg isMemberOfClass:[CLBeaconRegion class]] && [rg.identifier containsString:devId]) {
            [self.locationManager stopMonitoringForRegion:rg];
            break;
        }
    }
}

// check 當(dāng)前設(shè)備是否已注冊(cè)過(guò)IBeacon
- (BOOL)checkIBeacon:(NSString *)devId {
    
    NSSet *regions = [self.locationManager monitoredRegions];
    
    // 系統(tǒng)允許IBeacon注冊(cè)上線為20個(gè)召烂,達(dá)到20個(gè)批量移除,再添加
    if (regions.count == kBleIBeaconMonitorMaxCount) {
        [self removeIbeaconAllMonitors];
        return [self checkIBeacon:devId];
    } else {
        for (CLRegion *rg in regions) {
            if ([rg isMemberOfClass:[CLBeaconRegion class]]) {
                NSString *identifier = rg.identifier;
                // 該設(shè)備已經(jīng)注冊(cè)過(guò)IBeacon娃承,不再注冊(cè)
                if ([identifier containsString:L(devId)]) {
                    return NO;
                }
            }
        }
        return YES;
    }
}

// 移除所有IBeacon監(jiān)聽(tīng)
- (void)removeIbeaconAllMonitors {
    
    NSSet *regions = [self.locationManager monitoredRegions];
    for (CLRegion *rg in regions) {
        if ([rg isMemberOfClass:[CLBeaconRegion class]]) {
            [self.locationManager stopMonitoringForRegion:rg];
        }
    }
}

// 發(fā)起設(shè)備連接
- (void)repeatBleStartListening:(NSString *)devId {
    
    BOOL connectedCompleted = [self bleConnectedCompletedStatusWithDevId:devId];
    if (!connectedCompleted) {
        NSLog(@"---??ibeacon----50秒后藍(lán)牙重連");
        //  設(shè)備重連
        [self removeBleConnectedCompletedStatusWithDevId:devId];
    }
}

// 設(shè)置當(dāng)前設(shè)備的狀態(tài)為連接中
- (void)setupBleConnectedCompletedWithDevId:(NSString *)devId {
    [self.bleConnectedCompletedList setObject:@(YES) forKey:devId];
}

// 獲取當(dāng)前設(shè)備的連接狀態(tài)
- (BOOL)bleConnectedCompletedStatusWithDevId:(NSString *)devId {
    return [[self.bleConnectedCompletedList valueForKey:devId] boolValue];
}

// 移除當(dāng)前設(shè)備的連接狀態(tài)
- (void)removeBleConnectedCompletedStatusWithDevId:(NSString *)devId {
    return [self.bleConnectedCompletedList removeObjectForKey:devId];
}

// 重置設(shè)備連接狀態(tài)
- (void)resetStatesWithIdentifier:(NSString *)identifier {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.handleBeaconList setValue:@(NO) forKey:identifier];
        self.needRequestStateForRegion = YES;
        
    });
}
#pragma mark - backgroup task
- (void)beginBackgroundUpdateTask {
    
    weakify(self);
    self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        strongify(self);
        [self endBackgroundUpdateTask];
    }];
}

- (void)endBackgroundUpdateTask {
    [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
    self.backgroundTaskId = UIBackgroundTaskInvalid;
}

#pragma mark - CLLocationManagerDelegate

// notifyOnEntry:缺省為NO奏夫。設(shè)置為YES時(shí),當(dāng)用戶進(jìn)入一個(gè)iBeaconRegion內(nèi)历筝,無(wú)論此應(yīng)用處于什么狀態(tài)酗昼,調(diào)用此委托方法
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    
    if ([region isMemberOfClass:[CLBeaconRegion class]]) {
        NSLog(@"---??ibeacon----進(jìn)入IBeacon區(qū)域-----%@", region.identifier);
    }
}

// notifyOnExit:缺省為NO。設(shè)置為YES時(shí)梳猪,當(dāng)用戶進(jìn)入一個(gè)iBeaconRegion內(nèi)麻削,無(wú)論此應(yīng)用處于什么狀態(tài),調(diào)用此委托方法
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    
    if ([region isMemberOfClass:[CLBeaconRegion class]]) {
        NSLog(@"---??ibeacon----離開(kāi)IBeacon區(qū)域-----%@", region.identifier);
    }
}

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    
    if ([region isMemberOfClass:[CLBeaconRegion class]]) {
        NSLog(@"---??ibeacon----發(fā)起監(jiān)聽(tīng)成功-----%@", region.identifier);
    }
}

- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(nullable CLRegion *)region withError:(NSError *)error {
    
    if ([region isMemberOfClass:[CLBeaconRegion class]]) {
        NSLog(@"---??ibeacon----監(jiān)聽(tīng)失敗-----%@", region.identifier);
    }
}

// notifyEntryStateOnDisplay:缺省為NO春弥。設(shè)置為YES時(shí)碟婆,當(dāng)屏幕點(diǎn)亮且在一個(gè)iBeaconRegion內(nèi),無(wú)論此應(yīng)用處于什么狀態(tài)惕稻,調(diào)用此委托方法
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
    
    if (![region isMemberOfClass:[CLBeaconRegion class]]) {
        return;
    }
    NSLog(@"---??ibeacon----觸發(fā)-----%ld--%@", (long)state, region.identifier);
    NSString *identifier = region.identifier;
    NSArray<NSString *> *identifierInfos = [region.identifier componentsSeparatedByString:@"_"];
    
    if (identifierInfos.count != kBleUnlockReginIdentifierElementCount) {
        return;
    }
    
    switch (state) {
        case CLRegionStateInside: {
            
            BOOL isHandling = [[self.handleBeaconList objectForKey:identifier] boolValue];
            if (isHandling) {
                return;
            }
            [self.handleBeaconList setValue:@(YES) forKey:identifier];
            //            NSString *pid = [identifierInfos objectAtIndex:0];
            NSString *devId = [identifierInfos objectAtIndex:1];
            //            NSString *uid = [identifierInfos objectAtIndex:3];
            
            NSLog(@"will find device %@", devId);
            NSTimeInterval limitSeconds = [NSDate dateWithTimeIntervalSinceNow:5].timeIntervalSince1970;
            do {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:2]];
            } while (![SmartDevice deviceWithDeviceId:devId] && ([NSDate date].timeIntervalSince1970 < limitSeconds));
            
            self.deviceModel = [SmartDevice deviceWithDeviceId:devId].deviceModel;
            if (!self.deviceModel) {
                NSLog(@"not find device %@", devId);
                [self resetStatesWithIdentifier:identifier];
                return;
            }
            NSLog(@"did find device %@", self.deviceModel.devId);
            
            // devId一致、設(shè)備不在線才可以發(fā)起連接藍(lán)牙
            if ([self.deviceModel.devId isEqualToString:devId] && !self.deviceModel.isOnline) {
                
                // 查找到設(shè)備才開(kāi)啟藍(lán)牙
                [self addBleConnectedStateObserver];
                [self bleStartListening];
                
                // 50秒后如果藍(lán)牙沒(méi)連上重連一次
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(50 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self repeatBleStartListening:devId];
                });
            }
            [self resetStatesWithIdentifier:identifier];
        }
        case CLRegionStateOutside:
        case CLRegionStateUnknown:
            
            if (_needRequestStateForRegion) {
                if (_requestStateForRegionCount < MAX_RETRY_COUNT) {
                    _requestStateForRegionCount++;
                    [self.locationManager requestStateForRegion:region];
                } else {
                    _needRequestStateForRegion = NO;
                    _requestStateForRegionCount = 0;
                }
            }
            break;
        default:
            break;
    }
}

- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region {
    
}

2.解鎖

家里面的門鎖蝙叛,汽車的門鎖俺祠,如果硬件的模組支持IBeacon,iPhone進(jìn)入門鎖/汽車藍(lán)牙的范圍借帘,門鎖發(fā)送IBeacon廣播包蜘渣,喚醒APP并發(fā)起重連,重連成功之后APP下發(fā)指令來(lái)解鎖肺然,解鎖成功之后需要馬上移除IBeacon監(jiān)聽(tīng)蔫缸,防止重復(fù)開(kāi)鎖。

踩坑點(diǎn)

???IBeacon是Core Location框架提供的一個(gè)能力际起,那就必須開(kāi)啟位置權(quán)限拾碌,并且位置權(quán)限為始終允許吐葱,精確位置也要打開(kāi)。否則APP在后臺(tái)校翔、kill進(jìn)程的時(shí)候弟跑,是沒(méi)法通過(guò)IBeacon喚醒APP的。除了定位權(quán)限防症,后臺(tái)藍(lán)牙通訊的權(quán)限也必須開(kāi)啟孟辑,如果你的業(yè)務(wù)場(chǎng)景是:手機(jī)作為藍(lán)牙中心 server,主動(dòng)發(fā)現(xiàn)藍(lán)牙設(shè)備蔫敲,建立連接饲嗽,后臺(tái)不斷刷新和保持藍(lán)牙通信會(huì)話,那么需要開(kāi)啟Uses Bluetooth LE accessories奈嘿。如果你的業(yè)務(wù)場(chǎng)景是:把手機(jī)模擬成藍(lán)牙設(shè)備貌虾,被迫連接,那么需要開(kāi)啟Acts as a Bluetooth LE accessory指么。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酝惧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伯诬,更是在濱河造成了極大的恐慌晚唇,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盗似,死亡現(xiàn)場(chǎng)離奇詭異哩陕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赫舒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門悍及,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人接癌,你說(shuō)我怎么就攤上這事心赶。” “怎么了缺猛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵缨叫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我荔燎,道長(zhǎng)耻姥,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任有咨,我火速辦了婚禮琐簇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘座享。我一直安慰自己婉商,他們只是感情好似忧,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著据某,像睡著了一般橡娄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癣籽,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天挽唉,我揣著相機(jī)與錄音,去河邊找鬼筷狼。 笑死瓶籽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的埂材。 我是一名探鬼主播塑顺,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼俏险!你這毒婦竟也來(lái)了严拒?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤竖独,失蹤者是張志新(化名)和其女友劉穎裤唠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體莹痢,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡种蘸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竞膳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片航瞭。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坦辟,靈堂內(nèi)的尸體忽然破棺而出刊侯,到底是詐尸還是另有隱情,我是刑警寧澤锉走,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布滔吠,位于F島的核電站,受9級(jí)特大地震影響挠日,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翰舌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一嚣潜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧椅贱,春花似錦懂算、人聲如沸只冻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)喜德。三九已至,卻和暖如春垮媒,著一層夾襖步出監(jiān)牢的瞬間舍悯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工睡雇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萌衬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓它抱,卻偏偏與公主長(zhǎng)得像秕豫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子观蓄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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