Cocopods組件化過(guò)程

iOS的項(xiàng)目進(jìn)行組件化,往往會(huì)使用cocoapods包管理工具,該方案以此為基礎(chǔ)。二進(jìn)制庫(kù)在iOS項(xiàng)目中,指的是靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù),當(dāng)組件提供靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)的時(shí)候,可以加速項(xiàng)目編譯與構(gòu)建,因?yàn)殪o態(tài)庫(kù)與動(dòng)態(tài)庫(kù)本身就是已經(jīng)編譯好的庫(kù)文件,從而能達(dá)到加速的目的。

目標(biāo)

  1. pod組件同時(shí)提供源碼與二進(jìn)制庫(kù)
  2. 項(xiàng)目進(jìn)行調(diào)試的時(shí)候,pod組件庫(kù)切換為源碼模式,方便開發(fā)進(jìn)行源碼斷點(diǎn)調(diào)試
  3. 項(xiàng)目進(jìn)行集成與構(gòu)建的時(shí)候,pod組件庫(kù)切換為二進(jìn)制模式,加快編譯構(gòu)建速度
  4. 開發(fā)組件的時(shí)候不因?yàn)樵创a與二進(jìn)制的切換方案而喪失依賴其他組件的能力

方案說(shuō)明與步驟

對(duì)于某一個(gè)組件來(lái)說(shuō),組件的pod庫(kù)應(yīng)該包含源碼和靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)兩種文件,這樣才能夠在開發(fā)的過(guò)程中使用源碼進(jìn)行編譯調(diào)試,在編譯構(gòu)建的時(shí)候使用靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)。關(guān)鍵問(wèn)題在于如何切換,cocoapods的pod庫(kù)是通過(guò)podfile文件指明依賴的庫(kù)與對(duì)應(yīng)版本,當(dāng)使用pod install的時(shí)候,cocoapods會(huì)通過(guò)podfile文件,到cocoapods的中央倉(cāng)庫(kù)中找到該庫(kù)對(duì)應(yīng)的podspec文件,再通過(guò)podspec文件中的信息來(lái)構(gòu)建pod庫(kù)。
一個(gè)pod庫(kù)的podspec文件如下:

Pod::Spec.new do |s|
  s.name             = 'HBAuthentication'
  s.version          = '0.1.6-beta5'
  s.summary          = '基礎(chǔ)認(rèn)證組件'
  s.description      = <<-DESC
iOS認(rèn)證組件,相關(guān)文檔請(qǐng)?jiān)L問(wèn)內(nèi)部wiki:
http://***.***.com/member/Auth
                       DESC

  s.homepage         = 'http://***.***.com/Hbec_IOS_common/HBAuthentication'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'Neo' => '***@***.com' }
  s.source           = { :git => 'git@***.com:Hbec_IOS_common/HBAuthentication.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '7.0'

  s.resource_bundles = {
    'HBAuthentication' => ['HBAuthentication/Assets/*.{png,cer,json,der,p12}']
  }
  s.source_files = 'HBAuthentication/Classes/**'
end

cocoapods從中央倉(cāng)庫(kù)拉取到對(duì)應(yīng)版本的podsepc文件以后,通過(guò)s.source獲得對(duì)應(yīng)版本tag的代碼git版本庫(kù),而后通過(guò)s.source_files、s.resource_bundles指明該庫(kù)的源碼文件與資源文件對(duì)應(yīng)的路徑,從而最終進(jìn)行源碼依賴構(gòu)建編譯。如果該庫(kù)的為二進(jìn)制庫(kù),則需要通過(guò) s.public_header_files、s.ios.vendored_libraries來(lái)指明該庫(kù)的二進(jìn)制庫(kù)的頭文件、library文件的路徑。所以,該方案要求一個(gè)pod庫(kù)的工程文件中不僅僅要包含源代碼文件,還要包含將源代碼編譯成靜態(tài)庫(kù)或者動(dòng)態(tài)庫(kù)的二進(jìn)制文件,切換二進(jìn)制庫(kù)與源碼的時(shí)機(jī)應(yīng)該在 pod install 的時(shí)候,而表明是構(gòu)建源碼還是二進(jìn)制庫(kù),則需要通過(guò)install的時(shí)候,修改podspec文件中的s.source_files、s.public_header_files、s.ios.vendored_bibraries屬性,來(lái)切換該pod庫(kù)包含的內(nèi)容。因?yàn)閜odspec文件本身為ruby文件,我們可以利用ENV對(duì)象,來(lái)獲取命令行中執(zhí)行pod install時(shí)候傳入的環(huán)境變量,例如可以在podspec文件中這樣寫:

  if ENV['SOURCECODE']
    s.source_files = 'HBAuthentication/Classes/**'
  else
    s.source_files = 'Example/HBAuthenticationBinary/Products/Binary-universal/include/**'
    s.public_header_files = '**/*.h'
    s.ios.vendored_libraries = '**/**.a'
  end

