Gradle 打包

參考資料:
http://gold.xitu.io/post/580c85768ac247005b5472f9
http://www.lxweimin.com/p/9df3c3b6067a
http://mp.weixin.qq.com/s?__biz=MzA4NTQwNDcyMA==&mid=2650661971&idx=1&sn=3fb69537bbc5fbb14d152ba6381c3b83#rd
https://segmentfault.com/a/1190000004229002
http://wiki.jikexueyuan.com/project/deep-android-gradle/

dex 打包
http://blog.csdn.net/mynameishuangshuai/article/details/52703029

For Android 準(zhǔn)備的基礎(chǔ)

構(gòu)建工具
Gradle是一種構(gòu)建工具,Android Studio默認(rèn)采用Gradle來構(gòu)建,Eclipse中使用的ant來構(gòu)建Android;
構(gòu)建工具指的是對項(xiàng)目進(jìn)行編譯、運(yùn)行、簽名、打包、依賴管理等一系列功能的合集,另外一個非常重要的功能是管理依賴(第三方庫管理);

Google 開發(fā)了Andriod Studio 插件 Android Gradle Plugin 用來構(gòu)建 Android App;

新增內(nèi)容(基礎(chǔ)知識)##

Gradle是一個框架,定義了自己一些規(guī)則,我們需要遵循她的設(shè)計規(guī)則:

  1. 在Gradle中,每一個待編譯的工程都叫做一個Project,如:Android Project目錄下的各種lib引入庫,都是一個Project。
  2. 在每個Project在構(gòu)建時,又包含了一系列Task,比如:Android APK的編譯包含:java源代碼編譯Task、Android資源編譯Task、簽名Task等等;
  3. 一個Project有多少個task,由其編譯腳本指定的插件決定,什么是插件?插件就是用來定義Task,并執(zhí)行這些Task的東西;

Gradle負(fù)責(zé)定義流程和規(guī)則,而具體的編譯工作則是通過插件的方式來完成,
如:編譯Java的有java插件,編譯Android lib 的有Android lib 的插件;

總之:Gradle中每一個待編譯的工程,都是一個Project,而Project的編譯的工作,是由其定義的一個一個Task來定義與執(zhí)行的;

在Android工程中,每一個Library、每一個App都是單獨(dú)的Project,同時在每一個Project的根目錄下,都有一個build.gradle文件,表示Project的編譯腳本;

settings.gradle文件
在Android工程中,我們一般都有多個Project,如上,每個project都有一個build.gradle文件與此對應(yīng);在工程的根目錄,有一個build.gradle文件,她負(fù)責(zé)配置其他子Project的,與settings.gradle文件,settings.gradle文件指出該工程包含多少個 子 Project;

image.png

有了這2個文件,在項(xiàng)目的根目錄進(jìn)行編譯時,可以把項(xiàng)目中的所有project都編譯好;

Gradle 相關(guān)命令

  1. gradle projects 查看工程信息;
  2. gradle tasks 查看任務(wù)信息;
  3. gradle task-name 執(zhí)行任務(wù),如:gralde clean,gradle properties

task 的依賴關(guān)系
task和task之間可能有關(guān)系,如:某task的執(zhí)行,需要其他task先執(zhí)行完成,這就是依賴關(guān)系;如:assemble task就依賴其他task先執(zhí)行,assemble 才能執(zhí)行;
可以指定 assemble 依賴于 自己定義的 task,這樣,自定義的task會優(yōu)先執(zhí)行;

gradle工作流程

  1. 初始化階段:對于多project build而言,就是執(zhí)行 settings.gradle;
  2. Configuration階段:解析每個project中的build.gradle文件,在這2個階段之間,可加入一些定制化的hook;
  3. 預(yù)執(zhí)行階段:現(xiàn)整個 build的 project及內(nèi)部的task關(guān)系已確定;
  4. 執(zhí)行任務(wù)階段;

gradle編程模型
Gradle執(zhí)行的時候,會把腳本轉(zhuǎn)化成Java對象,Gradle主要3種對象,并與三種不同的腳本文件對應(yīng):

  1. Gradle對象:執(zhí)行g(shù)radle xxx,gradle會從默認(rèn)配置腳本中構(gòu)造出一個Gradle對象,整個執(zhí)行過程中,只有這么一個對象,類型是Gradle;
  2. Project對象:由build.gralde轉(zhuǎn);
  3. Settings對象:settings.gradle轉(zhuǎn);

