豆瓣的混合開發(fā)框架 -- Rexxar

混合開發(fā)的直白解釋是 Native 和 Web 技術(shù)都要用兔辅。但形式上,應(yīng)用仍然和瀏覽器無關(guān)击喂,用戶還是需要在 App Store 和 Android Market 下載應(yīng)用维苔。只是在開發(fā)時(shí),開發(fā)者以 Native 代碼為主體懂昂,在合適的地方部分使用 Web 技術(shù)介时。比如在 iOS 中的 UIViewController 內(nèi)放置一個(gè) UIWebview(一個(gè)瀏覽器引擎,只擁有渲染 HTML凌彬,CSS 和執(zhí)行 JavaScript 的核心功能)沸柔。這樣,部分用戶界面就可以在 UIWebView 中使用 Web 技術(shù)實(shí)現(xiàn)铲敛。

促使我們?cè)谝苿?dòng)開發(fā)中使用 Web 技術(shù)主要?jiǎng)恿υ谟诤峙欤啾扔?Native 技術(shù),Web 技術(shù)具有諸多優(yōu)勢(shì):

高效率的界面開發(fā):HTML原探,CSS乱凿,JavaScript 的組合被證明在用戶界面開發(fā)方面具有很高的效率。

跨平臺(tái):統(tǒng)一的瀏覽器內(nèi)核標(biāo)準(zhǔn)咽弦,使得 Web 技術(shù)具有跨平臺(tái)特性徒蟆。iOS 和 Android 可以使用一套代碼。

熱更新:可越過發(fā)布渠道自主更新應(yīng)用型型。

這些優(yōu)勢(shì)都和開發(fā)效率有關(guān)段审。Web 技術(shù)具有這些優(yōu)勢(shì)的原因是,Web 技術(shù)是一個(gè)開放標(biāo)準(zhǔn)闹蒜∷峦鳎基于開放的標(biāo)準(zhǔn)已經(jīng)發(fā)展出來龐大生態(tài),而且這個(gè)生態(tài)從 PC 時(shí)代發(fā)展至今已積累多年绷落,開發(fā)者可以利用生態(tài)中產(chǎn)出的各種成果姥闪,從而省去很多重復(fù)工作。

在大型移動(dòng)應(yīng)用的開發(fā)中砌烁,項(xiàng)目代碼龐雜筐喳,通常還需要 iOS催式,Android,移動(dòng) Web 和 桌面 Web 全平臺(tái)支持避归。這種情況下荣月,更高的開發(fā)效率就成了開發(fā)者不得不考慮的議題。這也是為何雖然移動(dòng)端的 Web 技術(shù)在使用范圍和性能上有諸多劣勢(shì)梳毙,仍然有很多開發(fā)者付出努力哺窄,探索如何在移動(dòng)開發(fā)中使用 Web 技術(shù)。

我們也是基于以上各種考慮账锹,決定在豆瓣的移動(dòng)開發(fā)中實(shí)踐一些混合開發(fā)技術(shù)萌业。

Rexxar 的背景

豆瓣在 2014 年推出一個(gè)主應(yīng)用:豆瓣 App。這個(gè)主應(yīng)用慢慢成長牌废,逐漸覆蓋了豆瓣在 Web 上的大部分功能咽白。隨著項(xiàng)目的擴(kuò)大,產(chǎn)品線的擴(kuò)展鸟缕,豆瓣App 成為了一個(gè)需要同時(shí)提供 iOS晶框,Android 和移動(dòng) Web 頁面的多平臺(tái)支持的服務(wù)。工程技術(shù)團(tuán)隊(duì)為了更從容地應(yīng)對(duì)這種狀況懂从,開始投入較大的精力提高團(tuán)隊(duì)的開發(fā)效率授段。混合開發(fā)是其中主要的措施之一番甩。