當(dāng)在命令行中傳入環(huán)境變量參數(shù)的時(shí)候 SOURCECODE=1 pod install 的時(shí)候,則podspec文件中if 語(yǔ)句通過(guò)ENV對(duì)象來(lái)獲取SOURCECODE參數(shù)來(lái)表明不同的文件包含屬性,從而能夠切換該pod庫(kù)源碼或者二進(jìn)制庫(kù)。
通過(guò)cocoapods的環(huán)境變量來(lái)控制組件庫(kù)spec文件的配置信息,后面會(huì)詳細(xì)說(shuō)到。通過(guò)以上的分析,那么該方案大體上分為這幾個(gè)步驟:

  1. 創(chuàng)建pod項(xiàng)目
  2. 創(chuàng)建對(duì)應(yīng)的二進(jìn)制庫(kù)target
  3. 生成與源碼對(duì)應(yīng)的二進(jìn)制文件
  4. 設(shè)置pod庫(kù)的podspec文件,切換源碼和二進(jìn)制庫(kù)的配置
  5. 發(fā)布含有源碼和二進(jìn)制庫(kù)的pod庫(kù)

創(chuàng)建pod項(xiàng)目和創(chuàng)建對(duì)應(yīng)的二進(jìn)制庫(kù)target

通過(guò) pod lib create HBAuthentication 創(chuàng)建出的pod庫(kù)項(xiàng)目,目錄大概如下:

.
├── Example
│   ├── HBAuthentication
│   ├── HBAuthentication.xcodeproj
│   ├── HBAuthentication.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   ├── Pods
│   └── Tests
├── HBAuthentication
│   ├── Assets
│   └── Classes
├── HBAuthentication.podspec
├── LICENSE
├── README.md
├── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj
└── com.touker.hbauthentication.HBAuthentication.docset
    └── Contents

項(xiàng)目的源碼包含在Class文件中,如下:

├── Assets
│   └── content.json
└── Classes
    ├── HBAuthAPI.h
    ├── HBAuthAPI.m
    ├── HBAuthBridge.h
    ├── HBAuthBridge.m
    ├── HBAuthInfo.h
    ├── HBAuthInfo.m
    ├── HBAuthObject.h
    ├── HBAuthObject.m
    ├── HBAuthStoreManager.h
    ├── HBAuthStoreManager.m
    ├── HBAuthUtil.h
    ├── HBAuthUtil.m

一個(gè)源碼的pod庫(kù)項(xiàng)目大概就是這樣,現(xiàn)在需要?jiǎng)?chuàng)建對(duì)應(yīng)的二進(jìn)制庫(kù),以靜態(tài)庫(kù)為例,在項(xiàng)目中添加對(duì)應(yīng)的靜態(tài)庫(kù)target:file->New->Target->iOS->Framework & Library->Cocoa Touch Static Library

image

target命名為:HBAuthenticationBinary,創(chuàng)建后項(xiàng)目目錄如下:

