如何在復(fù)雜業(yè)務(wù)場景中優(yōu)雅實(shí)現(xiàn)Android指紋驗證玖瘸?

前言

目前指紋領(lǐng)域無論從產(chǎn)品角度還是技術(shù)角度都已經(jīng)趨于成熟杰捂,但是當(dāng)各位開發(fā)者準(zhǔn)備深入探究的時候舆床,卻發(fā)現(xiàn)網(wǎng)上很多文章都是皮毛,很難有較深的啟示琼娘。本文將著重介紹指紋驗證開發(fā)整個過程峭弟,包括技術(shù)選型附鸽、產(chǎn)品的設(shè)計方案邏輯脱拼、代碼的架構(gòu)以及后續(xù)測試中遇到的兼容性問題等幾個方面。在這里拋磚引玉坷备,希望能給予大家一些啟發(fā)熄浓。

技術(shù)選型

產(chǎn)品:咱們 Android 端能做指紋驗證嗎?
開發(fā):不能省撑,一堆兼容問題赌蔑。
產(chǎn)品:咱們 Android 端能做指紋驗證嗎?
開發(fā):不能竟秫,一堆兼容問題娃惯。
產(chǎn)品:咱們 Android 端能做指紋驗證嗎?
開發(fā):不能肥败,一堆兼容問題趾浅。
產(chǎn)品:咱們 Android 端能做指紋驗證嗎?
開發(fā):我……我試試吧……

著手調(diào)研馒稍,開發(fā)前肯定先拿市面上競品的功能來瞧瞧皿哨。我們同比了支付寶、微信支付和招商App纽谒。

產(chǎn)品:怎么支付寶和微信就沒兼容問題了证膨?

開發(fā):那是因為支付寶和騰迅有自己的協(xié)議!(一聽怎么XXX支持鼓黔,怎么XXX沒問題央勒,升起無名火)這個標(biāo)準(zhǔn)直接和設(shè)備廠商合作不见,而應(yīng)用方只有微信和支付寶自己。支付寶指紋支付標(biāo)準(zhǔn)是 IFAA 订歪,騰訊的指紋支付標(biāo)準(zhǔn)是 SOTER脖祈,也就是說沒有其他應(yīng)用方會使用這個標(biāo)準(zhǔn)。所以很看應(yīng)用方和設(shè)備廠商的協(xié)商程度∷⒔現(xiàn)在 IFAA 沒有開源盖高,只有 SOTER 是開源的了,如果接入眼虱,我們能省去兼容性測試的工作量喻奥,而且有些 6.0 以下的機(jī)型 SOTER 也支持。還有D笮(星星眼)每個指紋將會有唯一 ID撞蚕,也就是說,我們能把賬號和指紋綁定起來过牙,更加安全甥厦。

產(chǎn)品:不行不行!這 SOTER 壓根沒支持華為寇钉,華為用戶是我們的主要用戶群刀疙,而且以后機(jī)型的擴(kuò)展受第三方支持的限制。

開發(fā):之前小米和華為就沒有支持 SOTER 標(biāo)準(zhǔn)扫倡,現(xiàn)在小米是支持了谦秧,華為不見得會支持,因為 SOTER 和廠商合作撵溃,出廠的時候就將私鑰存儲在 TEE 中疚鲤,華為目前多 TEE 系統(tǒng)開發(fā)尚未成熟,只能支持一個 TEE 缘挑,顯然華為不愿意將唯一的 TEE 交給騰訊掌控集歇。其他手機(jī)廠商一般使用高通或第三方的 TEE 系統(tǒng)方案,這些系統(tǒng)目前都支持多 TEE 運(yùn)行環(huán)境语淘,即使將其中一個 TEE 的公共密鑰交給騰訊運(yùn)營诲宇,并不影響手機(jī)廠商運(yùn)營自己的 TEE 平臺。

產(chǎn)品:不接入了亏娜,我們用 Google API焕窝。

