iOS NetworkExtension学习

系统库

--

1.NEFilterControlProvider
2.NEFilterDataProvider

3.NEFilterFlow
4.NEFilterManager

5.NEFilterProvider
6.NEFilterProviderConfiguration

7.NEFlowMetaData

8.NEHotspotConfigurationManager
9.NEHotspotHelper

NEFilterProvider

网络内容筛选器由两个筛选器扩展组成,

筛选器数据提供程序扩展在网络内容通过设备上的网络堆栈时对其进行检查,
并决定是否应阻止或允许网络内容传递到其最终目标.

由于筛选器可以访问流经设备的所有网络内容, 因此它在非常严格的沙箱中运行。沙箱通过阻止所有网络访问、ipc 和磁盘写入操作, 防止筛选器将网络内容移动到其地址空间之外。 筛选器负责向筛选器数据提供程序扩展提供信息, 以便筛选器可以完成其工作。筛选器通知它没有足够的信息来决定特定的网络内容流。然后, 筛选器可以从服务器下载更多的筛选规则, 并将这些规则写入筛选器,从而可以访问这些规则的位置。

NEFilterProvider相关的API

- (void)startFilterWithCompletionHandler:(void (^)(NSError *error))completionHandler;

开启过滤器
此方法由系统调用以启动筛选器. 子类必须重写此方法. 当调用此方法时, 筛选器执行初始化筛选器所需的任何步骤, 然后执行完成处理block。


- (void)stopFilterWithReason:(NEProviderStopReason)reason 
           completionHandler:(void (^)(void))completionHandler;

停止过滤器,NEProviderStopReason是停止的原因,此方法由系统调用以停止筛选器。子类方法需要重写该方法。

NEFilterProviderConfiguration

筛选器配置设置。

主要的属性值包含如下:

@property BOOL filterBrowsers;

布尔值,返回YES或者NO取决于有没有webKit浏览器对象。

@property BOOL filterSockets;

默认是NO,布尔值是什么取决于是否使用了socket

@property(copy) NSDictionary<NSString *,id> *vendorConfiguration;

设置特定参数的字典,所有的字典中的value值必须遵守NSSecureCoding协议


@property(copy) NSString *serverAddress;

服务地址


@property(copy) NSString *username;

用户名


@property(copy) NSString *organization;

组织


@property(copy) NSData *passwordReference;

密码数据


@property(copy) NSData *identityReference;

特定属性,证书或者绑定的key

NEFilterFlow

NEFilterFlow就是网络数据流。

NEFilterManager

创建和管理网络内容过滤器配置并控制网络内容过滤器。允许每个应用程序创建单个筛选器配置,NEFilterManager类具有一个类方法sharedManager, 可以访问单个NEFilterManager实例。该单个实例对应于单个过滤配置。

过滤器配置存储在由NetWork Extension框架管理的Network Extension首选项中。必须先将过滤器配置从网络扩展首选项显式加载到内存中,然后才能使用它,并且必须先将任何更改明确保存到网络扩展首选项,然后才能在系统上生效。

**注意 **

在使用NEFilterManager这个类时,一定要让自己的Xcode配置上Network Extension的能力,具体如下图


image.png

NEFilterManager 头文件


/*
* This header is generated by classdump-dyld 0.1
* on Wednesday, September 20, 2017 at 9:28:09 PM Eastern European Summer Time
* Operating System: Version 11.0 (Build 15A372)
* Image Source: /System/Library/Frameworks/NetworkExtension.framework/NetworkExtension
* classdump-dyld is free of use, Copyright © 2013 by Elias Limneos.
*/

#import <NetworkExtension/NEPrettyDescription.h>

@class NEConfiguration, NEConfigurationManager, NSString, NEFilterProviderConfiguration;

@interface NEFilterManager : NSObject <NEPrettyDescription> {

    bool _hasLoaded;
    NEConfiguration* _configuration;
    NEConfigurationManager* _configurationManager;

}

