iOS 完整項(xiàng)目制作Framework ( 下 )

原博地址 :http://ios.jobbole.com/81583/?

本篇主要是根據(jù)對(duì)制作完整版的項(xiàng)目作為SDK靜態(tài)庫(kù)的詳細(xì)整理,與上篇文章并沒(méi)有太大關(guān)聯(lián)膝藕,有興趣的可以從這篇文章開始一步一步的學(xué)習(xí)制作 (PS 項(xiàng)目中所提到的demo 背镇,這里并沒(méi)有引入,因?yàn)椴┲鳑](méi)有從原博客中發(fā)現(xiàn)其鏈接可下載地址 ,還望見(jiàn)諒)

完成這篇教程渐苏,你將:

用 Xcode 構(gòu)建一個(gè)基本靜態(tài)庫(kù)工程

構(gòu)建一個(gè)依賴與這個(gè)靜態(tài)庫(kù)的 app

探索如何把靜態(tài)庫(kù)轉(zhuǎn)換成一個(gè)完整的 framework

最后收叶,你將會(huì)看到如何把一個(gè)圖片文件打包到 framework 中的資源包中

現(xiàn)在開始

這篇教程的主要目的是解釋如何在 iOS 項(xiàng)目中創(chuàng)建一個(gè)可復(fù)用的 framework骄呼,因此不會(huì)像本站中其他教程一樣,只會(huì)有少量的 Objective-C 代碼判没,用來(lái)闡述所涉及的概念蜓萄。

這里可以先下載好RWKnobControl資源文件。當(dāng)你在創(chuàng)建靜態(tài)庫(kù)項(xiàng)目這個(gè)部分里創(chuàng)建第一個(gè)工程的過(guò)程中澄峰,你會(huì)看到如何使用它們嫉沽。

你要?jiǎng)?chuàng)建的所有的這些代碼和工程文件在Github上都能訪問(wèn)到,并且還有每個(gè)構(gòu)建部分的獨(dú)立提交摊阀。

什么是 Framework耻蛇?

Framework 是一種資源集合,它把一個(gè)靜態(tài)庫(kù)和它的頭文件匯集成一個(gè)單一結(jié)構(gòu)胞此,這樣 Xcode 能夠很容易的將其集成到你的工程中去臣咖。

在 OS X 中允許我們創(chuàng)建動(dòng)態(tài)鏈接庫(kù)。通過(guò)動(dòng)態(tài)鏈接漱牵,framework 能夠顯式的實(shí)時(shí)更新而無(wú)需應(yīng)用程序重新鏈接它們夺蛇。在運(yùn)行時(shí),一份靜態(tài)庫(kù)的副本被所有進(jìn)程共享酣胀,這能夠顯著減少內(nèi)存使用提升系統(tǒng)性能刁赦。如你所見(jiàn),這是個(gè)強(qiáng)大的東西闻镶。

在 iOS 中你不能用這種方式給系統(tǒng)添加自定義的 framework甚脉,因此只能使用 Apple 提供的動(dòng)態(tài)庫(kù)。

然而铆农,這不意味著 framework 跟 iOS 就毫無(wú)相關(guān)了牺氨。對(duì)于在不同 app 中進(jìn)行代碼復(fù)用,靜態(tài)鏈接庫(kù)仍然是一個(gè)便捷的打包方式墩剖。

既然 framework 本質(zhì)上是對(duì)靜態(tài)庫(kù)的一站式購(gòu)物猴凹,那這篇教程中首要事情你了解如何創(chuàng)建和使用靜態(tài)庫(kù)。當(dāng)這篇教程進(jìn)展到構(gòu)建 framework 時(shí)岭皂,你會(huì)知道接下來(lái)會(huì)發(fā)生什么郊霎。

創(chuàng)建靜態(tài)庫(kù)工程

打開 Xcode 并且通過(guò)點(diǎn)擊FileNewProject和iOSFramework and LibraryCocoa Touch Static Library來(lái)創(chuàng)建一個(gè)新的靜態(tài)庫(kù)工程。

把工程命名為RWUIControls并且保存工程到一個(gè)空目錄爷绘。

一個(gè)靜態(tài)庫(kù)工程由頭文件和實(shí)現(xiàn)文件組成书劝,它們由工程自己創(chuàng)建編譯进倍。

為了讓開發(fā)者更方便的使用你的庫(kù)和框架,你需要導(dǎo)入一個(gè)頭文件來(lái)訪問(wèn)所有的你希望公開的類庄撮,好讓他們只需訪問(wèn)這個(gè)頭文件就行背捌。

當(dāng)創(chuàng)建靜態(tài)庫(kù)工程的時(shí)候,Xcode 添加了RWUIControls.h和RWUIControls.m洞斯。你不需要實(shí)現(xiàn)文件毡庆,因此右鍵RWUIControls.m選擇刪除,按提示把它移到垃圾箱中烙如。

打開RWUIControls.h并且用下面的代碼替換文件內(nèi)容:

Objective-C

1

#import

這句代碼導(dǎo)入了UIKit的傘型頭文件么抗,它包含有自身所需要的庫(kù)。當(dāng)你創(chuàng)建不同的組件類時(shí)亚铁,你要把它們添加到這個(gè)文件里蝇刀,這樣能夠確保它們讓這個(gè)庫(kù)的使用者能訪問(wèn)。

你構(gòu)建這個(gè)工程時(shí)會(huì)依賴UIKit徘溢,但 Xcode 靜態(tài)庫(kù)工程沒(méi)有默認(rèn)的鏈接到UIkit吞琐。為了修正這個(gè)問(wèn)題,要添加UIKit作為一個(gè)依賴然爆。選擇工程的導(dǎo)航器站粟,并且在主面板選擇RWUIControls目標(biāo)。

單擊Build Phases然后展開Link Binary With Libraries部分曾雕。單擊+來(lái)添加一個(gè)新的框架奴烙,查找UIKit.framework,單擊add添加剖张。