Project對象
Project包含若干個Tasks,Project對應(yīng)具體工程,需要為Project加載所需要的插件,如:為java工程加入Java插件;

  • 加載插件 :調(diào)用apply方法, https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html
    apply plugin: 'com.android.library'
    apply plugin: 'com.android.application'
    Groovy支持函數(shù)調(diào)用時,通過 參數(shù)名1:參數(shù)值1,,參數(shù)名2:參數(shù)值2來傳遞參數(shù);
    // 加載自定義的插件(這里為一個工具文件)
    apply from: rootProject.getRootDir().getAbsolutePath() + "/utils.gradle"
  • 設(shè)置屬性
    gradle可能包含不止一個build.gradle文件,考慮在多個腳本中設(shè)置屬性:
    gradle提供名為 extra property的方法,表示額外屬性,在第一次定義該屬性時需通過ext前綴來標(biāo)示他是一個額外的屬性,后面的存在,就不需要ext前綴了,ext屬性支持Project和Gradle對象,意思是為Project和Gradle對象設(shè)置ext屬性;
 ext {
     local = 'Hello groovy'
 }
 task printProperties {
     println local        // Local extra property
     if (project.hasProperty('cmd')) {
         println cmd        // Command line property
     }
}

如果在 utils.gradle 中定義了一些函數(shù),然后想在其他 build.gradle 中調(diào)用這些函數(shù)。那該怎么做呢?

[utils.gradle]
//utils.gradle 中定義了一個獲取 AndroidManifests.xml versionName 的函數(shù)
def getVersionNameAdvanced(){
     // 下面這行代碼中的 project 是誰?
      def xmlFile = project.file("AndroidManifest.xml")
      def rootManifest = new XmlSlurper().parse(xmlFile)
      return rootManifest['@android:versionName']
}
//現(xiàn)在,想把這個 API 輸出到各個 Project。由于這個 utils.gradle 會被每一個 Project Apply,所以
//我可以把 getVersionNameAdvanced 定義成一個 closure,然后賦值到一個外部屬性
// 下面的 ext 是誰的 ext?
ext{ //此段花括號中代碼是閉包
    //除了 ext.xxx=value 這種定義方法外,還可以使用 ext{}這種書寫方法。
    //ext{}不是 ext(Closure)對應(yīng)的函數(shù)調(diào)用。但是 ext{}中的{}確實(shí)是閉包。
    getVersionNameAdvanced = this.&getVersionNameAdvanced
}

問題

  1. project是誰?
    當(dāng)一個project apply 一個gradle文件時,這個gradle文件會轉(zhuǎn)化成一個script對象;
    script中有一個delegate對象,這個delegate,默認(rèn)加載(即調(diào)用apply)它的project對象;
    在 apply函數(shù)中,除了 from參數(shù),還有個to參數(shù),通過to參數(shù),可改變delegate對象為其他;
    delegate就是當(dāng)在script中,操作一些不是script自己定義的變量,或者函數(shù)時,gradle會到script的delegate對象中去找,看有沒有定義這些變量or函數(shù);
    ==》這樣project就是加載utils.gradle的Project;
  2. ext是誰的ext?
    ==》 project對應(yīng)的ext了;此處為 Project 添加了一些 closure。那么,在 Project 中
    就可以調(diào)用 getVersionNameAdvanced 函數(shù)了

在Java和Groovy中:可能會把常用的函數(shù)放到一個輔助類中,通過import他們,并調(diào)用;
但在Gradle中,更正規(guī)的方式在 xxx.gradle中定義插件,然后通過Task的方式來完成工作;

Task介紹
task是Gradle中的一種數(shù)據(jù)類型,表示一些要執(zhí)行的工作,不同的插件可添加不同task,每一個task需要和一個project關(guān)聯(lián);
Task 的 API 文檔位于 https://docs.gradle.org/current/dsl/org.gradle.api.Task.html

[build.gradle]
// Task 是和Project關(guān)聯(lián)的,所以,需要利用Project的task函數(shù)來創(chuàng)建一個Task
task myTask  // 新建task名字
task myTask {}  // 閉包
task myType << { task action }  // << 符號是 doLast縮寫
task myTask(type:SomeType)
task myTask(type:SomeType) { }

