一农尖、Xposed模塊開發(fā)教程-通俗易懂理解篇

簡(jiǎn)介(本篇文章只作為理解)

怎么為Xposed開發(fā)新的模塊么荒揣?那么讀讀這篇教程(或者我們可以稱他為”泛讀短文”)學(xué)著怎么去做。這不僅包括“創(chuàng)建這個(gè)文件然后插入…”這類的技巧画机,也包括這些技巧背后的思想冶伞。這些思想正是創(chuàng)造價(jià)值的步驟以及你真正需要了解你做了什么和為什么這么做的原因。如果你覺得本文“太長(zhǎng)步氏,不想讀”响禽,那么你可以只看最后的源代碼和閱讀<u>“使工程成為Xposed模塊“</u>部分。但是如果你讀了整篇文章你就會(huì)有更好的理解。你之后會(huì)節(jié)省出來(lái)閱讀這個(gè)的時(shí)間芋类,因?yàn)槟悴槐貞{自己弄清楚每件事隆嗅。

修改主題

你將重新創(chuàng)建在github上可以找到的紅色鐘表的的例子。它包括將狀態(tài)欄的鐘表變?yōu)榧t色并且加入一個(gè)笑臉的功能侯繁。我選擇這個(gè)例子是因?yàn)樗浅P∨衷胰菀卓匆娝龅男薷摹2⑶抑梗彩褂昧丝蚣芩峁┑囊恍┗痉椒ā?/p>

Xposed如何工作

在你開始做出自己的修改之前丽焊,你應(yīng)當(dāng)大致了解Xposed如何工作(如果覺得這部分無(wú)聊可以跳過(guò))。以下就是原理:

有一個(gè)叫做”Zygote”的進(jìn)程咕别,它是android運(yùn)行環(huán)境的核心技健。每個(gè)應(yīng)用都從一份它的拷貝(“fork”)產(chǎn)生。這個(gè)進(jìn)程在手機(jī)啟動(dòng)時(shí)由一個(gè)叫 /init.rc 的腳本啟動(dòng)顷级。這個(gè)進(jìn)程的啟動(dòng)在 /system/bin/app_process 加載所需要的類和調(diào)用初始化方法后完成凫乖。

這里就是Xposed發(fā)揮用處的地方了。當(dāng)你安裝完框架后弓颈,一個(gè)擴(kuò)展過(guò)的app_process就會(huì)被復(fù)制到 /system/bin 下帽芽。這個(gè)擴(kuò)展過(guò)的啟動(dòng)進(jìn)程會(huì)將一個(gè)額外的jar包添加到環(huán)境變量,并在特定場(chǎng)合調(diào)用里面的方法翔冀。比如:當(dāng)虛擬機(jī)創(chuàng)建完成后和Zygote的main方法被調(diào)用前导街。并且在那個(gè)方法當(dāng)中,我們已經(jīng)是Zygote的一部分纤子,而且能夠在它的上下文context中活動(dòng)搬瑰。

jar包的位置是 /data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar 它的源代碼可以在這里找到。查看XposedBridge的類控硼,你能找到main方法泽论。這就是我上文中所寫過(guò)的,它在每個(gè)進(jìn)程的最開始部分被調(diào)用卡乾。一些初始化的工作在那里完成翼悴,并且我們的模塊在那里加載(之后我再講模塊的加載)。

方法的hook/替換

真正使Xpoesed有威力的就是hook方法調(diào)用幔妨。當(dāng)你反編譯并修改APK時(shí)鹦赎,你能夠在任何你想的地方直接修改/替換指令。然而误堡,你事后需要重新編譯/給APK簽名古话,并且只能發(fā)布整個(gè)安裝包。使用Xposed能讓你放置的hook锁施,你并不能修改程序內(nèi)部的方法代碼(清楚地定義你想要在何處做什么樣的修改是不可能的)陪踩。然而杖们,你可以在方法調(diào)用的前后注入你的代碼。這也是java中能夠被清楚尋址的最小單位膊毁。