開發(fā):那好,來制定下條件先:

  1. 設(shè)備硬件不支持直接沒得玩
  2. 手機(jī)要有除了指紋外的安全認(rèn)證方式(比如密碼维贺、圖案) 它掂,這是安卓系統(tǒng)的雙重鎖規(guī)則。
  3. 用戶手機(jī)至少錄入了一個指紋,沒錄入指紋說明平時沒有用過指紋驗證功能虐秋,這種用戶我們就不管了榕茧。
  4. 使用 Google API,不管什么情況客给,只要驗證的指紋是系統(tǒng)指紋列表里存在的用押,就驗證通過,Google API 是沒有提供指紋唯一ID的靶剑,所以想要根據(jù)本機(jī)上的指紋索引來區(qū)別不同手指無法做到蜻拨,也就無法實(shí)現(xiàn)指紋和賬號綁定。
  5. 僅支持 Android 6.0 以上系統(tǒng)桩引,Google 官方支持指紋識別的標(biāo)準(zhǔn)接口是在 Android6.0 開始的缎讼,如果廠商在這之前就已經(jīng)做了指紋識別,那我們就不管了坑匠。(開發(fā)者也可以使用廠商提供的第三方指紋識別SDK)

產(chǎn)品:(點(diǎn)頭)可以血崭,開干吧!用 Google API 兼容性問題處理和測試量較大厘灼,所以我們支持的機(jī)型做成可配置夹纫,控制風(fēng)險。第一期先支持幾個機(jī)型设凹。

2018.12.10 更新
SOTER 已支持部分華為機(jī)型SOTER 支持機(jī)型 wiki

架構(gòu)

好了舰讹,demo 寫完了,看下了產(chǎn)品文檔围来。啥跺涤?場景這么復(fù)雜匈睁?监透!分支繁多,還需要結(jié)合到之前存在的手勢驗證功能(用戶有兩種安全方式可選:指紋驗證和手勢驗證)航唆。

業(yè)務(wù)場景有四個:

  1. 冷啟動app的指紋驗證
  2. 切換賬號登陸后的引導(dǎo)設(shè)置
  3. 在設(shè)置頁用戶手動開啟指紋登陸
  4. 設(shè)置頁手動關(guān)閉指紋登陸

每一次驗證的狀態(tài)胀蛮,都會通過 AuthenticationCallback 回調(diào),我們可以理解為是指紋驗證的生命周期糯钙。

public class MyAuthCallback extends FingerprintManagerCompat.AuthenticationCallback {

        @Override
        public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
            super.onAuthenticationSucceeded(result);
        }

        @Override
        public void onAuthenticationError(int errMsgId, CharSequence errString) {
            //驗證過程中遇到不可恢復(fù)的錯誤
            super.onAuthenticationError(errMsgId, errString);
        }

        @Override
        public void onAuthenticationFailed() {
            super.onAuthenticationFailed();
        }

        @Override
        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
            //驗證過程中遇到可恢復(fù)錯誤
            super.onAuthenticationHelp(helpMsgId, helpString);
        }
    }

onAuthenticationSucceeded 和 onAuthenticationError 的回調(diào)意味著本次的認(rèn)證結(jié)束粪狼,會根據(jù)當(dāng)前所處業(yè)務(wù)場景給予用戶不同的引導(dǎo)。

而 onAuthenticationFailed 和 onAuthenticationHelp 的情況任岸,四個業(yè)務(wù)場景都是一樣的再榄,都是在界面上提示用戶,我們可以合并一起處理享潜。

所以我們根本不需要一個業(yè)務(wù)場景就對應(yīng)一個 AuthenticationCallback 回調(diào)類困鸥,我們可以只用一個 AuthenticationCallback 回調(diào)類來根據(jù)當(dāng)前所處的業(yè)務(wù)場景分發(fā)行為。但是我又不想在 onAuthenticationSucceeded 和 onAuthenticationError 的回調(diào)中有 Switch 邏輯。所以對于四個場景各不相同的 onAuthenticationSucceeded 和 onAuthenticationError 的回調(diào)方法疾就,我們用狀態(tài)模式來分離澜术,這樣把與特定狀態(tài)相關(guān)的行為局部化,并且將不同場景下的行為分割開來猬腰。(需要給用戶什么提示鸟废,什么操作,包括驗證次數(shù)超限的處理姑荷,取決于當(dāng)前所處的場景狀態(tài))

