第二十章 Android 中常用的WebView

我们了解过Web,对于HTTP协议,我们不是做网站开发,Android端只需要简单的了解基本的原理就可以了。首先由客户端发送请求给服务端,然后服务端返回对应的指令,最后根据返回的指令进行解析和处理。这就是一个简单的网络交互协议。

1. WebView的用法

在做Android开发的时候,我们可能会碰到一些特殊的需求,比如说在应用 程序中加载一个网页,或者插入一些广告啥的,而且需求中又不允许打开系统的浏览器,怎么办?Android已经考虑到这种需要了,所以提供了一个WebView控件,在自己的应用程序中嵌入一个浏览器。这样就可以轻松展示各种网页。

WebView的用法很简单,和一般的控件都一样。

  1. 新建一个activity_main.xml,然后插入一个WebView 控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <WebView
        android:id="@+id/wb_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
  1. MainActivity 设置WebView的方法
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        WebView  wb_main= (WebView) findViewById(R.id.wb_main);
        wb_main.getSettings().setJavaScriptEnabled(true);//支持JavaScriptEnable
        wb_main.setWebViewClient(new WebViewClient());
        wb_main.loadUrl("http://www.baidu.com");
    }
}

通过getSetting()可以设置浏览器的属性,这里用了setJavaScriptEnabled()的来让WebView支持JavaScript脚本。然后调用WebView的setWebViewClient()的方法并传入一个实例。最后是希望加载的网页
3.最后一步,记得加上权限

    <uses-permission android:name="android.permission.INTERNET"/>

这样就完成了一个简单的加载网页。

2. WebView的方法

2.1 加载url

根据加载的方式不同分为三种:

  //方式1. 加载一个网页:
  webView.loadUrl("http://www.baidu.com/");   // 加载url页面
 //方式2:加载apk包中的html页面
  webView.loadUrl("file:///android_asset/test.html");
  //方式3:加载手机本地的html页面
   webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html"); 

// 另外1、: 加载 HTML 页面的一小段内容
  WebView.loadData(String data, String mimeType, String encoding) 如:
webView_main.loadData(data, "text/html","utf-8");
// 参数说明:
// 参数1:需要截取展示的内容
// 内容里不能出现 ’#’, ‘%’, ‘\’ , ‘?’ 这四个字符,若出现了需用 %23, %25, %27, %3f 对应来替代,否则会出现异常
// 参数2:展示内容的类型
// 参数3:字节码

//另外2、:
webView_main.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);

loadDataWithBaseURL()的作用呢?难道是结合体?因为webView_main.loadData(data, "text/html","utf-8");//这个方法中虽然设置了字符,但是还是会显示中文乱码。所以建议使用 webView_main.loadDataWithBaseURL(null, data, "text/html", "utf-8", null);

2.2 前进后退网页
//是否可以后退
Webview.canGoBack() 
//后退网页
Webview.goBack()

//是否可以前进                     
Webview.canGoForward()
//前进网页
Webview.goForward()

//以当前的index为起始点前进或者后退到历史记录中指定的steps
//如果steps为负数则为后退,正数则为前进
Webview.goBackOrForward(intsteps)

如果在请求WebView的时候,进入二级的WebView的时候,点击Back键,实际上是整个Activity都结束,调用了finish()方法,所以这个时候需要调用goBack()方法。

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KEYCODE_BACK) && wb_main.canGoBack()) {
            wb_main.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

或者.

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(event.getKeyCode() == KeyEvent.KEYCODE_BACK){
            if(wb_main.canGoBack() ){
                //获取浏览记录
                WebBackForwardList backForwardList= wb_main.copyBackForwardList();
                //这里的判断是为了让页面在有上一个页面的情况下,跳转到上一个html页面,而不是退出当前activity
                 if(backForwardList.getCurrentIndex()>0){
                     String  historyUrl =  backForwardList.getItemAtIndex(backForwardList.getCurrentIndex()-1).getUrl();
                     if(historyUrl !=url ){
                         wb_main.goBack();
                         return true;
                     }
                 }

            } else{
                return  true;
            }
        }
        return true;
    }

2.3 缓存
//清除网页访问留下的缓存
//由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
Webview.clearCache(true);

//清除当前webview访问的历史记录
//只会webview访问历史记录里的所有记录除了当前访问记录
Webview.clearHistory();

//这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
Webview.clearFormData();

1.2 WebView的常用类

1.2.1 WebSetting类