如果不綁定到頭文件的話切诀,靜態(tài)包是沒(méi)有用的舔箭。這些編譯好的類和方法是包含在二進(jìn)制文件中矾端。你創(chuàng)建的類,有一些你可以在外部使用盒刚,另一個(gè)則只能在包內(nèi)使用顾犹。

接下來(lái)倒庵,你需要在構(gòu)件時(shí)添加引用,把公開的頭文件放到編譯者能使用的地方蹦渣。最后,你要復(fù)制這些東西到框架里貌亭。

當(dāng)你在Xcode里看到Build Phases 時(shí)柬唯,選擇 EditorAdd Build PhaseAdd Copy Headers Build Phase.

注意:如果你發(fā)現(xiàn)選項(xiàng)變灰了,試試點(diǎn)擊下方的空白區(qū)域看看圃庭,然后再嘗試一遍锄奢。

把RWUIControls.h從導(dǎo)航器拖到面板的Public部分失晴。這確保這個(gè)頭文件對(duì)任何使用你庫(kù)的用戶都可用。

注意:這可能有點(diǎn)多此一舉拘央,但把包含有你工程所有公開類頭文件的頭文件放到公有部分非常重要涂屁。否則,開發(fā)者在企圖使用這個(gè)庫(kù)的時(shí)候會(huì)發(fā)生編譯錯(cuò)誤灰伟。這對(duì)任何人都不是開玩笑的拆又,當(dāng) Xcode 讀取公有頭的時(shí)又不能讀取你忘記添加的公有文件。

創(chuàng)建一個(gè) UI 控件

現(xiàn)在你已經(jīng)設(shè)置好了你的工程栏账,是時(shí)候給庫(kù)添加些功能了帖族。既然這個(gè)教程的目的是講訴如何構(gòu)建一個(gè) framework,而不是如何構(gòu)建一個(gè) UI 控件挡爵,那你會(huì)借用些上篇教程的一些代碼竖般。在你之前下載的 zip 文件你會(huì)找到 RWKnobControl 目錄。把它拖到 Xcode 的RWUIControls組別茶鹃。

選擇Copy items into destination group’s folder并確保要拷貝的新文件勾選了響應(yīng)的單選框涣雕。

這會(huì)同時(shí)把實(shí)現(xiàn)文件添加到編譯列表,默認(rèn)的頭文件在Project group闭翩。這意味著它們都是私有的挣郭。

注意:這三個(gè)部分的命名如果不拆分開理解會(huì)有點(diǎn)令人誤解。Public如你所預(yù)料的男杈。Private頭仍然會(huì)暴露你的頭文件丈屹,這有點(diǎn)讓人困惑。Project頭是你工程用到的特定私有文件伶棒,這有點(diǎn)諷刺旺垒。因此,你會(huì)慢慢發(fā)現(xiàn)要么頭文件是放到Public要么放在Project部分肤无。

現(xiàn)在你需要分享主控件頭RWKnobControl.h 先蒋,有如下幾步要做。首先從Project 組中拖拽Copy Headers 到Public 組宛渐。

另一種方式竞漾,當(dāng)你編輯文件的時(shí)候會(huì)發(fā)現(xiàn)更改Target Membership面板中的值會(huì)更方便。當(dāng)你開發(fā)庫(kù)繼續(xù)添加文件的時(shí)候這會(huì)非常方便窥翩。

注意:在你往庫(kù)中添加新的類時(shí)业岁,記得保持成員是最新的。盡可能減少公有的頭文件寇蚊,并確保其余的在Project組笔时。

用控件的頭文件做的另一件事就是把RWUIControls.h它添加到庫(kù)的主頭文件中。這樣開發(fā)者使用你的庫(kù)時(shí)只需要像下面這樣包含這一個(gè)文件就行仗岸,而不是一堆允耿。

Objective-C

1

#import

因此借笙,把下面的代碼添加到RWUIControls.h

Objective-C

1

2// Knob Control

#import

配置 Build 設(shè)置

現(xiàn)在你非常接近這個(gè)工程的編譯部分了。然而较锡,有幾個(gè)確保庫(kù)盡可能對(duì)用戶友好的設(shè)置需要配置业稼。

首先,你需要提供一個(gè)目錄名給你公有頭文件將要拷貝到那里去蚂蕴。這確保當(dāng)你使用靜態(tài)庫(kù)的時(shí)候能定位到相關(guān)的頭文件低散。

單擊工程導(dǎo)航欄的工程,然后選擇RWUIControls靜態(tài)庫(kù)目標(biāo)掂墓。選擇Build Setting標(biāo)簽谦纱,然后搜索public header。雙擊Public Header Folder Path設(shè)置并輸入下面的路徑:

Objective-C

1

include/$(PROJECT_NAME)

之后你會(huì)看到這個(gè)目錄君编。

現(xiàn)在你需要改變一些其他的設(shè)置跨嘉,尤其是那些保留在二進(jìn)制庫(kù)中的。編譯器給了你移除無(wú)用代碼的選項(xiàng)吃嘿,指那些從不會(huì)訪問(wèn)到的代碼祠乃。并且你還能移除 debug 符號(hào),例如函數(shù)名和其他 debug 時(shí)相關(guān)的細(xì)節(jié)兑燥。

既然你創(chuàng)建 framework 給其他人使用亮瓷,那最好把它們都禁用了然后讓用戶自行選擇最適合他們工程的配置。要做這些的話降瞳,跟之前一樣使用搜索就行嘱支,更新下面的設(shè)置:

Dead Code Stripping– 設(shè)為 NO

Strip Debug Symbols During Copy– 設(shè)為 NO for all configurations

Strip Style – 設(shè)為 Non-Global Symbols

構(gòu)建運(yùn)行。你仍然什么東西看沒(méi)看到挣饥,但這仍然是件好事除师,這足以說(shuō)明工程成功的構(gòu)建的并且沒(méi)有警告和錯(cuò)誤。