另外一點(diǎn):需要在運(yùn)行時刻根據(jù)狀態(tài)來改變行為盒延,比如說用戶從一個正常態(tài),轉(zhuǎn)移到驗證過程異呈竺幔或者驗證過程被劫持的狀態(tài)兰英。

驗證過程異常情況,也即是說供鸠,受用戶 root 或自定制情況畦贸,通過測試的同一個機(jī)型有可能驗證過程異常。

驗證過程被劫持楞捂,因為 Google API 只返回 true 或 false薄坏,我們當(dāng)然不能無條件相信這個驗證結(jié)果,所以需要在應(yīng)用內(nèi)產(chǎn)生一對非對稱的密鑰寨闹,保證驗證過程不會被篡改胶坠。如果拿到驗證結(jié)果解密失敗,就進(jìn)入了被劫持的狀態(tài)了繁堡。

驗證過程異常和驗證被劫持的狀態(tài)基本處理一致沈善,都是屬于用戶無法再繼續(xù)驗證的場景,我們可以把這兩個狀態(tài)合為一椭蹄。按照開發(fā)的思路闻牡,有異常,被劫持绳矩,那肯定是失敗了罩润,是吧? 但是按照產(chǎn)品的思路翼馆,其他 3 個業(yè)務(wù)場景按失敗處理割以,但如果是關(guān)閉指紋的場景下(4. 設(shè)置頁手動關(guān)閉指紋登陸),就算是失敗了应媚,也要讓他去關(guān)閉成功严沥,不然可能會出現(xiàn)用戶手機(jī)中途 root 或極端情況下,無法關(guān)閉指紋中姜,從而引起客訴消玄。

按照分析我們可以發(fā)現(xiàn),被劫持和驗證過程異常的情況的處理,依賴于當(dāng)時所處的場景莱找,所以呢酬姆,我們無法把被劫持和驗證過程異常當(dāng)做一個獨(dú)立的狀態(tài)了。只能抽出作為一個公共方法奥溺。

綠色底為 Activity 層辞色,白色底為 Util 層

為了不和業(yè)務(wù)邏輯耦合在一起,工具類包裝了一層浮定,主要封裝了驗證條件的判斷相满,指紋類的初始化等等,最主要的是封裝了加密類 CryptoObjectCreatorHelper 桦卒,我們考慮到安全因素立美,如果不加密的話,就意味著App 無條件信任認(rèn)證的結(jié)果方灾,這個過程可能被攻擊建蹄,數(shù)據(jù)可以被篡改,這是 App 在這種情況下必須承擔(dān)的風(fēng)險裕偿。但是這個加密過程和業(yè)務(wù)是無關(guān)的洞慎,我們不想讓 Activity 層感知到,所以密鑰和加密對象的銷毀嘿棘,會統(tǒng)一由工具類來把控劲腿。

為了安全,每次驗證過程的密鑰都不同鸟妙,驗證過程一結(jié)束焦人,也就是回調(diào) onAuthenticationSucceeded 和 onAuthenticationError 時,都需要銷毀掉密鑰重父,但是我們不想讓業(yè)務(wù)層來操作花椭,所以工具類也有自己的一個 AuthenticationCallback ,在 AuthenticationCallback 里做一些和業(yè)務(wù)無關(guān)的操作坪郭,再回調(diào) Activity 的 AuthenticationCallbackListener 个从。

工具類的 CallBack 是 FingerprintManagerCompat.AuthenticationCallback 實(shí)現(xiàn)類脉幢,業(yè)務(wù)層的 AuthenticationCallbackListener 是自定義接口歪沃,因為不想把和業(yè)務(wù)無關(guān)的往上傳遞,比如說嫌松,驗證成功的 AuthenticationResult 沪曙,驗證錯誤的 typeId,這些業(yè)務(wù)并不關(guān)心萎羔。Activity 的 AuthenticationCallbackListener 會把請求統(tǒng)一轉(zhuǎn)發(fā)給控制器 FingerPrintTypeController液走,在轉(zhuǎn)發(fā)給控制器的前后,我們可以做一些通用的業(yè)務(wù)操作,比如說停止界面的掃描動畫缘眶,發(fā)一些異步的請求等等嘱根,這個就是代理模式的應(yīng)用了。

