iOS 扫码(闪光灯、自动拉近放大)

需求:产品要实现类似微信扫码一样效果的功能,光线暗的时候,能够自动打开闪光灯(并出现闪光灯控制开关图标),然后用户可以手动控制闪光灯的开关。
还有一个是实现自动拉近放大功能。


1.png

踩过的坑:当时不知道是手冻还是什么,把videoPreView的引用类型写成了weak,导致了镜头所在的layer加载不显示,当时查了好久没找到问题,心态崩了,找的小伙伴帮我排查,最后他打断点发现打印self.videoPreView的frame为(0,0,0,0)。我又自己看了一下,发现self.videoPreView为nil,就看了一下属性。果然是属性写错了,以后一定要谨慎细心。真丢脸啊😓

#import "QRCodeScanningViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <ImageIO/ImageIO.h>
#import "GoodsDetailViewController.h"

@interface QRCodeScanningViewController ()<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,UIGestureRecognizerDelegate>{
    BOOL bHadAutoVideoZoom;
}

@property (weak, nonatomic) IBOutlet UIButton *torchBtn;//灯泡开关
@property (weak, nonatomic) IBOutlet UILabel *torchStatusLabel;//灯泡底下的开关显示

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *scanBottomConstraint;
@property (weak, nonatomic) IBOutlet UIImageView *scanningBar;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftReturnBtnTopConstraint;

@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) AVCaptureDevice *device;
@property (nonatomic, strong) AVCaptureSession *session;
@property (strong, nonatomic) AVCaptureDeviceInput * input;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *layer;
@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;//拍照
@property (nonatomic, strong) UIView *videoPreView; ///视频预览显示视图
@property (nonatomic, assign) CGPoint centerPoint;//二维码的中心点
@property (nonatomic, assign) BOOL isAutoOpen;//默认NO 闪光灯



@end

@implementation QRCodeScanningViewController

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    self.navigationController.navigationBar.hidden = YES;
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    self.navigationController.navigationBar.hidden = NO;
    [self turnTorchOn:NO];
    [self stopScanning];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self  creatSubviews];
    [self scanCameraAuth];

}

#pragma mark - UI

- (void)creatSubviews{
    //默认不显示闪光灯
    [self.torchBtn setSelected:NO];
    self.torchBtn.hidden = self.torchStatusLabel.hidden =YES;
    //适配齐刘海
    self.leftReturnBtnTopConstraint.constant = (6+STATUSH);
    
}

- (void)scanCameraAuth{
    __weak typeof(self)  weakSelf = self;
    [self requestCameraPemissionWithResult:^(BOOL granted) {
        if (granted) {
            [weakSelf startScanning];
            [weakSelf networkStatusAlert];
        } else {
            [weakSelf showAlertToPromptCameraAuthorization];
        }
    }];

}

#pragma mark - btn

- (IBAction)returnBack:(UIButton *)sender {
    [self leftBarButtonItemReturnAction];
}

- (IBAction)lighting:(UIButton *)sender {
    sender.selected = !sender.selected;
    [self turnTorchOn:sender.selected];
}


#pragma mark - Helpers
- (void)startScanning {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(animateScanningBar) userInfo:nil repeats:YES];

    if (!self.layer) {
        AVCaptureSession *session = [[AVCaptureSession alloc] init];
        session.sessionPreset = AVCaptureSessionPresetHigh;

        /// Input.
        self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];

        /// Output. Must work in a serial queue.
        dispatch_queue_t serialQueue = dispatch_queue_create("ScanningQueue", NULL);
        //扫描结果 自动放大
        AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
        [output setMetadataObjectsDelegate:self queue:serialQueue];
        //闪光灯
        AVCaptureVideoDataOutput *dataOutput = [[AVCaptureVideoDataOutput alloc] init];
        [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

//        CGRect cropRect = CGRectMake((SCREEN_WIDTH-220)*0.5, SCREEN_HEIGHT*0.5-60, 220, 220);
//        if (!CGRectEqualToRect(cropRect,CGRectZero)){
//            output.rectOfInterest = cropRect;
//        }

        self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
        NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey,nil];
        [self.stillImageOutput setOutputSettings:outputSettings];

        if ([session canAddInput:self.input]) {
            [session addInput:self.input];
        }
        if ([session canAddOutput:output]) {
            [session addOutput:output];
        }
        if ([session canAddOutput:dataOutput]) {
            [session addOutput:dataOutput];
        }
        if ([session canAddOutput:self.stillImageOutput]){
            [session addOutput:self.stillImageOutput];
        }

        /* 扫条形码
        AVMetadataObjectTypeEAN13Code,
        AVMetadataObjectTypeEAN8Code,
        AVMetadataObjectTypeUPCECode,
        AVMetadataObjectTypeCode39Code,
        AVMetadataObjectTypeCode39Mod43Code,
        AVMetadataObjectTypeCode93Code,
        AVMetadataObjectTypeCode128Code,
        AVMetadataObjectTypePDF417Code
        */

        NSArray *types = @[AVMetadataObjectTypeQRCode];
        NSMutableArray *typesAvailable = [NSMutableArray array];
        for (NSString *type in types) {
            if ([output.availableMetadataObjectTypes containsObject:type]) [typesAvailable addObject:type];
        }
        output.metadataObjectTypes = typesAvailable;

        /// Preview layer.
        AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
        layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        layer.frame = SCREEN_BOUNDS;

        [self.view insertSubview:self.videoPreView atIndex:0];
        [self.videoPreView.layer insertSublayer:layer atIndex:0];

        self.layer = layer;
        self.session = session;
    }

    [self.session startRunning];
    bHadAutoVideoZoom = NO;//还未自动拉近的值
    [self setVideoScale:1 ];//设置拉近倍数为1

}