XposedBridge 有一個(gè)私有的 native 方法叫做<span style="color:red"> hookMethodNative胀莹。這個(gè)方法也在擴(kuò)展后的 app_process 中被實(shí)現(xiàn)了。它會(huì)將方法類型轉(zhuǎn)為“native”婚温,并把方法的實(shí)現(xiàn)與本地的通用方法相連描焰。這意味著,每當(dāng)被hook的方法調(diào)用后栅螟,調(diào)用者不知道實(shí)際調(diào)用的是通用的方法荆秦。在這個(gè)方法中,位于 XposedBridge 的 handleHookedMethod 方法會(huì)被調(diào)用力图,</span>并向方法調(diào)用傳遞參數(shù)步绸、this指針以及其他東西。之后這個(gè)方法負(fù)責(zé)喚起之前方法調(diào)用注冊(cè)過(guò)的回調(diào)吃媒。上述這些行為能夠改變調(diào)用的參數(shù)瓤介、實(shí)例/靜態(tài)變量、喚起其他方法赘那、處理調(diào)用結(jié)果刑桑。。募舟§舾或者跳過(guò)這些東西。它的彈性非常大拱礁。

現(xiàn)在創(chuàng)建一個(gè)模塊吧琢锋!

創(chuàng)建工程

一個(gè)模塊就是一個(gè)普通的app,只不過(guò)多了一些特殊的文件和元數(shù)據(jù)呢灶。所以在我們創(chuàng)建新的android工程以前吴超,我假設(shè)你已經(jīng)做過(guò)這個(gè)了。如果沒有鸯乃,官方文檔講的很詳細(xì)烛芬。對(duì)于SDK,我選擇了4.0.3(API15)飒责。我建議你也使用這個(gè),并且不要立刻開始仆潮。你不需要?jiǎng)?chuàng)建Activity宏蛉,因?yàn)槲覀兊男薷牟恍枰魏斡脩艚缑妗性置;卮疬^(guò)了這個(gè)問(wèn)題后拾并,你應(yīng)該有一個(gè)空白的工程項(xiàng)目。


使工程成為Xposed模塊

現(xiàn)在我們把工程變成Xposed能加載的東西。我們需要以下幾個(gè)步驟嗅义。

AndroidManifest.xml
<span style="color:red">Xposed Installer的模塊列表搜尋所有有一種特殊元數(shù)據(jù)標(biāo)記的應(yīng)用程序屏歹。</span>你可以到 AndroidManifest.xml => Application => Application Nodes (在底部) => Add => Meta Data 下面去創(chuàng)建這個(gè)標(biāo)記。<span style="color:red">標(biāo)記名稱應(yīng)該是 xposedmodule 之碗,值應(yīng)該是 true蝙眶。</span>給resource留空。重復(fù)以上過(guò)程創(chuàng)建 xposedminversion (見下文) 和 xposeddescription (你創(chuàng)建的模塊的簡(jiǎn)單描述)褪那。XML文件現(xiàn)在就是這個(gè)樣子:

<?xml version="1.0" encoding="utf-8"?>
 <manifest  xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.robv.android.xposed.mods.tutorial"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk android:minSdkVersion="15" />
 
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="Easy example which makes the status bar clock red and adds a smiley" />
        <meta-data
            android:name="xposedminversion"
            android:value="30" />
    </application>
</manifest>

XposedBridgeApi.jar

接下來(lái)幽纷,讓程序能夠找到 XposedBridge 的API。你可以從
這里下載 XposedBridgeApi-(version).jar 的最新版博敬。把它復(fù)制到叫做lib的子文件夾下友浸。右鍵單擊選擇Build Path => Add to Build Path。文件名當(dāng)中的(version)是你在manifest文件的xposedminversion標(biāo)簽所插入的版本偏窝。

保證API類沒有被包含(但僅僅是參考)在你編譯過(guò)的APK里收恢,否則你會(huì)得到一個(gè)IllegalAccessError錯(cuò)誤。libs(含有s)文件夾是eclipse自動(dòng)生成的祭往,不要把API文件放在那里伦意。

模塊的實(shí)現(xiàn)

現(xiàn)在你可以給你的模塊創(chuàng)建一個(gè)類了。我的類叫做”Tutorial”链沼,位于de.robv.android.xposed.mods.tutorial這個(gè)包中

package de.robv.android.xposed.mods.tutorial;
 
public class Tutorial {
 
}

第一步默赂,我們僅僅生成一些日志表明模塊已經(jīng)加載。一個(gè)模塊可以有多個(gè)入口點(diǎn)括勺。你選擇哪個(gè)取決于你想修改什么缆八。你可以在安卓系統(tǒng)啟動(dòng)時(shí)、在一個(gè)app將要啟動(dòng)時(shí)疾捍、在一個(gè)app的資源文件初始化時(shí)或其他時(shí)候奈辰,調(diào)用一個(gè)函數(shù)。