那控制器 FingerPrintTypeController 和四個場景的關(guān)系又是如何巷懈?我們看看類圖该抒。

可以看到,四個場景顶燕,對應(yīng)四個狀態(tài)類凑保,控制器和狀態(tài)類實(shí)現(xiàn)了同一個接口,在內(nèi)部根據(jù)當(dāng)前場景轉(zhuǎn)發(fā)給對應(yīng)的類涌攻, 那怎么根據(jù)場景轉(zhuǎn)發(fā)給對應(yīng)類欧引?我們建立一個映射表,把場景和類對應(yīng)起來恳谎。每次匹配的話只要 O(1) 復(fù)雜度芝此。

 private interface FingerPrintType {
        void onAuthenticationSucceeded();

        void onAuthenticationError(String content);
    }

 private class LoginAuthType implements FingerPrintType {
        @Override
        public void onAuthenticationSucceeded() { }

        @Override
        public void onAuthenticationError(String content) { }
    }

    private class ClearType implements FingerPrintType {
        @Override
        public void onAuthenticationSucceeded() { }

        @Override
        public void onAuthenticationError(String content) { }
    }

    private class LoginSettingType implements FingerPrintType {
       @Override
        public void onAuthenticationSucceeded() { }

        @Override
        public void onAuthenticationError(String content) { }
    }

    private class SettingType implements FingerPrintType {
        @Override
        public void onAuthenticationSucceeded() { }

        @Override
        public void onAuthenticationError(String content) { }
    }

    private class FingerPrintTypeController implements FingerPrintType {
        private Map<String, FingerPrintType> typeMappingMap = new HashMap<>();

        public FingerPrintTypeController() {
            typeMappingMap.put(GESTURE_FINGER_SETTING, new SettingType());
            typeMappingMap.put(GESTURE_FINGER_LOGIN_SETTING, new LoginSettingType());
            typeMappingMap.put(GESTURE_FINGER_CLEAR, new ClearType());
            typeMappingMap.put(GESTURE_FINGER_LOGIN, new LoginAuthType());
        }

        @Override
        public void onAuthenticationSucceeded() {
            typeMappingMap.get(mType).onAuthenticationSucceeded();
        }

        @Override
        public void onAuthenticationError(String content) {
            typeMappingMap.get(mType).onAuthenticationError(content);
        }
    }

這個時候產(chǎn)品又說了,同樣是異常情況因痛,但是被劫持和異常過程異常的提示文案要不一樣癌蓖,ok,那我們將提示語和操作分離開來婚肆,提示和業(yè)務(wù)場景的對應(yīng)關(guān)系也預(yù)先緩存在 Map 里租副,直接 get 獲取具體提示,作為參數(shù)傳入就可以了较性。

      //普通異常情況提示
        exceptionTipsMappingMap = new HashMap<>();
        exceptionTipsMappingMap.put(GESTURE_FINGER_SETTING, getString(R.string.fingerprint_no_support_fingerprint_gesture));
        exceptionTipsMappingMap.put(GESTURE_FINGER_LOGIN_SETTING, getString(R.string.fingerprint_no_support_fingerprint_gesture));
        exceptionTipsMappingMap.put(GESTURE_FINGER_CLEAR, null);
        exceptionTipsMappingMap.put(GESTURE_FINGER_LOGIN, getString(R.string.fingerprint_no_support_fingerprint_account));

兼容問題

1. 明明符合條件用僧,isHardwareDetected() 返回 false?

表現(xiàn)機(jī)型:MI 5s赞咙、vivo X9

在同一機(jī)型上調(diào)用 FingerprintManagerCompat 的 isHardwareDetected() 和 hasEnrolledFingerprints() 時候责循,返回的都是 false,但是調(diào)用 FingerprintManager 的 isHardwareDetected()
和 hasEnrolledFingerprints() 時,卻是返回 true攀操。

解決:是否符合指紋條件可以多加一層判斷院仿。

2. Letv X500 Android 6.0,API23 不按正常的套路回調(diào)

