Hybrid應(yīng)用開(kāi)發(fā)初探

Hybrid開(kāi)發(fā)定義和使用范圍

為什么要采用hybrid:

現(xiàn)階段的應(yīng)用開(kāi)發(fā),會(huì)遇到如下問(wèn)題和挑戰(zhàn):
1 一些頁(yè)面或業(yè)務(wù)恃泪,和運(yùn)營(yíng)強(qiáng)相關(guān),無(wú)法native固定(例如電子商務(wù) 詳情展示)
2 客戶端發(fā)版周期長(zhǎng),一些需求想要很快上線,或變化非常頻繁

現(xiàn)有3類主流APP任斋,分別為:Web App、Hybrid App(混合模式應(yīng)用耻涛,Hybrid有“混合的”意思)废酷、 Native App;

Native App 和 Web App不作解釋了抹缕,主要解釋Hybrid App澈蟆。
Hybrid App按網(wǎng)頁(yè)語(yǔ)言與程序語(yǔ)言的混合,通常分為三種類型:多View混合型卓研,單View混合型趴俘,Web主體型。

單頁(yè)混合型

即在同一個(gè)頁(yè)面內(nèi)奏赘,同時(shí)包括Native View和Web View寥闪。互相之間是覆蓋(層疊)的關(guān)系磨淌。這種Hybrid App的開(kāi)發(fā)成本較高疲憋,開(kāi)發(fā)難度較大,但是體驗(yàn)較好梁只。如百度搜索為代表的單頁(yè)混合型移動(dòng)應(yīng)用缚柳,既可以實(shí)現(xiàn)充分的靈活性埃脏,又能實(shí)現(xiàn)較好的用戶體驗(yàn)。一般如無(wú)特殊需求喂击,不會(huì)采用此種方式剂癌。

Web主體型

這種常見(jiàn)于市面上第三方hybrid框架實(shí)現(xiàn)。例如Wex5翰绊,AppCan和Rexsee都屬于Web主體型移動(dòng)應(yīng)用中間件佩谷。基本可以實(shí)現(xiàn)跨平臺(tái)监嗜,主要以網(wǎng)頁(yè)語(yǔ)言編寫谐檀,利用框架生成native的殼子。但是一般用戶體驗(yàn)存在缺陷裁奇。常見(jiàn)于一些小型或功能單一app桐猬。

多主體混合型

即Native View和Web View獨(dú)立展示,交替出現(xiàn)刽肠。這種應(yīng)用混合邏輯相對(duì)簡(jiǎn)單溃肪。這種移動(dòng)應(yīng)用主體通常是Native App,Web技術(shù)只是起到補(bǔ)充作用音五。開(kāi)發(fā)難度和Native App基本相當(dāng)惫撰。常見(jiàn)的Hybrid App是Native View與WebView交替的場(chǎng)景出現(xiàn)。

與App內(nèi)接入H5的區(qū)別:

hybrid的開(kāi)發(fā)模式與我們之前一些運(yùn)營(yíng)頁(yè)面采用h5的根本區(qū)別在于躺涝,后者只是在一些不重要的功能上實(shí)現(xiàn)可運(yùn)營(yíng)和便于分享厨钻,并不接入到應(yīng)用的主要流程中,與native的交互較少坚嗜,對(duì)應(yīng)用的影響小夯膀,作為開(kāi)發(fā)的一個(gè)小模塊獨(dú)立存在。hybrid開(kāi)發(fā)則是將web頁(yè)面作為native的重要補(bǔ)充苍蔬,應(yīng)用功能的重要組成部分诱建,需要考慮上線節(jié)奏,web與native的通訊碟绑,優(yōu)化web體驗(yàn)等問(wèn)題俺猿,對(duì)于應(yīng)用來(lái)講,web與native的地位蜈敢,被大大拉平了辜荠。

如何區(qū)分Hybrid APP中的原生頁(yè)面和H5頁(yè)面

