Android 6.0+新的運行時權(quán)限 開發(fā)者需要知道的一切

Android 6.0+新的運行時權(quán)限 開發(fā)者需要知道的一切

android M 的名字官方剛發(fā)布不久碗硬,最終正式版即將來臨扛或!
android在不斷發(fā)展绵咱,最近的更新 M 非常不同,一些主要的變化例如運行時權(quán)限將有顛覆性影響熙兔。驚訝的是android社區(qū)鮮有談?wù)撨@事兒悲伶,盡管這事很重要或許在不遠的將來會引發(fā)很嚴重的問題艾恼。
這是今天我寫這篇博客的原因。這里有一切關(guān)于android運行時權(quán)限你需要知道的麸锉,包括如何在代碼中實現(xiàn)∧粕埽現(xiàn)在亡羊補牢還不晚。

新運行時權(quán)限

android的權(quán)限系統(tǒng)一直是首要的安全概念花沉,因為這些權(quán)限只在安裝的時候被詢問一次柳爽。一旦安裝了,app可以在用戶毫不知曉的情況下訪問權(quán)限內(nèi)的所有東西碱屁。
難怪一些壞蛋利用這個缺陷惡意收集用戶數(shù)據(jù)用來做壞事了磷脯!
android小組也知道這事兒。7年了娩脾!權(quán)限系統(tǒng)終于被重新設(shè)計了争拐。在android6.0棉花糖,app將不會在安裝的時候授予權(quán)限晦雨。取而代之的是架曹,app不得不在運行時一個一個詢問用戶授予權(quán)限。

注意權(quán)限詢問對話框不會自己彈出來闹瞧。開發(fā)者不得不自己調(diào)用绑雄。如果開發(fā)者要調(diào)用的一些函數(shù)需要某權(quán)限而用戶又拒絕授權(quán)的話,函數(shù)將拋出異常直接導(dǎo)致程序崩潰奥邮。

另外万牺,用戶也可以隨時在設(shè)置里取消已經(jīng)授權(quán)的權(quán)限。

你或許已經(jīng)感覺到背后生出一陣寒意洽腺。脚粟。。如果你是個android開發(fā)者蘸朋,意味著要完全改變你的程序邏輯核无。你不能像以前那樣直接調(diào)用方法了,你不得不為每個需要的地方檢察權(quán)限藕坯,否則app就崩潰了团南!
是的。我不能哄你說這是簡單的事兒炼彪。盡管這對用戶來說是好事吐根,但是對開發(fā)者來說就是噩夢。我們不得不修改編碼不然不論短期還是長遠來看都是潛在的問題辐马。
這個新的運行時權(quán)限僅當(dāng)我們設(shè)置targetSdkVersion to 23(這意味著你已經(jīng)在23上測試通過了)才起作用拷橘,當(dāng)然還要是M系統(tǒng)的手機。app在6.0之前的設(shè)備依然使用舊的權(quán)限系統(tǒng)。

已經(jīng)發(fā)布了的app會發(fā)生什么

新運行時權(quán)限可能已經(jīng)讓你開始恐慌了冗疮。“hey萄唇,伙計!我三年前發(fā)布的app可咋整呢赌厅。如果他被裝到android 6.0上,我的app會崩潰嗎轿塔?L卦浮?”
莫慌張勾缭,放輕松揍障。android小隊又不傻,肯定考慮到了這情況俩由。如果app的targetSdkVersion 低于 23毒嫡,那將被認為app沒有用23新權(quán)限測試過,那將被繼續(xù)使用舊有規(guī)則:用戶在安裝的時候不得不接受所有權(quán)限幻梯,安裝后app就有了那些權(quán)限咯兜畸!

然后app像以前一樣奔跑!注意碘梢,此時用戶依然可以取消已經(jīng)同意的授權(quán)咬摇!用戶取消授權(quán)時,android 6.0系統(tǒng)會警告煞躬,但這不妨礙用戶取消授權(quán)肛鹏。