上面都用到了Project的一個函數(shù),task,注意:

  1. 一個Task包含若干action,所以 Task有doFirst和doLast二個函數(shù),用于添加需要最先執(zhí)行的Action和最后需要執(zhí)行的Action,action是一個閉包;
    2.Task創(chuàng)建的時候可指定Type,通過 type:名字表達(dá),就是告訴gradle,這個新建的Task對象會從哪個基類Task派生,如:Copy是Gradle中的一個類,當(dāng) task myTask(type:Copy)的時候,創(chuàng)建的Task是一個Copy Task;
    3.當(dāng)使用task myTask {XXX}的時候,花括號是一個閉包,這會導(dǎo)致gradle在創(chuàng)建此task之后,返回給用戶之前,會先執(zhí)行了 閉包內(nèi)容;
    4.當(dāng)使用task myTask << {XXX}的時候,創(chuàng)建task對象,并把closure作為一個action加到此task的action隊列中,并且告訴他“最后才執(zhí)行這個closure”;

Script Block
gradle文件中包含一些 Script Block,她的作用是讓我們來配置相關(guān)信息的,不同的SB有不同的配置;
如:

buildscript {   // 這是一個Script Block
    repositories {
        jcenter()
    }

script block

每個SB后面都需要跟一個花括號,閉包;
https://docs.gradle.org/current/javadoc/ ,可輸入SB名字,進(jìn)行查找;
解釋幾個SB:

  1. subprojects:它會遍歷 工程 中的 每個子 Project,在其closure中,默認(rèn)參數(shù)是子project對應(yīng)的Project對象,由于其他SB都在subprojects中,所以相當(dāng)于對每個Project都配置了一些信息;
  2. buildscript::它的 closure 是在一個類型為 ScriptHandler 的對象上執(zhí)行的。主意用來所依賴的 classpa
    th 等信息。通過查看 ScriptHandler API 可知,在 buildscript SB 中,你可以調(diào)用 ScriptHandler 提供
    的 repositories(Closure )、dependencies(Closure)函數(shù)。這也是為什么 repositories 和 dependencies
    兩個 SB 為什么要放在 buildscript 的花括號中的原因。這就是所謂的行話,得知道規(guī)矩。不知道
    規(guī)矩你就亂了。記不住規(guī)矩,又不知道查 SDK,那么就徹底抓瞎,只能到網(wǎng)上到處找答案了!
buildscript

Android 自己定義了好多 ScriptBlock。Android 定義的 DSL 參考文檔在
https://developer.android.com/tools/building/plugin-for-gradle.html








其他一些:##


Gradle Wrapper
參考:
http://mp.weixin.qq.com/s?__biz=MzA4NTQwNDcyMA==&mid=2650661971&idx=1&sn=3fb69537bbc5fbb14d152ba6381c3b83#rd
我們可以在項(xiàng)目的根目錄,輸入 gradlew -v 可查看 gradle 版本;
gradlew 為 gradle wapper 的縮寫

注意:如果沒有配置 全局的 gralde 環(huán)境變量,在Android studio 的 命令框中,需要輸入./ 再加 graldew來使用相關(guān)命令,如下:

常用命令
./gradlew -v 查看版本號 (win 下 輸入 gradlew -v)
./gradlew clean 清除/app目錄下的build文件夾
./gradlew build 檢查依賴并編譯打包
./gradlew build 命令把 debug、release 環(huán)境的包都打出來;
./gradlew assembleDebug 編譯并打Debug包
./gradlew assembleRelease 編譯并打Release的包

基本的Gradle
構(gòu)建Android程序,需要構(gòu)建腳本, gradle默認(rèn)提供了一些配置與默認(rèn)值,簡化了我們的構(gòu)建工作;

Project與Tasks
Gradle中有2個非常重要的對象,Project 和 Tasks;
注意: Android Studio 中的project和Gradle中的project不是同一個概念。
這里的project指的是 gradle中的project;
每個project有至少一個tasks,每個build.gradle文件代表一個project,tasks在build.gradle中定義,一個tasks包含了多個動作,然后按順序一個一個執(zhí)行,類似java中的方法;

構(gòu)建生命周期
一旦一個tasks被執(zhí)行,后面將不再執(zhí)行,不包含依賴的tasks總是優(yōu)先執(zhí)行,一個構(gòu)建會經(jīng)歷以下3個階段:

  1. 初始化階段:project實(shí)例在這兒創(chuàng)建,如果有多個模塊,即有多個build.gradle文件,多個project將會被創(chuàng)建;
  2. 配置階段:在該階段,build.gradle腳本將會執(zhí)行,為每個project創(chuàng)建和配置所有的tasks;
  3. 執(zhí)行階段:這一階段,gradle會決定哪一個tasks會被執(zhí)行,哪一個tasks會被執(zhí)行完全依賴開始構(gòu)建時傳入的參數(shù)和當(dāng)前所在的文件夾位置有關(guān)

build.gradle的配置文件
基于gradle構(gòu)建的項(xiàng)目,至少有一個 build.gradle文件,下面的是Android的build.gradle:
這個 就是 實(shí)際構(gòu)建開始的地方

// 定義全局的相關(guān)屬性,使用 jcenter作為倉庫
buildscript {
    repositories {
        jcenter()
    }
   // 定義構(gòu)建過程
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.3'
    }
}
// 用來定義各個模塊的默認(rèn)屬性,在所有模塊中的可見
allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