.
├── Example
│   ├── HBAuthentication
│   ├── HBAuthentication.xcodeproj
│   ├── HBAuthentication.xcworkspace
|   ├── HBAuthenticationBinary
│   ├── Podfile
│   ├── Podfile.lock
│   ├── Pods
│   └── Tests
├── HBAuthentication
│   ├── Assets
│   └── Classes
├── HBAuthentication.podspec
├── LICENSE
├── README.md
├── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj
└── com.touker.hbauthentication.HBAuthentication.docset
    └── Contents

緊接著將class文件夾下的源文件添加到HBAuthenticationBinary的target目錄下,添加的時(shí)候選擇不復(fù)制,添加文件索引。

image

此時(shí)項(xiàng)目文件如下:

image

緊接著設(shè)置Build Phases中的Compile Source與想要對(duì)外暴露的Headers,如下:

image

靜態(tài)庫(kù)的源碼設(shè)置已經(jīng)完成。

生成與源碼對(duì)應(yīng)的二進(jìn)制文件

靜態(tài)庫(kù)需要考慮支持的目標(biāo)架構(gòu),arm架構(gòu)或者是x86架構(gòu),前者用于真機(jī)后者用于模擬器調(diào)試,一般在不考慮靜態(tài)庫(kù)大小的情況下,可以將幾種架構(gòu)打成一個(gè)靜態(tài)庫(kù),方便使用。可以通過(guò)xcodebuild命令行工具進(jìn)行打包和架構(gòu)合并,要生成.a文件,為了支持真機(jī)和模擬器的版本構(gòu)建,通過(guò)xcodebuild與lipo工具,來(lái)生成支持x86、arm64、armv7的靜態(tài)庫(kù),將此操作寫成腳本,通過(guò)Aggregate Target來(lái)執(zhí)行,腳本如下:

set -e
set +u
### Avoid recursively calling this script.
if [[ $UF_MASTER_SCRIPT_RUNNING ]]
then
exit 0
fi
set -u
export UF_MASTER_SCRIPT_RUNNING=1
### Constants.
# RESOURCE_BUNDLE="HBAuthenticationBinary"
# 靜態(tài)庫(kù)target對(duì)應(yīng)的scheme名稱
SCHEMENAME="HBAuthenticationBinary"
# .a與頭文件生成的目錄,在項(xiàng)目中的HBAuthenticationBinary目錄下的Products目錄中
BASEBUILDDIR=$PWD/${SCHEMENAME}/Products
rm -fr "${BASEBUILDDIR}"
mkdir "${BASEBUILDDIR}"
# 支持全架構(gòu)的二進(jìn)制文件目錄
UNIVERSAL_OUTPUTFOLDER=${BASEBUILDDIR}/Binary-universal
# 支持真機(jī)的二進(jìn)制文件目錄
IPHONE_DEVICE_BUILD_DIR=${BASEBUILDDIR}/Binary-iphoneos
# 支持模擬器的二進(jìn)制文件目錄
IPHONE_SIMULATOR_BUILD_DIR=${BASEBUILDDIR}/Binary-iphonesimulator
### Functions
## List files in the specified directory, storing to the specified array.
#
# @param $1 The path to list
# @param $2 The name of the array to fill
#
##
list_files ()
{
    filelist=$(ls "$1")
    while read line
    do
        eval "$2[\${#$2[*]}]=\"\$line\""
    done <<< "$filelist"
}
### Take build target.
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]
then
SF_SDK_PLATFORM=${BASH_REMATCH[1]} # "iphoneos" or "iphonesimulator".
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
### Build simulator platform. (i386, x86_64)
# echo "========== Build Simulator Platform =========="
# echo "===== Build Simulator Platform: i386 ====="
# xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_SIMULATOR_BUILD_DIR}/i386" SYMROOT="${SYMROOT}" ARCHS='i386' VALID_ARCHS='i386' $ACTION
echo "===== 構(gòu)建x86_64架構(gòu) ====="
xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${SCHEMENAME}" -configuration "${CONFIGURATION}" -sdk iphonesimulator CONFIGURATION_BUILD_DIR="${IPHONE_SIMULATOR_BUILD_DIR}/x86_64" ARCHS='x86_64' VALID_ARCHS='x86_64' $ACTION
# Build device platform. (armv7, arm64)
echo "========== Build Device Platform =========="
echo "===== Build Device Platform: armv7 ====="
xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${SCHEMENAME}" -configuration "${CONFIGURATION}" -sdk iphoneos CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/armv7" ARCHS='armv7 armv7s' VALID_ARCHS='armv7 armv7s' $ACTION
echo "===== Build Device Platform: arm64 ====="
xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${SCHEMENAME}" -configuration "${CONFIGURATION}" -sdk iphoneos CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/arm64" ARCHS='arm64' VALID_ARCHS='arm64' $ACTION
### Build universal platform.
echo "========== Build Universal Platform =========="
## Copy the framework structure to the universal folder (clean it first).
rm -rf "${UNIVERSAL_OUTPUTFOLDER}"
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
## Copy the last product files of xcodebuild command.
cp -R "${IPHONE_DEVICE_BUILD_DIR}/arm64/lib${SCHEMENAME}.a" "${UNIVERSAL_OUTPUTFOLDER}/lib${SCHEMENAME}.a"
### Smash them together to combine all architectures.
lipo -create "${IPHONE_SIMULATOR_BUILD_DIR}/x86_64/lib${SCHEMENAME}.a" "${IPHONE_DEVICE_BUILD_DIR}/armv7/lib${SCHEMENAME}.a" "${IPHONE_DEVICE_BUILD_DIR}/arm64/lib${SCHEMENAME}.a" -output "${UNIVERSAL_OUTPUTFOLDER}/lib${SCHEMENAME}.a"

