RNCodePush热更新组件详细接入教程

CodePush简介

CodePush 是微软提供的一套提供给 React Native 和 Cordova 开发者,直接部署移动应用更新给用户设备的云服务。CodePush 作为一个中央仓库,开发者可以推送更新 (JS, HTML, CSS and images),应用可以从客户端 SDK 里面查询更新。CodePush 可以让应用有更多的可确定性,也可以让你直接接触用户群。在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。
关于热更新

React Native 官方并没有提供热更新的技术方案,但是它是支持热更新的。

React Native 中的热更新有点像 App 的版本更新,也就是根据查询 server 端的版本和手机端目前 App 的版本进行对比,然后来执行是否更新的操作。

根本原因在于 React Native 的加载启动机制:React Native 会将一系列资源打包成js bundle文件,系统加载js bundle文件,解析并渲染。所以,React Native热更新的根本原理就是更换js bundle文件,并重新加载,新的内容就完美的展示出来了。

一。CodePush热更新组件详细接入教程《安装和RN集成》
1、安装 CodePush CLI
npm install -g code-push-cli 2、注册 CodePush账号 code-push register
这将会启动浏览器,要求验证Github或微软帐号。一旦验证成功,它将创建一个CodePush帐号跟你的Github或MSA相连,并生成一个访问密钥(Access Key),然后你可以拷贝/粘贴到CLI(它会提示你这样做)
如果没有自动打开浏览器,检查设置默认的浏览器

3、//热更新平台的账号信息
register info code-push for android
github username: wq
password: xxxx
4、验证我的登录是否成功
$ code-push login

5、在CodePush服务器注册App(不同平台使用不同的名字)
添加Android平台应用;smallred是你app_name
code-push app add <appName> <os> <platform>

如:
$ code-push app add smallred Android react-native

│ Name │ Deployment Key │
│ Production │ Fhxxx57 │
│ Staging │ atxxx57 │

1-如果你的App既有iOS又有Android,请为不同平台创建单独的App;

2-成功,会返回Deployment Key。

3-所有新的Apps自动会出现2个部署环境:staging代表开发版的热更新部署,用于测试更新;production代表生产版的。

4-在ios中,将staging的key复制在info.plist的CodePushDeploymentKey值中
在android中,复制在Application的getPackages的CodePush构造中。
ps:你可以通过code-push deployment ls <app_name> -k命令来查看deployment key。

我们可以输入如下命令来查看我们刚刚添加的App
$ code-push app list

二、RN代码中集成CodePush的SDK
1.在根目录(项目目录)执行安装集成的组件react-native-code-push
npm install react-native-code-push --save 安装完后,link连接,将Staging中的Deployment Key输入:atxxx57 react-native link react-native-code-push
至此Code Push for Android的SDK已经集成完成。

2.在android中配置参数
在 android/app/build.gradle文件里面添如下代码:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
然后在/android/settings.gradle中添加如下代码:
include ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')

3.运行 code-push deployment -k ls <appName>获取 部署秘钥。默认的部署名是 staging,所以 部署秘钥(deployment key ) 就是 staging。
code-push deployment -k ls smallred
如果之前的都配置正确,那这里可以看到Production与Staging的Deployment Key,
将这两个key粘贴下来.如果环境来决定需要用到哪个key.
在刚开始,肯定需要测试,
那就将Staging对应的Deployment Key,替换到下面deployment-key-here的代码中.
地址:https://www.jianshu.com/p/87ccfb795635

4.添加配置。当APP启动时我们需要让app向CodePush咨询JS bundle的所在位置,这样CodePush就可以控制版本。更新 MainApplication.java文件:

public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
@Override
protected List<ReactPackage> getPackages() {
// 3. Instantiate an instance of the CodePush runtime and add it to the list of
// existing packages, specifying the right deployment key. If you don't already
// have it, you can run "code-push deployment ls <appName> -k" to retrieve your key.
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CodePush("atxxx57", MainApplication.this, BuildConfig.DEBUG),
//new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG)
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

关于deployment-key的设置

在上述代码中我们在创建CodePush实例的时候需要设置一个deployment-key,因为deployment-key分生产环境与测试环境两种,所以建议大家在build.gradle中进行设置。在build.gradle中的设置方法如下:

打开android/app/build.gradle文件,找到android { buildTypes {} }然后添加如下代码即可:
android {
...
buildTypes {
debug {
...
// CodePush updates should not be tested in Debug mode
...
}

    releaseStaging {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'
        ...
    }

    release {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
        ...
    }
}
...

}
心得:另外,我们也可以将deployment-key存放在local.properties中:

code_push_key_production=Fhxxx57
code_push_key_staging=atxxx57
然后在就可以在android/app/build.gradle可以通过下面方式来引用它了:
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
...
buildTypes {
debug {
...
// CodePush updates should not be tested in Debug mode
...
}

    releaseStaging {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_production")+'"'
        ...
    }

    release {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_staging")+'"'
        ...
    }
}
...

}
在android/app/build.gradle设置好deployment-key之后呢,我们就可以这样使用了:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
...
new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.
...
);
}
5.修改versionName。
在 android/app/build.gradle中有个 android.defaultConfig.versionName属性,我们需要把 应用版本改成 1.0.0(默认是1.0,但是codepush需要三位数)。

android{
defaultConfig{
versionName "1.0.0"
}
}

详细的操作在官网demo示例中:
https://github.com/Microsoft/react-native-code-push/blob/master/Examples/CodePushDemoApp/App.js

三。配置Android平台《发布更新》

7、发布更新RN的bundle到微软服务器
CodePush支持两种发布更新的方式:
一是通过code-push release-react简化方式,
二是通过code-push release的复杂方式。

一简化方式、命令格式:
code-push release-react <appName> <platform>
如eg:
code-push release-react smallred ios
code-push release-react smallred android
code-push release-react smallred ios --t 1.0.0 --dev false --d Production --des "1.优化操作流程" --m true
code-push release-react smallred android --t 1.0.0 --dev false --d Production --des "1.优化操作流程" --m true

[--bundleName <bundleName>] 指明生成JS Bundle的文件名
[--deploymentName <deploymentName>] 部署环境名:Staging(临时环境)、Production(生产环境)
[--description <description>] 更新内容描述
[--development <development>] 指明是否要生成一个非最小化,开发的JS bundle文件。默认是false,禁用警告提示并且bundle文件是最小化的。
[--disabled <disabled>] 指明一个版本更新是否可以被用户下载。如果没有指定,版本更新是有效的(如:用户将要下载的那一刻你的应用称为同步)。如果你想发布一个更新但不是立即生效,那么这个参数是有价值的,直到你明确用[补丁]发布,当你要让用户能够下载(如:公告博客上线)。
[--entryFile <entryFile>] 指明相对应用根目录的路径入口JavaScript 文件。
[--mandatory] 更新是否强制性(true、false)
[--sourcemapOutput <sourcemapOutput>] 指明生成的JS bundle 的sourcemap写入的相对路径。如果没有指定,sourcemaps文件不会生成。
[--targetBinaryVersion <targetBinaryVersion>] app的版本号,如果没有指定,默认使用Info.plist中的version值
[--rollout <rolloutPercentage>]
指定可以接收这次更新的用户百分比(在1-100的数字)如果没有设置这个参数,它会设置为100。

二复杂方式、生成bundle
发布更新之前,需要先把 js打包成 bundle,如:

第一步: 在 工程目录里面新增 bundles文件:mkdir bundles
第二步: 运行命令打包 react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试。
eg:
react-native bundle --platform android --entry-file index.js --bundle-output ./bundles/index.android.bundle --dev false
成功将返回:
Loading dependency graph, done.
bundle: Writing bundle output to: ./bundles/index.android.bundle
bundle: Done writing bundle output
Assets destination folder is not set, skipping...