很多人從頁(yè)面的設(shè)計(jì)上來(lái)區(qū)分的。如:(1)頂部顯示網(wǎng)頁(yè)鏈接抓狭;(2)有加載的進(jìn)度條伯病;(3)沒(méi)有底部tab導(dǎo)航欄;(4)頂部顯示兩個(gè)導(dǎo)航條;
但是現(xiàn)在app的h5頁(yè)面做的可以以假亂真了午笛,這些統(tǒng)統(tǒng)不管用惭蟋。
以淘寶為例:


設(shè)置-開(kāi)發(fā)者選項(xiàng)-顯示布局邊界

H5中使用了webview控件,其作為一個(gè)控件药磺,只有一個(gè)邊界框告组,所以通過(guò)這一點(diǎn),就比較容易區(qū)分出一個(gè)界面是webview實(shí)現(xiàn)的還是原生布局控件實(shí)現(xiàn)的
這次再來(lái)看看:

幾個(gè)主流HybridApp:淘寶癌佩、京東木缝、大眾點(diǎn)評(píng)等

Hybrid中Native和H5的使用范圍:

Native
1 應(yīng)用核心邏輯:例如 下單、支付等
2 對(duì)手機(jī)native功能(如照相围辙、定位)重度依賴的頁(yè)面
3 用戶體驗(yàn)要求強(qiáng)我碟,運(yùn)營(yíng)要求弱的頁(yè)面
H5:
1.功能開(kāi)發(fā)不完善,試運(yùn)營(yíng)階段(試錯(cuò)成本低)
2.強(qiáng)運(yùn)營(yíng)需求姚建,在功能調(diào)整或內(nèi)容的運(yùn)營(yíng)上很靈活
3.階段性的營(yíng)銷活動(dòng)矫俺,希望被分享出去

Hybrid開(kāi)發(fā)中要解決的幾個(gè)問(wèn)題

一、H5 和 Native 上線時(shí)間不一致掸冤,如何銜接厘托?
二、H5 和 Native 之間如何進(jìn)行通信稿湿?
三铅匹、H5 頁(yè)面如何接近 Native 的體驗(yàn)?
針對(duì)幾個(gè)問(wèn)題缎罢,參考了美團(tuán)團(tuán)隊(duì)技術(shù)分享的解決方案伊群,同時(shí)根據(jù)自己的理解做了適當(dāng)?shù)臄U(kuò)展:

1. H5 和 Native 上線時(shí)間不一致考杉,如何銜接策精?

比如一個(gè)功能以H5形式作出,但H5的發(fā)布滯后于native崇棠,當(dāng)H5上線之后咽袜,客戶端需要給H5提供一些跳轉(zhuǎn)的入口,這個(gè)跳轉(zhuǎn)的入口提供的應(yīng)該是在不發(fā)版的情況下去給出的枕稀。
這就需要對(duì)路由的跳轉(zhuǎn)做到后臺(tái)的可配置询刹。
現(xiàn)階段的跳轉(zhuǎn):(Native 到 Native)
這種組件化的全局統(tǒng)跳協(xié)議,利用ARouter萎坷、天貓統(tǒng)跳協(xié)議等其他路由機(jī)制凹联,都可以實(shí)現(xiàn)。



對(duì)這個(gè)跳轉(zhuǎn)去做一些擴(kuò)展:對(duì)路由協(xié)議擴(kuò)展后哆档,讓他能支持跳轉(zhuǎn)到H5里蔽挠。如下圖:



通過(guò)后臺(tái)動(dòng)態(tài)決定一個(gè)頁(yè)面,究竟是native還是h5的展現(xiàn)形式瓜浸。
舉個(gè)例子:
在APP里一個(gè)購(gòu)物下單的流程澳淑,用戶需要訪問(wèn)列表頁(yè)比原,商家的詳情頁(yè),創(chuàng)建訂單杠巡,最后購(gòu)買成功量窘。對(duì)一些新的產(chǎn)品,有新的產(chǎn)品詳情和創(chuàng)建訂單樣式氢拥“鐾可以通過(guò)h5上線的方式:

可以看到流程的兩端都是native,中間環(huán)節(jié)從native到h5可以動(dòng)態(tài)切換
備注:這些路由配置嫩海,是實(shí)際需求的少數(shù)厘线,作為主體方案的有效補(bǔ)充存在。

2. H5 和 Native 如何進(jìn)行通信出革?
傳統(tǒng)的JSInterface(兼容性)

看一段html代碼

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" dir="ltr">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <script type="text/javascript">
        function showToast(toast) {
            javascript:control.showToast(toast);
        }
        function log(msg){
            console.log(msg);
        }
    </script>

</head>

<body>
<input type="button" value="toast"
       onClick="showToast('Hello world')" />
</body>
</html>

對(duì)應(yīng)的java代碼:

public class MainActivity extends AppCompatActivity {

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView)findViewById(R.id.webView);

        WebSettings webSettings = webView.getSettings();

        webSettings.setJavaScriptEnabled(true);

        webView.addJavascriptInterface(new JsInterface(), "control");

        webView.loadUrl("file:///android_asset/interact.html");
    }

    public class JsInterface {

        @JavascriptInterface
        public void showToast(String toast) {
            Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
            log("show toast success");
        }

        public void log(final String msg){
            webView.post(new Runnable() {
                @Override
                public void run() {
                    webView.loadUrl("javascript: log(" + "'" + msg + "'" + ")");
                }
            });
        }
    }
}

通過(guò)webView.addJavascriptInterface(new JsInterface(), "control")造壮,將js的control與native的JsInterface聯(lián)系起來(lái),實(shí)現(xiàn)了js向native的調(diào)用骂束。反過(guò)來(lái)耳璧,webView.loadUrl("javascript: log(" + "'" + msg + "'" + ")"),loadUrl調(diào)用到j(luò)s中定義的log方法展箱,實(shí)現(xiàn)了native到j(luò)s的回調(diào)旨枯。

但是,混驰,攀隔,
4.2版本之前的addjavascriptInterface接口引起的漏洞,可能導(dǎo)致惡意網(wǎng)頁(yè)通過(guò)Js方法遍歷剛剛通過(guò)addjavascriptInterface注入進(jìn)來(lái)的類的所有方法從中獲取到getClass方法栖榨,然后通過(guò)反射獲取到Runtime對(duì)象昆汹,進(jìn)而調(diào)用Runtime對(duì)象的exec方法執(zhí)行一些操作,惡意的Js代碼如下:

function execute(cmdArgs) {
    for (var obj in window) {
        if ("getClass" in window[obj]) {
            alert(obj);
            return  window[obj].getClass().forName("java.lang.Runtime")  
                 .getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
        }
    }
}

4.2以后通過(guò)為可以被Js調(diào)用的方法添加@JavascriptInterface注解來(lái)解決婴栽,但是4.2之前的版本兼容性存在問(wèn)題满粗。而且這種類似于函數(shù)式的調(diào)用方式,擴(kuò)展性和兩端的兼容性都受限愚争,所以他也就沒(méi)法廣泛采用了映皆。

UrlRouter

嚴(yán)格的說(shuō),UrlRouter不算是js和java的通信轰枝,它只是一個(gè)通過(guò)url來(lái)讓前端喚起native頁(yè)面的框架捅彻。不過(guò)千萬(wàn)不要小看它的作用,如果協(xié)議定義的合理鞍陨,它可以讓前端步淹,Android和iOS三端有一個(gè)高度的統(tǒng)一,十分方便。

public class NavWebViewClient extends WebViewClient {

    private Context context;