echo "========== Create Standard Structure =========="
cp -r "${IPHONE_DEVICE_BUILD_DIR}/arm64/usr/local/include/" "${UNIVERSAL_OUTPUTFOLDER}/include/"
# mkdir -p "${UNIVERSAL_OUTPUTFOLDER}/lib/"
# cp "${UNIVERSAL_OUTPUTFOLDER}/lib${SCHEMENAME}.a" "${UNIVERSAL_OUTPUTFOLDER}/lib/lib${SCHEMENAME}.a"

將該腳本保存問(wèn)build.sh,在Aggregate Target中設(shè)置Build Phases的Run Script,如下:

image

將靜態(tài)庫(kù)文件和頭文件輸出到 HBAuthenticationBinary/Products 目錄。
運(yùn)行Aggregate Target以后,HBAuthenticationBinary目錄結(jié)構(gòu)如下:

├── HBAuthenticationBinary
│   └── Products
│       ├── Binary-iphoneos
│       │   ├── arm64
│       │   │   ├── libHBAuthenticationBinary.a
│       │   │   ├── libPods-HBAuthenticationBinary.a
│       │   │   └── usr
│       │   │       └── local
│       │   │           └── include
│       │   │               ├── HBAuthAPI.h
│       │   │               ├── HBAuthBridge.h
│       │   │               ├── HBAuthInfo.h
│       │   │               ├── HBAuthObject.h
│       │   │               └── HBAuthStoreManager.h
│       │   └── armv7
│       │       ├── libHBAuthenticationBinary.a
│       │       ├── libPods-HBAuthenticationBinary.a
│       │       └── usr
│       │           └── local
│       │               └── include
│       │                   ├── HBAuthAPI.h
│       │                   ├── HBAuthBridge.h
│       │                   ├── HBAuthInfo.h
│       │                   ├── HBAuthObject.h
│       │                   └── HBAuthStoreManager.h
│       ├── Binary-iphonesimulator
│       │   └── x86_64
│       │       ├── libHBAuthenticationBinary.a
│       │       ├── libPods-HBAuthenticationBinary.a
│       │       └── usr
│       │           └── local
│       │               └── include
│       │                   ├── HBAuthAPI.h
│       │                   ├── HBAuthBridge.h
│       │                   ├── HBAuthInfo.h
│       │                   ├── HBAuthObject.h
│       │                   └── HBAuthStoreManager.h
│       └── Binary-universal
│           ├── include
│           │   ├── HBAuthAPI.h
│           │   ├── HBAuthBridge.h
│           │   ├── HBAuthInfo.h
│           │   ├── HBAuthObject.h
│           │   └── HBAuthStoreManager.h
│           └── libHBAuthenticationBinary.a