在這個(gè)教程靠后面的一部分乱豆,你將了解到在一個(gè)特定的app中需要做出的修改奖恰。那么先讓我們了解一下 “讓我知道什么時(shí)候加載一個(gè)新app” 這個(gè)入口點(diǎn)。所有入口點(diǎn)都被標(biāo)記為IXposedMod的子接口宛裕。這種情況下瑟啃,你需要實(shí)現(xiàn) IXposedHookLoadPackage 這個(gè)接口。其實(shí)它只有一個(gè)僅有一個(gè)參數(shù)的方法揩尸。這個(gè)方法向被實(shí)現(xiàn)的模塊提供更多關(guān)于運(yùn)行環(huán)境上下文的信息蛹屿。在我們的例子中,我們用log輸出加載的app的名稱岩榆。

package de.robv.android.xposed.mods.tutorial;
 
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
 
public class Tutorial implements IXposedHookLoadPackage {
    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
        XposedBridge.log("Loaded app: " + lpparam.packageName);
    }
}

這個(gè)log方法向標(biāo)準(zhǔn)logcat以及 /data/data/de.robv.android.xposed.installer/log/debug.log(通過(guò)Xposed Installer可以輕易訪問(wèn)到)輸出信息(tag Xposed)错负。

assets/xposed_init

現(xiàn)在唯一遺漏的就是提示XposedBridge哪些類包含了入口點(diǎn)坟瓢。這項(xiàng)工作通過(guò)一個(gè)叫 xposed_init 的文件完成。在assets文件夾下創(chuàng)建一個(gè)新的名叫xposed_init的text文件犹撒。在該文件中每行包含一個(gè)類的全名折联。在這個(gè)例子中,它是 de.robv.android.xposed.mods.tutorial.Tutorial识颊。

試試看

保存你的文件诚镰。以Android Application的方式運(yùn)行你的程序。因?yàn)檫@是你第一次安裝它谊囚,在使用前你需要先啟用怕享。打開Xposed Installer這個(gè)app并確保你安裝了xposed框架。之后切換到Modules標(biāo)簽镰踏。你應(yīng)該能在那里找到你的app函筋。在選擇框內(nèi)打鉤使得它可用。然后重啟奠伪。你當(dāng)然什么變化也看不到跌帐,但如果檢查log記錄,以應(yīng)該會(huì)看見以下的東西:

Loading Xposed (for Zygote)...
Loading modules from   /data/app/de.robv.android.xposed.mods.tutorial-1.apk
Loading class de.robv.android.xposed.mods.tutorial.Tutorial
Loaded app: com.android.systemui
Loaded app: com.android.settings
... (many more apps follow)

瞧绊率!它起作用了〗髁玻現(xiàn)在你擁有了一個(gè)Xposed模塊。它能夠變得比寫一些log更加有用…

探索你的目標(biāo)并尋找修改它的方式

好了滤否,下面要開始講的部分也許會(huì)非常不同脸狸,這取決于你想做什么。如果你之前修改過(guò)apk藐俺,也許你會(huì)知道在這里應(yīng)當(dāng)如何思考炊甲。總的來(lái)說(shuō)欲芹,你需要了解目標(biāo)的一些實(shí)現(xiàn)細(xì)節(jié)卿啡。在本教程中,目標(biāo)選定為狀態(tài)欄的時(shí)鐘菱父。這有助于了解到狀態(tài)欄以及其他一些東西都是系統(tǒng)UI的一部分【蹦龋現(xiàn)在讓我們?cè)谀抢镩_始我們的探索。

可能性1:反匯編浙宜。這會(huì)告訴你它實(shí)際的實(shí)現(xiàn)官辽,但是會(huì)很難閱讀和理解,因?yàn)槟愕玫降亩际莝mali格式的東西粟瞬∫俺纾可能性2:獲得AOSP源代碼。比如這里亩钟,這里乓梨。ROM不同代碼也很不一樣,但在本例中他們的實(shí)現(xiàn)是相似的甚至是相同的清酥。我會(huì)先看AOSP扶镀,然后看看這么做夠不夠。如果我需要細(xì)節(jié)焰轻,我會(huì)看看實(shí)際的反匯編的代碼臭觉。