onAuthenticationError 和 onAuthenticationFailed,理論上應(yīng)該是識別失敗的情況速和,但是該機(jī)型點(diǎn)擊取消指紋識別也會先回調(diào)一次Error歹垫,如果遇到這種情況,只能根據(jù)具體項目環(huán)境中去進(jìn)行規(guī)避適配了颠放。

3. 魅族上遇到的坑

onAuthenticationHelp 回調(diào)不按套路出牌排惨,正常官網(wǎng)文檔解釋,這個方法的回調(diào)時機(jī)是在指紋認(rèn)證期間發(fā)生可恢復(fù)性的錯誤時回調(diào)碰凶。結(jié)果在魅族上暮芭,啟動指紋識別認(rèn)證的時候就會回調(diào)這個方法鹿驼,里面?zhèn)鬟f回來的信息提示是“等待按下手指”,也就是說辕宏,它的 onAuthenticationHelp 回調(diào)跟官網(wǎng)時機(jī)不一樣畜晰,而且方法的作用也變了,它在正常的情況回調(diào)了 onAuthenticationHelp瑞筐。

解決:不影響驗證流程舷蟀,無需解決

4. 小米 鎖屏和切后臺生命周期不一致

產(chǎn)品需求:用戶鎖屏或切到后臺時(onStop)自動停止指紋驗證,回到界面時(onResume)自動調(diào)起驗證面哼。

所以我在指紋回調(diào)方法中加入了標(biāo)志位 isInAuth野宜。onStop時保存 isInAuth,onResume時 isInAuth == true 則自動調(diào)起驗證魔策。

        @Override
        public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
            isInAuth = false;
        }

        @Override
        public void onAuthenticationError(int errMsgId, CharSequence errString) {
            isInAuth = false;
        }

        @Override
        public void onAuthenticationFailed() {
            isInAuth = true;
        }

        @Override
        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
            isInAuth = true;
        }

然而小米6匈子、米mix2 鎖屏?xí)r的生命周期是 onAuthenticationError -> onStop;切到后臺是 onStop -> onAuthenticationError闯袒。導(dǎo)致不同流程下拿到 isInAuth 標(biāo)志位不一致虎敦,無法自動調(diào)起驗證。

解決:界面指紋按鈕可以手動調(diào)起驗證政敢,無需兼容處理其徙。

小米5生命周期同上,但是無論是自動還是手動調(diào)起驗證喷户,馬上就回調(diào)了 onAuthenticationError唾那,也就是說 MI5 從后臺切回來后,指紋驗證流程中斷褪尝。

解決:用一個棧來存儲調(diào)用方法順序闹获,如果驗證方法調(diào)起,馬上就回調(diào) onAuthenticationError 方法河哑,則判定是屬于兼容問題避诽,按驗證失敗來解決。

5. 密鑰解密失敗

三星SM-A9100 璃谨、Nexus 6P密鑰解密失敗
解決:暫無法解決

其他兼容解決方案:

  • 三星passSdk(不過從2018下半年開始沙庐,Pass SDK 將不再提供 DEVICE_FINGERPRINT_UNIQUE_ID 。也就是不再為每個已注冊的指紋提供索引了佳吞。因此將無法通過 SDK 區(qū)分使用哪個指紋來驗證用戶拱雏。)
  • 魅族 flyme開發(fā)平臺提供了指紋驗證官方api

非兼容問題

1. 新注冊指紋密鑰解密失敗

系統(tǒng)中注冊了一個新的指紋的情況下,即使指紋在系統(tǒng)指紋列表里容达,驗證也不通過古涧。
解決:刪除了當(dāng)前無效的key,然后根據(jù)參數(shù)再次生成密鑰花盐。

 @Override
        public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
            ...
            /**
             * doFinal方法會檢查結(jié)果是不是會攔截或者篡改過羡滑,
             * 如果是的話會拋出一個異常,異常的時候都將認(rèn)證當(dāng)做是失敗來處理
             */
            try {
                result.getCryptoObject().getCipher().doFinal();
                mCustomCallback.onAuthenticationSucceeded(true);
            } catch (IllegalBlockSizeException e) {
                //如果是新錄入的指紋算芯,會拋出該異常柒昏,需要重新生成密鑰對重新驗證,這里加個次數(shù)限制熙揍,避免進(jìn)入驗證異常->重新驗證->又驗證異常的死循環(huán)
                if (happenCount == 0) {
                    beginAuthenticate();
                    happenCount++;
                    return;
                }
                mCustomCallback.onAuthenticationSucceeded(false);
            } catch (Exception e) {
                mCustomCallback.onAuthenticationSucceeded(false);
            }
           ...
        }