WebView加载网页内容,但是对于HTML文本的Javascript代码却无法加载运行。为了解决这个问题要借助WebSettings类。WebSettings类除了可以设置是否支持Javascript外,还具有set系列方法来设置WebView的属性和状态。WebSettings对象通过WebView对象的getSettings()方法来获取

方法 描述
setJavaScriptEnabled(boolean flag) 设置是否支持Javascript
setBlockNetworkImage(boolean flag) 设置是否阻止网络图片加载
setBuiltInZoomControls(boolean enabled) 将HTML文本内容加载到WebView中
setCacheMode(int mode) 设置缓存模式
setDefaultFontSize(int size) 设置默认字体大小
setFixedFontFamily(String font) 设置固定使用的字体
setDefaultTextEncodingName(String encoding) 设置解码时默认的字符集
setSupportZoom(boolean support) 设置是否支持变焦
setAllowFileAccess(boolean allow) 设置是否允许访问WebView中文件。就是file:///android_asset和file:///android_res路径下的资产和资源文件。默认允许访问。

注意:5.1以上默认禁止了https和http混用 这是开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

2.4 WebViewClient类

WebView解决了支持Javascript的问题。但是新的问题又出来了。当点击WebView中的超链接后,原本希望目标网页在当前WebView中显示,但是却打开了系统浏览器来加载目标网页。为了解决这个问题,要借助WebViewClient类。WebViewClient类专门用来辅助WebView处理各种通知、请求等事件。通过WebView对象调用setWebViewClient()方法来指定一个WebViewClient对象,重写WebViewClient对象中的shouldOverrideUrlLoading()方法,使得当有新连接时,使用当前WebView来显示网页。WebViewClient除此之外,还有其他的方法

方法 描述
shouldOverrideUrlLoading() 新的链接在当前WebView中打开
onPageStarted() 网页开始加载
onPageFinished() 网页加载完毕
doUpdateVisitedHistory() 更新访问历史记录的数据库
onLoadResource() 加载指定Url地址提供的资源
onFormResubmission() 应用程序重新请求网页数据
onScaleChanged() WebView发生改变
2.5 WebChromeClient类

对于网页中一般的Javascript都可以被WebView加载执行了。但是某些特殊的Javascript语句依然无法执行。例如Javascript语句中的Alert、Confirm、Prompt等对话框。为了解决这个问题,要借助WebChromeClient类。WebChromeClient类专门用来辅助WebView处理Javascript的对话框、网站图标、网站Title、加载进度等。

方法 描述
onJsAlert() 处理Javascript中Alert对话框
onJsConfirm() 处理Javascript中Confirm对话框
onJsPrompt() 处理Javascript中Prompt对话框
onProgressChanged() 加载进度条改变
onCloseWindow() 关闭WebView
onCreateWindow() 创建WebView
onReceivedIcon() Icon图标改变
onReceivedTitle() 网页Title改变
onRequestFocus() WebView显示焦点

3. Android 和Js的交互

在实际开发过程中,Android与Js的交互都是通过WebView来完成的。WebView是二者之间的桥梁。

  • Android 调用Js的代码
  • Js调用Android的代码
Android与Js的交互

3.1 Android 调用JS的代码

我们是做安卓开发的,所以在实际的开发过程中,有h5的人会写好对应的方法,然后我们只需要根据它提供给我们的方法,调起js的代码就可以了。这里写一个例子来说明一下。

调用JS前
调用JS后
  1. 首先在一个布局文件中有这样两个控件。activity_main2.xml.一个Button,一个WebView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<Button
    android:id="@+id/button"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:text="@string/btn_click"
    />
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

  1. 接下来在assert文件下创建一个html文件。(创建asserts文件,main->New->Folder->Asserts Folder),(创建html文件,可以自己创建一个File文件,然后后缀加上 login.html)
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Carson_Ho</title>
    <script>
         function callJS(){
             alert("Android调用了JS的callJS方法");
        }
</script>

</head>

</html>
  1. 接下来就是对布局的一些处理,上图的逻辑很简单,我们在点击按钮的时候出发弹窗,然后根据弹窗吊起Js。
