Android實(shí)現(xiàn)釘釘自動(dòng)打卡功能(AccessibilityService版本)

Android實(shí)現(xiàn)釘釘自動(dòng)打卡功能(AccessibilityService版本)

===============================================

目錄


[TOC]

為什么要做這個(gè)項(xiàng)目?

有天早晨下大雨,小編雖然出門早卻還是路上堵的遲到了,心中一句XXX崩騰而過(guò)啊,這月全勤又沒(méi)了,無(wú)奈之余想起既然技術(shù)能解決一切,那能不能搞個(gè)自動(dòng)打卡的功能(好像有點(diǎn)作弊的嫌疑...哈O(∩_∩)O哈哈~),這樣以后就不用在考慮會(huì)遲到了!于是一個(gè)邪惡的程序就誕生了.

一. 項(xiàng)目需求

項(xiàng)目功能:
  1. 程序啟動(dòng)后,一直后臺(tái)運(yùn)行,自動(dòng)啟動(dòng)釘釘,并進(jìn)入相應(yīng)的打卡頁(yè)面進(jìn)行打卡(需要用到模擬點(diǎn)擊功能).
  2. 程序的執(zhí)行時(shí)間段為上午8-9點(diǎn)為上班打卡,18-19點(diǎn)為下班打卡(時(shí)間段根據(jù)需求即可).
  3. 確認(rèn)打卡成功之后程序進(jìn)入休眠狀態(tài),等待下次指令.
  4. 程序必須24小時(shí)處于激活狀態(tài),避免被系統(tǒng)清理
項(xiàng)目流程:
WX20180727-192204@2x.png

二. 資源準(zhǔn)備

大致需要準(zhǔn)備以下東西:

  1. 一臺(tái)空閑的andorid手機(jī),能root最好.
  2. 下載釘釘,登陸賬號(hào)
  3. 手機(jī)設(shè)置充電不鎖屏,并且連接了相應(yīng)的打卡wifi.

三. 核心代碼架構(gòu)

項(xiàng)目的核心在于利用程序模擬人工打卡操作,需要用到android模擬點(diǎn)擊功能的相關(guān)api,目前比較常用的黑科技主要是以下兩種:

AccessibilityService

AccessibilityService本來(lái)是做一些輔助功能的砖茸,提供了一系列的事件回調(diào)弯洗,幫助我們指示一些用戶及界面的狀態(tài)變化袁辈,主要給殘障人群提供幫助.手機(jī)上的所有操作都會(huì)通過(guò)onAccessibilityEvent方法返回,我們可以利用該原理做到模擬點(diǎn)擊我們需要的操作程序.
不過(guò)木张,現(xiàn)在AccessibilityService已經(jīng)基本偏離了它設(shè)計(jì)的初衷,至少在國(guó)內(nèi)是這樣,越來(lái)越多的App借用AccessibilityService來(lái)實(shí)現(xiàn)了一些其它功能,甚至是灰色產(chǎn)品。

UiAutomator

基于UIAutomation的用戶界面自動(dòng)化測(cè)試框架达传,可以跨應(yīng)用工作,谷歌親生的.
UIAutomation在Android4.3發(fā)布時(shí)有了新版本迫筑,官方簡(jiǎn)介
Android4.3之前:使用inputManager或者更早的WindowsManager來(lái)注入KeyEvent


當(dāng)然,除了以上兩種,還有其他的一些能實(shí)現(xiàn)模擬點(diǎn)擊的框架,這里我就不一一贅述了,今天我們要用的就是利用AccessibilityService 輔助功能來(lái)實(shí)現(xiàn)我們的自動(dòng)打卡功能.


四. 功能實(shí)現(xiàn)


4.1 配置AccessibilityService,監(jiān)聽(tīng)手機(jī)操作

1.繼承AccessibilityService類,監(jiān)聽(tīng)手機(jī)運(yùn)行狀態(tài)信息

public class MainAccessService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        //手機(jī)的所有操作信息都會(huì)通過(guò)這個(gè)方法回調(diào)
        
    }
    
    @Override
    public void onInterrupt() {

    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();

    }
}


2.配置AccessibilityService,創(chuàng)建accessibility_service_config.xml文件

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"

                       android:accessibilityEventTypes="typeAllMask" //過(guò)濾所有時(shí)間
                       android:accessibilityFlags="flagReportViewIds" //輔助服務(wù)額外的flag信息
                       android:accessibilityFeedbackType="feedbackSpoken"http://事件的反饋類型
                       android:notificationTimeout="100" //通知超時(shí)時(shí)間
                       android:canRetrieveWindowContent="true" //是否可以獲取窗口內(nèi)容