@property (assign) bool hasLoaded;                                                 //@synthesize hasLoaded=_hasLoaded - In the implementation block
@property (retain) NEConfiguration* configuration;                                 //@synthesize configuration=_configuration - In the implementation block
@property (readonly) NEConfigurationManager* configurationManager;                 //@synthesize configurationManager=_configurationManager - In the implementation block
@property (copy) NSString* localizedDescription; 
@property (retain) NEFilterProviderConfiguration* providerConfiguration; 
@property (getter=isEnabled) bool enabled; 
+(id)sharedManager;
-(id)providerConfiguration;
-(void)setLocalizedDescription:(id)arg1 ;
-(id)init;
-(void).cxx_destruct;
-(id)description;
-(id)localizedDescription;
-(bool)isEnabled;
-(void)setEnabled:(bool)arg1 ;
-(void)setConfiguration:(id)arg1 ;
-(id)configuration;
-(id)descriptionWithIndent:(int)arg1 options:(unsigned long long)arg2 ;
-(void)setHasLoaded:(bool)arg1 ;
-(void)loadFromPreferencesWithCompletionHandler:(/*^block*/ id)arg1 ;
-(id)configurationManager;
-(void)createEmptyConfiguration;
-(id)initFilterManagerWithPluginType:(id)arg1 ;
-(void)removeFromPreferencesWithCompletionHandler:(/*^block*/ id)arg1 ;
-(void)saveToPreferencesWithCompletionHandler:(/*^block*/ id)arg1 ;
-(void)setProviderConfiguration:(id)arg1 ;
-(bool)hasLoaded;
@end


API介绍

+ (NEFilterManager *)sharedManager;

创建NEFilterManager的单例,返回一个NEFilterManager类对象

- (void)loadFromPreferencesWithCompletionHandler:(void (^)(NSError *error))completionHandler;

加载筛选器配置,在调用saveToPreferencesWithCompletionHandler之前,您必须至少调用此方法一次:这是您的应用程序启动后的第一次。


- (void)saveToPreferencesWithCompletionHandler:(void (^)(NSError *error))completionHandler;

将过滤配置保存在Extension的参数中,在应用程序启动后第一次调用此方法之前,必须至少调用一次loadFromPreferencesWithCompletionHandler:


- (void)removeFromPreferencesWithCompletionHandler:(void (^)(NSError *error))completionHandler;

将过滤配置在Extension中移除,从Extension中删除配置后,NEFilterManager对象仍将包含配置参数。 调用loadFromPreferencesWithCompletionHandler:将从NEFilterManager对象中清除配置参数。


@property(copy) NSString *localizedDescription;

描述过滤器信息,如果在创建配置时将此属性设置为nil,则它将自动设置为调用程序的显示名称。


@property(strong) NEFilterProviderConfiguration *providerConfiguration;

过滤器设置的NEFilterProviderConfiguration对象,如果调用loadFromPreferencesWithCompletionHandler:之后属性为nil,则Extension中不存在过滤器信息。

NEFilterControlProvider

NEFilterControlProvider 是为应用程序扩展创建一个主题类。

NEFilterControlProvider主要是向关联的过滤器数据提供程序提供信息,以便它可以执行准确过滤网络内容的任务。过滤器控制提供程序有多种方法向关联的过滤器提供数据:

通过将信息写入磁盘。例如,过滤器控制提供程序可以在磁盘上的过滤数据提供程序可以从数据库中读取的位置维护过滤规则的数据库。

通过定义将键映射到生成块页面时要使用的自定义参数集的字典。过滤器数据提供程序为系统提供所需自定义参数的密钥,系统使用该密钥从过滤器控制提供程序获取自定义参数并生成自定义块页面。

通过定义将键映射到要附加到URL的字符串的字典。过滤器数据提供程序为系统提供了要附加的字符串的键,系统使用该键从过滤器控制提供程序中获取要附加的字符串,并将该字符串附加到URL。

在使用该类时,需要在info.plist中添加对应的key,如下:

<key>NSExtension</key>
<dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.networkextension.filter-control</string>
    <key>NSExtensionPrincipalClass</key>
    <string>MyCustomFilterControlProvider</string>
</dict>

NEFilterControlProvider的头文件相关的类

#import <NetworkExtension/NEFilterProvider.h>
#import <NetworkExtension/NSExtensionRequestHandling.h>

