Xcode8下快速集成极光推送并兼顾iOS10

不同版本极光推送SDK集成各有差异,集成时一定要注意版本号,楼主已将博文更新成最新的SDK JPush v3.0.2. 各位童鞋先阅读下JPush v3.0.2的升级指南吧!
极光的最近更新
极光资源下载

JPush SDK v3.0.2 升级指南
  • 更新时间
    2017-02-13

  • 更新信息
    修复:DNS解析失败带来的崩溃问题,提升稳定性

  • 升级提示
    建议升级!
    注意:支持 Xcode 8.0 以上版本 开启 bitcode。

  • 升级指南
    1.注意 3.0.0及以上版本将不再支持处理器为i386的模拟器。
    2.添加libresolv.tbd库(2.2.0及以上版本要求)
    3.Xcode7 升级到 Xcode8,替换原先导入的 .dylib 框架为 .tbd (特别留意)

本博文修改历史
  • 2017.03.25 ------------ JPush v3.0.2
  • 2016.12.13 ------------ JPush v2.2.0
  • 2016.09.28 ----------- JPush v2.1.9

简介

iOS10下,远程推送发生了变化,新增的UserNotifications.framework将本地推送和远程推送整合在一起。 最近刚刚更新了Xcode8,自动创建证书和配置文件确实方便许多。琰君分享下以开发环境为例(非生产环境)在Xcode8下,快速集成极光推送并兼顾iOS10。

注意:极光的远程推送是免费的,并同时兼顾iOS,Android,Windows Phone三个平台,但相应的用户统计,终端统计等功能是不免费的。如果你需要用户统计,终端统计这些功能意味着需要付费才能使用。

参考链接

开发证书配置
APNs 推送原理及问题
iOS 推送全解析,你不可不知的所有 Tips!

接下来假设你都了解证书相关的,推送的一些概念和极光推送的知识。那么相信你应该知道需要一台iOS设备和一个苹果开发者帐号才能去体验远程推送。如果你清楚远程推送的原理,那可以直接从以下第2步开始。

集成步骤

  1. 远程推送原理
  2. Xcode8创建项目,配置自动创建App ID/证书/配置文件
  3. 创建APNs 推送证书
  4. 在极光推送后台创建应用,并上传APNs 推送证书
  5. 项目中集成极光推送SDK
  6. notification payload 和远程推送类型
  7. 获取 APNs推送内容
  8. 极光推送后台发送远程推送测试
1. 远程推送原理

当iOS设备连网的情况下,iOS设备和苹果服务器建立了一个长链接,即便应用处于挂起和后台的状态,苹果可以给iOS设备中的应用发送通知。


远程推送原理
概念
  1. iOS:iOS设备
  1. APNs Server:苹果服务器
  2. Your App: 自己的应用
  3. Your Server:自己的服务器
推送流程
  1. iOS 应用注册推送通知,iOS设备将设备的UDID和应用的Bundle ID发送到苹果服务器。
  2. 苹果服务器将接收到的UDIDBundle ID加密生成一个deviceToken,并返回给对应iOS应用。
  3. iOS应用将接收到的deviceToken发送到自己的服务器,服务器并保存。
  4. 自己的服务器需配置APNs 推送证书,当需要推送时,去后台查询推送目标设备的deviceToken,将notification payloaddeviceToken一起发送给苹果服务器。notification payload是一个JSON字典,包含着发给应用程序的数据,并且包含通知的类型(类型决定系统如何通知用户)。
  5. 苹果服务器通过deviceToken找到对应设备下的对应应用,推送消息。
说明
  1. 真机测试并且包含推送功能需要创建对应App ID/证书/配置文件, 这步可以用Xcode8 自动创建,而不需要到苹果开发者平台去创建。如果不是Xcode8,则需要去开发者平台申请,确保App ID包含推送通知服务,并且在Xcode中配置,保证真机测试即可。
  2. 我们自己的服务器需要配置 APNs 推送证书,同样的分为开发证书和生产证书。需要到苹果开发者平台去申请。
  3. 如果不借助第三方推送平台,我们需要完成推送流程中的1,3,4步。借助极光推送,那么我们只需要完成推送流程中的1,3步,但同样需要我们完成第4步中的申请APNs 推送证书,并且上传到极光推送平台。
2. Xcode8配置自动创建App ID/证书/配置文件
  1. 在Xcode8下,确保已经登录付费苹果开发者帐号。请开启Application Target的Capabilities->Push Notifications选项。