要構(gòu)建的話扔枫,選擇構(gòu)建目標(biāo)為iOS Device并按下cmd+B來(lái)執(zhí)行構(gòu)建汛聚。一旦完成,項(xiàng)目導(dǎo)航器的 Products 組別里的libRWUIControls.a會(huì)從紅色變?yōu)楹谏碳觯@表示文件已生成倚舀。右鍵libRWUIControls.a并且選擇Show in Finder。

在這個(gè)目錄中你能看到生成的靜態(tài)庫(kù)忍宋,libRWUIControls.a痕貌,并且公有頭文件單獨(dú)放在include/RWUIControls。

創(chuàng)建一個(gè)依賴開發(fā)項(xiàng)目

當(dāng)你不能親眼看到你在做什么的時(shí)候糠排,為 iOS 開發(fā)一個(gè) UI 控件庫(kù)極其的困難舵稠,現(xiàn)在似乎就是這樣。

沒(méi)人要你盲目的工作,因此在這個(gè)部分你將會(huì)創(chuàng)建一個(gè)新的 Xcode 工程柱查,它會(huì)用到你剛創(chuàng)建的庫(kù)。這能讓你通過(guò)一個(gè)示例 app 來(lái)開發(fā) framework云石。自然地唉工,這個(gè) app 的代碼會(huì)完全的與庫(kù)本身的代碼分離開來(lái),這樣一來(lái)會(huì)讓結(jié)構(gòu)更清晰汹忠。

關(guān)閉靜態(tài)庫(kù)工程淋硝。然后創(chuàng)建一個(gè)新的工程。選擇iOS/Application/Single View Application宽菜,并取名為UIControlDevApp谣膳。設(shè)置類前綴為RW并指定僅 iPhone 可用。最后保存到RWUIControls相同的目錄铅乡。

把RWUIControls.xcodeproj拖到UIControlDevApp組別來(lái)把RWUIControls作為一個(gè)依賴項(xiàng)继谚。

注意:你不能在兩個(gè)不同的窗口中打開同一個(gè)工程。如果你發(fā)現(xiàn)你不能切換到庫(kù)工程阵幸,請(qǐng)檢查你沒(méi)有在另一個(gè) Xcode 窗口中打開它花履。

你可以簡(jiǎn)單的拷貝代碼而不是重新創(chuàng)建上一篇教程的 app。首先選擇Main.storyboard挚赊,RWViewController.h和RWViewController.m然后刪除它們诡壁。接著拷貝DevApp文件夾到UIControlDevApp組別。

現(xiàn)在添加靜態(tài)庫(kù)作為示例 app 的依賴構(gòu)建:

* 在工程中選擇UIControlDevApp工程荠割。

* 導(dǎo)航至UIControlDevApp目標(biāo)的Build Phases標(biāo)簽妹卿。

* 打開Target Dependencies面板并單擊 + 來(lái)顯示選擇器。

* 找到RWUIControls靜態(tài)庫(kù)蔑鹦,單擊Add來(lái)添加夺克。這個(gè)動(dòng)作表示當(dāng)構(gòu)建示例 app 的時(shí)候,Xcode 會(huì)檢查是否靜態(tài)庫(kù)需要重新構(gòu)建举反。

為了鏈接靜態(tài)庫(kù)懊直,展開Link Binary With Libraries面板并再次點(diǎn)擊 +。選擇libRWUIControls.a單擊添加火鼻。

這個(gè)行為會(huì)讓 Xcode 把示例 app 與靜態(tài)庫(kù)鏈接起來(lái)室囊,就像鏈接系統(tǒng) framework 一樣比如UIKit。

構(gòu)建運(yùn)行魁索。你會(huì)看到跟上一 篇教程中熟悉的畫面融撞。

嵌套工程的好處就是你能夠在不離開示例 app 工程的情況下繼續(xù)開發(fā)靜態(tài)庫(kù),正如你在不同的部位維護(hù)代碼一樣粗蔚。你每次構(gòu)建項(xiàng)目的時(shí)候尝偎,你也要同時(shí)檢查 public/project 頭成員是否正確設(shè)置。如果丟失了任何必須的頭文件那么示例 app 將不會(huì)成功構(gòu)建。

創(chuàng)建 Framework

現(xiàn)在, 你可能會(huì)不耐煩地敲打你的腳趾并且想要知道 framework 到底什么時(shí)候才會(huì)開始致扯。這可以理解肤寝,因?yàn)榈侥壳盀橹鼓阕隽艘淮蠖褨|西但還沒(méi)有看到 framework。

好的抖僵,某些東西要開始變化了鲤看,馬上就來(lái)了。到現(xiàn)在你還沒(méi)有創(chuàng)建一個(gè) framework 的原因是因?yàn)樗褪且粋€(gè)靜態(tài)庫(kù)和頭文件的集合 – 正是你之前所做的耍群。

制作一個(gè) framework 會(huì)有幾點(diǎn)特別的地方:

目錄結(jié)構(gòu)义桂。Frameworks 有著 Xcode 認(rèn)可的特殊目錄結(jié)構(gòu)。你會(huì)創(chuàng)建一個(gè)構(gòu)建任務(wù)蹈垢,這將為你創(chuàng)建這種結(jié)構(gòu)慷吊。

當(dāng)你構(gòu)建庫(kù)的時(shí)候,它只會(huì)生成當(dāng)前必須的架構(gòu)曹抬,例如 i386溉瓶,arm7,等等谤民。為了讓一個(gè)框架有效嚷闭,在構(gòu)建的時(shí)候它需要包含所有需要運(yùn)行的架構(gòu)。你將會(huì)創(chuàng)建一個(gè)新的產(chǎn)品赖临,它將構(gòu)建必須的架構(gòu)并把它們放到框架中胞锰。

在這個(gè)部分會(huì)有大量的神奇腳本,但我會(huì)講慢點(diǎn)兢榨,它們不會(huì)很復(fù)雜嗅榕。

框架結(jié)構(gòu)