@class NSDictionary, NSString;

@interface NEFilterControlProvider : NEFilterProvider <NSExtensionRequestHandling> {

    NSDictionary* _remediationMap;
    NSDictionary* _URLAppendStringMap;

}

@property (copy) NSDictionary* remediationMap; 
@property (copy) NSDictionary* URLAppendStringMap; 
@property (readonly) unsignedlonglong hash; 
@property (readonly) Class superclass; 
@property (copy,readonly) NSString* description; 
@property (copy,readonly) NSString* debugDescription; 
-(void).cxx_destruct;
-(void)handleNewFlow:(id)arg1 completionHandler:(/*^block*/ id)arg2 ;
-(void)handleReport:(id)arg1 ;
-(void)notifyRulesChanged;
-(void)setRemediationMap:(id)arg1 ;
-(void)setURLAppendStringMap:(id)arg1 ;
-(id)remediationMap;
-(id)URLAppendStringMap;
-(void)handleRemediationForFlow:(id)arg1 completionHandler:(/*^block*/ id)arg2 ;
@end

相关的API


- (void)handleNewFlow:(NEFilterFlow *)flow 
    completionHandler:(void (^)(NEFilterControlVerdict *))completionHandler;
    

处理新的信息流,其中flow指的是NEFilterFlow对象,包含有关网络内容流的详细信息,completionHandler是一个block回调。


- (void)notifyRulesChanged;

通过该方法,过滤控制器可以通知过滤数据规则的改变,

- (void)handleRemediationForFlow:(NEFilterFlow *)flow 
               completionHandler:(void (^)(NEFilterControlVerdict *))completionHandler;
               

处理遗漏的数据流信息

- (void)handleReport:(NEFilterReport *)report;

处理返回的数据

NEFilterDataProvider

网络请求的内容以NEFilterFlow对象的形式传递给过滤器数据提供者,每个NEFilterFlow对象对应于设备上运行的应用程序打开网络连接。过滤器数据提供程序可以在接收到新流时选择传递或阻止数据,也可以在进行传递或阻止决策之前要求系统在出站或入站方向上查看更多流数据。

除了传递或阻止网络数据之外,过滤器数据提供程序还可以告诉系统它需要更多信息才能决定特定的数据流。然后,系统将要求过滤器控制提供程序更新当前的规则集,并将它们放在磁盘上可从过滤器数据提供程序扩展中读取的位置

当NEFilterFlow对象源自WebKit浏览器对象时,过滤器数据提供程序可以通过以下方式影响用户体验:

如果筛选器数据提供程序选择阻止该网页,则会在WebKit浏览器对象中显示一个特殊的“阻止”页面,通知用户他们访问内容的尝试已被阻止。过滤器数据提供程序可以选择添加指向此阻止页面的链接,从而为用户提供请求访问内容的选项。

如果筛选器数据提供程序选择允许该网页,则它还可以指定将字符串附加到网页URL。这允许过滤器数据提供程序将WebKit浏览器对象定向到网页的“安全”版本。

为了保护用户的隐私,过滤器数据提供程序扩展沙箱可防止扩展程序将网络内容移动到其地址空间之外。

在使用改类时也需要添加如下的key

<key>NSExtension</key>
<dict>
    <key>NSExtensionPointIdentifier</key>
    <string>com.apple.networkextension.filter-data</string>
    <key>NSExtensionPrincipalClass</key>
    <string>MyCustomFilterDataProvider</string>
</dict>

另外,在创建分类时,需要创建一个类继承自NEFilterDataProvider,并且重写以下方法

handleNewFlow:

handleInboundDataFromFlow:readBytesStartOffset:readBytes:

handleOutboundDataFromFlow:readBytesStartOffset:readBytes:

handleInboundDataCompleteForFlow:

handleOutboundDataCompleteForFlow:

handleRemediationForFlow:

handleRulesChanged

NEFilterDataProvider相关的头文件

