Ionic2Cordova藍(lán)牙插件封裝

首先有Ionic2以及Cordova環(huán)境
如果沒有在命令行執(zhí)行以下命令

    npm install -g ionic cordova  //全局安裝ionic 和cordova指令
    ionic start myApp tabs --v1  創(chuàng)建ionic2項(xiàng)目之前文章講到了 “--v1&&--v2代表ionic不同版本”
    npm install -g plugman  //全局安裝cordova插件命令 
    cordova platform add android //添加android平臺(tái) 默認(rèn)創(chuàng)建的項(xiàng)目只包含ios平臺(tái) 其他的平臺(tái)需要使用命令添加

現(xiàn)在基本基本開發(fā)環(huán)境已經(jīng)就緒如果需要具體安裝環(huán)境請(qǐng)?zhí)D(zhuǎn)到Ionic2探索總結(jié)

首先我們查看一下plugman的幫助命令 直接輸入plugman回車就能看到幫助,從幫助中找到下面這一句話

    plugman create --name <pluginName> --plugin_id <pluginID> --plugin_version <version> [--path <directory>] [--variable NAME=VALUE]

這句話就是創(chuàng)建插件的命令,下面我給出一個(gè)創(chuàng)建的事例代碼 最好是到剛才創(chuàng)建好的項(xiàng)目跟目錄執(zhí)行

    plugman create --name bluetooths --plugin_id bluetooths --plugin_version 0.0.1 
    /*
    [--path <directory>]這個(gè)是可選的枯夜,如果你想創(chuàng)建到別的目錄下的話可以通過這個(gè)可選的指定路徑喜最,如果僅僅想創(chuàng)建到當(dāng)前路徑下的話 可以省略這個(gè)可選的指令  
    */

來看一下插件創(chuàng)建完畢后的目錄以及文件

    .
    ├── plugin.xml
    ├── src       
    └── www
        └── bluetooths.js

這是當(dāng)前的目錄聘裁,然而感覺缺點(diǎn)什么?缺的是各平臺(tái)的代碼铜邮。我們?cè)倩仡^看看plugman這個(gè)命令的幫助 有這樣的命令

    Add a Platform to a Plugin
    --------------------------

        $ plugman platform add --platform_name <platform>

    Parameters:

    - <platform>: One of android, ios

    Remove a Platform from a Plugin
    -------------------------------

        $ plugman platform remove --platform_name <platform>

    Parameters:

    - <platform>: One of android, ios

看到這應(yīng)該就知道了 我們添加平臺(tái)

    cd bluetooths
    plugman platform add --platform_name android
    plugman platform add --platform_name ios

我們查看目錄

    .
    ├── plugin.xml
    ├── src
    │   ├── android
    │   │   └── bluetooths.java
    │   └── ios
    │       └── bluetooths.m
    └── www
        └── bluetooths.js

    4 directories, 4 files

分析文件

plugin.xml

    <?xml version='1.0' encoding='utf-8'?>
    <plugin id="bluetooths" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0"   @1 xmlns:android="http://schemas.android.com/apk/res/android">
        <name>bluetooths</name>           @2
        <js-module name="bluetooths" src="www/bluetooths.js">   @3
            <clobbers target="cordova.plugins.bluetooths" />    @4
        </js-module>                                            @5
        <platform name="android">                               @6
            <config-file parent="/*" target="res/xml/config.xml">
                <feature name="bluetooths">
                    <param name="android-package" value="bluetooths.bluetooths" />
                </feature>
            </config-file>
            <config-file parent="/*" target="AndroidManifest.xml" />
            <source-file src="src/android/bluetooths.java" target-dir="src/bluetooths/bluetooths" />
        </platform>
        <platform name="ios">                                 @7
            <config-file parent="/*" target="config.xml">
                <feature name="bluetooths">
                    <param name="ios-package" value="bluetooths" />
                </feature>
            </config-file>
            <source-file src="src/ios/bluetooths.m" />
        </platform>
    </plugin>

1, 這個(gè)行指定了這個(gè)插件的id 版本

2, 插件名字

3, 4昔搂,5, 這個(gè)是插件的js部分 src說明js插件的文件的位置 target代表在怎么在全局中引用這個(gè)插件如果在es5中可以直接使用cordova.plugins.bluetooths這個(gè)對(duì)象上的各個(gè)方法,如果在es6以及typescript中使用的時(shí)候得先在代碼的最上邊加入這個(gè)

    declare var cordova:any
    ...
    cordova.plugins.bluetooths.function...