public class Main2Activity extends AppCompatActivity {
    WebView mWebView;
    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        mWebView =(WebView) findViewById(R.id.webView);
        WebSettings webSettings = mWebView.getSettings();
        // 设置与Js交互的权限
        webSettings.setJavaScriptEnabled(true);
        // 设置允许JS弹窗
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        // 先载入JS代码
        // 格式规定为:file:///android_asset/文件名.html
        mWebView.loadUrl("file:///android_asset/login.html");
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 通过Handler发送消息
                mWebView.post(new Runnable() {
                    @Override
                    public void run() {
                        // 注意调用的JS方法名要对应上
                        // 调用javascript的callJS()方法
                        mWebView.loadUrl("javascript:callJS()");
                    }
                });

            }
        });

        // 由于设置了弹窗检验调用结果,所以需要支持js对话框
        // webview只是载体,内容的渲染需要使用webviewChromClient类去实现
        // 通过设置WebChromeClient对象处理JavaScript的对话框
        //设置响应js 的Alert()函数
        mWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder b = new AlertDialog.Builder(Main2Activity.this);
                b.setTitle("Alert");
                b.setMessage(message);
                b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                });
                b.setCancelable(false);
                b.create().show();
                return true;
            }

        });


    }
}

【注意】永远不要阻塞UI线程,这是开发Android程序的一个真理。虽然是真理,我们却往往不自觉的犯一些错误违背它,一个开发中常犯的错误就是:在UI线程中去等待JavaScript 的回调。Android 4.4中,提供了新的Api来做这件事情。evaluateJavascript() 就是专门来异步执行JavaScript代码的。专门用于异步调用JavaScript方法,并且能够得到一个回调结果。

调用方式 优点 缺点 使用场景
使用loadUrl() 方便简洁 效率低;无返回值 无需返回值,对性能要求低
使用evaluateJavascript() 效率高 向下兼容差(4.4以上) Android 4.4以上
mWebView.evaluateJavascript(script, new ValueCallback<String>() {
     @Override
     public void onReceiveValue(String value) {
          //返回Js的结果
     }
});

修改代码,既兼容4.4以上,有包括4.4以下

  button.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onClick(View v) {
                if(Build.VERSION.SDK_INT<19){
                  mWebView.post(new Runnable() {
                      @Override
                      public void run() {
                          mWebView.loadUrl("javascript:callJS()");
                      }
                  });
                }else{
                      //已经是异步了,无需再开下线程了
                    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
                        @Override
                        public void onReceiveValue(String s) {
                            Log.e(TAG, "onReceiveValue: "+s );
                        }
                    });
                }
            }
        });

3.2 JS调用安卓的代码

在安卓实际开发过程中,JS的一些代码,也可以调用安卓的功能。方法有以下三种:

3.2.1 通过WebView的addJavascriptInterface()进行对象映射

具体的方法:

  1. 定义一个与JS对象映射关系的Android类,然后定义一个JS需要调用的方法
public class Main3JS  extends Object {
    // 定义JS需要调用的方法
    // 被JS调用的方法必须加入@JavascriptInterface注解
    @JavascriptInterface
    public  void  ToJs(String msg){
        Log.e("tag","JS调用Android的代码");
    }
}
  1. 编写一个html文件,registe.html。定义一个test对象,然后调用Android 映射的对象,最后在点击按钮的时候,其实就是在调用callAndroid()这个函数。
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
    <script>
         function callAndroid(){
             // 由于对象映射,所以调用test对象等于调用Android映射的对象
            test.ToJs("js调用了android中的ToJs方法");
        }
</script>

</head>
<body>

<button type="button" id="button1" onclick="callAndroid()" >JS点击调用安卓的代码</button>
</body>
</html>

  1. 新建一个Main3Activity文件,布局里面只有一个webView。设置加载JS的方法,然后调用addJavascriptInterface()这个方法,将第一步的Main3J类带入,然后是第二个test对象。
public class Main3Activity extends AppCompatActivity {
    WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        mWebView = (WebView) findViewById(R.id.WebView);
        WebSettings webSettings = mWebView.getSettings();

        // 设置与Js交互的权限
        webSettings.setJavaScriptEnabled(true);

        // 通过addJavascriptInterface()将Java对象映射到JS对象
        //参数1:Javascript对象名
        //参数2:Java对象名
        mWebView.addJavascriptInterface(new Main3JS(this), "test");//AndroidtoJS类对象映射到js的test对象

        // 加载JS代码
        // 格式规定为:file:///android_asset/文件名.html
        mWebView.loadUrl("file:///android_asset/registe.html");
    }
}

最后结果如上图所示。这种方法使用简单,仅将Android对象和JS对象映射即可。但是存在数据泄露的风险。

3.2.2 通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url

回调拦截url的原理很简单,Android 通过WebViewClient的回调方法shouldOverrideUrlLoading ()拦截 url,然后解析url,根据设定的url协议调用不同的方法。

  • 具体步骤
  1. 编写一个html文件,定义一个协议。当Js通过Android 的加载的协议后,就会回调shouldOverrideUrlLoading ()方法。
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <script>
         function callAndroid(){
          //定义协议
          document.location="js://webview?location=1";
        }