/>

3.AndroidManifest引用創(chuàng)建的配置文件(以下是配置必須)

<service android:name=".MainAccessService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>

            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config"/>
        </service>

4.在設(shè)置中打開(kāi)輔助功能服務(wù)


檢查輔助服務(wù)是否開(kāi)啟

 private void openAccessSettingOn(){
        if (!isAccessibilitySettingsOn(getApplicationContext())) {
            Toast.makeText(getApplicationContext(), "請(qǐng)開(kāi)啟輔助服務(wù)", Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
            startActivity(intent);
        }
    }


private boolean isAccessibilitySettingsOn(Context mContext) {
        int accessibilityEnabled = 0;
        // TestService為對(duì)應(yīng)的服務(wù)
        final String service = getPackageName() + "/" + MainAccessService.class.getCanonicalName();
        // com.z.buildingaccessibilityservices/android.accessibilityservice.AccessibilityService
        try {
            accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(),
                    android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
        TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');

        if (accessibilityEnabled == 1) {
            String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(),
                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
            if (settingValue != null) {
                mStringColonSplitter.setString(settingValue);
                while (mStringColonSplitter.hasNext()) {
                    String accessibilityService = mStringColonSplitter.next();

                    if (accessibilityService.equalsIgnoreCase(service)) {
                        return true;
                    }
                }
            }
        }
        return false;

    }


4.2 實(shí)現(xiàn)自動(dòng)化打卡流程


配置好AccessibilityService服務(wù)后,接下來(lái)我們就可以在onAccessibilityEvent方法中寫我們自動(dòng)化腳本的邏輯了.具體流程看第一節(jié)中的圖.

4.2.1 保證手機(jī)處于桌面(以下是部分核心代碼)
AccessibilityNodeInfo node=getRootInActiveWindow();
if (node == null || !Comm.launcher_PakeName.equals(node.getPackageName().toString())) {
                throw new Exception("程序不在初始化啟動(dòng)器頁(yè)面,拋出異常");
            }

注意上面的手動(dòng)異常和下面所有的手動(dòng)拋出異常到最后是會(huì)有大作用的,后面會(huì)講到.

4.2.2 啟動(dòng)釘釘
AccessibilityNodeInfo node=getRootInActiveWindow();
int m = 10;
            while (m > 0) {
                LogUtil.D("循環(huán)--" + node);
                if (node != null && Comm.dingding_PakeName.equals(node.getPackageName().toString())) {
                    node = getRootInActiveWindow(); //刷新根頁(yè)面節(jié)點(diǎn)
                    LogUtil.D("已進(jìn)入app" + node);                
                    break;
                } else {
                    startApplication(getApplicationContext(), Comm.dingding_PakeName);
                }
                sleepT(1000);  //1秒鐘啟動(dòng)一次
                if (node != null) {
                    node = refshPage();
                }
                m--;
            }
            if (m <= 0) {
                throw new Exception("進(jìn)入釘釘主頁(yè)異常");
            }

這里我用了10次循環(huán)去嘗試啟動(dòng)釘釘,,假如10次之后都沒(méi)有進(jìn)入釘釘或者已進(jìn)入釘釘,都將拋出異常,此次腳本終止.(目的是防止出現(xiàn)啟動(dòng)時(shí)卡死,導(dǎo)致腳本也卡死)

4.2.3 判斷是否位于釘釘主頁(yè)面

通過(guò)Android SDK的uiautomatorviewer工具(在tools文件夾下,需要手機(jī)root,studio的sdk可能和elipse的不同),查看頁(yè)面的節(jié)點(diǎn)信息,如下圖:

12.jpg

可以得到底部絕對(duì)布局的資源id是com.alibaba.android.rimet:id/home_bottom_tab_root,而且這個(gè)id是唯一的,也就是說(shuō)我們只要找到這個(gè)節(jié)點(diǎn)的資源id,就代表已經(jīng)進(jìn)入了釘釘程序的主頁(yè)了.

具體代碼:

String resId="com.alibaba.android.rimet:id/home_bottom_tab_root";
AccessibilityNodeInfo info=getRootInActiveWindow();
List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByViewId(resId);
if(list==null||list.size()==0){
     throw new Exception("已進(jìn)入app,未找到主頁(yè)節(jié)點(diǎn)");

}

4.2.4 進(jìn)入工作頁(yè)面

到這一步,我們程序已進(jìn)入釘釘主頁(yè),接下來(lái)需要進(jìn)入考勤打卡所在的工作頁(yè)面
在底部選項(xiàng)卡中,找到工作按鈕布局所在的資源id(com.alibaba.android.rimet:id/home_bottom_tab_button_work),點(diǎn)擊工作頁(yè)按鈕,進(jìn)入工作頁(yè),如下圖:

CB989BA02A7AB74285EA28D92A998E19.jpg

具體代碼

String resId="com.alibaba.android.rimet:id/home_bottom_tab_button_work";
AccessibilityNodeInfo info=getRootInActiveWindow();
List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByViewId(resId);
if(list==null||list.size()==0){
     throw new Exception("已進(jìn)入主頁(yè),未找到工作頁(yè)按鈕");
}else{
      list.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);
}

4.2.5 已進(jìn)入工作頁(yè),查找考勤打卡按鈕,進(jìn)行點(diǎn)擊操作,進(jìn)入考勤打卡頁(yè)面

到這一步,我們程序默認(rèn)已經(jīng)在工作頁(yè)面了,接下來(lái)需要做的就是點(diǎn)擊考勤打卡選項(xiàng),進(jìn)入考勤頁(yè)面.
這里有些許的復(fù)雜,因?yàn)椴荒苤苯诱业娇记诖蚩ㄋ诓季值膇d,只能先查找其所在的父布局的id(com.alibaba.android.rimet:id/oa_fragment_gridview),然后再找到考勤打卡的節(jié)點(diǎn).