正如之前提到的,一個(gè)框架有著特殊的目錄結(jié)構(gòu)吵聪,看起來(lái)像是這樣:

現(xiàn)在在靜態(tài)庫(kù)編譯過(guò)程中要給它添加一個(gè)腳本凌那。選擇RWUIControls工程,并選擇RWUIControls靜態(tài)庫(kù)目標(biāo)吟逝。選擇Build Phases標(biāo)簽并通過(guò)選擇Editor/Add Build Phase/Add Run Script Build Phase來(lái)添加一個(gè)新的腳本帽蝶。

在 Build Phases 部分創(chuàng)建了一個(gè)新的面板,這能讓你在編譯階段的某個(gè)時(shí)刻運(yùn)行一個(gè)任意的 Bash 腳本块攒。如果你想在編譯過(guò)程中改變腳本的運(yùn)行時(shí)刻就在列表中拖動(dòng)面板励稳。對(duì)于框架工程來(lái)說(shuō),在最后運(yùn)行腳本就行囱井,因此你可以默認(rèn)放置即可驹尼。

雙擊重命名面板標(biāo)題為Build Framework。

把下面的 Bash 腳本粘貼到腳本框中:

Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16set-e

exportFRAMEWORK_LOCN="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework"

# Create the path to the real Headers die

mkdir-p"${FRAMEWORK_LOCN}/Versions/A/Headers"

# Create the required symlinks

/bin/ln-sfhA"${FRAMEWORK_LOCN}/Versions/Current"

/bin/ln-sfhVersions/Current/Headers"${FRAMEWORK_LOCN}/Headers"

/bin/ln-sfh"Versions/Current/${PRODUCT_NAME}"\

"${FRAMEWORK_LOCN}/${PRODUCT_NAME}"

# Copy the public headers into the framework

/bin/cp-a"${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/"\

"${FRAMEWORK_LOCN}/Versions/A/Headers"

這段腳本首先創(chuàng)建了RWUIControls.framework/Versions/A/Headers目錄庞呕,然后創(chuàng)建了一個(gè)框架所必須的三個(gè)語(yǔ)法鏈接

Versions/Current => A

Headers => Versions/Current/Headers

RWUIControls => Versions/Current/RWUIControls

最后新翎,公有頭文件從你之前指定的公有頭文件路徑拷貝到Versions/A/Headers目錄程帕。-a參數(shù)確保了在拷貝的時(shí)候編輯時(shí)間不會(huì)改變,從而防止不必要的重新構(gòu)建地啰。

現(xiàn)在愁拭,選擇RWUIControls靜態(tài)庫(kù)方案和iOS Device構(gòu)建目標(biāo),然后通過(guò)cmd+B構(gòu)建亏吝。

右鍵libRWUIControls.a并在Finder中顯示敛苇。

在構(gòu)建目錄中你可以訪問(wèn)到RWUIControls.framework,并確認(rèn)目錄的結(jié)構(gòu)顯示的是正確的:

在完成你框架的道路上這真是一個(gè)質(zhì)的飛躍顺呕,但你會(huì)發(fā)現(xiàn)仍然沒(méi)有一個(gè)靜態(tài)庫(kù)。這就是接下來(lái)要做的括饶。

多架構(gòu)構(gòu)建

iOS app 需要在不同的架構(gòu)上運(yùn)行:

arm7: 用于 iOS 7 所支持的最老的設(shè)備

arm7s: 用于 iPhone 5 和 5C

arm64: 用于 iPhone 5S 和 iPhone 6 等 64-bit ARM 處理器

i386: 用于 32-bit 模擬器

x86_64: 用于 64-bit 模擬器

每種架構(gòu)都需要不同的二進(jìn)制文件株茶,并且當(dāng)你構(gòu)建一個(gè) app 的時(shí)候,無(wú)論你當(dāng)前是何種設(shè)備 Xcode 都會(huì)正確的構(gòu)建相應(yīng)的架構(gòu)图焰。

這意味著構(gòu)建會(huì)很快启盛。當(dāng)你歸檔 app 或構(gòu)建 release 模式的 app 時(shí),Xcode 會(huì)構(gòu)建所有的三種 ARM 架構(gòu)技羔,從而讓 app 運(yùn)行到大部分設(shè)備上僵闯。那其他的版本呢?

自然地藤滥,當(dāng)你構(gòu)建框架時(shí)鳖粟,你想要開發(fā)者能夠盡可能使用所有的架構(gòu),對(duì)嗎拙绊?如果是這樣那表示你會(huì)得到同行的尊敬與敬佩向图。

因此你需要讓 Xcode 構(gòu)建所有的五種架構(gòu)。這個(gè)過(guò)程會(huì)創(chuàng)建一個(gè)所謂的臃腫的庫(kù)标沪,它包含有每個(gè)架構(gòu)部分榄攀。啊哈!

注意:其實(shí)這里強(qiáng)調(diào)的另一個(gè)原因是要?jiǎng)?chuàng)建一個(gè)依賴靜態(tài)庫(kù)的示例 app:這個(gè)庫(kù)只為示例 app 需要的架構(gòu)構(gòu)建金句,并只會(huì)在某些東西改變的時(shí)候才重新編譯檩赢。為什么這會(huì)令你異常興奮?因?yàn)檫@會(huì)讓開發(fā)周期盡可能的縮短违寞。

單擊 RWUIControls 工程贞瞒,創(chuàng)建一個(gè)新的目標(biāo)(target)。

選擇iOS/Other/Aggregate, 單擊Next并命名目標(biāo)為Framework趁曼。

注意:為什么要使用Aggregate目標(biāo)來(lái)構(gòu)建一個(gè) Framework 為什么不直接新建憔狞?因?yàn)?Frameworks 對(duì) OS X 的支持更好,這個(gè)事實(shí)體現(xiàn)在 Xcode 為 OS X 應(yīng)用提供了一個(gè)非常方便直接的 Cocoa Framework 構(gòu)建目標(biāo)彰阴。為了解決這個(gè)問(wèn)題瘾敢,你要使用Aggregate構(gòu)建目標(biāo)(target)來(lái)做為編譯框架目錄結(jié)構(gòu)的 bash 腳本的鉤子(hook)。你開始明白這里面瘋狂的地方了嗎?