你可以找找名稱中有“clock”的類。其他需要找的是用到的資源和布局辱志。如果你下載官方的AOSP代碼蝠筑,你可以從 <span style="color:red"> frameworks/base/packages/SystemUI</span> 開始找。你會(huì)找到好幾處“clock”出現(xiàn)的地方揩懒。找到有好幾種方式實(shí)現(xiàn)修改是正常而且真實(shí)的什乙。時(shí)刻記住你“只能” hook方法。所以你必須另找其他能夠插入代碼實(shí)現(xiàn)功能的地方已球,要么在方法的前面或是后面臣镣,或者是替換掉方法。你應(yīng)當(dāng)hook一個(gè)盡可能明確的方法智亮,而不是一個(gè)被調(diào)用成千上萬(wàn)次的用于解決性能問(wèn)題和非計(jì)劃中的副作用的方法忆某。

在本例當(dāng)中,你或許會(huì)發(fā)現(xiàn)布局 res/layout/status_bar.xml 包含一個(gè)指向帶有類com.android.systemui.statusbar.policy.Clock的自定義view±龋現(xiàn)在你腦子里也許會(huì)有好多點(diǎn)子弃舒。文字的顏色是通過(guò)textAppearance屬性定義的,所以最干凈的更改它的方法就是修改外觀的定義状原。然而聋呢,用Xposed框架改變外觀屬性幾乎是不可能的(這需要深入本地代碼)。替換狀態(tài)欄的布局也許是可能的遭笋,但對(duì)于你試圖做出的小小修改來(lái)說(shuō)是殺雞用牛刀坝冕。取而代之的是,看看這個(gè)類瓦呼。有一個(gè)叫updateLock的方法喂窟,似乎每分鐘都調(diào)用一次用于更新時(shí)間。

final void updateClock() {
    mCalendar.setTimeInMillis(System.currentTimeMillis());
    setText(getSmallTime());
}

這個(gè)方法用于修改來(lái)說(shuō)是很好的央串,因?yàn)檫@是一個(gè)足夠具體的看似唯一能夠修改時(shí)鐘文字的方法磨澡。如果我們?cè)谶@個(gè)方法的每次調(diào)用之后都加些修改時(shí)鐘文字和顏色的東西,應(yīng)該就能起作用质和。那么稳摄,我們開始做吧。

對(duì)于單獨(dú)修改字體顏色部分饲宿,有一種更好的辦法厦酬。參見“替換資源”中“修改布局”的例子胆描。

使用反射尋找并hook方法

現(xiàn)在我們已經(jīng)知道了哪些東西?我們?cè)赾om.android.systemui.statusbar.policy.Clock有一個(gè)叫做updateClock的希望干涉的方法仗阅。我們?cè)谙到y(tǒng)UI資源中找到了這個(gè)類昌讲,所以它僅僅在系統(tǒng)UI進(jìn)程當(dāng)中有效。其它一些類屬于框架减噪,而且在任何地方都有效短绸。如果我們?cè)?handleLoadPackage 中試圖直接獲取任何這個(gè)類的信息和引用,就會(huì)失敗筹裕。因?yàn)樘幱阱e(cuò)誤的進(jìn)程中醋闭。所以讓我們實(shí)現(xiàn)一種僅在某個(gè)特定包即將加載時(shí)執(zhí)行特定代碼的情況:

public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
    if (!lpparam.packageName.equals("com.android.systemui"))
        return;
 
    XposedBridge.log("we are in SystemUI!");
}

使用參數(shù),我們能輕松檢查是否在正確的包中朝卒。一旦我們核實(shí)了這一點(diǎn)证逻,我們就通過(guò)ClassLoader取得那個(gè)包中的也被這個(gè)變量引用的類。現(xiàn)在我們可以尋找com.android.systemui.statusbar.policy.Clock這個(gè)類以及它的updateClock方法扎运,然后告訴XposedBridge去hook這個(gè)方法:

package de.robv.android.xposed.mods.tutorial;
 
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
 
public class Tutorial implements IXposedHookLoadPackage {
    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.packageName.equals("com.android.systemui"))
            return;
 
        findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called before the clock was updated by the original method
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called after the clock was updated by the original method
            }
    });
    }
}