問題又來了,這時候你的app崩潰嗎恩沛?
善意的主把這事也告訴了android小組在扰,當(dāng)我們在targetSdkVersion 低于23的app調(diào)用一個需要權(quán)限的函數(shù)時,這個權(quán)限如果被用戶取消授權(quán)了的話雷客,不拋出異常芒珠。但是他將啥都不干,結(jié)果導(dǎo)致函數(shù)返回值是null或者0.

別高興的太早搅裙。盡管app不會調(diào)用這個函數(shù)時崩潰妓局,返回值null或者0可能接下來依然導(dǎo)致崩潰。
好消息(至少目前看來)是這類取消權(quán)限的情況比較少呈宇,我相信很少用戶這么搞好爬。如果他們這么辦了,后果自負咯甥啄。
但從長遠看來存炮,我相信還是會有大量用戶會關(guān)閉一些權(quán)限。我們app不能在新設(shè)備完美運行這是不可接受的。
怎樣讓他完美運行呢穆桂,你最好修改代碼支持最新的權(quán)限系統(tǒng)宫盔,而且我建議你立刻著手搞起!
代碼沒有成功改為支持最新運行時權(quán)限的app,不要設(shè)置targetSdkVersion 23 發(fā)布享完,否則你就有麻煩了灼芭。只有當(dāng)你測試過了,再改為targetSdkVersion 23 般又。

警告:現(xiàn)在你在android studio新建項目彼绷,targetSdkVersion 會自動設(shè)置為 23。如果你還沒支持新運行時權(quán)限茴迁,我建議你首先把targetSdkVersion 降級到22

PROTECTION_NORMAL類權(quán)限

當(dāng)用戶安裝或更新應(yīng)用時寄悯,系統(tǒng)將授予應(yīng)用所請求的屬于 PROTECTION_NORMAL 的所有權(quán)限(安裝時授權(quán)的一類基本權(quán)限)。這類權(quán)限包括:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

只需要在AndroidManifest.xml中簡單聲明這些權(quán)限就好堕义,安裝時就授權(quán)猜旬。不需要每次使用時都檢查權(quán)限,而且用戶不能取消以上授權(quán)倦卖。

讓你的app支持新運行時權(quán)限

是時候讓我們的app支持新權(quán)限模型了洒擦,從設(shè)置compileSdkVersion and targetSdkVersion 為 23開始吧.

android {
    compileSdkVersion 23
    ...

    defaultConfig {
        ...
        targetSdkVersion 23
        ...
    }

例子,我想用以下方法添加聯(lián)系人怕膛。

privatestaticfinal String TAG = "Contacts";
privatevoid insertDummyContact() {
// Two operations are needed to insert a new contact.
    ArrayList operations = new ArrayList(2);

// First, set up a new raw contact.
    ContentProviderOperation.Builder op =
            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null);
    operations.add(op.build());

// Next, set the name for the contact.
    op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
            .withValue(ContactsContract.Data.MIMETYPE,
                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
"__DUMMY CONTACT from runtime permissions sample");
    operations.add(op.build());

// Apply the operations.
    ContentResolver resolver = getContentResolver();
try {
        resolver.applyBatch(ContactsContract.AUTHORITY, operations);
    } catch (RemoteException e) {
        Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    } catch (OperationApplicationException e) {
        Log.d(TAG, "Could not add a new contact: " + e.getMessage());
    }
}

上面代碼需要WRITE_CONTACTS權(quán)限秘遏。如果不詢問授權(quán),app就崩了嘉竟。
下一步像以前一樣在AndroidManifest.xml添加聲明權(quán)限邦危。

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

下一步,不得不再寫個方法檢查有沒有權(quán)限舍扰。如果沒有彈個對話框詢問用戶授權(quán)倦蚪。然后你才可以下一步創(chuàng)建聯(lián)系人。
權(quán)限被分組了边苹,如下表:

同一組的任何一個權(quán)限被授權(quán)了陵且,其他權(quán)限也自動被授權(quán)。例如个束,一旦WRITE_CONTACTS被授權(quán)了慕购,app也有READ_CONTACTS和GET_ACCOUNTS權(quán)限了。
源碼中被用來檢查和請求權(quán)限的方法分別是Activity的checkSelfPermission和requestPermissions茬底。這些方法在api23引入沪悲。

finalprivateint REQUEST_CODE_ASK_PERMISSIONS = 123;

privatevoid insertDummyContactWrapper() {
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
return;
    }
    insertDummyContact();
}

如果已有權(quán)限,insertDummyContact()會執(zhí)行阱表。否則殿如,requestPermissions被執(zhí)行來彈出請求授權(quán)對話框贡珊,如下:

不論用戶同意還是拒絕,activity的onRequestPermissionsResult會被回調(diào)來通知結(jié)果(通過第三個參數(shù))涉馁,grantResults,如下:

@Override
publicvoid onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
caseREQUEST_CODE_ASK_PERMISSIONS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
                insertDummyContact();
            } else {
// Permission Denied
                Toast.makeText(MainActivity.this, "WRITE_CONTACTS Denied", Toast.LENGTH_SHORT)
                        .show();
            }
break;
        default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

這就是新權(quán)限模型工作過程门岔。代碼真復(fù)雜但是只能去習(xí)慣它。烤送。寒随。為了讓app很好兼容新權(quán)限模型,你不得不用以上類似方法處理所有需要的情況帮坚。
如果你想捶墻妻往,現(xiàn)在是時候了。叶沛。蒲讯。

處理 “不再提醒”

如果用戶拒絕某授權(quán)忘朝。下一次彈框灰署,用戶會有一個“不再提醒”的選項的來防止app以后繼續(xù)請求授權(quán)。

如果這個選項在拒絕授權(quán)前被用戶勾選了局嘁。下次為這個權(quán)限請求requestPermissions時溉箕,對話框就不彈出來了,結(jié)果就是悦昵,app啥都不干肴茄。
這將是很差的用戶體驗,用戶做了操作卻得不到響應(yīng)但指。這種情況需要好好處理一下寡痰。在請求requestPermissions前,我們通過activity的shouldShowRequestPermissionRationale方法來檢查是否需要彈出請求權(quán)限的提示對話框棋凳,代碼如下:

final private int REQUEST_CODE_ASK_PERMISSIONS = 123;

private void insertDummyContactWrapper() {
int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                showMessageOKCancel("You need to allow access to Contacts",
new DialogInterface.OnClickListener() {
@Override
publicvoid onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                                        REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
return;
            }
        requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
return;
    }
    insertDummyContact();
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setPositiveButton("OK", okListener)
            .setNegativeButton("Cancel", null)
            .create()
            .show();
}

當(dāng)一個權(quán)限第一次被請求和用戶標(biāo)記過不再提醒的時候,我們寫的對話框被展示拦坠。
最后一種情況,onRequestPermissionsResult 會收到PERMISSION_DENIED 剩岳,系統(tǒng)詢問對話框不展示贞滨。

搞定!

一次請求多個權(quán)限

當(dāng)然了有時候需要好多權(quán)限拍棕,可以用上面方法一次請求多個權(quán)限晓铆。不要忘了為每個權(quán)限檢查“不再提醒”的設(shè)置。
修改后的代碼:

final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
 
