Flutter&Native通信-1


11 Flutter 與 Native通信原理/實(shí)戰(zhàn)筏养。

[Flutter與Android通信開發(fā)指南] (http://events.jianshu.io/p/575440e754d2)
[原始作者] (https://www.imooc.com/article/309626)

在做Flutter開發(fā)的時候逢艘,離不開Flutter之間的通信财喳,比如:初始化Flutter時Native向Dart傳遞數(shù)據(jù)删豺,Dart調(diào)用Native的相冊選擇圖片隐绵,Dart調(diào)用Native的模塊進(jìn)行一些復(fù)雜的計算,native將一些數(shù)據(jù)(GPS信息盲链、陀螺儀蝇率、傳感器等)主動傳遞給Dart等。

幾種通信場景:

  • 初始化Flutter時刽沾,Native向Dart傳遞數(shù)據(jù)本慕;
  • Native發(fā)送數(shù)據(jù)給Dart;
  • Dart發(fā)送數(shù)據(jù)給Native侧漓;
  • Dart發(fā)送數(shù)據(jù)給Native锅尘,然后Native回傳數(shù)據(jù)給Dart。

Flutter 與 Native通信機(jī)制

通信機(jī)制:通過Channel(平臺通道)來完成布蔗。消息使用Channel在Flutter與Native之間傳遞藤违。

Channel 所支持?jǐn)?shù)據(jù)類型對照表。

Dart ~ Android ~ iOS

null ~ null ~ nil(NSNull when nested)
bool ~ java.lang.Boolean ~ NSNumber numberWithBool:
int ~ java.lang.Integer ~ NSNumber numberWithInt:
int,超32bits ~ java.lang.Long ~ NSNumber numberWithLong:
double ~ java.lang.Double ~ NSNumber numberWithDouble:
String ~ java.lang.String ~ NSString
Unit8List ~ byte[] ~ FlutterStandardTypedData typedDataWithBytes:
Int32List ~ int[] ~ FlutterStandardTypedData typedDataWithInt32:
Int64List ~ long[] ~ FlutterStandardTypedData typedDataWithInt64:
Float64List~ double[] ~ FlutterStandardTypedData typedDataWithFloat64:
List ~ java.util.ArrayList ~ NSArray
Map ~ java.util.HashMap ~ NSDictionary

Flutter 定義了三種不同類型的Channel

  • BasicMessageChannel:用于傳遞字符串和半結(jié)構(gòu)化的信息纵揍,持續(xù)通信顿乒,收到消息后可以回復(fù)此消息,如:Native將遍歷到的文件信息 陸續(xù) 傳遞給Dart骡男,再比如:Flutter將從服務(wù)器端 陸續(xù) 獲取到的信息交給native加工淆游,native處理完后返回等傍睹。
  • MethodChannel:用于傳遞方法調(diào)用(method invocation)一次性通信:如Flutter調(diào)用native代碼,如:拍照犹菱,信息選擇等拾稳。
  • EventChannel:用于數(shù)據(jù)流(event Stream)的通信,持續(xù)通信腊脱,收到消息后無法回復(fù)此消息访得,通常用于native向Dart的通信(eg:手機(jī)電量變化,網(wǎng)絡(luò)連接變化陕凹,陀螺儀悍抑,傳感器等。)

以上三種類型的Channel都是 全雙工通信杜耙,即A<=>B, Dart可以主動發(fā)送消息給platform端搜骡,并且platform接收到消息后可以做出回應(yīng);
同樣佑女,platform端可以主動發(fā)送消息給Dart端记靡,Dart端接收后返回給platform端。


BasicMessageChannel用法:

Native Android端:

1.構(gòu)造方法原型