findAndHookMethod是一個(gè)Helper函數(shù)瑟曲。注意靜態(tài)導(dǎo)入,如果你像連接中說(shuō)的一樣做了豪治,那就會(huì)被自動(dòng)加入洞拨。這個(gè)方法使用系統(tǒng)UI包的ClassLoader尋找 Clock 這個(gè)類,然后尋找其中的updateClock方法负拟。如果這個(gè)方法中有任何參數(shù)烦衣,你必須事后列出這些參數(shù)的類型。有許多方法做這件事掩浙,但因?yàn)槲覀兊姆椒]有參數(shù)花吟,所以就先跳過(guò)這個(gè)步驟。至于最后一點(diǎn)厨姚,你需要提供一個(gè) XC_MethodHook 類的實(shí)現(xiàn)衅澈。對(duì)于更小的更改,你可以使用匿名類谬墙。如果你的代碼很多今布,最好創(chuàng)建普通的類并且只在這里創(chuàng)建實(shí)例。helper之后會(huì)如之前所說(shuō)的拭抬,做出所有hook這個(gè)方法的必要工作部默。

<span style="color:red">XC_MethodHook中有兩個(gè)你可以重寫的方法。你可以兩個(gè)都重寫造虎,或者都不重寫傅蹂。但后者的做法顯然是沒有道理的。這些方法就是beforeHookedMethod 和 afterHookedMethod。</span>不難猜出他們?cè)谠蟹椒ㄖ?后執(zhí)行份蝴。你可以使用“before”方法在方法調(diào)用前估計(jì)/操縱參數(shù)(通過(guò)param.args)犁功。甚至阻止調(diào)用原來(lái)的方法(發(fā)送你自己的結(jié)果)「惴Γ“after”方法可以用來(lái)做一些基于原來(lái)方法的結(jié)果的事波桩。你也可以在這個(gè)地方操縱結(jié)果。當(dāng)然请敦,你可以在方法調(diào)用的前/后添加你自己要執(zhí)行的代碼。

如果你要徹底替換一個(gè)方法储玫,去看看子類XC_MethodReplacement侍筛。在那里,你只需要重寫replaceHookedMethod撒穷。

XposedBridge為每個(gè)hook過(guò)的方法維護(hù)一個(gè)注冊(cè)過(guò)的回調(diào)的表匣椰。擁有最高優(yōu)先級(jí)(在hookMethod中被定義)的將被優(yōu)先調(diào)用。原有的方法總是具有最低的優(yōu)先級(jí)端礼。所以如果你hook了一個(gè)擁有回調(diào)A(高優(yōu)先級(jí))和回調(diào)B(默認(rèn)優(yōu)先級(jí))的方法禽笑,那么不管被hook的方法是如何被調(diào)用的,執(zhí)行順序總是這樣的:A.before -> B.before -> original method -> B.after -> A.after蛤奥。所以A可以影響B(tài)看到的參數(shù)佳镜,即把它們傳遞下去以前大幅度地修改它們。原有的方法的結(jié)果會(huì)先被B處理凡桥,但是A擁有原先調(diào)用者最終將得到什么樣結(jié)果的決定權(quán)蟀伸。

最終步驟:在方法調(diào)用之前/后執(zhí)行你自己的代碼

好了,你已經(jīng)在正確的上下文運(yùn)行環(huán)境中(比如:系統(tǒng)UI進(jìn)程)有了一個(gè)在updateClock方法每次被調(diào)用時(shí)都會(huì)被調(diào)用的方法∶骞簦現(xiàn)在讓我們修改一些東西吧啊掏。

第一個(gè)要檢查的:我們有具體的Clock類型的引用么?是的衰猛,我們有迟蜜。這就是param.thisObject參數(shù)。所以如果方法通過(guò)myClock.updateClock()被調(diào)用啡省,那么param.thisObject 就是 myClock娜睛。