/*
* This header is generated by classdump-dyld 0.1
* on Wednesday, September 20, 2017 at 9:28:09 PM Eastern European Summer Time
* Operating System: Version 11.0 (Build 15A372)
* Image Source: /System/Library/Frameworks/NetworkExtension.framework/NetworkExtension
* classdump-dyld is free of use, Copyright © 2013 by Elias Limneos.
*/

#import <NetworkExtension/NEFilterProvider.h>
#import <NetworkExtension/NSExtensionRequestHandling.h>

@class NSString;

@interface NEFilterDataProvider : NEFilterProvider <NSExtensionRequestHandling>

@property (readonly) unsignedlonglong hash; 
@property (readonly) Class superclass; 
@property (copy,readonly) NSString* description; 
@property (copy,readonly) NSString* debugDescription; 
-(id)handleNewFlow:(id)arg1 ;
-(id)handleInboundDataFromFlow:(id)arg1 readBytesStartOffset:(unsigned long long)arg2 readBytes:(id)arg3 ;
-(id)handleOutboundDataFromFlow:(id)arg1 readBytesStartOffset:(unsigned long long)arg2 readBytes:(id)arg3 ;
-(id)handleInboundDataCompleteForFlow:(id)arg1 ;
-(id)handleOutboundDataCompleteForFlow:(id)arg1 ;
-(void)handleRulesChanged;
-(id)handleRemediationForFlow:(id)arg1 ;
@end

NEFilterDataProvider 相关的API

- (NEFilterNewFlowVerdict *)handleNewFlow:(NEFilterFlow *)flow;

为新创建的网络内容流做出过滤方式

- (NEFilterDataVerdict *)handleInboundDataFromFlow:(NEFilterFlow *)flow 
                              readBytesStartOffset:(NSUInteger)offset 
                                         readBytes:(NSData *)readBytes;
                                         

对入栈数据做出过滤决策,flow参数就是数据流,offse是读取的数据进度,readBytes:要过滤的数据的NSData对象


- (NEFilterDataVerdict *)handleOutboundDataFromFlow:(NEFilterFlow *)flow 
                               readBytesStartOffset:(NSUInteger)offset 
                                          readBytes:(NSData *)readBytes;

对出栈数据做出过滤决策,flow参数就是数据流,offse是读取的数据进度,readBytes:要过滤的数据的NSData对象


- (NEFilterDataVerdict *)handleInboundDataCompleteForFlow:(NEFilterFlow *)flow;

- (NEFilterDataVerdict *)handleOutboundDataCompleteForFlow:(NEFilterFlow *)flow;

上面的两个方法分别对入栈和出栈的数据做出过滤的决策。


- (void)handleRulesChanged;

当Filter Control Provider调用notifyRulesChanged方法或返回NEFilterControlVerdict并将updateRules属性设置为YES时,系统将调用此方法。

NEHotspotHelper

https://lpd-ios.github.io/2017/03/09/NEHotspotHelper/

NEHotspotHelper 可以使应用程序参与到WIFI热点的过程中,Hotspot Helper接受在后台处理的命令,从而来控制Hotspot Network状态机。可以参阅About the Hotspot Network Subsystem

在使用NEHotspotHelper进行开发时,需要以下几点准备工作
应用程序的info.plist必须添加一个包含“网络认证”的UIBackgroundModes数组
应用程序必须设置“com.apple.developer.networking.HotspotHelper”作为它的权利之一。该权利的值是一个布尔值true
申请NEHotspot权限时,需要发送Email到networkextension@apple.com或点击申请链接
更多信息可参阅Hotspot Network Subsystem Programming Guide

相关的API

Register a Hotspot Helper


+ (BOOL)registerWithOptions:(NSDictionary<NSString *, NSObject *> *)options 
                    queue:(dispatch_queue_t)queue 
                    handler:(NEHotspotHelperHandler)handler
                    
  @param options
    <key>kNEHotspotHelperOptionDisplayName</key>
    <string>WIFI的注释tag字符串</string>                  
    
   @param queue
   dispatch_queue_t 用来调用handle的block
    
    @param handler
    NEHotspotHelperHandler block 用于执行处理 
    
    @return 注册成功YES, 否则NO
    
    @discussion
    一旦这个API调用成功,应用程序有资格在后台启动,并参与各种热点相关公布功能,当应用程序启动此方法应该调用一次,再次调用它不会产生影响,并返回NO                
                    