33.jpg

具體代碼:

        String resId="com.alibaba.android.rimet:id/oa_fragment_gridview";
        AccessibilityNodeInfo info=getRootInActiveWindow();
        List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByViewId(resId);
        if(list!=null||list.size()!=0){
            AccessibilityNodeInfo node = list.get(0);
            if (node != null || node.getChildCount() >= 8) {
                node = node.getChild(7);
                if (node != null) {  //已找到考勤打卡所在節(jié)點(diǎn),進(jìn)行點(diǎn)擊操作
                    node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }else{
                    throw new Exception("已進(jìn)入工作頁(yè),但未找到考勤打卡節(jié)點(diǎn)");
                }
            }else{
                throw new Exception("已進(jìn)入工作頁(yè),但未找到考勤打卡節(jié)點(diǎn)");
            }
        }else{
            throw new Exception("已進(jìn)入工作頁(yè),但未找到相關(guān)節(jié)點(diǎn)");
        }
4.2.6 確認(rèn)已考勤打卡頁(yè)面

到這一步,我們程序認(rèn)為已經(jīng)進(jìn)入了考勤打卡頁(yè)面了,接下來(lái)我們需要再確認(rèn)一下目前所在節(jié)點(diǎn)是不是考勤打卡頁(yè)面的節(jié)點(diǎn).
這個(gè)頁(yè)面是一個(gè)webview頁(yè)面,所以判斷是否已進(jìn)入考勤打卡界面,我們只要找到了webview布局的一個(gè)唯一資源id標(biāo)識(shí)即可(com.alibaba.android.rimet:id/webview_frame),

55.jpg

代碼:

String resId="com.alibaba.android.rimet:id/webview_frame";
AccessibilityNodeInfo info=getRootInActiveWindow();
List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByViewId(resId);
if(list==null||list.size()==0){
     throw new Exception("進(jìn)入考勤打卡頁(yè)面異常");
}

4.2.7 執(zhí)行打卡操作

到這一步,程序已確認(rèn)進(jìn)入考勤打卡頁(yè)面,可以開(kāi)始執(zhí)行打卡操作.按照我們一些的步驟,打卡操作只需要你找到相應(yīng)的打卡按鈕節(jié)點(diǎn),然后通過(guò)節(jié)點(diǎn)的點(diǎn)擊操作接口,但是很不幸的是,由于考勤打卡頁(yè)面時(shí)webview頁(yè)面,我們不能定位到詳細(xì)的打卡按鈕所在的節(jié)點(diǎn)(準(zhǔn)確來(lái)說(shuō)有時(shí)可以,有時(shí)不可以,而且這情況發(fā)生在同一臺(tái)手機(jī)上,差點(diǎn)把小編折騰死,只能用最壞情況操作了),因?yàn)槲覀兏菊也坏剿馁Y源id,我們唯一能找到的只能是他的父節(jié)點(diǎn)(com.alibaba.android.rimet:id/webview_frame),然后并沒(méi)卵用!