    public NavWebViewClient(Context context){
        this.context = context;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if( Nav.from(context).toUri(url)){
            return true;
        }

        view.loadUrl(url);
        return true;
    }
}

在方法shouldOverrideUrlLoading中贤旷,攔截后交給Nav處理广料,如果返回true則成功攔截,返回false則交給webview去load url幼驶。Nav中的解析處理艾杏,可以根據(jù)業(yè)務(wù)特點(diǎn),根據(jù)scheme host url地址解析出跳轉(zhuǎn)路徑和攜帶的參數(shù)盅藻。
關(guān)于攜帶參數(shù)购桑,再多說(shuō)兩句:h5與native要約定傳參的格式,比如json格式氏淑,那么在json字串里約定好字段的含義勃蜘,就可以傳參,比如要實(shí)現(xiàn)跳轉(zhuǎn)到指定頁(yè)面假残,并攜帶參數(shù):

{"p": "orderlist","pa": {"tp": "per"}}

字段p代碼代碼頁(yè)面缭贡,字段pa代表參數(shù),pa字段后面的json表示此頁(yè)面需要的具體傳參辉懒。要注意傳參部分要進(jìn)行加密處理阳惹。

JSBridge

這種方式不算新,一些大公司都有自己的jsBridge封裝方式眶俩,這里簡(jiǎn)要說(shuō)明一下基本原理莹汤。
WebView中有一個(gè)WebChromeClient類,有三個(gè)監(jiān)聽(tīng)函數(shù):

@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    return super.onJsPrompt(view, url, message, defaultValue, result);
}

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    return super.onJsAlert(view, url, message, result);
}

@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    return super.onJsConfirm(view, url, message, result);
}

在js中颠印,alert和confirm本身的使用概率還是很高的纲岭,不建議使用這兩個(gè)通道,onJsPrompt方法則可以用來(lái)js與java通信线罕。通過(guò)在回調(diào)函數(shù)中message參數(shù)傳遞通訊協(xié)議止潮,native根據(jù)協(xié)議解析決定自己的操作。

onJsPrompt方法中message參數(shù):hybrid://JSBridge:1538351/method?{“message”:”msg”}

sheme是hybrid://闻坚,host是JSBridge沽翔,方法名字是toast兢孝,傳遞的參數(shù)是以json格式傳遞的
java層的處理:

public class InjectedChromeClient extends WebChromeClient {
    private final String TAG = "InjectedChromeClient";

    private JsCallJava mJsCallJava;

    public InjectedChromeClient() {
        mJsCallJava = new JsCallJava();
    }

    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
        result.confirm(mJsCallJava.call(view, message));
        return true;
    }
}

核心的call方法做了哪些窿凤?