需要注意的是:
忽略了资源输出是因为 输出资源文件后,会把bundle文件覆盖了。
输出的bundle文件名不叫其他,而是 index.android.bundle,是因为 在debug模式下,工程读取的bundle就是叫做 index.android.bundle。
平台可以选择 android 或者 ios。

发布更新
打包bundle结束后,就可以通过CodePush发布更新了。在终端输入
code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --deploymentName: 更新环境 --description: 更新描述 --mandatory: 是否强制更新
eg:
code-push release smallred ./bundles/index.android.bundle 1.1.3 --deploymentName Production --description "1.1.3支持文章缓存。" --mandatory true
code-push release smallred ./bundles/index.android.bundle 1.0.1 --deploymentName Staging --description "1.0.1支持文章缓存。" --mandatory true
成功将返回:
Successfully released an update containing the "./bundles/index.android.bundle" file to the "Production" deployment of the "smallred" app.

9、查看发布的历史记录
在终端输入 code-push deployment history <appName> Staging 可以看到Staging版本更新的时间、描述等等属性。
如eg:
code-push deployment history smallred Production
code-push deployment history smallred Staging

部署测试

在应用创建时,会自动生成Staging与Production这两个环境.

应用在开发阶段,通常都是在Staging下进行开发的,而Production作为生产环境.
当应用在开发阶段开发完毕,可使用code-push promote命令从Staging 迁移到Production中

CodePush简介

CodePush 是微软提供的一套提供给 React Native 和 Cordova 开发者,直接部署移动应用更新给用户设备的云服务。CodePush 作为一个中央仓库,开发者可以推送更新 (JS, HTML, CSS and images),应用可以从客户端 SDK 里面查询更新。CodePush 可以让应用有更多的可确定性,也可以让你直接接触用户群。在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。
关于热更新

React Native 官方并没有提供热更新的技术方案,但是它是支持热更新的。

React Native 中的热更新有点像 App 的版本更新,也就是根据查询 server 端的版本和手机端目前 App 的版本进行对比,然后来执行是否更新的操作。

根本原因在于 React Native 的加载启动机制:React Native 会将一系列资源打包成js bundle文件,系统加载js bundle文件,解析并渲染。所以,React Native热更新的根本原理就是更换js bundle文件,并重新加载,新的内容就完美的展示出来了。

一。CodePush热更新组件详细接入教程《安装和RN集成》
1、安装 CodePush CLI
npm install -g code-push-cli 2、注册 CodePush账号 code-push register
这将会启动浏览器,要求验证Github或微软帐号。一旦验证成功,它将创建一个CodePush帐号跟你的Github或MSA相连,并生成一个访问密钥(Access Key),然后你可以拷贝/粘贴到CLI(它会提示你这样做)
如果没有自动打开浏览器,检查设置默认的浏览器

3、//热更新平台的账号信息
register info code-push for android
github username: xmfengwankeji
password: fengwan777
4、验证我的登录是否成功
$ code-push login

5、在CodePush服务器注册App(不同平台使用不同的名字)
添加Android平台应用;smallred是你app_name
code-push app add <appName> <os> <platform>

如:
$ code-push app add smallred Android react-native

│ Name │ Deployment Key │
│ Production │ FhW9iTw89LOuCywielf8Z9AV_8o-e4b0d9e2-373f-4966-a7e5-a158ec8b9b57 │
│ Staging │ ataVr8Yk2HYxxlS29OUm_SFejDxHe4b0d9e2-373f-4966-a7e5-a158ec8b9b57 │

1-如果你的App既有iOS又有Android,请为不同平台创建单独的App;

2-成功,会返回Deployment Key。

3-所有新的Apps自动会出现2个部署环境:staging代表开发版的热更新部署,用于测试更新;production代表生产版的。