接下來(lái):我們對(duì)clock做什么?Clock類型并不可用冕杠,你不能將param.thisObject轉(zhuǎn)換為類(也不要試著這樣做)微姊。然而它是從TextView繼承而來(lái)。所以一旦你把Clock的引用轉(zhuǎn)換為TextView分预,你可以使用像setText, getText 和 setTextColor之類的方法兢交。我們的改動(dòng)應(yīng)該在原有的方法設(shè)置了新的時(shí)間以后進(jìn)行。因?yàn)樵诜椒ū徽{(diào)用前什么都沒有做笼痹,我們可以空著beforeHookedMethod配喳。沒有必要調(diào)用(空的)“super”方法酪穿。

所以以下是完整的源代碼:

package de.robv.android.xposed.mods.tutorial;
 
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import android.graphics.Color;
import android.widget.TextView;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
 
public class Tutorial implements IXposedHookLoadPackage {
    public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.packageName.equals("com.android.systemui"))
            return;
 
        findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                TextView tv = (TextView) param.thisObject;
                String text = tv.getText().toString();
                tv.setText(text + " :)");
                tv.setTextColor(Color.RED);
            }
        });
    }
}

對(duì)結(jié)果感到滿意

現(xiàn)在啟動(dòng)/安裝你的app。因?yàn)槟愕谝淮螁?dòng)它時(shí)已經(jīng)在<span style="color:red">Xposed Installer中把它設(shè)置為了可用晴裹,</span>你就不需要在做這一步了被济。重啟即可。然而涧团,如果你正在使用這個(gè)紅色鐘表的例子只磷,你也許想禁用它。兩者都對(duì)它們的updateClock 處理程序使用了默認(rèn)的優(yōu)先級(jí)泌绣。所以你不清楚哪個(gè)會(huì)勝出(實(shí)際上這依賴于處理方法的字符串表示形式钮追,但不要依賴這個(gè)方式)。

FAQ&參考資料

1.Xposed模塊開發(fā)教程阿迈,該篇講解通俗易懂元媚,所以轉(zhuǎn)發(fā)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苗沧,隨后出現(xiàn)的幾起案子刊棕,更是在濱河造成了極大的恐慌,老刑警劉巖待逞,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件甥角,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡飒焦,警方通過(guò)查閱死者的電腦和手機(jī)蜈膨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牺荠,“玉大人翁巍,你說(shuō)我怎么就攤上這事⌒荽疲” “怎么了灶壶?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)杈曲。 經(jīng)常有香客問(wèn)我驰凛,道長(zhǎng),這世上最難降的妖魔是什么担扑? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任恰响,我火速辦了婚禮,結(jié)果婚禮上涌献,老公的妹妹穿的比我還像新娘胚宦。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布枢劝。 她就那樣靜靜地躺著井联,像睡著了一般。 火紅的嫁衣襯著肌膚如雪您旁。 梳的紋絲不亂的頭發(fā)上烙常,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音鹤盒,去河邊找鬼蚕脏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侦锯,可吹牛的內(nèi)容都是我干的蝗锥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼率触,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了汇竭?” 一聲冷哼從身側(cè)響起葱蝗,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎细燎,沒想到半個(gè)月后两曼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玻驻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年悼凑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片璧瞬。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡户辫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嗤锉,到底是詐尸還是另有隱情渔欢,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布瘟忱,位于F島的核電站奥额,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏访诱。R本人自食惡果不足惜垫挨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望触菜。 院中可真熱鬧九榔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至攻旦,卻和暖如春喻旷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牢屋。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工且预, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烙无。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓锋谐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親截酷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涮拗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • 文 | 陽(yáng)光下的海棠 從小到大,我一直是一個(gè)不善于表達(dá)的孩子念搬,許多想說(shuō)的話更多地留存在心底抑堡,徘徊于唇齒間。閑暇時(shí)刻...
    陽(yáng)光下的海棠閱讀 535評(píng)論 0 4
  • 這是一場(chǎng)人生的逆戰(zhàn)朗徊。 最近的生活有了新鮮的樣子首妖,參加了六哥的《第六期知識(shí)管理訓(xùn)練營(yíng)》,讓我找到了從前工作生活的節(jié)奏...
    樂活少女樂閱讀 534評(píng)論 0 0
  • 你是一個(gè)傻女人 在你的心里 愛情是你的生命 你愿意為它付出一切 從不問(wèn)自己值不值得 從沒有想過(guò)也許最后 只會(huì)收獲眼...
    身后一扇窗閱讀 155評(píng)論 0 0
  • 04年荣倾,新生悯搔,滿懷信仰開啟大學(xué)之旅。各色陌生人總有幾個(gè)會(huì)走在一起舌仍,性趣或興趣妒貌。高中老師編織的大學(xué)夢(mèng),分分鐘土崩瓦解...
    玄離閱讀 670評(píng)論 0 0