由于項(xiàng)目已經(jīng)發(fā)展到一定程度侵贵,我們并不希望推倒以往的開發(fā)方式,也沒有一切從頭來的野心和勇氣缘薛。只是希望在不影響 App 的性能前提下窍育,在合適的地方使用 Web 技術(shù)部分地提高開發(fā)效率。而豆瓣App 中又確實(shí)存在部分頁面是重度展示宴胧,并輕度交互的漱抓。這些頁面恰恰適合使用 Web 技術(shù)來實(shí)現(xiàn)。

經(jīng)過團(tuán)隊(duì)的一些努力恕齐,項(xiàng)目中部分頁面已經(jīng)使用 Web 技術(shù)實(shí)現(xiàn)乞娄,并取得了不錯(cuò)的效果。工程師使用 Web 技術(shù)可以以更快的速度完成產(chǎn)品需求显歧,并且將一份代碼部署到兩個(gè)平臺(tái)仪或。開發(fā)效率得到了實(shí)質(zhì)性提高。即使不提熱更新士骤,減少 Android 項(xiàng)目方法數(shù)這種附帶好處范删,我們也已喜歡上這項(xiàng)技術(shù),決定在豆瓣移動(dòng)開發(fā)中推動(dòng)混合開發(fā)技術(shù)的使用拷肌。

現(xiàn)在瓶逃,我們將這個(gè)過程的主要產(chǎn)出:Rexxar 這個(gè)項(xiàng)目開源束铭。一方面廓块,是為了給大家提供一些借鑒的方向厢绝;另一方面,是為了提高項(xiàng)目本身的質(zhì)量带猴。我們知道還存在不少問題昔汉。所以,會(huì)悉心接受大家的意見和建議拴清。

Rexxar 的介紹

Rexxar 是一個(gè)針對(duì)移動(dòng)端的混合開發(fā)框架“胁。現(xiàn)在支持 Android 和 iOS 平臺(tái)。并有一個(gè) Web 基礎(chǔ)庫口予。

團(tuán)隊(duì)中喜歡玩魔獸的同學(xué)將該項(xiàng)目命名為 Rexxar(《魔獸世界》中人物娄周,出生于卡利姆多大陸的菲拉斯,同時(shí)具有雷骨獸人和南部菲拉斯野生食人魔兩種血統(tǒng))沪停。

各平臺(tái)代碼倉庫地址如下:

Rexxar Web:https://github.com/douban/rexxar-web

Rexxar iOS:https://github.com/douban/rexxar-ios

Rexxar Android:https://github.com/douban/rexxar-android

Rexxar 主要由以下三部分組成:

Rexxar Route煤辨,我們使用 URL 來標(biāo)識(shí)每一個(gè)頁面。在 App 中通過指明 URL 跳轉(zhuǎn)到此頁面木张。所以众辨,需要一個(gè)路由表。通過路由表可以根據(jù) URL 找到一個(gè) Rexxar Web 的對(duì)應(yīng)資源來正確展示相應(yīng)頁面舷礼;

Rexxar Web鹃彻,前端代碼庫,由 HTML妻献、CSS蛛株、JavaScript、Image 等組成育拨,用來提供在移動(dòng)客戶端使用的用戶頁面谨履;

Rexxar Container,一個(gè)前端代碼的運(yùn)行容器至朗。它其實(shí)是一個(gè)內(nèi)嵌的瀏覽器(WebView)屉符,我們?yōu)閮?nèi)嵌瀏覽器提供了一些必要的原生端支持,包括 API 的 OAuth 授權(quán)锹引、圖片緩存矗钟、Native UI 組件的調(diào)用等;現(xiàn)在有 Android 和 iOS 兩個(gè)版本的實(shí)現(xiàn)嫌变。

在項(xiàng)目實(shí)踐中吨艇,Rexxar Web 和 Rexxar Route 由一個(gè)項(xiàng)目實(shí)現(xiàn),并部署于同一個(gè) Web 項(xiàng)目中腾啥。

Rexxar Route

Rexxar Route 比較簡(jiǎn)單东涡,只需要表達(dá)一個(gè)路由表即可冯吓。我們使用了一個(gè) json 文件來表達(dá)路由表。給出一個(gè)路由表的例子:

{
    count: 4,
    items: [{
        remote_file: "https://img1.doubanio.com/dae/rexxar/files/orders/orders-70dbdbcb1c.html",
        uri: "douban://douban.com/orders[/]?.*"
    }, {
        remote_file: "https://img1.doubanio.com/dae/rexxar/files/related_doulists/related_doulists-1d7d99e1fb.html",
        uri: "douban://douban.com/(tag|tv|movie|book|music)/(\w+)/related_doulists[/]?.*"
    }   ],
    deploy_time: "Fri, 04 Mar 2016 11:12:29 GMT"
}

我們發(fā)布的每個(gè)版本的 App 安裝包都會(huì)包含最新版本的 routes.json 文件疮跑。在 App 啟動(dòng)時(shí)组贺,都會(huì)嘗試下載最新版本的 routes.json。在遇到無法解析的 URL 時(shí)祖娘,也會(huì)去下載新版 routes.json失尖。

Rexxar Web

Rexxar Web 是 Rexxar 前端實(shí)現(xiàn)。Rexxar Container 的實(shí)現(xiàn)和 Rexxar Web 的實(shí)現(xiàn)是分離的渐苏。Rexxar Container 對(duì) Rexxar Web 使用何種技術(shù)實(shí)現(xiàn)并不關(guān)心掀潮。所以,你可以選擇自己的前端技術(shù)和 Rexxar Container 進(jìn)行組合琼富。比如仪吧,我們?cè)跇I(yè)務(wù)層選擇了 React 作為前端開發(fā)框架。

Rexxar Web 包括了三部分內(nèi)容:

工具

一套開發(fā) Rexxar Web 所需的打包鞠眉,調(diào)試薯鼠,發(fā)布工具。

公共的前端組件

通用的錯(cuò)誤處理凡蚜、Loading等效果

頁面點(diǎn)擊反饋效果

List 的支持

對(duì) Rexxar Container 實(shí)現(xiàn)的 Widget 的調(diào)用

ActionBar 的 title 定制

ActionBar 的 button 定制

Dialog

下拉刷新

Toast

有了這些組件人断,我們?nèi)粘.a(chǎn)品開發(fā)的難度就降低了。普通移動(dòng)開發(fā)工程師經(jīng)過一段時(shí)間的學(xué)習(xí)朝蜘,也可以像前端工程師一樣恶迈,以 Rexxar 為工具為 App 做一些產(chǎn)品開發(fā)了。這部分可以視為一個(gè)純粹的前端項(xiàng)目谱醇。

Rexxar Container

我們使用混合開發(fā)技術(shù)提高開發(fā)效率的一個(gè)前提是暇仲,不損傷 App 的使用體驗(yàn)「笨剩基于這個(gè)前提奈附,在 Native 和 Web 如何分工方面我們做了一些嘗試。首先煮剧,為了保證使用體驗(yàn)斥滤,我們把 App 里頁面切換留給了 Native。這樣勉盅,每個(gè)頁面(Controller 或者 Activity)都是一個(gè) Container佑颇。Container 內(nèi)嵌一個(gè)瀏覽器內(nèi)核。頁面內(nèi)的功能和邏輯在 Native 和 Web 之間如何分工呢草娜?我們嘗試過有幾種策略:

純?yōu)g覽器方案:也就是 Native 除了扔給內(nèi)嵌瀏覽器一個(gè) URL 地址之外挑胸,就不做任何事情了,剩余的事情都由 Web 完成宰闰。這和用 Safari 或 Chrome 等普通瀏覽器打開一個(gè)網(wǎng)頁并沒有太多區(qū)別茬贵。只是我們固定了訪問的地址簿透。

前端模板渲染容器方案:這種方案大部分事情由 Native 完成,Web 部分只是負(fù)責(zé)頁面元素的呈現(xiàn)解藻,不參與頁面界面之外的其他部分老充。我們?cè)诳蛻舳舜鎯?chǔ)了一個(gè) HTML 作為 UI 模板。Native 代碼負(fù)責(zé)獲取數(shù)據(jù)舆逃,向 HTML 文件模板中填入動(dòng)態(tài)數(shù)據(jù)蚂维,得到一個(gè)可以在內(nèi)嵌瀏覽器渲染的 HTML 文件。這個(gè)過程有點(diǎn)類似于 Web 框架里模板渲染庫(例如路狮,Jinja2)的作用。