4-在ios中,将staging的key复制在info.plist的CodePushDeploymentKey值中
在android中,复制在Application的getPackages的CodePush构造中。
ps:你可以通过code-push deployment ls <app_name> -k命令来查看deployment key。

我们可以输入如下命令来查看我们刚刚添加的App
$ code-push app list

二、RN代码中集成CodePush的SDK
1.在根目录(项目目录)执行安装集成的组件react-native-code-push
npm install react-native-code-push --save 安装完后,link连接,将Staging中的Deployment Key输入:ataVr8Yk2HYxxlS29OUm_SFejDxHe4b0d9e2-373f-4966-a7e5-a158ec8b9b57 react-native link react-native-code-push
至此Code Push for Android的SDK已经集成完成。

2.在android中配置参数
在 android/app/build.gradle文件里面添如下代码:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
然后在/android/settings.gradle中添加如下代码:
include ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')

3.运行 code-push deployment -k ls <appName>获取 部署秘钥。默认的部署名是 staging,所以 部署秘钥(deployment key ) 就是 staging。
code-push deployment -k ls smallred
如果之前的都配置正确,那这里可以看到Production与Staging的Deployment Key,
将这两个key粘贴下来.如果环境来决定需要用到哪个key.
在刚开始,肯定需要测试,
那就将Staging对应的Deployment Key,替换到下面deployment-key-here的代码中.
地址:https://www.jianshu.com/p/87ccfb795635

4.添加配置。当APP启动时我们需要让app向CodePush咨询JS bundle的所在位置,这样CodePush就可以控制版本。更新 MainApplication.java文件:

public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
@Override
protected List<ReactPackage> getPackages() {
// 3. Instantiate an instance of the CodePush runtime and add it to the list of
// existing packages, specifying the right deployment key. If you don't already
// have it, you can run "code-push deployment ls <appName> -k" to retrieve your key.
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CodePush("ataVr8Yk2HYxxlS29OUm_SFejDxHe4b0d9e2-373f-4966-a7e5-a158ec8b9b57", MainApplication.this, BuildConfig.DEBUG),
//new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG)
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

关于deployment-key的设置

在上述代码中我们在创建CodePush实例的时候需要设置一个deployment-key,因为deployment-key分生产环境与测试环境两种,所以建议大家在build.gradle中进行设置。在build.gradle中的设置方法如下:

打开android/app/build.gradle文件,找到android { buildTypes {} }然后添加如下代码即可:
android {
...
buildTypes {
debug {
...
// CodePush updates should not be tested in Debug mode
...
}

    releaseStaging {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'
        ...
    }

    release {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
        ...
    }
}
...

}
心得:另外,我们也可以将deployment-key存放在local.properties中:

code_push_key_production=FhW9iTw89LOuCywielf8Z9AV_8o-e4b0d9e2-373f-4966-a7e5-a158ec8b9b57
code_push_key_staging=ataVr8Yk2HYxxlS29OUm_SFejDxHe4b0d9e2-373f-4966-a7e5-a158ec8b9b57
然后在就可以在android/app/build.gradle可以通过下面方式来引用它了:
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
...
buildTypes {
debug {
...
// CodePush updates should not be tested in Debug mode
...
}

    releaseStaging {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_production")+'"'
        ...
    }

    release {
        ...
        buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_staging")+'"'
        ...
    }
}
...

}
在android/app/build.gradle设置好deployment-key之后呢,我们就可以这样使用了:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
...
new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.
...
);
}
5.修改versionName。
在 android/app/build.gradle中有个 android.defaultConfig.versionName属性,我们需要把 应用版本改成 1.0.0(默认是1.0,但是codepush需要三位数)。

android{
defaultConfig{
versionName "1.0.0"
}
}

详细的操作在官网demo示例中:
https://github.com/Microsoft/react-native-code-push/blob/master/Examples/CodePushDemoApp/App.js