开启远程推送

2.勾选自动管理App ID证书配置文件

勾选自动管理

3.检查Xcode自动创建的App ID证书配置文件,保证下图中第4步App ID包含的远程推送服务。如果没问题就可以真机运行了。

检查Xcode生产的App ID/证书/配置文件

3. 创建APNs 推送证书
  1. 登录开发者网站,并点击按钮创建证书
点击按钮创建证书

2.选择开发环境APNs 推送证书点击右下角按钮创建

创建开发环境APNs 推送证书

3.选择工程的App ID

选择工程的App ID

4.上传证书请求文件,不知道的童鞋可参照开发证书配置

上传证书请求文件

5.点击下载证书,并双击安装到钥匙串.


安装APNs 推送证书

6.打开钥匙串,找到对应的APNs 推送证书,并选择右键导出包含私钥的证书。(确保证书左侧为向右的小箭头,导出的证书才会包含私钥.)


钥匙串导出证书

7.设置证书名字,并选择证书存放位置。


设置证书名字

8.设置证书密码,可不填。极光推送支持证书设置密码,但像leanCloud推送不支持证书设置密码,各位童鞋可按照实际情况来。最后输入电脑开密码,导出证书。

设置证书密码

输入电脑开机密码导出证书
4. 在极光推送后台创建应用,并上传APNs 推送证书

1.登录极光推送平台,切换到控制台,并创建应用。接下来在应用信息中上传开发推送证书。生产推送证书配置类似,不做赘述。

上传开发APNs 推送证书
  1. 核对应用的Bundle ID 等信息是否正确.
    核对Bundle ID 等信息
5. 项目中集成极光推送SDK

极光推送最新版本3.0.2已支持CocoaPods导入。

  • 方式一:CocoaPods导入,一句话搞定。
pod 'JPush', '3.0.2'
  • 方式二:手动导入SDK和系统依赖库
    jpush-ios-3.0.2.a
    jcore-ios-1.1.1.a
    JPUSHService.h
    
导入系统依赖库

CFNetwork.framework
CoreFoundation.framework
CoreTelephony.framework
SystemConfiguration.framework
CoreGraphics.framework
Foundation.framework
UIKit.framework
Security.framework
libz.tbd
Adsupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加)
UserNotifications.framework(Xcode8及以上)
libresolv.tbd (JPush 2.2.0及以上版本需要)

3. AppDelegate.m 配置
导入以下头文件

import "JPUSHService.h"

// 如果需要使用idfa功能所需要引入的头文件(可选)

import <AdSupport/AdSupport.h>

ifdef NSFoundationVersionNumber_iOS_9_x_Max

import <UserNotifications/UserNotifications.h>

endif

并且遵守`<JPUSHRegisterDelegate>`协议

@interface AppDelegate ()<JPUSHRegisterDelegate>
@end

注册远程推送,初始化极光推送SDK。

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

//-------------注册远程推送
//notice: 3.0.0及以后版本注册可以这样写,也可以继续用之前的注册方式
JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
[JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
//-------------极光推送SDK初始化
BOOL isProduction = NO;// NO为开发环境,YES为生产环境
//广告标识符 如果没有使用IDFA直接传nil
NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
[JPUSHService setupWithOption:launchOptions appKey:@"极光推送AppKey"
channel:nil
apsForProduction:isProduction
advertisingIdentifier:advertisingId];
return YES;
}

以上是注册远程推送极光版本,很简洁。下面是注册远程推送系统版本,可以参考下。

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

CGFloat version = [[[UIDevice currentDevice] systemVersion] floatValue];  
  
if (version >= 10.0)  
{  
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];  
    [center requestAuthorizationWithOptions:UNAuthorizationOptionCarPlay | UNAuthorizationOptionSound | UNAuthorizationOptionBadge | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {  
          
        if (granted) {  
            NSLog(@" iOS 10 request notification success");  
        }else{  
            NSLog(@" iOS 10 request notification fail");  
        }  
    }];  
}  
else if (version >= 8.0)  
{  
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert categories:nil];  
    [application registerUserNotificationSettings:setting];  
}else  
{     //iOS <= 7.0
    UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;  
    [application registerForRemoteNotificationTypes:type];  
}    

//注册通知  
[[UIApplication sharedApplication] registerForRemoteNotifications];  
  
return YES;  

}

将苹果服务器返回的`deviceToken`,上传到极光推送服务器。

-(void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
[JPUSHService registerDeviceToken:deviceToken];
}

