熱修復選擇(bugly+tinker、robust温艇、sophix)

在此之前一直在苦逼的coding因悲,不斷的增加功能,迭代中贝,這是當前移動互聯(lián)網(wǎng)初創(chuàng)團隊的標準模式囤捻。雖然我們不是創(chuàng)業(yè)公司,但是我們的團隊就是傳統(tǒng)公司的移動互聯(lián)網(wǎng)創(chuàng)業(yè)團隊,在移動互聯(lián)網(wǎng)保險沒有發(fā)展起來的時期快速上線蝎土,快速迭代视哑,搶占市場。
從去年11月上線到現(xiàn)在8個月的時間app從無到有誊涯,從0個用戶到現(xiàn)在360+萬挡毅,從0元保費到現(xiàn)在1500+萬。app算是步入正規(guī)暴构,當前首要任務是保證app線上的穩(wěn)定跪呈,雖然我們不管是開發(fā)人員還是測試人員都非常努力的去找bug,但是還是不能避免線上問題取逾,bug是永遠消滅不完的耗绿。
我們?yōu)榱司€上穩(wěn)定決定增加熱修復框架,很多人都去自己開發(fā)砾隅,但是我覺得專業(yè)的事情還是交給專業(yè)的人误阻,這樣我們可以專注的干對于團隊更重要的事。如下是我調(diào)研的目前主流的熱修復框架(robust晴埂,bugly+tinker究反,sophix)。
在此我只是寫如何選擇熱修復框架儒洛,具體的接入文檔我覺得在這里寫沒有任何意義精耐,官方的接入文檔比我講的詳細多了,如果你官方的文檔都看不懂我在這里更加說不清楚琅锻。

技術背景
微信tinker
美團robust
阿里sophix

接入文檔
微信tinker
美團robust
阿里sophix

阿里云對熱修復框架的比較如下圖:


84287FF4-784A-43CA-B041-2FD5FD860A5B.png

我覺得目前卦停,只看bugly+tinker、robust浅浮、sophix這三大類就可以了沫浆,其他的兼容性都會有些問題。

接入復雜性和易用性:

美團的Robust接入復雜性最高滚秩,需要修改的地方很多而且零散,而且對于差異化的代碼還需要使用注釋來標注一下淮捆,這樣易用性就下降了不少郁油。
如何接入Robust如下步驟:

1.在App的build.gradle,加入如下依賴
apply plugin: 'com.android.application'
//制作補丁時將這個打開攀痊,auto-patch-plugin緊跟著com.android.application
//apply plugin: 'auto-patch-plugin'
apply plugin: 'robust'      
compile 'com.meituan.robust:robust:0.4.5'
2.在整個項目的build.gradle加入classpath
 buildscript {
    repositories {
        jcenter()
    }
    dependencies {
         classpath 'com.meituan.robust:gradle-plugin:0.4.5'
         classpath 'com.meituan.robust:auto-patch-plugin:0.4.5'
   }
}
3.需要在項目的src同級目錄下配置部分配置robust.xml文件桐腌,具體項請參考app/robust.xml,在這里面有多個配置項苟径。
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <switch>
        <!--true代表打開Robust案站,請注意即使這個值為true,Robust也默認只在Release模式下開啟-->
        <!--false代表關閉Robust棘街,無論是Debug還是Release模式都不會運行robust-->
        <turnOnRobust>true</turnOnRobust>
        <!--<turnOnRobust>false</turnOnRobust>-->

        <!--是否開啟手動模式蟆盐,手動模式會去尋找配置項patchPackname包名下的所有類承边,自動的處理混淆,然后把patchPackname包名下的所有類制作成補丁-->
        <!--這個開關只是把配置項patchPackname包名下的所有類制作成補丁石挂,適用于特殊情況博助,一般不會遇到-->
        <!--<manual>true</manual>-->
        <manual>false</manual>

        <!--是否強制插入插入代碼,Robust默認在debug模式下是關閉的痹愚,開啟這個選項為true會在debug下插入代碼-->
        <!--但是當配置項turnOnRobust是false時富岳,這個配置項不會生效-->
        <!--<forceInsert>true</forceInsert>-->
        <forceInsert>false</forceInsert>

        <!--是否捕獲補丁中所有異常,建議上線的時候這個開關的值為true拯腮,測試的時候為false-->
        <catchReflectException>true</catchReflectException>
        <!--<catchReflectException>false</catchReflectException>-->

        <!--是否在補丁加上log窖式,建議上線的時候這個開關的值為false,測試的時候為true-->
        <!--<patchLog>true</patchLog>-->
        <patchLog>false</patchLog>

        <!--項目是否支持progaurd-->
        <proguard>true</proguard>
        <!--<proguard>false</proguard>-->
    </switch>

    <!--需要熱補的包名或者類名动壤,這些包名下的所有類都被會插入代碼-->
    <!--這個配置項是各個APP需要自行配置脖镀,就是你們App里面你們自己代碼的包名,
    這些包名下的類會被Robust插入代碼狼电,沒有被Robust插入代碼的類Robust是無法修復的-->
    <packname name="hotfixPackage">
        <name>com.meituan</name>
        <name>com.sankuai</name>
        <name>com.dianping</name>
        <name>com.pa.health</name>
    </packname>

    <!--不需要Robust插入代碼的包名蜒灰,Robust庫不需要插入代碼,如下的配置項請保留肩碟,還可以根據(jù)各個APP的情況執(zhí)行添加-->
    <exceptPackname name="exceptPackage">
        <name>com.meituan.robust</name>
    </exceptPackname>

    <!--補丁的包名强窖,請保持和類PatchManipulateImp中fetchPatchList方法中設置的補丁類名保持一致( setPatchesInfoImplClassFullName("com.meituan.robust.patch.PatchesInfoImpl")),
    各個App可以獨立定制削祈,需要確保的是setPatchesInfoImplClassFullName設置的包名是如下的配置項翅溺,類名必須是:PatchesInfoImpl-->
    <patchPackname name="patchPackname">
        <name>com.pa.health</name>
    </patchPackname>

    <!--自動化補丁中,不需要反射處理的類髓抑,這個配置項慎重選擇-->
    <noNeedReflectClass name="classes no need to reflect">

    </noNeedReflectClass>
</resources>
4.需要保存打包時生成的mapping文件以及build/outputs/robust/methodsMap.robust文件咙崎。
5.在Java中,合成補丁吨拍、下載補丁包褪猛、補丁包存放,補丁包安全驗證羹饰、補丁包版本管理都需要開發(fā)者進行管理伊滋,如下代碼
new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new RobustCallBack() {
            @Override
            public void onPatchListFetched(boolean result, boolean isNet) {
            }
            @Override
            public void onPatchFetched(boolean result, boolean isNet, Patch patch) {
            }
            @Override
            public void onPatchApplied(boolean result, Patch patch) {
                File file = new File(patch.getLocalPath());
                file.delete();
            }
            @Override
            public void logNotify(String log, String where) {
            }
            @Override
            public void exceptionNotify(Throwable throwable, String where) {
            }
        }).start();
public class PatchManipulateImp extends PatchManipulate {
    /***
     * connect to the network ,get the latest patches
     * l聯(lián)網(wǎng)獲取最新的補丁
     * @param context
     *
     * @return
     */
    @Override
    protected List<Patch> fetchPatchList(Context context) {
        //將app自己的robustApkHash上報給服務端,服務端根據(jù)robustApkHash來區(qū)分每一次apk build來給app下發(fā)補丁
        //apkhash is the unique identifier for  apk,so you cannnot patch wrong apk.
        //String robustApkHash = RobustApkHashUtils.readRobustApkHash(context);
        //connect to network to get patch list on servers
        //在這里去聯(lián)網(wǎng)獲取補丁列表
        Patch patch = new Patch();
        patch.setName("123");
        //we recommend LocalPath store the origin patch.jar which may be encrypted,while TempPath is the true runnable jar
        //LocalPath是存儲原始的補丁文件队秩,這個文件應該是加密過的笑旺,TempPath是加密之后的,TempPath下的補丁加載完畢就刪除馍资,保證安全性
        //這里面需要設置一些補丁的信息筒主,主要是聯(lián)網(wǎng)的獲取的補丁信息。重要的如MD5,進行原始補丁文件的簡單校驗乌妙,以及補丁存儲的位置使兔,這邊推薦把補丁的儲存位置放置到應用的私有目錄下,保證安全性
        patch.setLocalPath(Environment.getExternalStorageDirectory().getPath() + File.separator + "robust" + File.separator + "pahealth" + File.separator + "patch");

        //setPatchesInfoImplClassFullName 設置項各個App可以獨立定制冠胯,需要確保的是setPatchesInfoImplClassFullName設置的包名是和xml配置項patchPackname保持一致火诸,而且類名必須是:PatchesInfoImpl
        //請注意這里的設置
        patch.setPatchesInfoImplClassFullName("com.pa.health.PatchesInfoImpl");
        List patches = new ArrayList<Patch>();
        patches.add(patch);
        return patches;
    }