public String call(WebView webView, String jsonStr) {
    String methodName = "";
    String name = BRIDGE_NAME;
    String param = "{}";
    String result = "";
    String sid="";
    if (!TextUtils.isEmpty(jsonStr) && jsonStr.startsWith(SCHEME)) {
        Uri uri = Uri.parse(jsonStr);
        name = uri.getHost();
        param = uri.getQuery();
        sid = getPort(jsonStr);
        String path = uri.getPath();
        if (!TextUtils.isEmpty(path)) {
            methodName = path.replace("/", "");
        }
    }

    if (!TextUtils.isEmpty(jsonStr)) {
        try {
            ArrayMap<String, Method> methodMap = mInjectNameMethods.get(name);

            Object[] values = new Object[3];
            values[0] = webView;
            values[1] = new JSONObject(param);
            values[2]=new JsCallback(webView,sid);
            Method currMethod = null;
            if (null != methodMap && !TextUtils.isEmpty(methodName)) {
                currMethod = methodMap.get(methodName);
            }
            // 方法匹配失敗
            if (currMethod == null) {
                result = getReturn(jsonStr, RESULT_FAIL, "not found method(" + methodName + ") with valid parameters");
            }else{
                result = getReturn(jsonStr, RESULT_SUCCESS, currMethod.invoke(null, values));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        result = getReturn(jsonStr, RESULT_FAIL, "call data empty");
    }

    return result;
}

代碼的思路如下:
(1) 在js腳本中把對(duì)應(yīng)的方法名,參數(shù)等寫成一個(gè)符合協(xié)議的uri跨蟹,并且通過(guò)window.prompt方法發(fā)送給java層雳殊。

(2) 在java層的onJsPrompt方法中接受到對(duì)應(yīng)的message之后,通過(guò)JsCallJava類進(jìn)行具體的解析窗轩。

(3) 在JsCallJava類中夯秃,我們解析得到對(duì)應(yīng)的方法名,參數(shù)等信息,并且在map中查找出對(duì)應(yīng)的類的方法仓洼。

思考:為什么不對(duì)message中的字段進(jìn)行switch case的邏輯判斷介陶,而是要經(jīng)過(guò)mInjectNameMethods的遍歷呢?

在業(yè)務(wù)復(fù)雜,應(yīng)用已經(jīng)組件化的情況下色建,JSBridge一定是作為整體架構(gòu)的一部分存在的哺呜,那么其定義和使用可能是分離的,通過(guò)mInjectNameMethods遍歷的方法箕戳,JSBridge中定義方法的權(quán)利交給了業(yè)務(wù)部門某残,有效實(shí)現(xiàn)了解耦。

可以這么說(shuō)UrlRouter在頁(yè)面跳轉(zhuǎn)方面陵吸,JSBridge在方法調(diào)用方面玻墅,都具備各自的特點(diǎn)和優(yōu)勢(shì),可以有效的結(jié)合起來(lái)壮虫。

3 . H5 頁(yè)面如何接近 Native 的體驗(yàn)澳厢?
資源加載緩慢

1.模塊化你的 H5 頁(yè)面/應(yīng)用,引入模塊加載器
2.資源預(yù)加載
第一種方式是說(shuō)使用 WebView 自身的緩存機(jī)制
這種緩存囚似,系統(tǒng)會(huì)自動(dòng)把它清掉赏酥,我們沒(méi)法進(jìn)行控制
第二種方案是說(shuō),我們自己去構(gòu)建谆构,自己管理緩存
把這些需要預(yù)加載的資源放在 APP 里面裸扶,他可能是預(yù)制放進(jìn)去的,也可能是后續(xù)下載的搬素。
每當(dāng)這個(gè) WebView 發(fā)起資源請(qǐng)求的時(shí)候呵晨,我們會(huì)攔截到這些資源的請(qǐng)求,去本地檢查一下我們的這些靜態(tài)資源本地離線包有沒(méi)有熬尺。針對(duì)本地的緩存文件我們有些策略能夠及時(shí)的去更新它


資源預(yù)加載效果:

每個(gè)頁(yè)面在預(yù)加載后都有明顯提升(4G下明顯)摸屠,同時(shí)橫向比較,也可看出粱哼,在一系列的web加載過(guò)程中季二,平均時(shí)間再降低。也說(shuō)明了webview自身的緩存機(jī)制揭措。
騰訊開(kāi)源的hybrid框架(實(shí)際只是webview首屏優(yōu)化)胯舷,實(shí)踐了webview的優(yōu)化,具體原理可以去github:
https://github.com/Tencent/VasSonic

VasSonic有如下特點(diǎn)(缺點(diǎn)):
1.VasSonic的技術(shù)實(shí)現(xiàn)上绊含,需要服務(wù)端桑嘶、客戶端 同時(shí)修改配合;
2.目前sonic后臺(tái)僅支持node.js和php版本躬充,暫時(shí)還不支持其他后臺(tái)逃顶;
3.iOS 只支持UIWebView讨便,不支持WKWebView,主要是因?yàn)樵赪KWebView目前不支持NSURLProtocol攔截以政;
vassonic這套方案霸褒,對(duì)于現(xiàn)有項(xiàng)目還是有一定侵入性的,而且需要服務(wù)端配合盈蛮“涟裕可以參考其思路,完全照搬對(duì)于大項(xiàng)目有風(fēng)險(xiǎn)眉反。

最后放一張hybrid客戶端架構(gòu)圖

Zjiyyu.png

H5Container是架構(gòu)設(shè)計(jì)的重點(diǎn)和難點(diǎn)昙啄,其中nativeApi,HandwareApi都是對(duì)于手機(jī)對(duì)web提供功能的封裝寸五。Data Channel負(fù)責(zé)埋點(diǎn);JSBridge是處于底層的通訊接口梳凛,JSBridges為各個(gè)模塊的定制和擴(kuò)展。
Synchronize Service 模塊表示和服務(wù)器的長(zhǎng)連接通信模塊梳杏,用于接受服務(wù)器端各種推送韧拒,包括離線包等。 Source Merge Service 模塊表示對(duì)解壓后的H5資源進(jìn)行更新十性,包括增加文件叛溢、以舊換新以及刪除過(guò)期文件等。

總結(jié):

一般來(lái)說(shuō)Hybrid的項(xiàng)目一般是用在一些快速迭代試錯(cuò)的地方劲适。另外包括有一些非主流產(chǎn)品的頁(yè)面楷掉,我們傾向于用 Hybrid 的形式做.
但是像前端購(gòu)買一些交易環(huán)節(jié),特別核心的流程的話霞势,我們一般情況下會(huì)用 Native 的形式去寫這些頁(yè)面烹植,去提升,達(dá)到一個(gè)極致的用戶體驗(yàn)愕贡。不要為了hybrid而hybrid草雕,一切都是根據(jù)需求的實(shí)際情況出發(fā),同時(shí)hybrid的框架在設(shè)計(jì)時(shí)固以,協(xié)議方面要注意ios android兩端的統(tǒng)一墩虹,android端自身盡量考慮擴(kuò)展性和解耦,有利于后續(xù)開(kāi)發(fā)迭代的穩(wěn)定和迅速憨琳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诫钓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子栽渴,更是在濱河造成了極大的恐慌尖坤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闲擦,死亡現(xiàn)場(chǎng)離奇詭異慢味,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)墅冷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門纯路,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人寞忿,你說(shuō)我怎么就攤上這事驰唬。” “怎么了腔彰?”我有些...
    開(kāi)封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵叫编,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我霹抛,道長(zhǎng)搓逾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任杯拐,我火速辦了婚禮霞篡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘端逼。我一直安慰自己朗兵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布顶滩。 她就那樣靜靜地躺著余掖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪礁鲁。 梳的紋絲不亂的頭發(fā)上浊吏,一...
    開(kāi)封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音救氯,去河邊找鬼找田。 笑死,一個(gè)胖子當(dāng)著我的面吹牛着憨,可吹牛的內(nèi)容都是我干的墩衙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼甲抖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼漆改!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起准谚,我...
    開(kāi)封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤挫剑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后柱衔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體樊破,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愉棱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哲戚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奔滑。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顺少,靈堂內(nèi)的尸體忽然破棺而出朋其,到底是詐尸還是另有隱情,我是刑警寧澤脆炎,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布梅猿,位于F島的核電站,受9級(jí)特大地震影響秒裕,放射性物質(zhì)發(fā)生泄漏袱蚓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一簇爆、第九天 我趴在偏房一處隱蔽的房頂上張望癞松。 院中可真熱鬧,春花似錦入蛆、人聲如沸响蓉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枫甲。三九已至,卻和暖如春扼褪,著一層夾襖步出監(jiān)牢的瞬間想幻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工话浇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脏毯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓幔崖,卻偏偏與公主長(zhǎng)得像食店,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赏寇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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