6, android平臺(tái)的配置

7, ios平臺(tái)的配置

bluetooths.js

    var exec = require('cordova/exec');  //引入cordova內(nèi)部已經(jīng)實(shí)現(xiàn)與原生交互的接口

    exports.coolMethod = function(arg0, success, error) {
        exec(success, error, "bluetooths", "coolMethod", [arg0]);
    };

上面三行代碼實(shí)現(xiàn)了 導(dǎo)出一個(gè)名為coolMethod的方法 這個(gè)方法有三個(gè)參數(shù) arg0為我們調(diào)用這個(gè)方法的時(shí)候參數(shù)树叽,以及回調(diào)方法阿弃。

這個(gè)方法的內(nèi)部是調(diào)用cordova插件的接口前兩個(gè)是回調(diào)的方法,第三個(gè)是指定會(huì)響應(yīng)到那個(gè)插件缀雳,第四個(gè)表面看是調(diào)用指定的方法渡嚣,其實(shí)cordova插件的工作只是把coolMethod這個(gè)值傳了過去(這個(gè)在android代碼的時(shí)候說明) 以及后面的參數(shù)。

我們現(xiàn)在來看android的代碼

    public class bluetooths extends CordovaPlugin {

        @Override
        public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
            if (action.equals("coolMethod")) {
                String message = args.getString(0);
                this.coolMethod(message, callbackContext);
                return true;
            }
            return false;
        }

        private void coolMethod(String message, CallbackContext callbackContext) {
            if (message != null && message.length() > 0) {
                callbackContext.success(message);
            } else {
                callbackContext.error("Expected one non-empty string argument.");
            }
        }
    }

這個(gè)插件類繼承CordovaPlugin類,重寫execute這個(gè)方法
action:觸發(fā)的事件名 String類型
args:之前用戶調(diào)用插件穿的值 JSONArray類型
callbackContext:回調(diào)類 CallbackContext類型

為什么說只是傳了個(gè)方法的值過來,先看action是一個(gè)字符串類型的识椰,在下面我們通過action.equals("coolMethod")來判斷是否相等 這個(gè)類似于 ==绝葡。如果相等就調(diào)用this.coolMethod(message, callbackContext);這個(gè)內(nèi)部方法可以隨意更改。

當(dāng)我們完成這插件后,我們就需要把這個(gè)插件應(yīng)用到我們的項(xiàng)目中(ios因?yàn)闆]接觸過暫時(shí)不講)

    cd ../
    cordova plugin add ./bluetooths/

添加完成后點(diǎn)開plugins目錄看到有bluetoots這個(gè)文件夾說明插件添加成功腹鹉,調(diào)用在前面已經(jīng)說了藏畅,下面寫一下具體的用法

    declare var cordova:any
    ...
    cordova.plugins.bluetooths.coolMethod("message",(res)=>{
        alert(res)
    },(err)=>{
        alert(err)
    })

雖然cordvoa提供的插件庫比較豐富,但是我們的業(yè)務(wù)需要監(jiān)聽藍(lán)牙被用戶手動(dòng)在設(shè)置里更改后的信息功咒,因?yàn)閏ordova提供的插件并沒有這樣的監(jiān)聽愉阎,所以踩這個(gè)坑了。

藍(lán)牙監(jiān)聽插件js代碼

js這邊的代碼js這邊的代碼非常簡單

    var arg0="message"
    exports.registerReceiver = function(success,error){   //注冊(cè)監(jiān)聽的js方法
        exec(success,error,"bluetooths","registerReceiver",[arg0]);
    }
    exports.unregisterReceiver = function(success,error){
        exec(success,error,"bluetooths","unregisterReceiver",[arg0]);  //取消監(jiān)聽的js方法
    }

藍(lán)牙監(jiān)聽插件android代碼

添加權(quán)限

在android代碼里面基本都是純android api里的方法力奋,類榜旦。所以熟悉android的很容易寫出下面的代碼,當(dāng)然我是個(gè)純web前端開發(fā)出生的景殷,android代碼寫的不好請(qǐng)見諒溅呢。