注册远程通知失败,比如没有联网的状态下。

-(void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}


#####6.notification payload 和远程推送类型
发送远程推送的服务器发送给APNs的每个通知都包含payload。 payload是一个JSON字典,包含要发送到应用程序的任何自定义数据,并包含有关推送类型的信息(推送类型决定系统如何通知用户)。

远程推送分为普通推送,后台推送,静默推送三种方式。以下以远程推送的类型来讨论下payload的构造。以下只考虑iOS7之后的操作系统。

- 普通推送 
  - payload 构造:包含声音、内容、角标、自定义字段。

{
aps = {
alert = "显示内容";//alert对应的值也可以是字典,字典中body键的值对应显示内容
badge = 1; // App 角标,可推送 n、+n、-n 来实现角标的固定、增加、减少
sound = default; // 推送声音,默认系统三全音,如需使用自己的声音,需要将声音文件拖拽&拷贝至 Xcode 工程目录任意位置,并在推送时指定其文件名
};
proNo = "tb_pro_no_id249349874"; // 自定义字段
DesVc = "ProViewController";
}


 - 处于未启动,系统会显示通知,点击通知横幅启动,在以下方法中获取通知内容:

-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

 - 处于后台,系统会显示通知,但不会通知对应应用(即应用的方法不会被调用)。
 - 处于前台,iOS10之后会显示通知。(iOS10之前会不会展示通知,楼主也记不住了😭)在以下方法中获取通知内容:
   - iOS7 ~ iOS9

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void(^(UIBackgroundFetchResult))completionHandler

   - iOS10 after (UNUserNotificationCenterDelegate中的代理方法)

-(void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler

 
- 后台推送
 - 必须在 Xcode 工程中 TARGETS – Capabilities – Background Modes 中开启Remote notifications功能。
 - payload构造:必须携带 "content-available" = 1,必须携带 alert中的显示信息、badge、sound 中 至少 1 个字段。

{
aps = {
alert = "显示内容";//alert对应的值也可以是字典,字典中body键的值对应显示内容
badge = 1;
"content-available" = 1; // 必带字段
sound = default;
};
key1 = value1;
}

 - 处于未启动,同上述普通推送一致。
 - 处于后台或者挂起,系统会显示通知。通过下述获取通知内容,你的应用会在后台启动(如果应用为挂起状态,则唤醒它,处于后台状态),将有30秒的时间进行处理通知或者下载数据等操作。

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void(^(UIBackgroundFetchResult))completionHandler


 - 处于前台, 系统会显示通知。可通过以下方法获取内容:

   - iOS7 after

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void(^(UIBackgroundFetchResult))completionHandler

   - 注:iOS10 之后除了会调用上面的方法,还会调用此方法 (UNUserNotificationCenterDelegate中的代理方法)

-(void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler


- 静默推送
 - 系统不会显示通知,用户不会有任何察觉。
 - payload构造:必须携带 "content-available" = 1。必须不携带 alert中的显示内容、badge、sound。

{
aps = {
alert = "";//alert对应的值也可以为字典,字典中不能包含body键值对。
"content-available" = 1; // 必带字段
};
key1 = value1;
}

 - 处于未启动,获取不到通知内容
 - 处于后台,iOS7 之后你的应用会在后台启动(如果应用为挂起状态,则唤醒它,处于后台状态),将有30秒的时间进行处理通知或者下载数据等操作。可通过下述方法获取内容:

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void(^(UIBackgroundFetchResult))completionHandler

 - 处于前台, iOS7 之后可通过下述方法获取内容:

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void(^(UIBackgroundFetchResult))completionHandler



#####7.获取 APNs(通知) 推送内容
iOS 设备收到一条推送(APNs),用户点击推送通知打开应用时,应用程序根据状态不同进行处理,需在 AppDelegate 中的以下方法中添加代码以获取apn内容。
- 如果 App 状态为未运行,此函数将被调用,如果launchOptions包含UIApplicationLaunchOptionsRemoteNotificationKey表示用户点击apn 通知导致app被启动运行;如果不含有对应键值则表示 App 不是因点击apn而被启动,可能为直接点击icon被启动或其他。

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// apn 内容获取:
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey]
}

2.基于iOS 6 及以下的系统版本,如果 App状态为正在前台或者点击通知栏的通知消息,那么此函数将被调用,并且可通过AppDelegate的applicationState是否为UIApplicationStateActive判断程序是否在前台运行。

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo{
}