- (void)stopScanning {
    if (self.session.isRunning) {
        [self.session stopRunning];
    }

    if (self.timer.isValid) {
        [self.timer invalidate];
        self.timer = nil;
    }
}

- (void)animateScanningBar {
    int constant = (int)self.scanBottomConstraint.constant;
    if (constant > 0) {
        constant --;
    }else {
        constant = 218;
    }
    self.scanBottomConstraint.constant = constant;
}

#pragma mark - get
- (UIView *)videoPreView{
    if (!_videoPreView) {
        UIView *videoView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
        videoView.backgroundColor = [UIColor clearColor];
        _videoPreView = videoView;
    }
    return _videoPreView;
}

#pragma mark - Delegate Methods AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    NetworkStatus internetStatus = [Helper internetStatus];
    if (internetStatus == NotReachable) {
        return;
    }
    //识别扫码类型
    NSString *result;
    for(AVMetadataObject *current in metadataObjects){
        if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]]){
            NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue];
            if (scannedResult && ![scannedResult isEqualToString:@""]){
                result = scannedResult;
            }
        }
    }
//    NSLog(@"扫描%@", result);
    if (result.length<1) {
        return;
    }

    if (!bHadAutoVideoZoom) {
        AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)[self.layer transformedMetadataObjectForMetadataObject:metadataObjects.lastObject];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self changeVideoScale:obj];
        });
        bHadAutoVideoZoom  =YES;
        return;
    }
    if ([result hasPrefix:@"https"]||[result hasPrefix:@"http"]) {
        [self stopScanning];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self handlerJump:result];
        });
    }else{
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            [Helper addAlerViewOrAlertControllerWithTitle:@"提示" message: @"无效的二维码" buttonTitle:@"我知道了" forViewController:weakSelf];
        });
    }
}

//处理跳转
- (void)handlerJump:(NSString *)resultString{
     NSDictionary *dic = [NSDictionary dictionaryWithDictionary:[Helper getDictionaryFormURL:resultString]];
    if(![resultString containsString:@"nqyong.com"]){
        __weak typeof(self) weakSelf = self;
        NSString *msg = [NSString stringWithFormat:@"可能存在安全风险,是否打开此链接?\n%@",resultString];
        [self addTwoAlertControllerAction:@"提示" message:msg leftTitle:@"打开链接" rightTitle:@"取消" leftAction:^(UIAlertAction * _Nonnull action) {
            [weakSelf passScanningGoNextBaseWebviewTitle:@"" updateTitle:YES url:resultString contactKefu:NO];
        } rightAction:^(UIAlertAction * _Nonnull action) {
            [weakSelf leftBarButtonItemReturnAction];
        }];
    }else if ([resultString containsString:@"www.nqyong.com/downloadsApp.html"]){
         NSString *jumpString = [NSString stringWithFormat:@"https://store-h5.nqyong.com/channelShop?appid=%@",dic[@"appid"]];
        [self passScanningGoNextBaseWebviewTitle:@"商品列表" updateTitle:YES url:jumpString contactKefu:NO];
     }else if ([resultString containsString:@"h5.nqyong.com/goodsDetail?"]) {
        GoodsDetailViewController *GoodsDetailVC = (GoodsDetailViewController *)[UIStoryboard vcFrom:Goods identifier:[NSString stringWithFormat:@"%@",GoodsDetailViewController.class]];
        GoodsDetailVC.hidesBottomBarWhenPushed = YES;
        GoodsDetailVC.goodsID = dic[@"id"];
        GoodsDetailVC.goodsName = @"";
        [DataKeeper sharedKeeper].appId = dic[@"appid"];
        [self passScanningGoNextVC:GoodsDetailVC];
     }else{
        [self passScanningGoNextBaseWebviewTitle:@"" updateTitle:YES url:resultString contactKefu:NO];
     }
}