Manage Hotspot Networks


+ (BOOL)logoff:(NEHotspotNetwork *)network

@param network
对应当前关联的WIFI网络NEHotSpotNetwork

@return 注销命令已成功进入队列YES, 否则返回NO

@discussion
调用此方法使kNEHotspotHelperCommandTypeLogoff型的NEHotspotHelperCommand向应用程序发出的“handler”模块,网络参数必须符合当前关联的WIFI网络,即它必须来自对NEHotspotHelperCommand网络属性或方法supportedInterfaces

+ (NSArray *)supportedNetworkInterfaces

@return 
如果没有接口被管理,返回nil,否则返回NEHotspotNetwork对象数组

@discussion
每个网络接口由NEHotspotNetwork对象表示。当前返回的数组包含一个NEHotspotNetwork对象代表WIFI接口。这种方法的主要目的是当没有得到一个命令来处理它时,hotSpot Helper 显示UI中的状态
此方法加上NEHotspotNetwork的isChosenHelper方法允许应用程序知道它是否是当前处理的网络

Data Types


typedef void (^NEHotspotHelperHandler)(NEHotspotHelperCommand * cmd)

@discussion
当调用方法registerWithOptions:queue:handler:时,Hotspot Helper app提供这种类型的block。每次有要处理的命令时调用block

示例代码


NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@"WI-FI TAG", kNEHotspotHelperOptionDisplayName, nil];
    
    dispatch_queue_t queue = dispatch_queue_create("com.myapp.ex", 0); 
    
    BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd) {

        if(cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || 
           cmd.commandType == kNEHotspotHelperCommandTypeFilterScanList) 
        {
            for (NEHotspotNetwork* network  in cmd.networkList) 
            {
                if ([network.SSID isEqualToString:@"WX_moses"]) 
                {
                    [network setConfidence:kNEHotspotHelperConfidenceHigh];
                    [network setPassword:@"mypassword"];
                    NSLog(@"Confidence set to high for ssid: %@ (%@)\n\n", network.SSID, network.BSSID);
//                    NSMutableArray *hotspotList = [NSMutableArray new];     
//                    [hotspotList addObject:network];

                    // This is required
                    NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
                    [response setNetwork:network];
                    [response deliver];
                }
            }
        }
    }];


获取wifi列表

-(void)_getWifiList
{
    
    NSMutableDictionary* options = [[NSMutableDictionary alloc] init];
    [options setObject:@"??新网程-点我上网??" forKey:kNEHotspotHelperOptionDisplayName];
    
    dispatch_queue_t queue = dispatch_queue_create("com.pronetwayXY", NULL);
    BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd)
    {
        NEHotspotNetwork* network;
        NSLog(@"---------COMMAND TYPE:   %ld", (long)cmd.commandType);
        [cmd createResponse:kNEHotspotHelperResultAuthenticationRequired];
        if (cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || cmd.commandType ==kNEHotspotHelperCommandTypeFilterScanList)
        {
            NSLog(@"-----------WIFILIST:   %@", cmd.networkList);
            for (network  in cmd.networkList) {
                // NSLog(@"COMMAND TYPE After:   %ld", (long)cmd.commandType);
                if ([network.SSID isEqualToString:@"ssid"]|| [network.SSID isEqualToString:@"proict_test"]) {
                    
                    double signalStrength = network.signalStrength;
                    NSLog(@"Signal Strength: %f", signalStrength);
                    [network setConfidence:kNEHotspotHelperConfidenceHigh];
                    [network setPassword:@"password"];
                    
                    NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
                    NSLog(@"Response CMD %@", response);
                    
                    [response setNetworkList:@[network]];
                    [response setNetwork:network];
                    [response deliver];
                }
            }
        }
    }];
    
    NSLog(@"result :%d", returnType);
    NSArray *array = [NEHotspotHelper supportedNetworkInterfaces];
    NSLog(@"wifiArray:%@", array);
    NEHotspotNetwork *connectedNetwork = [array lastObject];
    NSLog(@"supported Network Interface: %@", connectedNetwork);
    
}