Rexxar Container 方案:Rexxar 采用的方案介于上述兩種方案之間蔚约。Rexxar Container 同樣提供了一個(gè)運(yùn)行前端代碼的容器奄妨。它也是一個(gè)內(nèi)嵌的瀏覽器(WebView)。只是苹祟,我們并不是只扔給內(nèi)嵌瀏覽器一個(gè) URL 地址就放手不管了砸抛,還對(duì)對(duì)內(nèi)嵌的瀏覽器做了很多開發(fā),為其包裝了很多附加功能树枫。

Rexxar Container 方案中直焙,Container 需要實(shí)現(xiàn)以下功能:

Rexxar Route 路由表的更新,已經(jīng)在客戶端的保存砂轻;

為 Rexxar Web 前端代碼發(fā)出的 API 請(qǐng)求提供包裝奔誓。帶上必要的 OAuth 參數(shù);

緩存 Rexxar Web 前端代碼所需要的靜態(tài)文件搔涝,包括 HTML厨喂、CSS、JavaScript庄呈、Image(圖片素材)等蜕煌;

緩存 Rexxar Web 中所需要加載的資源文件,例如圖片等诬留;

通過協(xié)議為 Rexxar Web 提供一些原生支持的功能:包括 Native UI 組件調(diào)用斜纪,獲取 Native 的計(jì)算結(jié)果。

這種實(shí)現(xiàn)方案文兑,是基于保證使用體驗(yàn)的前提下盒刚,盡量讓 Web 技術(shù)多做一些事情的考慮。

Rexxar Container 和 Rexxar Web 之間的交互

混合開發(fā)實(shí)踐中彩届,一般都會(huì)涉及到 Native 和 Web 如何通信的問題伪冰。這是因?yàn)槲覀儼岩患虑榻唤o兩種技術(shù)完成,那么它們之間便會(huì)存在有一些通信和協(xié)調(diào)樟蠕。很多混合開發(fā)方案會(huì)使用 JSBridge(Android: JsBridge贮聂,iOS:WebViewJavascriptBridge) 來實(shí)現(xiàn) Native 和 Web 的相互調(diào)用靠柑。

但在 Rexxar 中,我沒有使用類似 JSBridge 這樣的方案吓懈。而是通過從 Rexxar Web 發(fā)出 HTTP 請(qǐng)求的方式歼冰,由 Rexxar Container 截獲的方式進(jìn)行通信。Native 和 Web 之間協(xié)議是由 URL 定義的耻警。Rexxar Web 訪問某個(gè)特定的 URL, Rexxar Container 截獲這些 URL 請(qǐng)求隔嫡,調(diào)用 Native 代碼完成相應(yīng)的功能。

例如甘穿,Rexxar 中 UI 相關(guān)的功能的協(xié)議如下:

請(qǐng)求 douban://rexxar.douban.com/widget/nav_title腮恩,可以定義 Navigation Bar Title毅往。

請(qǐng)求 douban://rexxar.douban.com/widget/nav_menu寥裂,可以定義 Navigation Bar Button呛梆。

請(qǐng)求 douban://rexxar.douban.com/widget/toast全谤,可以出現(xiàn)一個(gè)消息通知 toast吠谢。

Rexxar Web 具體前端實(shí)現(xiàn)是在 DOM 中加入一個(gè) iframe 來加載此 URL合是,以來完成對(duì) Rexxar Container 的通知火窒。