三。配置Android平台《发布更新》

7、发布更新RN的bundle到微软服务器
CodePush支持两种发布更新的方式:
一是通过code-push release-react简化方式,
二是通过code-push release的复杂方式。

一简化方式、命令格式:
code-push release-react <appName> <platform>
如eg:
code-push release-react smallred ios
code-push release-react smallred android
code-push release-react smallred ios --t 1.0.0 --dev false --d Production --des "1.优化操作流程" --m true
code-push release-react smallred android --t 1.0.0 --dev false --d Production --des "1.优化操作流程" --m true

[--bundleName <bundleName>] 指明生成JS Bundle的文件名
[--deploymentName <deploymentName>] 部署环境名:Staging(临时环境)、Production(生产环境)
[--description <description>] 更新内容描述
[--development <development>] 指明是否要生成一个非最小化,开发的JS bundle文件。默认是false,禁用警告提示并且bundle文件是最小化的。
[--disabled <disabled>] 指明一个版本更新是否可以被用户下载。如果没有指定,版本更新是有效的(如:用户将要下载的那一刻你的应用称为同步)。如果你想发布一个更新但不是立即生效,那么这个参数是有价值的,直到你明确用[补丁]发布,当你要让用户能够下载(如:公告博客上线)。
[--entryFile <entryFile>] 指明相对应用根目录的路径入口JavaScript 文件。
[--mandatory] 更新是否强制性(true、false)
[--sourcemapOutput <sourcemapOutput>] 指明生成的JS bundle 的sourcemap写入的相对路径。如果没有指定,sourcemaps文件不会生成。
[--targetBinaryVersion <targetBinaryVersion>] app的版本号,如果没有指定,默认使用Info.plist中的version值
[--rollout <rolloutPercentage>]
指定可以接收这次更新的用户百分比(在1-100的数字)如果没有设置这个参数,它会设置为100。

二复杂方式、生成bundle
发布更新之前,需要先把 js打包成 bundle,如:

第一步: 在 工程目录里面新增 bundles文件:mkdir bundles
第二步: 运行命令打包 react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试。
eg:
react-native bundle --platform android --entry-file index.js --bundle-output ./bundles/index.android.bundle --dev false
成功将返回:
Loading dependency graph, done.
bundle: Writing bundle output to: ./bundles/index.android.bundle
bundle: Done writing bundle output
Assets destination folder is not set, skipping...

需要注意的是:
忽略了资源输出是因为 输出资源文件后,会把bundle文件覆盖了。
输出的bundle文件名不叫其他,而是 index.android.bundle,是因为 在debug模式下,工程读取的bundle就是叫做 index.android.bundle。
平台可以选择 android 或者 ios。

发布更新
打包bundle结束后,就可以通过CodePush发布更新了。在终端输入
code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --deploymentName: 更新环境 --description: 更新描述 --mandatory: 是否强制更新
eg:
code-push release smallred ./bundles/index.android.bundle 1.1.3 --deploymentName Production --description "1.1.3支持文章缓存。" --mandatory true
code-push release smallred ./bundles/index.android.bundle 1.0.1 --deploymentName Staging --description "1.0.1支持文章缓存。" --mandatory true
成功将返回:
Successfully released an update containing the "./bundles/index.android.bundle" file to the "Production" deployment of the "smallred" app.

9、查看发布的历史记录
在终端输入 code-push deployment history <appName> Staging 可以看到Staging版本更新的时间、描述等等属性。
如eg:
code-push deployment history smallred Production
code-push deployment history smallred Staging

部署测试

在应用创建时,会自动生成Staging与Production这两个环境.

应用在开发阶段,通常都是在Staging下进行开发的,而Production作为生产环境.
当应用在开发阶段开发完毕,可使用code-push promote命令从Staging 迁移到Production中

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

推荐阅读更多精彩内容