因?yàn)槭且僮魉{(lán)牙所以需要取得權(quán)限在AndroidManifest.xml文件中的manifest標(biāo)簽里添加下面的代碼

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

分發(fā)執(zhí)行函數(shù)

在js代碼中我們傳遞的是五個(gè)參數(shù) 但是經(jīng)過CordovaPlugin這個(gè)類的接受處理后我們?cè)赼dnroid看到的只有三個(gè)參數(shù)。
它把js這端的成功和失敗回調(diào)通過CallbackContext處理,使得我們可以通過類型為CallbackContext傳進(jìn)來的參數(shù)滨彻,調(diào)用js端的方法藕届,同時(shí)傳參給js方法。第三個(gè)參數(shù)也是就“bluetooths”是給CordovaPlugin的標(biāo)志亭饵,調(diào)用的是哪一個(gè)插件,最后兩個(gè)參數(shù)分別為調(diào)用的方法名以及參數(shù)梁厉。對(duì)應(yīng)到execute方法中的參數(shù)為action辜羊,args。

先匹配方法名調(diào)用不同的方法或者做不同的事代碼如下

    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
            if(action.equals("registerReceiver")){  //如果action==“registerReceiver”注冊(cè)
                String message = args.getString(0);
                this.registerReceiver(callbackContext);   //自定義方法后面講
                return true;
            }else if(action.equals("unregisterReceiver")){ 如果action==“unregisterReceiver” 取消
                this.unregisterReceiver(callbackContext);  //自定義方法后面講
            }
            return true;
        }

device對(duì)象轉(zhuǎn)化為JSONObject

這段代碼是從cordova-plugin-bluetooth-serial這個(gè)插件的328-338行代碼拷貝過來的

    private JSONObject deviceToJSON(BluetoothDevice device) throws JSONException {
        JSONObject json = new JSONObject();
        json.put("name", device.getName());
        json.put("address", device.getAddress());
        json.put("id", device.getAddress());
        if (device.getBluetoothClass() != null) {
            json.put("class", device.getBluetoothClass().getDeviceClass());
        }
        return json;
    }

藍(lán)牙顯示通信構(gòu)建方法(IntentFilter)

    private IntentFilter makeFilter() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); //添加連接action
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);//添加斷開action
        return filter;
    }

注冊(cè)和注銷

先在bluetooths對(duì)象中創(chuàng)建兩個(gè)私有對(duì)象

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    BroadcastReceiver mReceiver =null;

創(chuàng)建私方法 registerReceiver

    private void registerReceiver(final CallbackContext callbackContext) throws JSONException {
         final JSONArray unpairedDevices = new JSONArray(); //new  JSONArray對(duì)象
         mReceiver = new BroadcastReceiver(){
             public void onReceive(Context context, Intent intent) {
                 ...
             }
         }        //new廣播對(duì)象
         Activity activity = cordova.getActivity();
         activity.registerReceiver(mReceiver, makeFilter());
    }

在bluetooths對(duì)象中我們創(chuàng)建了一個(gè)藍(lán)牙對(duì)象和一個(gè)廣播對(duì)象词顾,
在registerReceiver方法創(chuàng)建類型為JSONArray的對(duì)象unpairedDevices是為了等會(huì)儲(chǔ)存device轉(zhuǎn)化后的JSONArray類型的對(duì)象八秃。
重點(diǎn)來了!H忭铩昔驱! 重點(diǎn)就在我們的mReceiver這個(gè)對(duì)象上,這是一個(gè)廣播對(duì)象上忍,這個(gè)對(duì)象需要實(shí)現(xiàn)onReceive方法骤肛,這個(gè)方法會(huì)在廣播被接收到的時(shí)候調(diào)用。那么什么時(shí)候廣播會(huì)被接受呢窍蓝?
這個(gè)mReceiver接收到廣播和 activity.registerReceiver(mReceiver, makeFilter()); 這一句代碼有關(guān)腋颠。
這句代碼是注冊(cè)這個(gè)監(jiān)聽到指定廣播,那些廣播被指定了呢吓笙?看上面的 藍(lán)牙顯示通信構(gòu)建方法(IntentFilter)

        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); //添加連接action
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);//添加斷開action

就是這淑玫,添加了兩個(gè)事件,這兩個(gè)事件觸發(fā)后都會(huì)被通過這個(gè)顯示通信的注冊(cè)的監(jiān)聽捕獲到。

處理監(jiān)聽結(jié)果

    if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_CONNECTED)){  
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//獲取設(shè)備對(duì)象
        try {
                JSONObject o = deviceToJSON(device,"CONNECTED");  //生成json格式的device信息
                unpairedDevices.put(o);
                callbackContext.success(o);
            } catch (JSONException e) {}
        }else if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)){
            ...
    } 