構(gòu)建腳本定義了Android構(gòu)建工具,還有Android的依賴庫

// 每個app都需要這個插件,Android plugin 提供了所有需要去構(gòu)建和測試的應(yīng)用
apply plugin: 'com.android.application'    

// 表示的是一個 依賴庫
apply plugin: 'com.android.library'

基本的Tasks
android插件依賴于Java插件,java依賴于base插件,
base插件有基本的tasks生命周期和一些通用的屬性;
base插件定義了例如assemble和clean任務(wù),Java插件定義了check和build任務(wù),這兩個任務(wù)不在base插件中定義。

這些tasks的約定含義:

assemble: 集合所有的output
clean: 清除所有的output
check: 執(zhí)行所有的checks檢查,通常是unit測試和instrumentation測試
build: 執(zhí)行所有的assemble和check
Java插件同時也添加了source sets的概念。

Android Tasks
Android插件繼承了基本tasks,并實(shí)現(xiàn)了自己的行為:

  1. assemble 針對每個版本創(chuàng)建一個apk
  2. clean 刪除所有的構(gòu)建任務(wù),包含apk文件
  3. check 執(zhí)行Lint檢查并且能夠在Lint檢測到錯誤后停止執(zhí)行腳本
  4. build 執(zhí)行assemble和check

默認(rèn)情況下assemble tasks定義了assembleDebug和assembleRelease,當(dāng)然你還可以定義更多構(gòu)建版本。除了這些tasks,android 插件也提供了一些新的tasks:

  1. connectedCheck 在測試機(jī)上執(zhí)行所有測試任務(wù)
  2. deviceCheck 執(zhí)行所有的測試在遠(yuǎn)程設(shè)備上
  3. installDebug和installRelease 在設(shè)備上安裝一個特殊的版本
  4. 所有的install task對應(yīng)有uninstall 任務(wù)

Android Studio中的tasks