無(wú)論何時(shí)創(chuàng)建一個(gè)新的 framework 目標(biāo)(target)都必須確保添加了靜態(tài)庫(kù)依賴簇抵。選擇 Framework 目標(biāo)(target)和Build Phases標(biāo)簽庆杜。展開Target Dependencies面板并添加靜態(tài)庫(kù)依賴。

這個(gè)目標(biāo)的主要構(gòu)建部分是多平臺(tái)編譯碟摆,你將會(huì)用到腳本來(lái)執(zhí)行晃财。正如你之前所做的,在Build Phases中創(chuàng)建一個(gè)Run Script典蜕。

雙擊断盛,把名字命名為MultiPlatform Build。

粘貼下面的腳本到腳本框中:

Shell

1

2

3

4

5

6

7

8

9

10

11set-e

# If we're already inside this script then die

if[-n"$RW_MULTIPLATFORM_BUILD_IN_PROGRESS"];then

exit0

fi

exportRW_MULTIPLATFORM_BUILD_IN_PROGRESS=1

RW_FRAMEWORK_NAME=${PROJECT_NAME}

RW_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a"

RW_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework"

set -e確保如果腳本的某部分失敗了那就讓整個(gè)腳本都失敗愉舔。這能幫你避免生成不完全的 framework钢猛。

接下來(lái),RW_MULTIPLATFORM_BUILD_IN_PROGRESS變量決定是否腳本有被遞歸的調(diào)用轩缤。如果有命迈,那就退出執(zhí)行。

然后就是設(shè)置一些變量火的『撸框架的名字將會(huì)跟工程名字一樣,例如RWUIControls馏鹤,還有靜態(tài)庫(kù)是libRWUIControls.a征椒。

接下來(lái)的腳本會(huì)設(shè)置些工程隨后會(huì)用到的函數(shù)。把下面的代碼添加到腳本框的底部:

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19functionbuild_static_library{

# Will rebuild the static library as specified

#???? build_static_library sdk

xcrunxcodebuild-project"${PROJECT_FILE_PATH}"\

-target"${TARGET_NAME}"\

-configuration"${CONFIGURATION}"\

-sdk"${1}"\

ONLY_ACTIVE_ARCH=NO\

BUILD_DIR="${BUILD_DIR}"\

OBJROOT="${OBJROOT}"\

BUILD_ROOT="${BUILD_ROOT}"\

SYMROOT="${SYMROOT}"$ACTION

}

functionmake_fat_library{

# Will smash 2 static libs together

#???? make_fat_library in1 in2 out

xcrunlipo-create"${1}""${2}"-output"${3}"

}

build_static_library需要SDK作為參數(shù)湃累,例如iphoneos7.0陕靠,然后會(huì)構(gòu)建相應(yīng)的靜態(tài)庫(kù)。大部分參數(shù)都是直接從當(dāng)前的構(gòu)建任務(wù)中傳進(jìn)來(lái)脱茉,但不同的地方在于ONLY_ACTIVE_ARCH是用來(lái)確保為當(dāng)前的 SDK 構(gòu)建所有的架構(gòu)剪芥。

make_fat_library使用lipo把兩個(gè)靜態(tài)庫(kù)變成一個(gè)。它的參數(shù)是兩個(gè)輸入庫(kù)后面緊跟著輸出位置琴许。點(diǎn)擊來(lái)了解更多關(guān)于lilp的信息税肪。

下個(gè)部分的腳本確定了更多變量,為了你能使用上面兩個(gè)方法榜田。你需要知道其他的 SDK 是什么益兄,例如iphoneos7.0應(yīng)該跳轉(zhuǎn)到iphonesimulator7.0反之亦然,還要定位 SDK 的構(gòu)建目錄箭券。

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name

if[["$SDK_NAME"=~([A-Za-z]+)]];then

RW_SDK_PLATFORM=${BASH_REMATCH[1]}

else

echo"Could not find platform name from SDK_NAME: $SDK_NAME"

exit1

fi

# 2 - Extract the version from the SDK

if[["$SDK_NAME"=~([0-9]+.*$)]];then

RW_SDK_VERSION=${BASH_REMATCH[1]}

else

echo"Could not find sdk version from SDK_NAME: $SDK_NAME"

exit1

fi

# 3 - Determine the other platform

if["$RW_SDK_PLATFORM"=="iphoneos"];then

RW_OTHER_PLATFORM=iphonesimulator

else

RW_OTHER_PLATFORM=iphoneos

fi

# 4 - Find the build directory

if[["$BUILT_PRODUCTS_DIR"=~(.*)$RW_SDK_PLATFORM$]];then

RW_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}"

else

echo"Could not find other platform build directory."

exit1

fi

這四個(gè)語(yǔ)句看起來(lái)都非常相似净捅,它們使用字符串比較和正則表達(dá)式來(lái)確定RW_OTHER_PLATFORM和RW_OTHER_BUILT_PRODUCTS_DIR的值。

這四個(gè)if語(yǔ)句的詳細(xì)解釋:

SDK_NAME將會(huì)是iphoneos7.0或iphonesimulator6.1辩块。這個(gè)正則表達(dá)式從字符串的開頭處開始提取非數(shù)字字符蛔六。因此荆永,它的結(jié)果是iphoneos或者iphonesimulator。

這個(gè)正則表達(dá)式從SDK_NAME變量取得數(shù)字版本號(hào)国章,例如 7.0 或 6.1 等等具钥。

這是簡(jiǎn)單的iphonesimulator和iphoneos之間的字符串比較,反之亦然液兽。

從產(chǎn)品構(gòu)建目錄路徑的末尾處得到平臺(tái)名稱并用其他平臺(tái)替換骂删。這個(gè)確保其他平臺(tái)的構(gòu)建目錄能被找到。當(dāng)加入兩個(gè)靜態(tài)庫(kù)的時(shí)候這至關(guān)重要四啰。