將 Native 和 Web 的通信以協(xié)議的形式規(guī)范起來甚垦,是因?yàn)槲覀兿M?Native 和 Web 之間的通信是可定義的届垫,可控的释液。有這種期望的原因是,我們以 Rexxar 完成的頁面装处,不僅僅在 App 內(nèi)使用误债,還會(huì)在移動(dòng) Web 頁面上使用。我們的移動(dòng)站點(diǎn)符衔,特別是分享到外部(如微信找前,微博)的頁面希望復(fù)用 Rexxar 在 App 內(nèi)的工作成果。如果判族,任由開發(fā)者自由地定義接口隨意的依賴于原生實(shí)現(xiàn)的功能躺盛,那么我們就無法順利地遷移到移動(dòng) Web 上去。標(biāo)準(zhǔn)瀏覽器并不支持 JSBridge 的大部分功能形帮。但可以看到我們已經(jīng)實(shí)現(xiàn)的協(xié)議槽惫,大部分在移動(dòng) Web 是被可以自動(dòng)被忽略(比如,nav_title, nav_menu)辩撑,或者我們也可以較容易地以移動(dòng) Web 支持的形式再實(shí)現(xiàn)一次(比如界斜,toast)。這樣合冀,Rexxar 中的前端業(yè)務(wù)代碼無需太多改動(dòng)各薇,即可遷移到移動(dòng) Web 和桌面 Web 端。

Rexxar Container 的技術(shù)實(shí)現(xiàn)

Rexxar Container 主要的工作是截獲 Rexxar Web 的數(shù)據(jù)請(qǐng)求和原生功能請(qǐng)求。Rexxar Container 截獲請(qǐng)求之后峭判,做相應(yīng)的反應(yīng)开缎。這種 Native 和 Web 的交互被抽象成三種接口:

Decorator:修改數(shù)據(jù)請(qǐng)求。例如林螃,數(shù)據(jù)請(qǐng)求加上 OAuth 認(rèn)證信息奕删。

Widget: 調(diào)用某些 Native UI 組件。例如疗认,調(diào)起一個(gè) Toast完残。

ContainerAPI:給 Web 一個(gè) Native 的計(jì)算結(jié)果。例如横漏,給出當(dāng)前位置信息谨设。

這三種接口都是由 Rexxar Web 發(fā)起某種形式的 URL 調(diào)用的。Rexxar Web 的業(yè)務(wù)代碼在 App 的 Rexxar Container 內(nèi)工作方式绊茧,和在普通瀏覽器里差別不大铝宵。我們只是在 Web 技術(shù)的基礎(chǔ)上做了一些拓展,保留了大部分 Web 原有的編寫和運(yùn)行方式华畏。代碼都是標(biāo)準(zhǔn) Web 式的,沒有為原生移動(dòng)開發(fā)做太多定制尊蚁。因此亡笑,移植到 Web 平臺(tái),在各種瀏覽器中横朋,代碼無需做太多修改就可以正確運(yùn)行仑乌。以 URL 作為協(xié)議,也為 Web 和 Native 劃定了清晰的邊界和數(shù)據(jù)傳遞方式琴锭。

我們?yōu)?iOS 和 Android 各開發(fā)了一個(gè) Rexxar Container晰甚。iOS 和 Android 平臺(tái)截獲請(qǐng)求的方式由于平臺(tái)差異,并不完全相同决帖。但本質(zhì)上都是在 Web 和 Native 之間實(shí)現(xiàn)了一個(gè) Proxy厕九。Web 發(fā)出的請(qǐng)求會(huì)被 Proxy 預(yù)先處理。要么是修改后再發(fā)出去地回,要么是由 Rexxar Container 自己處理扁远。

具體的實(shí)現(xiàn)可以參看兩個(gè)平臺(tái)的項(xiàng)目代碼。

Rexxar 頁面執(zhí)行過程

例如刻像,客戶端接到一個(gè)頁面請(qǐng)求畅买,要打開一個(gè) URL:douban://douban.com/movie/1292052。Rexxar 的工作流如下:

根據(jù) URL 查詢本機(jī)緩存的路由表 routes.json细睡,看是否能夠找到對(duì)應(yīng)的資源記錄(一般是一個(gè) HTML 文件)谷羞。如果找到不到,請(qǐng)求 Rexxar Route 服務(wù)溜徙,獲得最新的全量路由表 routes.json湃缎,更新本地緩存犀填,找到對(duì)應(yīng)的資源記錄;