3.此方法会在以下几种情况下调用
 - iOS7 ~ iOS9 前台接收普通推送。
 - iOS7之后开启Background Mode Remote Notification特性,在前台或者后台接收到后台推送和静默推送。

-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"iOS7及以上系统,收到通知:%@", [self logDic:userInfo]);

completionHandler(UIBackgroundFetchResultNewData);
}
-(NSString *)logDic:(NSDictionary *)dic {
if (![dic count]) {
return nil;
}
NSString *tempStr1 =
[[dic description] stringByReplacingOccurrencesOfString:@"\u"
withString:@"\U"];
NSString *tempStr2 =
[tempStr1 stringByReplacingOccurrencesOfString:@""" withString:@"\""];
NSString *tempStr3 =
[[@""" stringByAppendingString:tempStr2] stringByAppendingString:@"""];
NSData *tempData = [tempStr3 dataUsingEncoding:NSUTF8StringEncoding];
NSString *str =
[NSPropertyListSerialization propertyListFromData:tempData
mutabilityOption:NSPropertyListImmutable
format:NULL
errorDescription:NULL];
return str;
}

4.基于iOS 10及以上的系统版本,
原`[application: didReceiveRemoteNotification:]`将会被系统废弃,
由新增`UserNotifications.framework`中的以下两个方法替代。

[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:]
[UNUserNotificationCenterDelegate didReceiveNotificationResponse:withCompletionHandler:]

在极光推送SDK2.1.9版本以后可实现SDK封装的JPUSHRegisterDelegate协议方法,适配iOS10新增的delegate协议方法。
即以下两个方法:

ifdef NSFoundationVersionNumber_iOS_9_x_Max

pragma mark- JPUSHRegisterDelegate

//前台收到推送,可以采取必要的措施处理通知和更新APP的内容。
-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {

NSDictionary * userInfo = notification.request.content.userInfo;
UNNotificationRequest *request = notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge; // 推送消息的角标
NSString *body = content.body; // 推送消息体
UNNotificationSound *sound = content.sound; // 推送消息的声音
NSString *subtitle = content.subtitle; // 推送消息的副标题
NSString *title = content.title; // 推送消息的标题

if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"iOS10 前台收到远程通知:%@", [self logDic:userInfo]);
}
// 指定系统如何提醒用户,有Badge、Sound、Alert三种类型可以设置
// 如果不需提醒可传UNNotificationPresentationOptionNone
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}
//当用户点击了通知的某个操作,需要进行相应处理,如跳转到某个界面
-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
NSDictionary * userInfo = response.notification.request.content.userInfo;
UNNotificationRequest *request = response.notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge; // 推送消息的角标
NSString *body = content.body; // 推送消息体
UNNotificationSound *sound = content.sound; // 推送消息的声音
NSString *subtitle = content.subtitle; // 推送消息的副标题
NSString *title = content.title; // 推送消息的标题
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);
}
// 让系统知道你已处理完通知。
completionHandler();
}

endif

#####8. 极光推送后台发送远程推送测试
1.登录`极光推送`,切换到控制台,并点击对应的应用,点击推送按钮
![点击推送按钮](http://upload-images.jianshu.io/upload_images/790038-ce63654e0f2dafec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![点击发送通知](http://upload-images.jianshu.io/upload_images/790038-e67a3d8e1f5eec8e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2.设置推送内容
![设置推送内容](http://upload-images.jianshu.io/upload_images/790038-86e85fb6524a99e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

选择推送环境iOS开发环境,目标人群,发送时间。再点击可选设置设置消息的具体内容。
![选择推送环境](http://upload-images.jianshu.io/upload_images/790038-b8d4bb9b0e23c641.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


3.设置消息具体内容。

![设置推送内容](http://upload-images.jianshu.io/upload_images/790038-f8e05e4ad5093b25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


4.iOS设备接收到远程推送
![iOS设备接收到远程推送](http://upload-images.jianshu.io/upload_images/790038-9969a3408695827e.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
以下为打印的通知内容。

{
"_j_msgid" = 3017423712;
aps = {
alert = {
body = "你爱谈天,我爱笑~~";
subtitle = "每天坚持1小时,会有大收获。";
title = "天天";
};
badge = 100;
sound = default;
};
}



5.推送历史可以在这里看得到,但有延迟,可能远程推送已接收到,推送历史数据还没有更新到最新。
![推送历史](http://upload-images.jianshu.io/upload_images/790038-994708e85592d06b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


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

推荐阅读更多精彩内容