BasicMessageChannel(BinaryMessage messenger, String name, MessageCodec<T> codec)

  • BinaryMessage messenger: 消息信使团驱,是消息的發(fā)送和接收的工具摸吠,
  • String name: Channel的名字,也是唯一標(biāo)識符嚎花。
  • MessageCodec<T> codec: 消息的編解碼器寸痢,他有集中不同類型的實(shí)現(xiàn):
    • BinaryCodec: 最為簡單的一種Codec,因?yàn)槠浞祷刂殿愋秃腿雲(yún)⒌念愋拖嗤裳。鶠槎M(jìn)制格式(Android中為ByteBuffer啼止,iOS中為NSData)。實(shí)際上丛楚,BinaryCodec在編解碼過程中什么都沒做族壳,只是原封不動將二進(jìn)制數(shù)據(jù)消息返回而已憔辫∪ば或許你會因此覺得BinaryCodec沒有意義,但是在某些情況下它非常有用贰您,比如使用BinaryCodec可以使傳遞內(nèi)存數(shù)據(jù)塊時在編解碼階段免于內(nèi)存拷貝坏平;效率高。
    • StringCodec: 用于字符串與二進(jìn)制數(shù)據(jù)之間的編解碼锦亦,其編碼格式為UTF-8舶替;
    • JSONMessageCodec: 用于基礎(chǔ)數(shù)據(jù)與二進(jìn)制數(shù)據(jù)之間的編解碼,其支持基礎(chǔ)數(shù)據(jù)類型以及列表杠园、字典顾瞪。其在iOS端使用了NSJSONSerialization作為序列化的工具,而在Android端則使用了其自定義的JSONUtil與StringCodec作為序列化工具;
    • StandardMethodCodec: 是BasicMessageChannel的默認(rèn)編解碼器陈醒,其支持基礎(chǔ)數(shù)據(jù)類型惕橙、二進(jìn)制數(shù)據(jù)、列表钉跷、字典弥鹦,其工作原理;

2.setMessageHandler方法原型

void setMessageHandler(BasicMessageChannel.MessageHandler<T> handler)

  • BasicMessageChannel.MessageHandler<T> handler - 消息處理器爷辙,配合BinaryMessenger完成消息的處理彬坏;
    在創(chuàng)建好BasicMessageChannel后,如果要讓其接收Dart發(fā)來的消息膝晾,則需要調(diào)用它的setMessageHandler方法為其設(shè)置一個消息處理器栓始。

3.BasicMessageChannel.MessageHandler原型

public interface MessageHandler<T> {
void onMessage(T var1, BasicMessageChannel.Reply<T> var2);
}

  • onMessage(T var1, BasicMessageChannel.Reply<T> var2) - 用于接受消息,var1是消息內(nèi)容血当,var2是回復(fù)此消息的回調(diào)函數(shù)混滔;

4. send方法原型(向Dart發(fā)送消息)

void send(T message)
void send(T message, BasicMessageChannel.Reply<T> callback)

  • T message - 要傳遞給Dart的具體信息;
  • BasicMessageChannel.Reply<T> callback - 消息發(fā)出去后歹颓,收到Dart的回復(fù)的回調(diào)函數(shù)坯屿;

在創(chuàng)建好BasicMessageChannel后,如果要向Dart發(fā)送消息巍扛,可以調(diào)用它的send方法向Dart傳遞數(shù)據(jù)领跛。

public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler<String>, BasicMessageChannel.Reply<String> {
    private final Activity activity;
    private final BasicMessageChannel<String> messageChannel;

    static BasicMessageChannelPlugin registerWith(FlutterView flutterView) {
        return new BasicMessageChannelPlugin(flutterView);
    }
    private BasicMessageChannelPlugin(FlutterView flutterView) {
        this.activity = (Activity) flutterView.getContext();
        this.messageChannel = new BasicMessageChannel<>(flutterView, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
        // 設(shè)置消息處理器,處理來自Dart的消息
        messageChannel.setMessageHandler(this);
    }

    @Override
    public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {//處理Dart發(fā)來的消息
        reply.reply("BasicMessageChannel收到:" + s);//可以通過reply進(jìn)行回復(fù)
        if (activity instanceof IShowMessage) {
            ((IShowMessage) activity).onShowMessage(s);
        }
        Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
    }

    /**
     * 向Dart發(fā)送消息撤奸,并接受Dart的反饋
     * @param message  要給Dart發(fā)送的消息內(nèi)容
     * @param callback 來自Dart的反饋
     */
    void send(String message, BasicMessageChannel.Reply<String> callback) {
        messageChannel.send(message, callback);
    }
    @Override
    public void reply(String s) {
    }
}

Dart端:

1.構(gòu)造方法原型

const BasicMessageChannel(this.name, this.codec);
- String name: Channel名字吠昭,要和Native端保持一致。
- MessageCodec<T> codec: 消息的編解碼器胧瓜,要和native端保持一致矢棚,有4種類型的具體實(shí)現(xiàn)。

2.setMessageHandler方法原型

void setMessageHandler(Future<T> handler(T message))    
- Future<T> handler(T message)- 消息處理器府喳,配合BinaryMessager完成消息的處理蒲肋;

創(chuàng)建好BasicMessageChannel后,如果要讓其接收Native發(fā)來的消息钝满,則需要調(diào)用它的setMessageHandler方法為其設(shè)置一個消息處理器兜粘。

3.send方法原型

Future<T> send(T message)
- T message: 要傳遞給native的具體消息;
- Future<T>: 消息發(fā)出去后弯蚜,收到Native回復(fù)的回調(diào)函數(shù)孔轴;

在創(chuàng)建好BasicMessageChannel后,如果要向Native發(fā)送消息碎捺,可以調(diào)用它的send方法向Native傳遞數(shù)據(jù)路鹰。

import 'package:flutter/services.dart';
const BasicMessageChannel _basicMessageChannel = BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());
// 使用BasicMessageChannel接收來自Native的消息贷洲,并向Native回復(fù)。
// - message是Native發(fā)來的消息晋柱;
// - Future<String> 是Flutter向Native回復(fù)的消息恩脂。