現(xiàn)在你可以為其他平臺(tái)編譯了宁玫,隨后會(huì)加入產(chǎn)生的靜態(tài)庫(kù)。

把下面的腳本添加到末尾處:

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

13# Build the other platform.

build_static_library"${RW_OTHER_PLATFORM}${RW_SDK_VERSION}"

# If we're currently building for iphonesimulator, then need to rebuild

#?? to ensure that we get both i386 and x86_64

if["$RW_SDK_PLATFORM"=="iphonesimulator"];then

build_static_library"${SDK_NAME}"

fi

# Join the 2 static libs into 1 and push into the .framework

make_fat_library"${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"\

"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"\

"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}"

首先通過(guò)之前定義好的函數(shù)來(lái)編譯其他平臺(tái)柑晒。

如果你當(dāng)前要為模擬器編譯欧瘪,那默認(rèn)的 Xcode 只會(huì)為那個(gè)系統(tǒng)編譯,例如 i386 或者 x86_64敦迄。為了編譯所有的架構(gòu),第二部分調(diào)用build_static_library用iphonesimulator SDK重新編譯凭迹,來(lái)確保編譯了所有架構(gòu)罚屋。

最后調(diào)用make_fat_library函數(shù)把當(dāng)前構(gòu)建目錄的靜態(tài)庫(kù)和其他構(gòu)建目錄加到一起來(lái)制作完整的多架構(gòu)靜態(tài)庫(kù)。這個(gè)會(huì)放到 framework 里面嗅绸。

最后是個(gè)簡(jiǎn)單的拷貝命令的腳本脾猛。在末尾添加下面的腳本:

Objective-C

1

2

3

4

5

6# Ensure that the framework is present in both platform's build directories

cp-a"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}"\

"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework/Versions/A/${RW_FRAMEWORK_NAME}"

# Copy the framework to the user's desktop

ditto"${RW_FRAMEWORK_LOCATION}""${HOME}/Desktop/${RW_FRAMEWORK_NAME}.framework"

第一個(gè)命令保證 framework 出現(xiàn)在多平臺(tái)的構(gòu)建目錄里。

第二個(gè)部分拷貝完成的 framework 到用戶的桌面鱼鸠。這是可選步驟猛拴,但我發(fā)現(xiàn)把 framework 放到某個(gè)容易訪問(wèn)的地方會(huì)非常友好。

選擇Framework集合(aggregate) 方案蚀狰,并按下 cmd+B 來(lái)編譯框架愉昆。

編譯完成后桌面會(huì)出現(xiàn)RWUIControls.framework。

為了檢查多平臺(tái)時(shí)候正確編譯麻蹋,啟動(dòng)終端并執(zhí)行以下操作:

Objective-C

1

2$cd~/Desktop/RWUIControls.framework

$RWUIControls.frameworkxcrunlipo-infoRWUIControls

第一行是切換到框架目錄跛溉,第二行使用了 lipo 命令來(lái)得到關(guān)于RWUIControls庫(kù)的相關(guān)信息。這會(huì)列出這個(gè)庫(kù)里出現(xiàn)的所有部分扮授。

你能看到這兒有五個(gè)部分:i386, x86_64, arm7, arm7s and arm64芳室,正好是你在編譯的時(shí)候設(shè)置的。你之前運(yùn)行過(guò)lipo -info命令刹勃,你會(huì)看到這幾個(gè)部分的子集堪侯。

如何使用框架

好,現(xiàn)在你已經(jīng)有了一個(gè)框架和一些靜態(tài)庫(kù)荔仁,它們可以優(yōu)雅的解決你可能還沒(méi)遇到的問(wèn)題伍宦。但是這樣有什么意義呢芽死?

使用框架的一個(gè)主要優(yōu)點(diǎn)就是使用起來(lái)很簡(jiǎn)單。現(xiàn)在雹拄,你使用RWUIControls.framework創(chuàng)建一個(gè)簡(jiǎn)單的IOS app收奔。

用Xcode創(chuàng)建一個(gè)新項(xiàng)目,選擇 File/New/Project在選擇iOS/Application/Single View Application滓玖。調(diào)出你的新app的ImageViewer坪哄;讓它只能適配iPhone 并且存放在與上兩個(gè)項(xiàng)目相同的文件夾下。這個(gè)app將給你展示如何使用RWKnobControl手動(dòng)的旋轉(zhuǎn)一張圖片势篡。

查找ImageViewer 目錄下之前下好的zip文件翩肌,里面有樣圖。把sampleImage.jpg 從finder里拖到Xcode的ImageViewer 組里禁悠。

檢查Copy items into destination group’s folder 念祭,然后點(diǎn)擊Finish 按鈕完成導(dǎo)入。

用同樣的步驟導(dǎo)入框架碍侦,把RWUIControls.framework 從桌面拖到Xcode的Frameworks 組里粱坤。同樣的,在Copy items into destination group’s folder 之前瓷产,確保你已經(jīng)檢查過(guò)

打開RWViewController.m 并替換如下代碼:

Objective-C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50#import "RWViewController.h"

#import

@interfaceRWViewController()

@property(nonatomic,strong)UIImageView*imageView;

@property(nonatomic,strong)RWKnobControl*rotationKnob;

@end

@implementationRWViewController

-(void)viewDidLoad