    /**
     * @param context
     * @param patch
     * @return you can verify your patches here
     */
    @Override
    protected boolean verifyPatch(Context context, Patch patch) {
        //do your verification, put the real patch to patch
        //放到app的私有目錄
        patch.setTempPath(context.getCacheDir() + File.separator + "robust" + File.separator + "patch");
        //in the sample we just copy the file
        try {
            copy(patch.getLocalPath(), patch.getTempPath());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("copy source patch to local patch error, no patch execute in path " + patch.getTempPath());
        }

        return true;
    }

    public void copy(String srcPath, String dstPath) throws IOException {
        File src = new File(srcPath);
        if (!src.exists()) {
            throw new RuntimeException("source patch does not exist ");
        }
        File dst = new File(dstPath);
        if (!dst.getParentFile().exists()) {
            dst.getParentFile().mkdirs();
        }
        InputStream in = new FileInputStream(src);
        try {
            OutputStream out = new FileOutputStream(dst);
            try {
                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }

    /**
     * @param patch
     * @return you may download your patches here, you can check whether patch is in the phone
     */
    @Override
    protected boolean ensurePatchExist(Patch patch) {
        Log.e("ensurePatchExist","ensurePatchExist");
        return true;
    }
}

如何使用Robust如下步驟:

1.使用插件時,需要把auto-patch-plugin放置在com.android.application插件之后荠察,其余插件之前置蜀。
apply plugin: 'com.android.application'
apply plugin: 'auto-patch-plugin'
2.將保存下來的mapping文件和methodsMap.robust文件放在app/robust/文件夾下。
3.修改代碼悉盆,在改動的方法上面添加@Modify

注解或者在修改的方法里面調(diào)用RobustModify.modify()(針對Lambda表達式)

@Modify 
protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState);
 } //或者是被修改的方法里面調(diào)用RobustModify.modify()方法 protected 
void onCreate(Bundle savedInstanceState) 
{ 
      RobustModify.modify() 
      super.onCreate(savedInstanceState);
 }

新增的方法和字段使用@Add注解

//增加方法 
@Add 
public String getString() { 
      return "Robust";
 } 
//增加類
 @Add 
public class NewAddCLass {
       public static String get() {
             return "robust";
       } 
}
4.運行和生成線上apk同樣的命令盯荤,即可生成補丁,補丁目錄app/build/outputs/robust/patch.jar
5.補丁制作成功后會停止構建apk焕盟,出現(xiàn)類似于如下的提示秋秤,表示補丁生成成功 [圖片上傳失敗...(image-446c06-1514882647844)]

以上是接入和使用robust的簡要步驟詳細步驟請點擊這里

微信的tinker接入性和易用性也很復雜請看這里脚翘,但是由于bugly對他進行了封裝灼卢,接入性和易用性增加了不少,而且增加了補丁包的管理后臺来农,后臺管理有很多配置可以設置鞋真,例如版本管理、根據(jù)手機系統(tǒng)版本進行下發(fā)補丁包等沃于。
如何接入Tinker如下步驟:

1.添加插件依賴