NEHotspotConfigurationManager

NEHotspotConfigurationManager 是IOS 11刚刚推出的用户获取WiFi信息的框架。
当您的应用使用NEHotspotConfiguration创建新的热点配置并将其应用于Wi-Fi网络或尝试更新以前配置的网络时,设备会提示用户进行审批。 未经用户明确同意,您的应用无法进行配置更改。

您的应用可以使用removeConfigurationForHS20DomainName:或removeConfigurationForSSID:删除已添加的配置,但不删除其他应用或用户添加的配置。 用户还可以使用“设置”>“Wi-Fi”删除已配置的网络。

卸载应用程序后,iOS将删除应用程序已配置的所有网络的配置,包括其钥匙串条目。
NEHotspotConfigurationError中列出了热点配置管理器错误。
当你使用NEHotspotConfigurationManager这个类时,必须要在Xcode中打开Hotspot 这个能力

NEHotspotConfigurationManager的API

- (void)applyConfiguration:(NEHotspotConfiguration *)configuration 
         completionHandler:(void (^)(NSError *error))completionHandler;
                  

在提示用户许可后添加或更新Wi-Fi网络配置,然后在特定条件下尝试加入网络。
此方法仅在附近找到时才尝试加入网络。 此外,由于Hotspot 2.0发现机制可能会引起明显的延迟,因此该方法不会尝试加入Hotspot 2.0网络。

除了为Wi-Fi网络提供SSID之外,您的应用还必须使用NEHotspotEAPSettings和NEHotspotHS20Settings提供配置和身份验证信息。 使用Hotspot 2.0网络,应用程序必须提供HS2.0域名而不是SSID。

如果已通过移动设备管理(MDM)配置文件或运营商捆绑包配置了相同的SSID或HS2.0域名,则此方法不会添加配置。 如果您的应用程序配置了热点,并且稍后为具有相同域名的热点安装了MDM配置文件或Carrier软件包,则新配置将覆盖您的应用程序配置。


- (void)getConfiguredSSIDsWithCompletionHandler:(void (^)(NSArray<NSString *> *))completionHandler;

返回应用程序已配置的SSID或Wi-Fi热点域的名称,并调用可选的完成处理block

- (void)removeConfigurationForHS20DomainName:(NSString *)domainName;


删除应用之前添加的由Hotspot 2.0域名标识的Wi-Fi热点配置。使用该方法可以删除之前添加过的配置,但不能删除其他应用或用户添加的配置

- (void)removeConfigurationForSSID:(NSString *)SSID;

根据SSID来删除添加的配置

@property(class, readonly, strong) NEHotspotConfigurationManager *sharedManager;

NEHotspotConfigurationManager的单例对象

NEHotspotConfigurationManager的使用

- (void)_test
{
    
    NEHotspotConfiguration *configuration = [[NEHotspotConfiguration alloc] initWithSSID:@"youzu" passphrase:@"cuilinhao@@2018" isWEP:NO];
    NSLog(@"-------%@--", configuration);
    
    [[NEHotspotConfigurationManager sharedManager] applyConfiguration:configuration completionHandler:^(NSError * _Nullable error) {
        
        if ([[self _currentIphoneConnectedWiFiName] isEqualToString:@"NET"])
        {
            NSLog(@">>>>>>>>>>>>>>>>>>加入网络成功");
        }
        
        NSLog(@"----error---%@", error);
        
    }];
    
}


- (NSString *)_currentIphoneConnectedWiFiName
{
    NSString *wifiName = nil;
    
    CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();
    
    if (!wifiInterfaces)
    {
        return nil;
    }
    
    NSArray *interfaces = (__bridge NSArray *)wifiInterfaces;
    for (NSString *interfaceName in interfaces)
    {
        CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
        if (dictRef)
        {
            NSDictionary *networkInfoDic = (__bridge NSDictionary*)dictRef;
            wifiName = [networkInfoDic objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
            CFRelease(dictRef);
        }
    }
    CFRelease(wifiInterfaces);
    
    return wifiName;
}

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

推荐阅读更多精彩内容