private void insertDummyContactWrapper() {
    List<String> permissionsNeeded = new ArrayList<String>();
 
    final List<String> permissionsList = new ArrayList<String>();
    if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");
 
    if (permissionsList.size() > 0) {
        if (permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for (int i = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        return;
    }
 
    insertDummyContact();
}
 
private boolean addPermission(List<String> permissionsList, String permission) {
    if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if (!shouldShowRequestPermissionRationale(permission))
            return false;
    }
    return true;
}

如果所有權(quán)限被授權(quán)绰播,依然回調(diào)onRequestPermissionsResult骄噪,我用hashmap讓代碼整潔便于閱讀。

@Override
publicvoid onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
caseREQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
            {
            Map perms = new HashMap();
// Initial
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
// Fill with results
for (int i = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
// Check for ACCESS_FINE_LOCATION
if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
// All Permissions Granted
                insertDummyContact();
            } else {
// Permission Denied
                Toast.makeText(MainActivity.this, "Some Permission is Denied", Toast.LENGTH_SHORT)
                        .show();
            }
            }
break;
        default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

條件靈活的蠢箩,你自己設(shè)置腰池。有的情況尾组,一個權(quán)限沒有授權(quán),就不可用示弓;但是也有情況讳侨,能工作,但是表現(xiàn)的是有所限制的奏属。對于這個我不做評價跨跨,你自己設(shè)計吧。

用兼容庫使代碼兼容舊版

以上代碼在android 6.0以上運行沒問題囱皿,但是23 api之前就不行了勇婴,因為沒有那些方法。
粗暴的方法是檢查版本

if (Build.VERSION.SDK_INT >= 23) {
// Marshmallow+
} else {
// Pre-Marshmallow
}

但是太復(fù)雜嘱腥,我建議用v4兼容庫耕渴,已對這個做過兼容,用這個方法代替:

  • ContextCompat.checkSelfPermission()
    被授權(quán)函數(shù)返回PERMISSION_GRANTED齿兔,否則返回PERMISSION_DENIED 橱脸,在所有版本都是如此。
  • ActivityCompat.requestPermissions()
    這個方法在M之前版本調(diào)用分苇,OnRequestPermissionsResultCallback 直接被調(diào)用添诉,帶著正確的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。
  • ActivityCompat.shouldShowRequestPermissionRationale()
    在M之前版本調(diào)用医寿,永遠返回false栏赴。
    用v4包的這三方法,完美兼容所有版本靖秩!這個方法需要額外的參數(shù)须眷,Context or Activity。別的就沒啥特別的了沟突。下面是代碼:
private void insertDummyContactWrapper(){
int hasWriteContactsPermission = ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_CONTACTS);
if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.WRITE_CONTACTS)) {
            showMessageOKCancel("You need to allow access to Contacts",new DialogInterface.OnClickListener() {
@Override
public void onClick (DialogInterface dialog, int which){
                            ActivityCompat.requestPermissions(MainActivity.this,new String[] {Manifest.permission.WRITE_CONTACTS},
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        }
                    });
return;
        }
        ActivityCompat.requestPermissions(MainActivity.this,
new String[] {Manifest.permission.WRITE_CONTACTS},
                REQUEST_CODE_ASK_PERMISSIONS);
return;
    }
    insertDummyContact();
}    

后兩個方法花颗,我們也可以在Fragment中使用,用v13兼容包:FragmentCompat.requestPermissions() and FragmentCompat.shouldShowRequestPermissionRationale()和activity效果一樣事扭。

第三方庫簡化代碼

以上代碼真尼瑪復(fù)雜捎稚。為解決這事,有許多第三方庫已經(jīng)問世了求橄,真66溜真有速度今野。我試了很多最終找到了個滿意的hotchemi’s PermissionsDispatcher
他和我上面做的一樣罐农,只是簡化了代碼条霜。靈活易擴展,試一下吧涵亏。如果不滿足你可以找些其他的宰睡。

如果我的app還開著呢蒲凶,權(quán)限被撤銷了,會發(fā)生生么

權(quán)限隨時可以被撤銷拆内。