/// 被動發(fā)送消息
_basicMessageChannel.setMessageHandler((String message) => Future<String>((){
  setState((){
    showMessage = message; // 收到Native發(fā)來的消息
  });
  return "接收Native的消息:" + message; // 回復(fù)消息給native
}));
// 主動發(fā)送消息:使用BasicMessageChannel向Native發(fā)送消息,并接收Native的回復(fù)趣斤。
String response;
try {
  // Flutter主動發(fā)送消息俩块,并接收native回復(fù)。
  response = await _basicMessageChannel.send(value);
} on PlatformException catch(e) {
  print(e);
}

MethodChannel用法:

Native Android端:

1.構(gòu)造方法原型

//會構(gòu)造一個StandardMethodCodec.INSTANCE類型的MethodCodec
MethodChannel(BinaryMessenger messenger, String name)
MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec)

  • BinaryMessenger messenger - 消息信使浓领,是消息的發(fā)送與接收的工具玉凯;
  • String name - Channel的名字,也是其唯一標(biāo)識符联贩;
  • MethodCodec codec - 用作MethodChannel的編解碼器漫仆;

2.setMethodCallHandler方法原型

setMethodCallHandler(@Nullable MethodChannel.MethodCallHandler handler)

  • @Nullable MethodChannel.MethodCallHandler handler - 消息處理器,配合BinaryMessenger完成消息的處理泪幌;
    在創(chuàng)建好MethodChannel后盲厌,需要調(diào)用它的setMessageHandler方法為其設(shè)置一個消息處理器,以便能加收來自Dart的消息祸泪。

3.MethodChannel.MethodCallHandler原型

public interface MethodCallHandler {
void onMethodCall(MethodCall var1, MethodChannel.Result var2);
}

  • onMethodCall(MethodCall call, MethodChannel.Result result) - 用于接受消息吗浩,
    call是消息內(nèi)容,它有兩個成員變量String類型的call.method表示調(diào)用的方法名没隘,Object 類型的call.arguments表示調(diào)用方法所傳遞的入?yún)ⅲ?br> MethodChannel.Result result是回復(fù)此消息的回調(diào)函數(shù)提供了result.success懂扼,result.error,result.notImplemented方法調(diào)用右蒲;
public class MethodChannelPlugin implements MethodCallHandler {
    private final Activity activity;

    /**
     * Plugin registration.
     */
    public static void registerWith(FlutterView flutterView) {
        MethodChannel channel = new MethodChannel(flutterView, "MethodChannelPlugin");
        MethodChannelPlugin instance = new MethodChannelPlugin((Activity) flutterView.getContext());
        channel.setMethodCallHandler(instance);
    }
    private MethodChannelPlugin(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void onMethodCall(MethodCall call, Result result) {
        switch (call.method) {//處理來自Dart端的方法調(diào)用
            case "showMessage":
                showMessage(call.arguments());
                result.success("MethodChannelPlugin收到:" + call.arguments);//返回結(jié)果給Dart
                break;
            default: // 方法未實(shí)現(xiàn)
                result.notImplemented();
        }
    }

    /**
     * 展示來自Dart的數(shù)據(jù)
     * @param arguments
     */
    private void showMessage(String arguments) {
        if (activity instanceof IShowMessage) {
            ((IShowMessage) activity).onShowMessage(arguments);
        }
        Toast.makeText(activity, arguments, Toast.LENGTH_SHORT).show();
    }
}

Dart端:

1.構(gòu)造方法原型

const MethodChannel(this.name, [this.codec= const StandardMethodCodec()])
- String name: channel的名字阀湿,要和Native端保持一致;
- MechodCode codec:消息的編解碼器瑰妄,要和Native端保持一致陷嘴。

2.invokeMethod方法原型

Future<T> invodeMethod<T>(String method, [dynamic arguments])
- method: 要調(diào)用Native的方法名;
- [dynamic arguments]:調(diào)用Native方法傳遞的參數(shù)间坐,可不傳灾挨。

const MethodChannel _methodChannelPlugin = MethodChannel('MethodChannelPlugin');
...
String response;
try {
    // response dart調(diào)用native代碼返回的結(jié)果。調(diào)用原生send方法眶诈。
  response = await _methodChannelPlugin.invokeMethod('send', value);
} on PlatformException catch (e) {
  print(e);
}

EventChannel用法:

Native Android端:

1.構(gòu)造方法原型

//會構(gòu)造一個StandardMethodCodec.INSTANCE類型的MethodCodec
EventChannel(BinaryMessenger messenger, String name)
//或
EventChannel(BinaryMessenger messenger, String name, MethodCodec codec)