這邊只展示了監(jiān)聽連接后的處理結(jié)果絮蒿,斷開后的處理方式基本一樣尊搬,不過這有一點(diǎn)要說:我們的監(jiān)聽又不是監(jiān)聽一次,我們需要一直監(jiān)聽下去,所以我找到pltform/android/CordovaLib/src/org/apache/cordova/CallbackContext.java這個(gè)Cordova回調(diào)的源文件結(jié)合cordova-plugin-bluetooth-serial這個(gè)插件的BluetoothSerial.java文件中discoverUnpairedDevices方法里面不斷返回查找到的設(shè)備的信息
o
首先看一下PluginResult這個(gè)類簡要屬性

    public class PluginResult {
        private final int status;  //當(dāng)前結(jié)果的的狀態(tài)
        private final int messageType;  信息類型
        private boolean keepCallback = false;    是否繼續(xù)發(fā)送
        private String encodedMessage; 
       ...
       public PluginResult(Status status, JSONObject message) { //構(gòu)造函數(shù)
            this.status = status.ordinal();
            this.messageType = MESSAGE_TYPE_JSON;
            encodedMessage = message.toString();  //JSONObject轉(zhuǎn)化為Stirng儲(chǔ)存
        }
        public void setKeepCallback(boolean b) {
            this.keepCallback = b;  //更改是否保持回調(diào)
        }
    }

再看一下 CallbackCintext.java的一個(gè)方法

    public void sendPluginResult(PluginResult pluginResult) { //傳入一個(gè)PluginResult類的實(shí)例對(duì)象
        synchronized (this) {
            if (finished) {  //先判斷是不是已經(jīng)結(jié)束了
                LOG.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage());
                return;
            } else {
                finished = !pluginResult.getKeepCallback();
                //如果沒有結(jié)束取出pluginResult.keepCallback作為下一輪的判斷
            }
        }
        webView.sendPluginResult(pluginResult, callbackId); //向js發(fā)送消息
    }

通過上面一些分析android如何保持持續(xù)向js發(fā)送回調(diào)已經(jīng)明了土涝。

先判斷回調(diào)是否還存在佛寿,如果存在說明需要回調(diào) 。new PluginResult類的實(shí)例,設(shè)置下一回合還需要發(fā)送信息回铛,然后發(fā)送消息到j(luò)s的回調(diào)狗准,代碼如下。

    if (callbackContext != null) {
        PluginResult res = new PluginResult(PluginResult.Status.OK, o);//將信息寫入 同時(shí)設(shè)置后續(xù)還有返回信息
        res.setKeepCallback(true);
        callbackContext.sendPluginResult(res); 
    }