//跳转到webview之前,去掉扫码页
- (void)passScanningGoNextBaseWebviewTitle:(NSString *)title updateTitle:(BOOL)updateTitle url:(NSString *)url contactKefu:(BOOL)contactKefu{
    if (url.length == 0) return;
    RootWebViewController *root = [[RootWebViewController alloc]init];
    root.hidesBottomBarWhenPushed = YES;
    root.aTitle = title;
    root.contactKefu = contactKefu;
    root.updateTitle = updateTitle;
    root.request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    [self passScanningGoNextVC:root];
}
//设置navabar的代理路由
- (void)passScanningGoNextVC:(UIViewController *)vc{
    NSMutableArray *vcArray = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
    int index = (int)[vcArray indexOfObject:self];
    if (vcArray.count<2) {
        return;
    }
    [vcArray removeObjectAtIndex:index];
    [vcArray addObject: vc];
    [self.navigationController setViewControllers:vcArray animated:NO];
}

#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
    CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
    NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
    CFRelease(metadataDict);
    NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
    float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
    // brightnessValue 值代表光线强度,值越小代表光线越暗
//    NSLog(@"光线%f", brightnessValue);
    if (brightnessValue <= -2 &&!self.isAutoOpen) {
        self.isAutoOpen = YES;
        [self turnTorchOn:YES];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.torchBtn setSelected:YES];
            self.torchBtn.hidden = self.torchStatusLabel.hidden= NO;
        });
    }
}

#pragma mark -  打开/关闭手电筒
- (void)turnTorchOn:(BOOL)on{
    if ([self.device hasTorch] && [self.device hasFlash]){

        dispatch_async(dispatch_get_main_queue(), ^{
            self.torchStatusLabel.text = on?@"点击关闭":@"点击开启";
        });

        [self.device lockForConfiguration:nil];
        if (on) {
            [self.device setTorchMode:AVCaptureTorchModeOn];
            [self.device setFlashMode:AVCaptureFlashModeOn];
        } else {
            [self.device setTorchMode:AVCaptureTorchModeOff];
            [self.device setFlashMode:AVCaptureFlashModeOff];
        }
        [self.device unlockForConfiguration];
    } else {
        [Helper addAlerViewOrAlertControllerWithTitle:@"提示" message:@"当前设备没有闪光灯,不能提供手电筒功能"  buttonTitle:@"我知道了" forViewController:self];
    }
}

#pragma mark - 二维码自动拉近

- (void)changeVideoScale:(AVMetadataMachineReadableCodeObject *)objc
{
    NSArray *array = objc.corners;
    NSLog(@"cornersArray = %@",array);
    CGPoint point = CGPointZero;
    // 把字典转换为点,存在point里,成功返回true 其他false
    CGPointMakeWithDictionaryRepresentation((__bridge CFDictionaryRef)array[0], &point);

    NSLog(@"X:%f -- Y:%f",point.x,point.y);
    CGPoint point2 = CGPointZero;
    CGPointMakeWithDictionaryRepresentation((__bridge CFDictionaryRef)array[2], &point2);
    NSLog(@"X:%f -- Y:%f",point2.x,point2.y);

    self.centerPoint = CGPointMake((point.x + point2.x) / 2, (point.y + point2.y) / 2);
    CGFloat scace = 150 / (point2.x - point.x); //当二维码图片宽小于150,进行放大
    [self setVideoScale:scace];
    return;
}

- (void)setVideoScale:(CGFloat)scale
{
    [self.input.device lockForConfiguration:nil];

    AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
    CGFloat maxScaleAndCropFactor = ([[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] videoMaxScaleAndCropFactor])/16;

    if (scale > maxScaleAndCropFactor){
        scale = maxScaleAndCropFactor;
    }else if (scale < 1){
        scale = 1;
    }

    CGFloat zoom = scale / videoConnection.videoScaleAndCropFactor;
    videoConnection.videoScaleAndCropFactor = scale;

    [self.input.device unlockForConfiguration];

    CGAffineTransform transform = self.videoPreView.transform;

    //自动拉近放大
    if (scale == 1) {
        self.videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom);
        CGRect rect = self.videoPreView.frame;
        rect.origin = CGPointZero;
        self.videoPreView.frame = rect;
    } else {
        CGFloat x = self.videoPreView.center.x - self.centerPoint.x;
        CGFloat y = self.videoPreView.center.y - self.centerPoint.y;
        CGRect rect = self.videoPreView.frame;
        rect.origin.x = rect.size.width / 2.0 * (1 - scale);
        rect.origin.y = rect.size.height / 2.0 * (1 - scale);
        rect.origin.x += x * zoom;
        rect.origin.y += y * zoom;
        rect.size.width = rect.size.width * scale;
        rect.size.height = rect.size.height * scale;

        [UIView animateWithDuration:.5f animations:^{
            self.videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom);
            self.videoPreView.frame = rect;
        } completion:^(BOOL finished) {
        }];
    }

    NSLog(@"放大%f",zoom);
}

- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections
{
    for ( AVCaptureConnection *connection in connections ) {
        for ( AVCaptureInputPort *port in [connection inputPorts] ) {
            if ( [[port mediaType] isEqual:mediaType] ) {
                return connection;
            }
        }
    }
    return nil;
}

//#pragma mark 手势拉近/远 界面
//- (void)cameraInitOver{
//    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchDetected:)];
//    pinch.delegate = self;
//    [self.view addGestureRecognizer:pinch];
//}
//
//- (void)pinchDetected:(UIPinchGestureRecognizer*)recogniser
//{
//    self.effectiveScale = self.beginGestureScale * recogniser.scale;
//    if (self.effectiveScale < 1.0){
//        self.effectiveScale = 1.0;
//    }
//    [self setVideoScale:self.effectiveScale pinch:YES];
//}
//
//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
//{
//    if ( [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] ) {
//        _beginGestureScale = _effectiveScale;
//    }
//    return YES;
//}

#pragma mark - 相机权限Alert

- (void)requestCameraPemissionWithResult:(void(^)( BOOL granted))completion
{
    if ([AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)])
    {
        AVAuthorizationStatus permission =
        [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

        switch (permission) {
            case AVAuthorizationStatusAuthorized:
                completion(YES);
                break;
            case AVAuthorizationStatusDenied:
            case AVAuthorizationStatusRestricted:
                completion(NO);
                break;
            case AVAuthorizationStatusNotDetermined:{
                [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo
                                         completionHandler:^(BOOL granted) {

                 dispatch_async(dispatch_get_main_queue(), ^{
                     if (granted) {
                         completion(true);
                     } else {
                         completion(false);
                     }
                 });
               }];
            }
            break;
        }
    }
}

- (void)showAlertToPromptCameraAuthorization {
    UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"提示" message:@"您的相机功能没有打开,去“设置>拿趣用”设置一下吧" preferredStyle:UIAlertControllerStyleAlert];
    [alertCtr addAction:[UIAlertAction actionWithTitle:@"关闭" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        dispatch_async(dispatch_get_main_queue(), ^(void){
            [self leftBarButtonItemReturnAction];
        });
    }]];
    [alertCtr addAction:[UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        dispatch_async(dispatch_get_main_queue(), ^(void){
            [self.navigationController popToRootViewControllerAnimated:YES];
            [Helper openURL:UIApplicationOpenSettingsURLString];
        });
    }]];
    [self presentViewController:alertCtr animated:YES completion:nil];
}

-(void)addTwoAlertControllerAction:(NSString *)title message:(NSString *)message leftTitle:(NSString *)leftTitle rightTitle:(NSString *)rightTitle leftAction:(void (^)(UIAlertAction * _Nonnull action))leftAction  rightAction:(void (^)(UIAlertAction * _Nonnull action))rightAction{
    UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    [alertCtr addAction:[UIAlertAction actionWithTitle:leftTitle style:UIAlertActionStyleDefault handler:leftAction]];
    [alertCtr addAction:[UIAlertAction actionWithTitle:rightTitle style:UIAlertActionStyleDefault handler:rightAction]];
    [self presentViewController:alertCtr animated:YES completion:nil];
}

-(void)networkStatusAlert{
    NetworkStatus internetStatus = [Helper internetStatus];
    switch (internetStatus) {
        case NotReachable:{
            __weak typeof(self) weakSelf = self;
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf addTwoAlertControllerAction:@"提示" message:@"您的WLAN与蜂窝移动网功能没有打开,去“设置>拿趣用”设置一下吧" leftTitle:@"关闭" rightTitle:@"去设置" leftAction:^(UIAlertAction * _Nonnull action) {
                } rightAction:^(UIAlertAction * _Nonnull action) {
                    [weakSelf.navigationController popToRootViewControllerAnimated:YES];
                    [Helper openURL:UIApplicationOpenSettingsURLString];
                }];
            });
        }
            break;

        default:
            break;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270