  • BinaryMessenger messenger - 消息信使涨醋,是消息的發(fā)送與接收的工具瓜饥;
  • String name - Channel的名字逝撬,也是其唯一標(biāo)識符;
  • MethodCodec codec - 用作EventChannel的編解碼器乓土;

2.setStreamHandler方法原型

void setStreamHandler(EventChannel.StreamHandler handler)

  • EventChannel.StreamHandler handler - 消息處理器宪潮,配合BinaryMessenger完成消息的處理溯警;
    在創(chuàng)建好EventChannel后,如果要讓其接收Dart發(fā)來的消息狡相,則需要調(diào)用它的setStreamHandler方法為其設(shè)置一個消息處理器梯轻。

3.EventChannel.StreamHandler原型

public interface StreamHandler {
void onListen(Object args, EventChannel.EventSink eventSink);
void onCancel(Object o);
}

  • void onListen(Object args, EventChannel.EventSink eventSink) - Flutter Native監(jiān)聽事件時調(diào)用,Object args是傳遞的參數(shù)尽棕,EventChannel.EventSink eventSink是Native回調(diào)Dart時的會回調(diào)函數(shù)喳挑,eventSink提供success、error與endOfStream三個回調(diào)方法分別對應(yīng)事件的不同狀態(tài)滔悉;
  • void onCancel(Object o) - Flutter取消監(jiān)聽時調(diào)用伊诵;
public class EventChannelPlugin implements EventChannel.StreamHandler {
    private List<EventChannel.EventSink> eventSinks = new ArrayList<>();

    static EventChannelPlugin registerWith(FlutterView flutterView) {
        EventChannelPlugin plugin = new EventChannelPlugin();
        new EventChannel(flutterView, "EventChannelPlugin").setStreamHandler(plugin);
        return plugin;
    }
    void sendEvent(Object params) {
        for (EventChannel.EventSink eventSink : eventSinks) {
            eventSink.success(params);
        }
    }

    @Override
    public void onListen(Object args, EventChannel.EventSink eventSink) {
        eventSinks.add(eventSink);
    }
    @Override
    public void onCancel(Object o) {
    }
}

Dart端:

1.構(gòu)造方法原型

const EventChannel(this.name, [this.codec= const StandardMethodCodec()]);
- String name: channel的名字,要和Native端保持一致回官;
- MechodCode codec:消息的編解碼器曹宴,要和Native端保持一致。

2.receiveBroadcastStream 方法原型

Stream<dynamic> receiveBroadcastStream([dynamic arguments])
- dynamic arguments: 監(jiān)聽事件時向Native傳遞的數(shù)據(jù)歉提。

初始化一個廣播用于從Channel中接收數(shù)據(jù)笛坦,它返回一個Stream接下來需要調(diào)用Stream的listen方法來完成注冊。另外需要在頁面銷毀時苔巨,調(diào)用Stream的cancel方法來取消監(jiān)聽版扩。

class EventTest extends StatefulWidget {
  const EventTest({Key? key}) : super(key: key);
  @override
  State<EventTest> createState() => _EventTestState();
}
const EventChannel _eventChannelPlugin = EventChannel('EventChannelPlugin');

class _EventTestState extends State<EventTest> {
  late StreamSubscription? _streamSubscription;
  String showMessage = '';
  