根據(jù)路由表指示的 HTML 文件的路徑雁歌,看本地是否找到對(duì)應(yīng)的文件宏浩。如果找不到,請(qǐng)求 Rexxar Web 資源服務(wù)器靠瞎,更新本地緩存比庄;在 Rexxar Container 里展示該 HTML 文件;如有需要乏盐,會(huì)在 Container 中請(qǐng)求圖片資源佳窑,圖片資源也有緩存,Rexxar Container 會(huì)先檢查本地緩存父能。如不存在神凑,會(huì)請(qǐng)求 CDN 的圖片或者圖片服務(wù)器;

Rexxar Web 前端代碼在 Container 里繼續(xù)執(zhí)行何吝,發(fā)出 API 請(qǐng)求溉委。Rexxar Container 代理這些請(qǐng)求,為 API 請(qǐng)求添加 OAuth 驗(yàn)證爱榕,或增加某些參數(shù)瓣喊;

Rexxar Web 前端代碼繼續(xù)執(zhí)行,根據(jù) API 返回的結(jié)果黔酥,展示響應(yīng)的頁面藻三,可能會(huì)請(qǐng)求 CDN 的圖片或者圖片服務(wù)器等;

Rexxar Web 前端代碼繼續(xù)執(zhí)行跪者,如果需要修改 NavigationBar 等原生界面棵帽,可能通過定義好的協(xié)議請(qǐng)求 URL: douban://rexxar.douban.com

Rexxar Container 攔截請(qǐng)求渣玲,按定義好的協(xié)議作出反應(yīng)逗概。例如,修改 NavigationBar 上的按鈕柜蜈。如果需要仗谆,會(huì)向 Rexxar Web 回調(diào)約定好的 Javascript 函數(shù)。

Rexxar 的問題

性能

混合開發(fā)的問題在于現(xiàn)階段淑履,Web 的性能沒法和 Native 相比隶垮。這種狀況可能會(huì)長期存在。因?yàn)槊卦耄岸舜a運(yùn)行于內(nèi)嵌瀏覽器之上狸吞,和直接調(diào)用原生系統(tǒng)相比,理論上總會(huì)存在性能上的差距。我們現(xiàn)在基本是以規(guī)避的方式面對(duì)性能問題:即性能問題會(huì)明顯影響到用戶體驗(yàn)時(shí)蹋偏,我們就不使用 Rexxar 來做便斥,而是使用傳統(tǒng) Native 老老實(shí)實(shí)寫兩份代碼,一份 iOS威始,一份 Android枢纠。當(dāng)然,這就限縮了 Rexxar 的使用范圍黎棠。

在 Rexxar iOS 中晋渺,我們做了使用 WKWebView 替代 UIWebView 的嘗試。但是現(xiàn)在看起來這會(huì)是一個(gè)長遠(yuǎn)目標(biāo)脓斩。WKWebView 在速度和內(nèi)存消耗上都優(yōu)于 UIWebView木西。但 WKWebView 并不完善。對(duì)于 Rexxar iOS 而言随静,最重要的缺陷是不支持使用 NSURLProtocol 截獲 WKWebView 中發(fā)出的網(wǎng)絡(luò)請(qǐng)求八千。所以在現(xiàn)有的 Rexxar 的實(shí)現(xiàn)中,并沒有使用 WKWebView燎猛。但是恋捆,我們會(huì)持續(xù)努力,以尋找切換至 WKWebView 的可能性重绷。

錯(cuò)誤報(bào)告