{

[superviewDidLoad];

// Create UIImageView

CGRectframe=self.view.bounds;

frame.size.height*=2/3.0;

self.imageView=[[UIImageViewalloc]initWithFrame:CGRectInset(frame,0,20)];

self.imageView.image=[UIImageimageNamed:@"sampleImage.jpg"];

self.imageView.contentMode=UIViewContentModeScaleAspectFit;

[self.viewaddSubview:self.imageView];

// Create RWKnobControl

frame.origin.y+=frame.size.height;

frame.size.height/=2;

frame.size.width=frame.size.height;

self.rotationKnob=[[RWKnobControlalloc]initWithFrame:CGRectInset(frame,10,10)];

CGPointcenter=self.rotationKnob.center;

center.x=CGRectGetMidX(self.view.bounds);

self.rotationKnob.center=center;

[self.viewaddSubview:self.rotationKnob];

// Set up config on RWKnobControl

self.rotationKnob.minimumValue=-M_PI_4;

self.rotationKnob.maximumValue=M_PI_4;

[self.rotationKnobaddTarget:self

action:@selector(rotationAngleChanged:)

forControlEvents:UIControlEventValueChanged];

}

-(void)rotationAngleChanged:(id)sender

{

self.imageView.transform=CGAffineTransformMakeRotation(self.rotationKnob.value);

}

-(NSUInteger)supportedInterfaceOrientations

{

returnUIInterfaceOrientationMaskPortrait;

}

@end

這個(gè)簡(jiǎn)單的視圖控制器還需要做如下操作:

這個(gè)簡(jiǎn)單的視圖控制器還需要做如下操作:

導(dǎo)入#import 這個(gè)頭文件

設(shè)置UIImageView和RWKnobControl 的私有屬性成hold

創(chuàng)建UIImageView并設(shè)置成你之前添加到項(xiàng)目里的示例圖片

創(chuàng)建RWKnobControl站玄,適當(dāng)?shù)恼{(diào)整它的位置。

設(shè)置下按鈕控件的屬性濒旦,包括rotationAngleChanged:方法的事件監(jiān)聽(tīng)處理

rotationAngleChanged:方法僅僅監(jiān)聽(tīng)UIImageView的transform屬性株旷,因此圖片可以隨著按鈕的移動(dòng)而旋轉(zhuǎn)。

更多的使用RWKnobControl的細(xì)節(jié)請(qǐng)看上一章尔邓,里面解釋了怎么創(chuàng)建它晾剖。

Build并且運(yùn)行。你就會(huì)看到一個(gè)簡(jiǎn)單的app梯嗽,隨著按鈕的改變而造成圖片的旋轉(zhuǎn)齿尽。

使用資源包

你注意到RWUIControls 僅由代碼和頭文件構(gòu)成了么?你沒(méi)有使用其他的資源(圖片之類)灯节。在IOS上framework只能柏涵一個(gè)頭文件和一個(gè)靜態(tài)庫(kù)雕什。

現(xiàn)在系好安全帶,我們馬上要起飛了显晶。在這一節(jié)中贷岸,你會(huì)學(xué)習(xí)到如何使用框架本身的資源包突破這個(gè)限制。

為RWUIControls 包創(chuàng)建一個(gè)新的UIView 磷雇,把它放在右上角偿警,設(shè)置圖片為一條緞帶。

創(chuàng)建bundle

資源加到bundle里之后唯笙,RWUIControls 項(xiàng)目里會(huì)形成額外的target

打開UIControlDevApp 項(xiàng)目螟蒸。選擇RWUIControls 子項(xiàng)目盒使。點(diǎn)擊 Add Target按鈕,然后依次點(diǎn)擊OS X/Framework and Library/Bundle七嫌。輸入RWUIControlsResources少办。 然后從框架選項(xiàng)卡中選擇Core Foundation

bundle建立之后,需要做一些設(shè)置诵原。選擇RWUIControlsResources target然后點(diǎn)擊 Build Settings 選項(xiàng)卡英妓。找到base sdk,選擇Base SDK這一行绍赛,然后按下delete蔓纠。這樣就能從OSX系統(tǒng)變?yōu)镮OS系統(tǒng)。

你還需要把product name改為RWUIControls. 找到product name雙擊修改吗蚌。把${TARGET_NAME} 替換成RWUIControls

圖片默認(rèn)情況下會(huì)有兩個(gè)分辨率腿倚,這可能造成一些有趣的結(jié)果;比如當(dāng)你包含一個(gè)retina @2x的版本時(shí)蚯妇,它們會(huì)結(jié)合成一個(gè)多分辨率的TIFF格式敷燎,那并不是一件好事。找到hidpi然后把COMBINE_HIDPI_IMAGES 設(shè)置為NO

當(dāng)你創(chuàng)建frameword時(shí)箩言,bundle也會(huì)建立框架并把它添加成target的附屬硬贯。選擇Framework target,點(diǎn)擊Build Phases選項(xiàng)卡分扎。展開Target Dependencies 面板澄成,點(diǎn)擊 +, 然后選擇RWUIControlsResources 添加為附屬胧洒。

現(xiàn)在畏吓,在Framework target的Build Phases里,打開MultiPlatform Build 面板卫漫,添加如下代碼在末尾:

Objective-C

1

2

3# Copy the resources bundle to the user's desktop

ditto"${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.bundle"\

"${HOME}/Desktop/${RW_FRAMEWORK_NAME}.bundle"

這個(gè)命令會(huì)復(fù)制built bundle帶用戶桌面》票現(xiàn)在,建立框架列赎,你就能看到bundle 出現(xiàn)在桌面上了宏悦。

導(dǎo)入Bundle

為了再開發(fā)新的bundle,也要能在示例APP里用它包吝。就需要你把它添加為附屬饼煞,然后根據(jù)app添加到相應(yīng)的對(duì)象里。

在導(dǎo)航欄項(xiàng)目中诗越,選擇UIControlDevApp 項(xiàng)目砖瞧,然后點(diǎn)擊UIControlDevApp target。擴(kuò)展RWUIControls 組嚷狞,把RWUIControls.bundle拖到 Copy Bundle Resources 面板內(nèi)块促。

在Target Dependencies 面板點(diǎn)擊加號(hào)荣堰,添加成新的附屬,然后選擇RWUIControlsResources

建立一個(gè)Ribbon 視圖

從RWUIControls 項(xiàng)目里的RWUIControls 組里拖拽你之前下載好的zip文件到RWRibbon 目錄竭翠。