基本已經(jīng)完成了茵肃,我相信如果有同學(xué)完整的學(xué)習(xí)完了這一篇腔长,基本cordova插件的封裝沒有問題了,下面為完整android代碼

    package bluetooths;

    import org.apache.cordova.CordovaPlugin;
    import org.apache.cordova.CallbackContext;
    import android.app.Activity;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.widget.Toast;
    import org.apache.cordova.PluginResult;
    import org.json.JSONObject;

    /**
    * This class echoes a string called from JavaScript.
    */
    public class bluetooths extends CordovaPlugin  {
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        BroadcastReceiver mReceiver =null;
        @Override
        public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
            if(action.equals("registerReceiver")){
                String message = args.getString(0);
                this.registerReceiver(callbackContext);
                return true;
            }else if(action.equals("unregisterReceiver")){
                this.unregisterReceiver(callbackContext);
            }
            return true;
        }
        private void registerReceiver(final CallbackContext callbackContext) throws JSONException {
            final JSONArray unpairedDevices = new JSONArray(); //new  JSONArray對(duì)象
            mReceiver = new BroadcastReceiver() {           //new廣播對(duì)象
            @Override
            public void onReceive(Context context, Intent intent) {
            // Toast.makeText(context,"BroadcastReceiver",Toast.LENGTH_SHORT).show();
                if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_CONNECTED)){  
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//獲取設(shè)備對(duì)象
                    try {
                            JSONObject o = deviceToJSON(device,"CONNECTED");  //生成json格式的device信息
                            unpairedDevices.put(o);
                            if (callbackContext != null) {
                                PluginResult res = new PluginResult(PluginResult.Status.OK, o);//將信息寫入 同時(shí)設(shè)置后續(xù)還有返回信息
                                res.setKeepCallback(true);
                                callbackContext.sendPluginResult(res); 
                            }
                        } catch (JSONException e) {}
                // Toast.makeText(context,"接受到已連接验残,消息為:"+device.getName()+"address: "+device.getAddress(),Toast.LENGTH_LONG).show();
                }else if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)){  
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//獲取設(shè)備對(duì)象
                    try {
                            JSONObject o = deviceToJSON(device,"DISCONNECTED");  //生成json格式的device信息
                            unpairedDevices.put(o);
                            if (callbackContext != null) {
                                PluginResult res = new PluginResult(PluginResult.Status.OK, o);//將信息寫入 同時(shí)設(shè)置后續(xù)還有返回信息
                                res.setKeepCallback(true);
                                callbackContext.sendPluginResult(res); 
                            }
                        } catch (JSONException e) {}
                //    Toast.makeText(context,"接受到斷開連接捞附,消息為:"+device.getName()+"address: "+device.getAddress(),Toast.LENGTH_LONG).show();
                    }
                }
            };
            Activity activity = cordova.getActivity();
            activity.registerReceiver(mReceiver, makeFilter());
        }
        public void unregisterReceiver(final CallbackContext callbackContext){
            Activity activity = cordova.getActivity();
            activity.unregisterReceiver(mReceiver);
        }
        /*
        @deviceToJSON 將收到的設(shè)備對(duì)象轉(zhuǎn)化為JSONObject對(duì)象方便與js交互數(shù)據(jù)
        @device 設(shè)備對(duì)象,當(dāng)監(jiān)聽到設(shè)備變化后接受到的設(shè)備對(duì)象
        @connectType如果是連接發(fā)出的消息值為 CONNECTED 如果是斷開連接發(fā)出的消息為 DISCONNECTED
        */
        private final JSONObject deviceToJSON(BluetoothDevice device,String connectType) throws JSONException {
            JSONObject json = new JSONObject();    //創(chuàng)建JSONObject對(duì)象
            json.put("name", device.getName());     //設(shè)備名字
            json.put("address", device.getAddress());   //設(shè)備地址
            json.put("id", device.getAddress());   //設(shè)備唯一編號(hào)使用地址表示
            json.put("connectType",connectType);
            if (device.getBluetoothClass() != null) {
                json.put("class", device.getBluetoothClass().getDeviceClass());  //設(shè)備類型 主要分別設(shè)備是哪一種設(shè)備
            }
            return json;
        }
        private IntentFilter makeFilter() {
            IntentFilter filter = new IntentFilter();
            filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
            filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
            return filter;
        }

    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末您没,一起剝皮案震驚了整個(gè)濱河市鸟召,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌氨鹏,老刑警劉巖欧募,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異仆抵,居然都是意外死亡跟继,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門镣丑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舔糖,“玉大人,你說我怎么就攤上這事莺匠〗鹇穑” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵趣竣,是天一觀的道長摇庙。 經(jīng)常有香客問我,道長期贫,這世上最難降的妖魔是什么跟匆? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮通砍,結(jié)果婚禮上玛臂,老公的妹妹穿的比我還像新娘烤蜕。我一直安慰自己,他們只是感情好迹冤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布讽营。 她就那樣靜靜地躺著,像睡著了一般泡徙。 火紅的嫁衣襯著肌膚如雪橱鹏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天堪藐,我揣著相機(jī)與錄音莉兰,去河邊找鬼。 笑死礁竞,一個(gè)胖子當(dāng)著我的面吹牛糖荒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播模捂,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼捶朵,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了狂男?” 一聲冷哼從身側(cè)響起综看,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岖食,沒想到半個(gè)月后红碑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泡垃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年句喷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兔毙。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖兄春,靈堂內(nèi)的尸體忽然破棺而出澎剥,到底是詐尸還是另有隱情,我是刑警寧澤赶舆,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布哑姚,位于F島的核電站,受9級(jí)特大地震影響芜茵,放射性物質(zhì)發(fā)生泄漏叙量。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一九串、第九天 我趴在偏房一處隱蔽的房頂上張望绞佩。 院中可真熱鬧寺鸥,春花似錦、人聲如沸品山。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肘交。三九已至笆载,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涯呻,已是汗流浹背凉驻。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留复罐,地道東北人涝登。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像市栗,于是被迫代替她去往敵國和親缀拭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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