其實(shí)Binary-universal就是最終的靜態(tài)庫(kù)的文件,其他的Binary-iphonesimulator與Binary-iphoneos目錄下的文件都不需要包含到pod的git版本庫(kù)中。

設(shè)置pod庫(kù)的podspec文件,切換源碼和二進(jìn)制庫(kù)的配置

接下來(lái)設(shè)置podspec文件,內(nèi)容如下:

Pod::Spec.new do |s|
  s.name             = 'HBAuthentication'
  s.version          = '0.1.6-beta5'
  s.summary          = '基礎(chǔ)認(rèn)證組件'
  s.description      = <<-DESC
iOS認(rèn)證組件,相關(guān)文檔請(qǐng)?jiān)L問(wèn)內(nèi)部wiki:
http://***.***.com/member/Auth
                       DESC

  s.homepage         = 'http://***.***.com/Hbec_IOS_common/HBAuthentication'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'Neo' => '***@***.com' }
  s.source           = { :git => 'git@***.com:Hbec_IOS_common/HBAuthentication.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '7.0'

  s.resource_bundles = {
    'HBAuthentication' => ['HBAuthentication/Assets/*.{png,cer,json,der,p12}']
  }
  s.source_files = 'HBAuthentication/Classes/**'
end

  if ENV['SOURCECODE']
    puts '-----------'
    puts 'HBAuthentication Source Code'
  else
    puts '+++++++++++'
    puts 'HBAuthentication Binary'
      s.source_files = 'Example/HBAuthenticationBinary/Products/Binary-universal/include/**'
      s.public_header_files = 'Example/HBAuthenticationBinary/Products/Binary-universal/include/*.h'
      s.ios.vendored_libraries = 'Example/HBAuthenticationBinary/Products/Binary-universal/libHBAuthenticationBinary.a'
  end
  s.dependency 'CocoaLumberjack'
  s.dependency 'HBWebBridge'
end

發(fā)布含有源碼和二進(jìn)制庫(kù)的pod庫(kù)

此時(shí)在Example中測(cè)試該pod庫(kù),在podfile中添加該庫(kù)依賴:

  pod 'HBAuthentication', :path => '../'

然后使用 pod install 此時(shí),會(huì)發(fā)現(xiàn)Pods的Development Pods目錄下的HBAuthentication為下圖:

image

說(shuō)明為靜態(tài)庫(kù)依賴。
在Example項(xiàng)目中使用 SOURCECODE=1 pod install以后,則切換到源碼模式。

image

分別運(yùn)行測(cè)試,都沒(méi)有問(wèn)題,可以將工程文件提交到git倉(cāng)庫(kù),注意前面生成的其他架構(gòu)的文件目錄可以刪除,不提交到git版本庫(kù)中,因?yàn)槭嵌M(jìn)制文件,git對(duì)二進(jìn)制文件不能做到增量更新,隨著版本增加,git版本庫(kù)會(huì)越來(lái)越大,所以最好精簡(jiǎn)靜態(tài)庫(kù)的大小,最后在自己的私有cocoapods倉(cāng)庫(kù)中進(jìn)行pod庫(kù)的發(fā)布。私有cocoapods庫(kù)搭建參考官方文檔

subSpec的源碼切換方式
https://www.freesion.com/article/9213133904/

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

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