工程根目錄下“build.gradle”文件中添加:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        // tinkersupport插件, 其中l(wèi)astest.release指拉取最新版本涩咖,也可以指定明確版本號,例如1.0.4
        classpath "com.tencent.bugly:tinker-support:1.0.8"
    }
}
2.集成SDK

在app module的“build.gradle”文件中添加(示例配置):

 android {
        defaultConfig {
          ndk {
            //設置支持的SO庫架構
            abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
          }
        }
      }
      dependencies {
          compile "com.android.support:multidex:1.0.1" // 多dex配置
          //注釋掉原有bugly的倉庫
          //compile 'com.tencent.bugly:crashreport:latest.release'//其中l(wèi)atest.release指代最新版本號繁莹,也可以指定明確的版本號檩互,例如2.3.2
          compile 'com.tencent.bugly:crashreport_upgrade:1.3.1'
          compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中l(wèi)atest.release指代最新版本號,也可以指定明確的版本號咨演,例如2.2.0
      }

在app module的“build.gradle”文件中添加:

// 依賴插件腳本
apply from: 'tinker-support.gradle'

tinker-support.gradle內(nèi)容請點擊(示例配置)

3.Java代碼初始化SDK

我使用的是enableProxyApplication = true 的情況闸昨,無須你改造Application,主要是為了降低接入成本雪标,我們插件會動態(tài)替換AndroidMinifest文件中的Application為我們定義好用于反射真實Application的類(需要您接入SDK 1.2.2版本 和 插件版本 1.0.3以上)零院。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // 這里實現(xiàn)SDK初始化,appId替換成你的在Bugly平臺申請的appId
        // 調(diào)試時村刨,將第三個參數(shù)改為true
        Bugly.init(this, "900029763", false);
    }
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // you must install multiDex whatever tinker is installed!
        MultiDex.install(base);
        // 安裝tinker
        Beta.installTinker();
    }
}
4.配置AndroidManifest.xml
  1. 權限配置
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  1. Activity配置
<activity
    android:name="com.tencent.bugly.beta.ui.BetaActivity"
    android:configChanges="keyboardHidden|orientation|screenSize|locale"
    android:theme="@android:style/Theme.Translucent" />
5.混淆
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}

如何使用Tinker如下步驟:

1.打基準包

1.主要是修改tinker-support.gradle中的tinkerId = "base-1.0.1"


image.png

2.正常打包生成基準包


生成的基線版本
2.打補丁包

1.修改代碼
2.修改tinker-support.gradle中的tinkerId = "patch-1.0.1"
3.修改tinker-support.gradle中的baseApkDir = "app-0705-18-32-19",這個目錄是基準包生成的目錄
如下圖:

image.png

4.執(zhí)行構建補丁包的task
image.png

5.生成的補丁包在build/outputs/patch目錄下:
image.png

6.上傳補丁包到bugly
以上是接入和使用Tinker+bugly的簡要步驟詳細步驟請點擊這里撰茎。

阿里的sophix絕對是傻瓜式的接入和使用方式嵌牺,生成補丁包也是圖形化界面,oldapk和newapk上傳圖形工具生成補丁包。
如何接入Sophix如下步驟:

1.gradle遠程倉庫依賴, 打開項目找到app的build.gradle文件逆粹,添加如下配置:

添加maven倉庫地址:

repositories {
   maven {
       url "http://maven.aliyun.com/nexus/content/repositories/releases"
   }
}

添加gradle坐標版本依賴:

compile 'com.aliyun.ams:alicloud-android-hotfix:3.0.5'
2.權限說明

Sophix SDK使用到以下權限

<! -- 網(wǎng)絡權限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<! -- 外部存儲讀權限募疮,調(diào)試工具加載本地補丁需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3.配置AndroidManifest文件
<meta-data
android:name="com.taobao.android.hotfix.IDSECRET"
android:value="App ID" />
<meta-data
android:name="com.taobao.android.hotfix.APPSECRET"
android:value="App Secret" />
<meta-data
android:name="com.taobao.android.hotfix.RSASECRET"
android:value="RSA密鑰" />
4.混淆配置
#基線包使用,生成mapping.txt
-printmapping mapping.txt
#生成的mapping.txt在app/buidl/outputs/mapping/release路徑下僻弹,移動到/app路徑下
#修復后的項目使用阿浓,保證混淆結果一致
#-applymapping mapping.txt
#hotfix
-keep class com.taobao.sophix.**{*;}
-keep class com.ta.utdid2.device.**{*;}
#防止inline
-dontoptimize
5.Java接入范例