2. 設(shè)備已有指紋职祷,生成密鑰卻異常提示沒有指紋

非復(fù)現(xiàn),和設(shè)備無關(guān)届囚,懷疑是谷歌 API 的坑有梆。

java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use

解決:暫時只想到針對這個特定異常,直接使用無密鑰驗證意系,有一定的安全風(fēng)險泥耀,有更好方案歡迎補(bǔ)充。

本文完整 Demo 地址
Demo 僅供參考架構(gòu)和兼容處理蛔添,如果后續(xù)接入魅族和三星 SDK痰催,可以考慮用策略模式替換Goolge API。


更新:

Android P 引入了若干可提升應(yīng)用和運(yùn)行應(yīng)用的設(shè)備安全性的功能迎瞧。
其中一項:


我是 FeelsChaotic夸溶,一個寫得了代碼 p 得了圖,剪得了視頻畫得了畫的程序媛凶硅,致力于追求代碼優(yōu)雅缝裁、架構(gòu)設(shè)計和 T 型成長。

歡迎關(guān)注 FeelsChaotic 的簡書掘金足绅,如果我的文章對你哪怕有一點(diǎn)點(diǎn)幫助压语,歡迎 ??!你的鼓勵是我寫作的最大動力编检!

最最重要的胎食,請給出你的建議或意見,有錯誤請多多指正允懂!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厕怜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蕾总,更是在濱河造成了極大的恐慌粥航,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件生百,死亡現(xiàn)場離奇詭異递雀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚀浆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門缀程,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搜吧,“玉大人,你說我怎么就攤上這事杨凑÷四危” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵撩满,是天一觀的道長蜒程。 經(jīng)常有香客問我,道長伺帘,這世上最難降的妖魔是什么昭躺? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮伪嫁,結(jié)果婚禮上领炫,老公的妹妹穿的比我還像新娘。我一直安慰自己礼殊,他們只是感情好驹吮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晶伦,像睡著了一般碟狞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婚陪,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天族沃,我揣著相機(jī)與錄音,去河邊找鬼泌参。 笑死脆淹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沽一。 我是一名探鬼主播盖溺,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼铣缠!你這毒婦竟也來了烘嘱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蝗蛙,失蹤者是張志新(化名)和其女友劉穎蝇庭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捡硅,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哮内,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壮韭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片北发。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡纹因,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鲫竞,到底是詐尸還是另有隱情辐怕,我是刑警寧澤逼蒙,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布从绘,位于F島的核電站,受9級特大地震影響是牢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一踪少、第九天 我趴在偏房一處隱蔽的房頂上張望哆窿。 院中可真熱鬧,春花似錦社搅、人聲如沸驻债。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽合呐。三九已至,卻和暖如春笙以,著一層夾襖步出監(jiān)牢的瞬間淌实,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工猖腕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拆祈,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓倘感,卻偏偏與公主長得像放坏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子老玛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,504評論 25 707
  • 最近項目需要使用到指紋識別的功能淤年,查閱了相關(guān)資料后,整理成此文逻炊。 指紋識別是在Android 6.0之后新增的功能...
    湫水長天閱讀 3,720評論 2 46
  • Apple Pay自推出以來就備受關(guān)注余素,很多朋友非潮荩看好其前景,不過其安全性也受到更多人的關(guān)注桨吊,畢竟這是關(guān)乎大家錢...
    餅哥阿杜閱讀 1,758評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理威根,服務(wù)發(fā)現(xiàn)凤巨,斷路器,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 不是遠(yuǎn)足才能看到的幽靜洛搀, 不是被矚目才會綻放的明靜敢茁。 我想要成為那一灣水, 順風(fēng)到江里留美,順風(fēng)到海中…… 有不經(jīng)風(fēng)的...
    棲風(fēng)慢閱讀 211評論 0 1