</script>

</head>
<body>

<button type="button" id="button1" onclick="callAndroid()" >JS点击调用安卓的代码</button>
</body>
</html>

2.在Main4Activity 中定义webView,然后加载协议,最后调用webview的shouldOverrideUrlLoading ()方法。根据js.html的定义的协议格式:根据scheme(协议格式) & authority(协议名)判断(前两个参数)进行判断。

public class Main4Activity extends AppCompatActivity {
    private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main4);
        webView = (WebView) findViewById(R.id.webView);
        WebSettings webSettings= webView.getSettings();
        //设置加载JS权限
        webSettings.setJavaScriptEnabled(true);
        //设置允许JS弹窗
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
         //加载file文件

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

         webView.setWebViewClient(new WebViewClient(){
             // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
             // "js://webview?location=1"
             @Override
             public boolean shouldOverrideUrlLoading(WebView view, String url) {
                 Uri uri = Uri.parse(url);
                 //如果url的协议 = 预先约定的 js 协议
                  if(uri.getScheme().equals("js")){
                      // 如果 authority  = 预先约定协议里的 webview,即代表都符合约定的协议
                       if(uri.getAuthority().equals("webview")){
                            // 执行JS所需要调用的逻辑
                           System.out.println("js调用了Android的方法");
                           // 可以在协议上带有参数并传递到Android上
//                           HashMap<String, String> params = new HashMap<>();
//                           Set<String> collection = uri.getQueryParameterNames();
                           AlertDialog.Builder mBuilder= new AlertDialog.Builder(Main4Activity.this);
                           mBuilder.setTitle("Alert");
                           mBuilder.setMessage("JS要调用Android的代码");
                           mBuilder.setCancelable(true);
                           mBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                               @Override
                               public void onClick(DialogInterface dialogInterface, int i) {
                                   dialogInterface.dismiss();
                               }
                           });
                           mBuilder.create().show();

                       }
                        return  true;
                  }
                 return super.shouldOverrideUrlLoading(view, url);
             }
         });
    }
}

通过解析协议里面的值来进行调用android里面的代码。这样可以避免数据邪路的风险,但是返回数据麻烦。当用户点击webview中的网页链接的时候,安卓系统默认会启动一个新的应用专门成立url的跳转。如果希望点击链接继续在当前webview中响应,而不是新开Android的系统browser中响应该链接,必须覆盖 WebView的WebViewClient对象. 并重写shouldOverrideUrlLoading方法。

3.2.3 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
方法 作用 返回值 备注
alert() 弹出警告框 在文本中加入\n可换行
confirm() 弹出确认框 两个 返回布尔值(true,false)
prompt() 弹出输入框 任意设置返回值 确认:返回输入框中的值;取消返回null
  • 具体方法
    1.首先在three.html中设置点击按钮和调用的js方法
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Carson_Ho</title>

    <script>

    function clickprompt(){
    // 调用prompt()
    var result=prompt("js://webview?arg1=111&arg2=222");
    alert("demo " + result);
}

      </script>
</head>

<!-- 点击按钮则调用clickprompt()  -->
<body>
<button type="button" id="button1" onclick="clickprompt()">点击调用Android代码</button>
</body>
</html>

2.然后在Main5Activity方法中,自顶一个WebView,然后调用WebView的WebChromeClient(),重写里面的回调拦截方法


public class Main5Activity extends AppCompatActivity {

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main5);
        webView = (WebView) findViewById(R.id.webView);
        WebSettings  webSettings=webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webView.loadUrl("file:///android_asset/three.html");
        webView.setWebChromeClient(new WebChromeClient(){

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                Uri uri = Uri.parse(message);
                if (uri.getScheme().equals("js")) {
                    if (uri.getAuthority().equals("webview")) {
                        System.out.println("js调用了Android的方法");
                        // 可以在协议上带有参数并传递到Android上
                        HashMap<String, String> params = new HashMap<>();
                        Set<String> collection = uri.getQueryParameterNames();
                        //参数result:代表消息框的返回值(输入值)
                        result.confirm("js调用了Android的方法成功啦");
                    }
                    return true;
                }
                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);

            }
        });
    }
}

调用前
调用后

github地址:https://github.com/wangxin3119/MyWebViewDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,248评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,681评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,443评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,475评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,458评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,185评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,451评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,112评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,609评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,083评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,163评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,803评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,357评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,357评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,590评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,636评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,925评论 2 344

推荐阅读更多精彩内容