![A$PZHC}F`6YTR30Q~JH]{NM.png](http://upload-images.jianshu.io/upload_images/2003670-088f7832be095f82.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

依賴管理
gradle自動為android程序添加了倉庫,默認(rèn)是jcenter,我們添加的某個第三方j(luò)ar,稱為一個依賴,比如:support v7包,gson 等;
一個依賴需要定義3個元素:group,name和version,添加依賴使用的是 groovy 語法,如下:

// 依賴
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
}

依賴的配置
有些時候,你可能需要和sdk協(xié)調(diào)工作。為了能順利編譯你的代碼,你需要添加SDK到你的編譯環(huán)境。你不需要將sdk包含在你的APK中,因?yàn)樗缫呀?jīng)存在于設(shè)備中,所以配置來啦,我們會有5個不同的配置:

  1. compile
  2. apk
  3. provided
  4. testCompile
  5. androidTestCompile

compile 默認(rèn),其含義是包含所有的依賴包,即在APK里,compile的依賴會存在。
apk 的意思是apk中存在,但是不會加入編譯中,這個貌似用的比較少。
provided 的意思是提供編譯支持,但是不會寫入apk。
testCompile 和androidTestCompile 會添加額外的library支持針對測試。

這些配置將會被用在測試相關(guān)的tasks中,這會對添加測試框架例如JUnit或者Espresso非常有用,因?yàn)槟阒皇窍胱屵@些框架們能夠出現(xiàn)在測試apk中,而不是生產(chǎn)apk中。

構(gòu)建版本
一個app如果有多個版本,比如 release,debug,不同渠道不同版本等,使用 gralde 可以方便管理這些;

  1. Build types;
  2. Product flavors;
  3. Build variants
  4. Signing configurations;

buildTypes
gradle 的android插件中,一個版本構(gòu)建意味著一個app或者依賴庫如何被構(gòu)建,每個構(gòu)建版本可能有一些特殊面,比如 是否 debug,application id,應(yīng)用名稱,哪些資源是否需要刪掉等,可以定義一個構(gòu)建版本 buildTypes 方法,如:

    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

product flavors
product flavors 用來為一個app創(chuàng)建不同的版本,比如:app的付費(fèi)與免費(fèi); 如果 app 需要對內(nèi)對外 完全隔離,就可以使用 product flavors,

      // 多渠道打包
    productFlavors {
        // 個性化定制
        xiaomi {
            applicationId "groovy.better.com.groovytest.xiaomi"
            minSdkVersion 11
        }
        huawei {
            applicationId "groovy.better.com.groovytest.huawei"
            minSdkVersion 14
        }
        baidu {
            applicationId "groovy.better.com.groovytest.baidu"
            minSdkVersion 16
        }
    }

    // apk名稱修改
    applicationVariants.all { variant ->
        if (variant.buildType.name.equals('release')) {
            variant.outputs.each { output ->
                def appName = 'demo'
                def oldFile = output.outputFile
                def buildName
                def releaseApkName

                variant.productFlavors.each { product ->
                    buildName = product.name
                }

                releaseApkName = appName + getVersionByMainfest() + '_' + buildName + '_' + getNowTime() + '.apk'
                output.outputFile = new File(oldFile.parent, releaseApkName)
            }
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
}

// ----->  自定義的方法
//獲取時間戳
def getNowTime() {
    def date = new Date()
    def now = date.format('yyyyMMddHHmm')
    return now
}

//從androidManifest.xml中獲取版本號
def getVersionByMainfest() {
    def parser = new com.android.builder.core.DefaultManifestParser()
    return parser.getVersionName(android.sourceSets.main.manifest.srcFile)
}


BuildConfig配置
BuildConfig.java文件,無法進(jìn)行動態(tài)配置,她是通過 module 相應(yīng)的gradle文件生成的,可通過 module的 gralde文件,進(jìn)行一些全局的開關(guān)控制:

添加配置代碼:

buildTypes {

        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            buildConfigField 'String', 'TEST_NAME', '"test_debug"' // ildConfigField
            resValue "string", "test_name", "test_debug"   //resValue
        }

        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            buildConfigField 'String', 'TEST_NAME', '"test_release"' // ildConfigField
            resValue "string", "test_name", "test_release"   //resValue
        }
    }

生成的 BuildConfig.java 文件:

Paste_Image.png
  1. buildConfigField: 會根據(jù)gradle的配置,在原來默認(rèn)的BuildConfig.java基礎(chǔ)上,動態(tài)添加一個指定數(shù)據(jù)類型的value。
    buildConfigField 一共有3個參數(shù),具體參考上面的參考資料;
  2. resValue: buildConfigField主要改變了java常量,Gradle組件提供了resValue字段,用于動態(tài)生成value資源,在程序中也可以訪問到,其中生成的目標(biāo)存在generated.xml中,使用的規(guī)則與buildConfigField 類似,即類型+常量名+常量值,如上代碼 resValue 部分,生成generated.xml截圖:
Paste_Image.png

** 使用占位符動態(tài)配置 清單文件中 :meta-data **
請注意:占位符須與 gradle中的 名稱一致;
清單文件代碼:

Paste_Image.png

配置不同渠道上的值:

Paste_Image.png

構(gòu)建的生命周期
初始化階段:gralde尋找 settings.gradle文件,如果項(xiàng)目有多個模塊,settings.gralde文件定義了模塊的位置,如果這些子目錄包含其自己的 build.gradle文件,gradle將運(yùn)行其,并將它們合并到構(gòu)建任務(wù)中;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,570評論 2 379

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