我們?cè)趹?yīng)用中使用 Rexxar 之后鸠信,在收集到的 Crash Report 中,JavaScript 的相關(guān)錯(cuò)誤论寨,和瀏覽器相關(guān)的錯(cuò)誤開始增加。而對(duì)這類錯(cuò)誤爽茴,由于移動(dòng)應(yīng)用的使用環(huán)境更為復(fù)雜葬凳,錯(cuò)誤報(bào)告經(jīng)過了 JavaScript 引擎,原生系統(tǒng)兩層之后室奏,給出的錯(cuò)誤信息并不夠明確火焰。我們?cè)谶@方面的經(jīng)驗(yàn)也并不多,導(dǎo)致我們還沒有很好的辦法降低這類錯(cuò)誤胧沫。這對(duì)提高 App 的穩(wěn)定性帶來了問題昌简。

總結(jié)

Rexxar 這個(gè)混合開發(fā)框架在豆瓣移動(dòng)開發(fā)中使用,確實(shí)在一定程度上提高了我們的開發(fā)效率绒怨。以前一個(gè)頁面需要 iOS 和 Android 兩位工程師各開發(fā)一遍纯赎,現(xiàn)在只需要一位工程師寫一次前端代碼,甚至還可以應(yīng)用到移動(dòng) Web 上去南蹂。雖然 Rexxar 仍然存在一些問題犬金,和使用上的限制。但是在有限的使用中,我們?nèi)匀皇斋@不少晚顷。所以峰伙,在未來我們應(yīng)該會(huì)持續(xù)推動(dòng) Rexxar 在豆瓣移動(dòng)開發(fā)中的使用。

希望這個(gè) Rexxar 這個(gè)開源項(xiàng)目對(duì)大家能起到一點(diǎn)啟示效果该默。并得到大家的反饋和建議瞳氓,幫助我們提高。

全文完栓袖。感謝豆瓣團(tuán)隊(duì)的投稿匣摘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市叽赊,隨后出現(xiàn)的幾起案子恋沃,更是在濱河造成了極大的恐慌,老刑警劉巖必指,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囊咏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡塔橡,警方通過查閱死者的電腦和手機(jī)梅割,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葛家,“玉大人户辞,你說我怎么就攤上這事●耍” “怎么了底燎?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弹砚。 經(jīng)常有香客問我双仍,道長,這世上最難降的妖魔是什么桌吃? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任朱沃,我火速辦了婚禮,結(jié)果婚禮上茅诱,老公的妹妹穿的比我還像新娘逗物。我一直安慰自己,他們只是感情好瑟俭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布翎卓。 她就那樣靜靜地躺著,像睡著了一般尔当。 火紅的嫁衣襯著肌膚如雪莲祸。 梳的紋絲不亂的頭發(fā)上蹂安,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音锐帜,去河邊找鬼田盈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛缴阎,可吹牛的內(nèi)容都是我干的允瞧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蛮拔,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼述暂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起建炫,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤畦韭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后肛跌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺配,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年衍慎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了转唉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稳捆,死狀恐怖赠法,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乔夯,我是刑警寧澤砖织,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站末荐,受9級(jí)特大地震影響镶苞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鞠评,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壕鹉。 院中可真熱鬧剃幌,春花似錦、人聲如沸晾浴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脊凰。三九已至抖棘,卻和暖如春茂腥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背切省。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工最岗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朝捆。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓般渡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親芙盘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驯用,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • 1.首先我們要了解豆瓣框架為何而生,作用是什么儒老。 在大型移動(dòng)應(yīng)用的開發(fā)中蝴乔,項(xiàng)目代碼龐雜,通常還需要 iOS驮樊,And...
    Iam光星人閱讀 1,903評(píng)論 0 3
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,506評(píng)論 25 707
  • 人衰老起來薇正,快得超出你想象。 大多數(shù)人都在 22 歲左右大學(xué)畢業(yè)巩剖,三年之后铝穷,我們會(huì)驚奇發(fā)現(xiàn):很多少年少女,僅僅在社...
    簡(jiǎn)淺Jian閱讀 478評(píng)論 1 6
  • 歲月驚艷了流年 凡塵俗世迷了那雙清澈的眼 時(shí)光長河中 失去了多少 又收獲了多少 那個(gè)夏天炎炎烈日下 講述一個(gè)沒有結(jié)...
    遠(yuǎn)方孤雁閱讀 162評(píng)論 1 2