勾選 Copy the items into the destination group’s folder,確保他們能復(fù)制到RWUIControls 靜態(tài)包中振坚。

源碼中一個(gè)很重要的地方是如何引用圖片。如果你看一眼RWRibbonView.m 文件里的addRibbonView函數(shù)斋扰,你就能看到下面這行:

Objective-C

1

UIImage*image=[UIImageimageNamed:@"RWUIControls.bundle/RWRibbon"];

bundle就像一個(gè)目錄渡八,因此引用bundle里的圖片真的很簡(jiǎn)單。

想要從bundle添加圖片褥实,可以在右邊的面板中選擇它們呀狼,它們應(yīng)該屬于RWUIControlsResources target。

我們來(lái)討論一下框架的權(quán)限范圍應(yīng)不應(yīng)該是公開的损离?好哥艇,現(xiàn)在你需要導(dǎo)出RWRibbon.h 頭文件,選擇這個(gè)文件僻澎,然后從Target Membership 面板的下拉菜單里選擇Public 貌踏。

最后,你需要添加這個(gè)頭到框架的頭文件窟勃。打開RWUIControls.h 然后添加下面代碼:

Objective-C

1

2// RWRibbon

#import <RWUIControls/RWRibbonView.h>

添加Ribbon到示例APP

打開UIControlDevApp 項(xiàng)目里的RWViewController.m 祖乳。然后在@interface區(qū)間里添加下面的變量:

Objective-C

1

RWRibbonView*_ribbonView;

創(chuàng)建ribbon視圖,添加下面代碼到viewDidLoad 的末尾

Objective-C

1

2

3

4

5

6

7// Creates a sample ribbon view

_ribbonView=[[RWRibbonViewalloc]initWithFrame:self.ribbonViewContainer.bounds];

[self.ribbonViewContaineraddSubview:_ribbonView];

// Need to check that it actually works :)

UIView*sampleView=[[UIViewalloc]initWithFrame:_ribbonView.bounds];

sampleView.backgroundColor=[UIColorlightGrayColor];

[_ribbonViewaddSubview:sampleView];

構(gòu)建秉氧,運(yùn)行UIControlDevApp 眷昆,在下面,你就能看到一個(gè)新的ribbon控制器汁咏。

在ImageViewer里使用Bundle

最后想要和你分享的是怎么樣使用另一個(gè)app里的bundle亚斋,我們用你之前創(chuàng)建的ImageViewer app來(lái)示范

首先確認(rèn)下你的框架和bundle是不是最新的,之后選擇Framework 然后按下cmd+B構(gòu)建它

打開ImageViewer 項(xiàng)目攘滩,找到Frameworks組里的RWUIControls.framework 選項(xiàng)帅刊,使用 Move to Trash 刪除它。然后從你的桌面拖拽RWUIControls.framework 到你的Frameworks 組里漂问。這是一定要做的赖瞒,因?yàn)樾聦?dǎo)入的框架和你之前的有許多的不同纯续。

注意:如果Xcode拒絕添加框架逃魄,你沒(méi)有正確的刪除之前的山宾。發(fā)送了這種情況滤蝠,你可以從Finder打開ImageViewer 目錄拉讯,找到這個(gè)框架姆蘸,然后刪除它挪圾。

從桌面拖拽bundle導(dǎo)入到ImageViewer 組潘靖。選擇Copy items into destination group’s folder 并且確保勾選了ImageViewer 選框芒划。

你可以添加ribbon到圖片里冬竟,要像選擇它欧穴,你可以在RWViewController.m 代碼里做幾個(gè)簡(jiǎn)單的改變。

打開UIImageView和RWRibbonView 泵殴,修改imageView的類型:

Objective-C

1

@property(nonatomic,strong)RWRibbonView*imageView;

為了創(chuàng)建和配置UIImageView涮帘,用下面的代碼替換viewDidLoad方法:

Objective-C

1

2

3

4

5

6

7

8

9

10[superviewDidLoad];

// Create UIImageView

CGRectframe=self.view.bounds;

frame.size.height*=2/3.0;

self.imageView=[[RWRibbonViewalloc]initWithFrame:CGRectInset(frame,0,20)];

UIImageView*iv=[[UIImageViewalloc]initWithFrame:self.imageView.bounds];

iv.image=[UIImageimageNamed:@"sampleImage.jpg"];

iv.contentMode=UIViewContentModeScaleAspectFit;

[self.imageViewaddSubview:iv];

[self.viewaddSubview:self.imageView];

構(gòu)建運(yùn)行app,現(xiàn)在你就能看到使用了theRWUIControls 框架中的RWKnobControl 和RWRibbonView 的效果了笑诅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末调缨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吆你,更是在濱河造成了極大的恐慌弦叶,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妇多,死亡現(xiàn)場(chǎng)離奇詭異伤哺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)者祖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門立莉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人七问,你說(shuō)我怎么就攤上這事蜓耻。” “怎么了械巡?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵刹淌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我讥耗,道長(zhǎng)有勾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任葛账,我火速辦了婚禮柠衅,結(jié)果婚禮上皮仁,老公的妹妹穿的比我還像新娘籍琳。我一直安慰自己,他們只是感情好贷祈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布趋急。 她就那樣靜靜地躺著,像睡著了一般势誊。 火紅的嫁衣襯著肌膚如雪呜达。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天粟耻,我揣著相機(jī)與錄音查近,去河邊找鬼眉踱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛霜威,可吹牛的內(nèi)容都是我干的谈喳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼戈泼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婿禽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起大猛,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扭倾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后挽绩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膛壹,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年唉堪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恢筝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巨坊,死狀恐怖撬槽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情趾撵,我是刑警寧澤侄柔,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站占调,受9級(jí)特大地震影響暂题,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜究珊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一薪者、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剿涮,春花似錦言津、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瞬浓,卻和暖如春初婆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工磅叛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屑咳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓弊琴,卻偏偏與公主長(zhǎng)得像乔宿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子访雪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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