不過(guò)方法總是有的!
既然我們不能定位節(jié)點(diǎn),但我們可以定位坐標(biāo)啊,剛好tap命令可以模擬點(diǎn)擊屏幕坐標(biāo)!!!瞬間感覺(jué)自己是個(gè)天才!!


我們只需要找到上班打卡和下班打卡兩個(gè)按鈕所在的坐標(biāo)(不同分辨率的手機(jī)會(huì)有不同),然后使用adb命令直接模擬點(diǎn)擊即可!

點(diǎn)擊坐標(biāo)方法


    public static void clickXy(String x,String y){
        String cmd = "input tap "+x+" "+y ;

        try {

            execRootCmdSilent( cmd);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 執(zhí)行命令但不關(guān)注結(jié)果輸出
     */
    private  static int execRootCmdSilent(String cmd) {
        int result = -1;
        DataOutputStream dos = null;

        try {
            Process p = Runtime.getRuntime().exec("su");
            dos = new DataOutputStream(p.getOutputStream());

            dos.writeBytes(cmd + "\n");
            dos.flush();
            dos.writeBytes("exit\n");
            dos.flush();
            p.waitFor();
            result = p.exitValue();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

4.2.8 確定打卡成功

模擬點(diǎn)擊了打卡界面之后,如果操作成功,默認(rèn)會(huì)出現(xiàn)一個(gè)打卡成功的彈窗,我們可以根據(jù)這個(gè)彈窗來(lái)判斷是否打卡成功

由于這個(gè)彈窗也不能找到相關(guān)的id的詳細(xì)節(jié)點(diǎn),而且也不能通過(guò)text去查找,所以這里先通過(guò)遞歸方法拿到所有的幾點(diǎn),然后判斷每個(gè)節(jié)點(diǎn)的content-desc是否包含打卡成功的字樣,如果有,我們就默認(rèn)打卡成功!

66.jpg

首先找出所有節(jié)點(diǎn)

//遞歸獲取所有節(jié)點(diǎn)
    private List<AccessibilityNodeInfo> getAllNode(AccessibilityNodeInfo node, List<AccessibilityNodeInfo> list) {
        if (list == null) {
            list = new ArrayList<>();
        }
        if (node != null && node.getChildCount() != 0) {
            for (int i = 0; i < node.getChildCount(); i++) {
                AccessibilityNodeInfo info = node.getChild(i);
                if (node != null) {
                    list.add(info);
                    node = info;
                }
            }

        } else {
            return list;
        }
        return getAllNode(node, list);
    }

判斷節(jié)點(diǎn)是否包含打卡成功字樣

//檢查是否打卡成功
        AccessibilityNodeInfo node = getRootInActiveWindow();

        //查詢所有的根節(jié)點(diǎn),假如有彈窗,說(shuō)明打卡成功
        List<AccessibilityNodeInfo> list = getAllNode(node, null);
        LogUtil.D("所有節(jié)點(diǎn)個(gè)數(shù)-->" + list.size());
        if (list != null) {
            for (AccessibilityNodeInfo info : list) {
                String className = info.getClassName().toString();
                if ("android.app.Dialog".equals(className)) {
                    //說(shuō)明可能是打卡導(dǎo)致的成功彈窗
                    AccessibilityNodeInfo nodeInfo = info.getChild(0);
                    if (nodeInfo != null) {
                        nodeInfo = nodeInfo.getChild(1);
                        if (nodeInfo != null) {
                            String des = nodeInfo.getContentDescription().toString();
                            if (des.contains("打卡成功")) {
                                    //這里做你想做的事,比如發(fā)個(gè)郵件通知一下
                                return;
                            }
                        }
                    }

                }
            }
        }

每次模擬點(diǎn)擊之后,都要判斷一下是否有打卡成功彈窗,最多嘗試10次

//已進(jìn)入打卡頁(yè)面,執(zhí)行打卡操作
        int j = 10;
        while (j >= 0) {
            LogUtil.D("嘗試打卡操作->" + j);
            if(DoDaKa(order)){  //這里封裝了一下,這是模擬點(diǎn)擊之后,判斷彈窗打卡成功的方法
                //這里可以發(fā)送郵件
                return;
            }
            sleepT(2000);

            j--;
        }

4.2.9 異常處理

在上述流程中,基本每一步都拋出了大量異常,出現(xiàn)異常,即代表程序沒(méi)有按照我們?cè)O(shè)定的流程走,這時(shí)我們就需要去修正.一旦出現(xiàn)異常,我們讓腳本回到初始狀態(tài),也就是最初的桌面狀態(tài).android可以通過(guò)回退鍵來(lái)恢復(fù)到桌面.

代碼:

//程序異常時(shí)的操作方法
    private void AppCallBack() {
        int i = 10; //最多嘗試10次回退操作
        while (true) {
            //執(zhí)行回退操作
            AccessibilityNodeInfo node = getRootInActiveWindow();
            if (i < 0) { //10次還未到桌面
                //說(shuō)明可能卡住了,無(wú)法回退,強(qiáng)行停止程序進(jìn)程
                CMDUtil.stopProcess(node.getPackageName().toString());
                break;
            }
            LogUtil.D("執(zhí)行回退操作");
            performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
            if (node != null && Comm.launcher_PakeName.equals(node.getPackageName().toString())) {
                //已回退到啟動(dòng)頁(yè),退出循環(huán)
                LogUtil.D("桌面");
                break;
            }
            i--;
            sleepT(1000); //睡眠一秒
        }

    }

TIPS:
上溯所有流程的每一步,我們最好都加上1-2秒的延遲時(shí)間,畢竟頁(yè)面跳轉(zhuǎn)是需要時(shí)間的,對(duì)于手機(jī)性能差的手機(jī)相應(yīng)的時(shí)間可以再延遲一些.


五. 功能測(cè)試

到這里,我們的自動(dòng)打卡程序基本就已經(jīng)實(shí)現(xiàn)了,當(dāng)然,上面只是實(shí)現(xiàn)自動(dòng)打卡的核心代碼.還有很多的拓展空間,比如可以加上一個(gè)任務(wù)請(qǐng)求線程,實(shí)現(xiàn)在特定時(shí)間,來(lái)實(shí)現(xiàn)打上班卡還是打下班卡,以及打卡成功之后及時(shí)的郵件通知到手機(jī)上.也可以通過(guò)服務(wù)器來(lái)定時(shí)啟動(dòng)程序,控制腳本程序啥時(shí)候運(yùn)行,啥時(shí)候不運(yùn)行.發(fā)揮你的想象吧!


分割線

2018-07-31更新

測(cè)試發(fā)現(xiàn),4.2.8步驟監(jiān)測(cè)打卡成功的節(jié)點(diǎn)計(jì)算有時(shí)會(huì)出現(xiàn)大量的復(fù)雜節(jié)點(diǎn),極大的增加了程序的負(fù)擔(dān).
由于釘釘打卡成功會(huì)有通知,我們可以監(jiān)聽(tīng)手機(jī)的通知欄來(lái)判斷程序是否打卡成功,這種方式更加的輕量快捷!

分割線

2019-02-15更新

很多童鞋私信要源碼,現(xiàn)體統(tǒng)github地址

https://github.com/momoxiaoming/DDPunch

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宪赶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子脯燃,更是在濱河造成了極大的恐慌搂妻,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辕棚,死亡現(xiàn)場(chǎng)離奇詭異欲主,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逝嚎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門扁瓢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人补君,你說(shuō)我怎么就攤上這事引几。” “怎么了挽铁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵伟桅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叽掘,道長(zhǎng)楣铁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任更扁,我火速辦了婚禮盖腕,結(jié)果婚禮上赫冬,老公的妹妹穿的比我還像新娘。我一直安慰自己赊堪,他們只是感情好面殖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哭廉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪相叁。 梳的紋絲不亂的頭發(fā)上遵绰,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音增淹,去河邊找鬼椿访。 笑死,一個(gè)胖子當(dāng)著我的面吹牛虑润,可吹牛的內(nèi)容都是我干的成玫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拳喻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哭当!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起冗澈,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钦勘,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后亚亲,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體彻采,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年捌归,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肛响。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惜索,死狀恐怖特笋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情门扇,我是刑警寧澤雹有,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站臼寄,受9級(jí)特大地震影響霸奕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吉拳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一质帅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦煤惩、人聲如沸嫉嘀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剪侮。三九已至,卻和暖如春洛退,著一層夾襖步出監(jiān)牢的瞬間瓣俯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工兵怯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留彩匕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓媒区,卻偏偏與公主長(zhǎng)得像驼仪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袜漩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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