initialize的調(diào)用應該盡可能的早,必須在Application.attachBaseContext()或者Application.onCreate()的最開始進行SDK初始化操作蹋绽,否則極有可能導致崩潰芭毙。而查詢服務器是否有可用補丁的操作可以在后面的任意地方。

// initialize最好放在attachBaseContext最前面
SophixManager.getInstance().setContext(this)
                .setAppVersion(appVersion)
                .setAesKey(null)
                .setEnableDebug(true)
                .setPatchLoadStatusStub(new PatchLoadStatusListener() {
                    @Override
                    public void onLoad(final int mode, final int code, final String info, final int handlePatchVersion) {
                        // 補丁加載回調(diào)通知
                        if (code == PatchStatus.CODE_LOAD_SUCCESS) {
                            // 表明補丁加載成功
                        } else if (code == PatchStatus.CODE_LOAD_RELAUNCH) {
                            // 表明新補丁生效需要重啟. 開發(fā)者可提示用戶或者強制重啟;
                            // 建議: 用戶可以監(jiān)聽進入后臺事件, 然后應用自殺
                        } else if (code == PatchStatus.CODE_LOAD_FAIL) {
                            // 內(nèi)部引擎異常, 推薦此時清空本地補丁, 防止失敗補丁重復加載
                            // SophixManager.getInstance().cleanPatches();
                        } else {
                            // 其它錯誤信息, 查看PatchStatus類說明
                        }
                    }
                }).initialize();
// queryAndLoadNewPatch不可放在attachBaseContext 中卸耘,否則無網(wǎng)絡權限退敦,建議放在后面任意時刻,如onCreate中
SophixManager.getInstance().queryAndLoadNewPatch();

如何使用Sophix如下步驟:

1.下載打包工具

patch補丁包生成需要使用到打補丁工具SophixPatchTool, 如還未下載打包工具蚣抗,請前往下載Android打包工具侈百。
Mac版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_macos.zip

Windows版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_windows.zip

Linux版本打包工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/SophixPatchTool_linux.zip

調(diào)試工具地址:http://ams-hotfix-repo.oss-cn-shanghai.aliyuncs.com/hotfix_debug_tool-release.apk

該工具提供了Windows和macOS和Linux版本,Windows下運行SophixPatchTool.exe翰铡,macOS下運行SophixPatchTool.app钝域,Linux下(Ubuntu 16.04 64bit最佳)運行SophixPatchTool。并且需要安裝Java環(huán)境且在JDK7或以上才能正常使用锭魔。

2.生成Patch
image.png
  • 舊包:<必填> 選擇基線包路徑(有問題的APK)例证。
  • 新包:<必填> 選擇新包路徑(修復過該問題APK)。
  • 日志:打開日志輸出窗口赂毯。
  • 高級:高級選項
  • 設置:配置其他信息战虏。
  • GO!:開始生成補丁。
3.上傳補丁包到后臺

以上是接入和使用Sophix的簡要步驟詳細步驟請點擊這里党涕。

總結:

bugly+tinker烦感、robust、sophix膛堤。
robust是沒有后臺的需要自己開發(fā)而且接入和使用比較復雜手趣,所以沒有選擇济炎。
sophix還是內(nèi)測版驰后,我用的是內(nèi)測賬號雖然很好用但是將來需要收費而且沒有正式發(fā)布所以放棄了烙心。
最終選擇了bugly+tinker微信上10億用戶驗證過而且后臺使用也比較方便款票,順便還能管理bug卵沉。

遇到的問題:

深坑一

在使用Bugly的時候發(fā)現(xiàn)我提交的補丁包版本是2.4.0.214它抱,但是我過幾天再次登錄查看發(fā)現(xiàn) 變成了2.6.0.226了這是我最新的測試包的版本如下圖:

bugly.png

這還了得影響了幾百萬用戶配阵,于是馬上聯(lián)系bugly的客服是如下解釋的:
這個問題原因 是您測試時候使用了2.6.0版本和你當前2.4.0版本的tinkerid一樣導致
也就是我versionName和versionCode從2.4.0-214烙肺,改成了2.6.0-226了誉帅,但是我的tinkerid和原來一樣沒有改變淀散,這就導致bugly后臺的目標版本號改成了2.6.0-226右莱,好在這兩個版本的apk都可以收到這個補丁包沒有影響。
這個問題說明了versionName档插、versionCode和tinkerid一定要同事改掉慢蜓。

深坑二

昨天又使用Bugly+Tinker,除了發(fā)現(xiàn)上面的問題郭膛,還發(fā)現(xiàn)看日志補丁包下載成功然后合并失敗晨抡,報錯如下:

F66D1CCD71FEC09A0944EE004F131241.jpg

遇見這個錯誤我將這個libgetuiext2.so屏蔽了不生成補丁包,接著報如下錯誤:
F61B542878C86CF732E6EB457E4A2287.jpg

這兩個錯誤原因是则剃,安裝到手機上的apk是我用git代碼直接編譯生成的耘柱,但是補丁包生成使用的是之前發(fā)布的apk所以造成基準安裝包不一致,一直在報錯忍级。
搞明白這個原因之后帆谍,我用發(fā)布加固之前的apk安裝在手機上,在用這個apk生成的補丁包確實合并成功了轴咱,但是又出現(xiàn)下一個問題汛蝙,在應用市場上下載的apk也是合并失敗,這回日志就更少了朴肺,因為是release包窖剑,想了很長時間,晚上加班搞到半夜也沒發(fā)現(xiàn)原因戈稿。第二天早上繼續(xù)看文檔發(fā)現(xiàn)我為了屏蔽.so文件將tinkerSupport{ overrideTinkerPatchConfiguration = false }設置成false西土,也就是使用tinkerPatch{}中的配置,但是這個配置沒有設置加固屬性isProtectedApp = true,抱著最后的希望在tinkerPath{ buildConfig{ isProtectedApp = true}}增加了isProtectedApp = true鞍盗,然后發(fā)布補丁包需了,居然好使了fuck,折騰到半夜加上一上午總結出兩個坑

  1. 手機安裝的apk和生成補丁的apk一定要是一個
  2. 加固之后發(fā)布的apk一定要設置isProtectedApp = true
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末般甲,一起剝皮案震驚了整個濱河市肋乍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌敷存,老刑警劉巖墓造,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锚烦,居然都是意外死亡觅闽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門涮俄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛉拙,“玉大人,你說我怎么就攤上這事彻亲×趵耄” “怎么了室叉?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵睹栖,是天一觀的道長硫惕。 經(jīng)常有香客問我,道長野来,這世上最難降的妖魔是什么恼除? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮曼氛,結果婚禮上豁辉,老公的妹妹穿的比我還像新娘。我一直安慰自己舀患,他們只是感情好徽级,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著聊浅,像睡著了一般餐抢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上低匙,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天旷痕,我揣著相機與錄音,去河邊找鬼顽冶。 笑死欺抗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的强重。 我是一名探鬼主播绞呈,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼间景!你這毒婦竟也來了佃声?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤拱燃,失蹤者是張志新(化名)和其女友劉穎秉溉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碗誉,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡召嘶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哮缺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄跌。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尝苇,靈堂內(nèi)的尸體忽然破棺而出铛只,到底是詐尸還是另有隱情埠胖,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布淳玩,位于F島的核電站直撤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蜕着。R本人自食惡果不足惜谋竖,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望承匣。 院中可真熱鬧蓖乘,春花似錦、人聲如沸韧骗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袍暴。三九已至些侍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間容诬,已是汗流浹背娩梨。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留览徒,地道東北人狈定。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像习蓬,于是被迫代替她去往敵國和親纽什。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

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