當(dāng)app開著的時候被撤消了會發(fā)生什么呢旋圆?我試過了發(fā)現(xiàn)這時app會突然終止 terminated。app中的一切都被簡單粗暴的停止了麸恍,因為terminated灵巧!對我來說這可以理解,因為系統(tǒng)如果允許它繼續(xù)運行(沒有某權(quán)限)抹沪,這會召喚弗雷迪到我的噩夢里刻肄。或許更糟…

結(jié)論建議

我相信你對新權(quán)限模型已經(jīng)有了清晰的認識融欧。我相信你也意識到了問題的嚴峻敏弃。
但是你沒得選擇。新運行時權(quán)限已經(jīng)在棉花糖中被使用了噪馏。我們沒有退路麦到。我們現(xiàn)在唯一能做的就是保證app適配新權(quán)限模型.
欣慰的是只有少數(shù)權(quán)限需要運行時權(quán)限模型。大多數(shù)常用的權(quán)限逝薪,例如隅要,網(wǎng)絡(luò)訪問蝴罪,屬于Normal Permission 在安裝時自動會授權(quán)董济,當(dāng)然你要聲明,以后無需檢查要门。因此虏肾,只有少部分代碼你需要修改。
兩個建議:

  1. 嚴肅對待新權(quán)限模型
  2. 如果你代碼沒支持新權(quán)限欢搜,不要設(shè)置targetSdkVersion 23 封豪。尤其是當(dāng)你在Studio新建工程時,不要忘了修改炒瘟!

說一下代碼修改吹埠。這是大事,如果代碼結(jié)構(gòu)被設(shè)計的不夠好疮装,你需要一些很蛋疼的重構(gòu)缘琅。每個app都要被修正。如上所說廓推,我們沒的選擇。。堡掏。
列出所有你需要請求的權(quán)限所有情形,如果A被授權(quán)堆生,B被拒絕,會發(fā)生什么雷酪。blah淑仆,blah。
祝重構(gòu)順利哥力。把它列為你需要做的大事糯景,從現(xiàn)在就開始著手做,以保證M正式發(fā)布的時候沒有問題省骂。
希望本文對你有用蟀淮,快樂編碼!

另一篇:在Android 6.0 設(shè)備上動態(tài)獲取權(quán)限


譯文來自 http://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
翻譯摘錄來自 http://jijiaxin89.com/2015/08/30/Android-s-Runtime-Permission/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钞澳,一起剝皮案震驚了整個濱河市怠惶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轧粟,老刑警劉巖策治,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兰吟,居然都是意外死亡通惫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門混蔼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來履腋,“玉大人,你說我怎么就攤上這事惭嚣∽窈” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵晚吞,是天一觀的道長延旧。 經(jīng)常有香客問我,道長槽地,這世上最難降的妖魔是什么迁沫? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮捌蚊,結(jié)果婚禮上集畅,老公的妹妹穿的比我還像新娘。我一直安慰自己逢勾,他們只是感情好牡整,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著溺拱,像睡著了一般逃贝。 火紅的嫁衣襯著肌膚如雪谣辞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天沐扳,我揣著相機與錄音泥从,去河邊找鬼。 笑死沪摄,一個胖子當(dāng)著我的面吹牛躯嫉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杨拐,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼祈餐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哄陶?” 一聲冷哼從身側(cè)響起帆阳,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屋吨,沒想到半個月后蜒谤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡至扰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年鳍徽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敢课。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡阶祭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出翎猛,到底是詐尸還是另有隱情胖翰,我是刑警寧澤接剩,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布切厘,位于F島的核電站,受9級特大地震影響懊缺,放射性物質(zhì)發(fā)生泄漏疫稿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一鹃两、第九天 我趴在偏房一處隱蔽的房頂上張望遗座。 院中可真熱鬧,春花似錦俊扳、人聲如沸途蒋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽号坡。三九已至懊烤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宽堆,已是汗流浹背腌紧。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畜隶,地道東北人壁肋。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像籽慢,于是被迫代替她去往敵國和親浸遗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

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