  @override
  void initState() {
    // 注冊
    _streamSubscription = _eventChannelPlugin
        .receiveBroadcastStream()
        .listen(_onToDart, onError: _onToDartError);
    super.initState();
  }
  @override
  void dispose() {
    if (_streamSubscription != null) { // 取消注冊
      _streamSubscription?.cancel();
      _streamSubscription = null;
    }
    super.dispose();
  }
  void _onToDart(message) {
    setState(() {
      showMessage = message;
    });
  }
  void _onToDartError(error) {
    print(error);
  }
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

完整通信例子

1. 初始化Flutter時Native向Dart傳遞數(shù)據(jù)

在Flutter的API中提供了Native在初始化Dart頁面時傳遞數(shù)據(jù)給Dart的方式,這種傳遞數(shù)據(jù)的方式比下文中所講的其他幾種傳遞數(shù)據(jù)的方式發(fā)生的時機(jī)都早侄泽。
因?yàn)楹苌儆匈Y料介紹這種方式资厉,所以可能有很多同學(xué)還不知道這種方式,不過不要緊蔬顾,接下來我就向大家介紹如何使用這種方式來傳遞數(shù)據(jù)給Dart宴偿。
Android向Flutter傳遞初始化數(shù)據(jù)initialRoute
Flutter允許我們在初始化Flutter頁面時向Flutter傳遞一個String類型的initialRoute參數(shù),從參數(shù)名字它是用作路由名的诀豁,但是既然Flutter給我們開了這個口子窄刘,那我們是不是可以搞點(diǎn)事情啊,傳遞點(diǎn)我們想傳的其他參數(shù)呢舷胜,比如:

FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.someContainer, Flutter.createFragment("{name:'devio',dataList:['aa','bb',''cc]}"));
tx.commit();
//or
View flutterView = Flutter.createView(
      MainActivity.this,
      getLifecycle(),
      "route1"
    );
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(600, 800);
layout.leftMargin = 100;
layout.topMargin = 200;
addContentView(flutterView, layout);

然后在Flutter module通過如下方式獲让浼:
import 'dart:ui';//要使用window對象必須引入
String initParams=window.defaultRouteName;
//序列化成Dart obj 敢你想干的
...
通過上述方案的講解是不是給大家分享了一個新的思路呢。
接下來烹骨,我們先來看一下如何在Android上來傳遞這些初始化數(shù)據(jù)翻伺。

實(shí)例2. Native到Dart的通信(Native發(fā)送數(shù)據(jù)給Dart)

在Flutter 中Native向Dart傳遞消息可以通過BasicMessageChannel或EventChannel都可以實(shí)現(xiàn):
通過BasicMessageChannel的方式:
通過EventChannel的方式:
以上就是使用不同Channel實(shí)現(xiàn)Native到Dart通信的原理及方式,接下來我們來看一下實(shí)現(xiàn)Dart到Native之間通信的原理及方式沮焕。

3. Dart到Native的通信(Dart發(fā)送數(shù)據(jù)給Native)

在Flutter 中Dart向Native傳遞消息可以通過BasicMessageChannel或MethodChannel都可以實(shí)現(xiàn):
通過BasicMessageChannel的方式
通過MethodChannel的方式


https://hanshuliang.blog.csdn.net/article/details/119998492

Dart端:

Android端:

String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"
repositories {
maven {
// url 'D:/FlutterLearn/flutter_bybird1115/flutter_module/build/host/outputs/repo'
url '../flutter_module/build/host/outputs/repo'
}
maven {
url '$storageUrl/download.flutter.io'
}
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吨岭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子峦树,更是在濱河造成了極大的恐慌辣辫,老刑警劉巖旦事,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異急灭,居然都是意外死亡姐浮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門葬馋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卖鲤,“玉大人,你說我怎么就攤上這事畴嘶∩猓” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵掠廓,是天一觀的道長换怖。 經(jīng)常有香客問我,道長蟀瞧,這世上最難降的妖魔是什么沉颂? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮悦污,結(jié)果婚禮上铸屉,老公的妹妹穿的比我還像新娘。我一直安慰自己切端,他們只是感情好彻坛,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著踏枣,像睡著了一般昌屉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茵瀑,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天间驮,我揣著相機(jī)與錄音,去河邊找鬼马昨。 笑死竞帽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸿捧。 我是一名探鬼主播屹篓,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼匙奴!你這毒婦竟也來了堆巧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恳邀,沒想到半個月后懦冰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灶轰,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谣沸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了笋颤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乳附。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伴澄,靈堂內(nèi)的尸體忽然破棺而出赋除,到底是詐尸還是另有隱情,我是刑警寧澤非凌,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布举农,位于F島的核電站,受9級特大地震影響敞嗡,放射性物質(zhì)發(fā)生泄漏颁糟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一喉悴、第九天 我趴在偏房一處隱蔽的房頂上張望棱貌。 院中可真熱鬧,春花似錦箕肃、人聲如沸婚脱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽障贸。三九已至,卻和暖如春吟宦,著一層夾襖步出監(jiān)牢的瞬間惹想,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工督函, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嘀粱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓辰狡,卻偏偏與公主長得像锋叨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子宛篇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

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