谷歌支付匯總

google支付分為訂閱和應(yīng)用內(nèi)購買兩種侣诵,這里使用的是應(yīng)用內(nèi)購買這種方式,這里將整個(gè)google支付和支付驗(yàn)證的流程記錄下來。

注意項(xiàng):
前端需要商品ID調(diào)起支付
后端需要獲取token歇父,使用token去Google三方鏈接驗(yàn)證訂單

前端 導(dǎo)入google結(jié)算庫

google結(jié)算服務(wù)接入地址

def billing_version = "4.0.0"
implementation "com.android.billingclient:billing-ktx:$billing_version"

接入支付

流程:

  1. 初始化鏈接到google支付服務(wù)河狐,如果不能鏈接到說明設(shè)備環(huán)境有問題库说,要么是沒有翻墻,要么是google套件(google paly 躏结、server)沒有安裝完整,國內(nèi)手機(jī)都是閹割過的狰域,所以需要重新安裝google套件
  2. 查詢上次未消費(fèi)的商品媳拴,如果有未消費(fèi)的商品通知服務(wù)器,然后消費(fèi)掉兆览。因?yàn)閲獾闹Ц董h(huán)境和國內(nèi)不一樣屈溉,他們可以線上下單,然后到便利店去支付抬探,所以有未消費(fèi)的這種情況子巾。
    這時(shí)google支付的準(zhǔn)備工作已完成,下面就可以發(fā)起支付了
  3. 使用google后臺(tái)配置商品id進(jìn)行支付
  4. 支付完成后通知服務(wù)器驗(yàn)證訂單合法性并發(fā)貨
  5. 客戶端消費(fèi)商品

下面咋們上代碼

step1
初始化并連接到google服務(wù)

    // init方法
    public synchronized void init(Activity mActivity){
        //創(chuàng)建BillingClient 對(duì)面小压,查詢 消費(fèi)  支付都會(huì)使用這個(gè)對(duì)象
        this.mBillingClient = BillingClient.newBuilder(mActivity)
                .setListener(new PurchasesUpdatedListener() {//設(shè)置支付回調(diào)线梗,這里其實(shí)是商品狀態(tài)發(fā)生變化時(shí)就會(huì)回調(diào)
                    @Override
                    public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
                        LogUtils.d("call onPurchasesUpdated");
                        if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {//支付成功
                            for (Purchase purchase : purchases) {
                                if(purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) continue;
                                OrderManager.getInstance().paySuccess(purchase);
                                //通知服務(wù)器支付成功,服務(wù)端驗(yàn)證后怠益,消費(fèi)商品
                            }
                            //TODO客戶端同步回調(diào)支付成功
                        } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {//支付取消

                        } else {//支付失敗
                        }
                    }
                })
                .enablePendingPurchases()
                .build();
        //鏈接到google play
        this.connectBillPay();
    }       

    private void connectBillPay(){
        mBillingClient.startConnection(new BillConnectListener());
    }

    class BillConnectListener implements BillingClientStateListener {

        @Override
        public void onBillingSetupFinished(BillingResult billingResult) {
            if (billingResult.getResponseCode() ==  BillingClient.BillingResponseCode.OK) {
                //鏈接到google服務(wù)
                payEnable = true;
                queryPurchases();
            }
        }

        @Override
        public void onBillingServiceDisconnected() {
            //未鏈接到google服務(wù)
            payEnable = false;
            connectBillPay();
        }
    }

setp2
查詢已支付的商品仪搔,并通知服務(wù)器后消費(fèi)(google的支付里面,沒有消費(fèi)的商品蜻牢,不能再次購買)

    private void queryPurchases(){
        PurchasesResponseListener mPurchasesResponseListener = new PurchasesResponseListener() {
            @Override
            public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> purchasesResult) {
                if(billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK || purchasesResult == null) return;
                for (Purchase purchase : purchasesResult) {
                    if(purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) continue;
                    OrderManager.getInstance().paySuccess(purchase);
                    //這里處理已經(jīng)支付過的訂單烤咧,通知服務(wù)器去驗(yàn)證
                }
            }
        };
        mBillingClient.queryPurchasesAsync(BillingClient.SkuType.INAPP, mPurchasesResponseListener);
    }

setp3
發(fā)起支付

    /**
     * 
     * @param cpOrder 你自己的訂單號(hào)或者用戶id,用于關(guān)聯(lián)到對(duì)應(yīng)的用戶抢呆,發(fā)放道具時(shí)使用
     * @param productId google后臺(tái)配置產(chǎn)品ID
     */
    public void pay(final String cpOrder, final String productId) {
        if(mBillingClient == null || wrActivity.get() == null || !payEnable){
             //TODO客戶端同步回調(diào)支付失敗煮嫌,原因是為鏈接到google或者google的支付服務(wù)不能使用
            return;
        }
        //查詢商品詳情
        querySkuDetailsAsync(cpOrder, productId);
    }

     //查詢商品詳情
    void querySkuDetailsAsync(final String cpOrder, final String productId){
        List<String> skuList = new ArrayList<>();
        skuList.add(productId);
        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
        mBillingClient.querySkuDetailsAsync(params.build(),
                new SkuDetailsResponseListener() {
                    @Override
                    public void onSkuDetailsResponse(BillingResult billingResult,
                                                     List<SkuDetails> skuDetailsList) {
                        if (skuDetailsList != null && billingResult.getResponseCode() ==  BillingClient.BillingResponseCode.OK){
                            for(SkuDetails skuDetails : skuDetailsList){
                                if(productId.equals(skuDetails.getSku())){
                                    //發(fā)起支付
                                    launchBillingFlow(cpOrder, skuDetails);
                                }
                            }
                        }
                    }
                });
    }

  //吊起google支付頁面
    void launchBillingFlow(String cpOrder, SkuDetails skuDetails){
        mBillingClient.launchBillingFlow(
        wrActivity.get(),
        BillingFlowParams
                .newBuilder()
                .setSkuDetails(skuDetails)
                .setObfuscatedAccountId(cpOrder)//這里本來的意思存放用戶信息,類似于國內(nèi)的透傳參數(shù)镀娶,我這里傳的我們的訂單號(hào)立膛。老版本使用DeveloperPayload字段,最新版本中這個(gè)字段已不可用了
                .build()
        );
    }

服務(wù)器支付驗(yàn)證操作較為復(fù)雜,咋們?cè)谙旅鎲为?dú)提出來做一個(gè)小節(jié)

setp5
消費(fèi)商品

    public void consumePurchase(final Purchase purchase){
        if(mBillingClient == null || purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) return;
        LogUtils.d("消耗商品:\n商品id:" + purchase.getSkus() + "\n商品OrderId:" + purchase.getOrderId() + "\ntoken:" + purchase.getPurchaseToken());
        LogUtils.d("消耗商品:" + purchase.getAccountIdentifiers().getObfuscatedAccountId());
        ConsumeParams consumeParams = ConsumeParams.newBuilder()
                .setPurchaseToken(purchase.getPurchaseToken())
                .build();
        ConsumeResponseListener listener = new ConsumeResponseListener() {
            @Override
            public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
                if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                    //消費(fèi)失敗將商品重新放入消費(fèi)隊(duì)列
                    OrderManager.getInstance().consumeFinal(purchase);
                    return;
                }
                LogUtils.d("消費(fèi)成功");
            }
        };
        mBillingClient.consumeAsync(consumeParams, listener);
    }

服務(wù)端驗(yàn)證

做服務(wù)端驗(yàn)證前宝泵,需要做一下準(zhǔn)備工作

大致流程:
  1. 創(chuàng)建api項(xiàng)目這個(gè)和登錄用的項(xiàng)目不是同一個(gè)
  2. 開啟Google Play Android Developer API
  3. 設(shè)置oauth同意屏幕(就是拉起開發(fā)者授權(quán)賬號(hào)登錄時(shí)的登錄頁面)
  4. 創(chuàng)建web應(yīng)用的oauth客戶端ID
  5. 拉起授權(quán)頁面好啰,使用google開發(fā)者賬號(hào)給項(xiàng)目授權(quán),得到code
  6. 創(chuàng)建谷歌賬號(hào)儿奶,并開通開發(fā)者權(quán)限框往,需要支付25美元
  7. google play開發(fā)者后臺(tái)闯捎,API權(quán)限菜單中關(guān)聯(lián)剛剛創(chuàng)建的項(xiàng)目椰弊,一個(gè)google play賬號(hào)只需要也只能關(guān)聯(lián)一個(gè)api項(xiàng)目就行了,這個(gè)項(xiàng)目可以查詢關(guān)聯(lián)賬號(hào)中的所有應(yīng)用的訂單
  8. 通過code瓤鼻,拿到refreshToken秉版,這個(gè)token只有第一次才會(huì)返回需要永久儲(chǔ)存(這個(gè)refreshtoken很重要,需要保存下來)茬祷,如果弄丟清焕,只有重新創(chuàng)建一個(gè)oauth客戶端ID,然后重復(fù)步驟5祭犯,拿到新的refreshtoken(如果確認(rèn)信息沒有填寫錯(cuò)誤秸妥,仍舊提示clinet錯(cuò)誤,可以新創(chuàng)建一個(gè)客戶端ID沃粗,重復(fù)步驟5)
  9. 創(chuàng)建付款資料 完善收款信息
  10. 查詢訂單狀態(tài)前粥惧,需要先去申請(qǐng)產(chǎn)品ID和支付金額,支付是根據(jù)產(chǎn)品ID進(jìn)行支付 最盅。在此之前突雪,需要先創(chuàng)建付款資料
  11. 刷新refreshToken, 得到accessToken檩禾,通過accesstoken就可以去查詢訂單狀態(tài)了
  12. 回調(diào)查詢訂單狀態(tài)

上操作截圖

setp1
創(chuàng)建api項(xiàng)目google api console

image

setp2
開啟Google Play Android Developer API

image
image

搜索“Google Play Android Developer API”

image

開啟“Google Play Android Developer API”

image

setp3
開啟同意屏幕

image

這里填上必填項(xiàng)就行了挂签,這個(gè)授權(quán)同意屏幕,請(qǐng)求code時(shí)拉起來給咋們開發(fā)人員開的盼产,填啥都無所謂

setp4
創(chuàng)建oauth2客戶端id

image

創(chuàng)建頁面和創(chuàng)建成功后的修改頁面可以獲取到clientId和clientSecret

image

到這里api項(xiàng)目就已經(jīng)創(chuàng)建好了

setp5
獲取code
地址:https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri={填寫的重定向地址}&client_id={創(chuàng)建的clientId}
將上面的{XX}替換成創(chuàng)建api項(xiàng)目時(shí)填寫的重定向地址饵婆,和clientId,然后將連接放到瀏覽器中打開戏售,就會(huì)吊起授權(quán)界面侨核,使用你的開發(fā)者賬號(hào)授權(quán)登錄
請(qǐng)求方式:瀏覽器中打開

image
image

這里可以看到,重定向地址上有兩個(gè)參數(shù)code和scope灌灾,我們只需要code就行了搓译,這里的code是urlencode后的,使用時(shí)需要decode

setp6
創(chuàng)建谷歌賬號(hào)锋喜,并開通開發(fā)者權(quán)限(https://play.google.com/console/signup)些己,需要支付25美元豌鸡。

setp7
google play后臺(tái)關(guān)聯(lián)api項(xiàng)目

image

setp8
使用code換取refreshToken
地址:https://accounts.google.com/o/oauth2/token
請(qǐng)求方式:post
參數(shù):grant_type=authorization_code
code=獲取到的code(需要看看code中是否有%號(hào),如果有需要urldecode)
client_id=創(chuàng)建api項(xiàng)目是的clientId(客戶端ID)
client_secret=創(chuàng)建api項(xiàng)目時(shí)的clientSecret(客戶端密鑰)
redirect_uri=創(chuàng)建api項(xiàng)目時(shí)的重定向地址

image

這里就獲取到refreshToken了段标,重點(diǎn)重點(diǎn)重點(diǎn)涯冠,refreshToken保存下來,它只會(huì)在第一次請(qǐng)求中返回逼庞,后續(xù)用在發(fā)一樣的請(qǐng)求不會(huì)返回refreshtoken蛇更,如果不慎弄丟了,需要去重新創(chuàng)建一個(gè)WebClientId

setp9
進(jìn)入gooleplay管理后臺(tái) 創(chuàng)建付款資料 完善收款信息

lQLPDhtBotn-LwzNA0nNBkSwF1WGbraApR8CPDYhHUBGAA_1604_841.png

image.png

setp10

image.png

setp11
使用refreshToken獲取accessToken
地址:https://accounts.google.com/o/oauth2/token
請(qǐng)求方式:post
參數(shù):grant_type=refresh_token
refresh_token=剛剛獲取到的refreshToken
client_id=創(chuàng)建api項(xiàng)目是的clientId(客戶端ID)
client_secret=創(chuàng)建api項(xiàng)目時(shí)的clientSecret(客戶端密鑰)

image

setp12
查詢訂單狀態(tài)
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}?access_token={access_token}
packageName:app包名赛糟,必須是創(chuàng)建登錄api項(xiàng)目時(shí)派任,創(chuàng)建android客戶端Id使用包名
productId:對(duì)應(yīng)購買商品的商品ID
token:購買成功后Purchase對(duì)象的getPurchaseToken()
access_token:上面咋們獲取到的accessToken
請(qǐng)求方式:get
返回值:

{
  "purchaseTimeMillis": "1623980699933",//購買產(chǎn)品的時(shí)間,自紀(jì)元(1970 年 1 月 1 日)以來的毫秒數(shù)璧南。
  "purchaseState": 0,//訂單的購買狀態(tài)掌逛。可能的值為:0\. 已購買 1\. 已取消 2\. 待定
  "consumptionState": 0,//產(chǎn)品的消費(fèi)狀態(tài)穆咐〔鳎可能的值為: 0\. 尚未消耗 1\. 已消耗
  "developerPayload": "",
  "orderId": "GPA.3398-6726-1036-80298",//google訂單號(hào)
  "purchaseType": 0,
  "acknowledgementState": 0,
  "kind": "androidpublisher#productPurchase",
  "obfuscatedExternalAccountId": "SDK2106180944530041",//上面客戶支付時(shí)的透傳字段字旭,google指導(dǎo)是用來存放用戶信息的对湃,不能過長,否則客戶端不能支付
  "obfuscatedExternalProfileId": "",
  "regionCode": "HK"
}

下面附上代碼服務(wù)端獲取accessToken和驗(yàn)證訂單代碼

<?php
namespace app\api\controller\v1;
use app\api\controller\Base;
use service\ApiReturn;

/**
 * 支付簽名接口
 * Class UserLabel
 * @package app\api\controller\v1
 */
class Googlepay extends Base
{
    protected $refreshToken = '';
    protected $client_id = '';
    protected $client_secret = '';
    /**
     * 驗(yàn)證google內(nèi)購訂單
     * @param $parsedJson 來自客戶端遗淳,一個(gè)訂單數(shù)據(jù)的JSON字符串
     * @return array
     */
    public function google($post)
    {
        $parsedJson = $post['data'];
        if(empty($parsedJson))   return Apireturn::r(-1,'','數(shù)據(jù)為空');
        $parsedJson = json_decode($parsedJson, true);
        if(empty($parsedJson))   return Apireturn::r(-1,'','數(shù)據(jù)為空');
        //谷歌訂單號(hào)
        $transactionId = $parsedJson['orderId'];
        //訂單號(hào)
        $oid = $parsedJson['obfuscatedAccountId'];
        if(empty($transactionId))   return Apireturn::r(-1,'google訂單號(hào)空');
        if(empty($oid))   return Apireturn::r(-1,'訂單號(hào)空');
        if (!empty($transactionId)) {
            //記錄支付信息
            Order::I()->updateTransId($oid, $transactionId);
        }
        //商品id
        $pid = $parsedJson['productId'];
        $orderToken = $parsedJson['purchaseToken'];
        $packageName = $parsedJson['packageName'];
        //獲取accesstoken
        $accessToken = $this->getAccessToken();
        if ($accessToken) {
             //驗(yàn)證鏈接
            $url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$packageName.'/purchases/products/'.$pid.'/tokens/'.$orderToken.'?access_token='.$accessToken;
            $result = $this->httpCurl($url,'','GET');
            $contents = json_decode($result,true);
            if (!empty($contents)) {
                if (isset($contents['error'])) {
                    return Apireturn::r(-1,'請(qǐng)求的身份驗(yàn)證無效');
                }
                if($contents['consumptionState'] === 0 && $contents['purchaseState'] === 0){
                    //驗(yàn)證成功  購買成功並且沒有消耗  google支付中客戶端如果沒有進(jìn)行消耗是不能再次購買該商品
                    $res = Order::I()->finishPayIos($oid,$transactionId);
                    if($res === true){
                        return Apireturn::r(200,'購買成功');
                    }else {
                        return Apireturn::r(-1,$res);
                    }
                }else{
                    //訂單驗(yàn)證失敗
                    return Apireturn::r(-1,'訂單狀態(tài)有誤');
                }
            }
        } else {
            return Apireturn::r(-1,'TOKEN丟失');
        }
    }
    /**
     * google token
     * @return array
     */
    private function getAccessToken()
    {
        $cacheKey = "google.kanshu.access_token";
        $accessToken = cache($cacheKey);
        if ($accessToken) return $accessToken;
        $url = 'https://accounts.google.com/o/oauth2/token';
        $data['refresh_token'] = $this->refreshToken;
        $data['client_id'] = $this->client_id;
        $data['client_secret'] = $this->client_secret;
        $data['grant_type'] = 'refresh_token';
        $response = $this->httpCurl($url,$data,'POST');
        $result = json_decode($response, true);
        if ($result) {
            if (isset($result['access_token'])) {
                cache($cacheKey,$result['access_token'],$result['expires_in']-10);
                return $result['access_token'];
            }
        }
        return false;
    }
    //curl提交請(qǐng)求
    private function httpCurl($url, $params, $method = 'GET', $header = array(), $multi = false)
    {
        date_default_timezone_set('PRC');
        $opts = array(
            CURLOPT_TIMEOUT => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_HTTPHEADER => $header,
            CURLOPT_COOKIESESSION => true,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_COOKIE  => session_name() . '=' . session_id(),
        );
        /* 根據(jù)請(qǐng)求類型設(shè)置特定參數(shù) */
        switch (strtoupper($method)) {
            case 'GET':
                // $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);  鏈接后拼接參數(shù)  &  非拍柒?
                $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
                break;
            case 'POST':                //判斷是否傳輸文件
                $params                   = $multi ? $params : http_build_query($params);
                $opts[CURLOPT_URL]        = $url;
                $opts[CURLOPT_POST]       = 1;
                $opts[CURLOPT_POSTFIELDS] = $params;
                break;
            default:
                return ApiReturn::r(-1,'','不支持的請(qǐng)求方式');
                throw new Exception('不支持的請(qǐng)求方式!');
        }
        /* 初始化并執(zhí)行curl請(qǐng)求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        if ($error) {
            return ApiReturn::r(-1,'','請(qǐng)求發(fā)生錯(cuò)誤'.$error);
            throw new Exception('請(qǐng)求發(fā)生錯(cuò)誤:' . $error);
        }
        return $data;
    }
}

寫在最后

  • 這是本人借鑒頂部幾位 并對(duì)接后總結(jié)出來的大致文檔
  • 如有什么描述不夠清楚 可以回到頂部查看引用的其他幾位的文章

錯(cuò)誤1:此版本的應(yīng)用未配置為通過GooglePlay結(jié)算屈暗。有關(guān)詳情拆讯,請(qǐng)?jiān)L問幫助中心。
app內(nèi)錯(cuò)誤截圖

出現(xiàn)問題原因
是打包的時(shí)候养叛,versionCode的值比提交到google play后臺(tái)的版本要高种呐。
打包的時(shí)候,和google play后臺(tái)上的包的簽名不一致弃甥,APK與發(fā)布證書一起簽署爽室。(重要提示:使用“Google Play應(yīng)用程序簽名”時(shí),只有直接從Google PlayStore下載才有效淆攻!
登錄測試機(jī)已登錄谷歌賬號(hào)阔墩,并已添加到谷歌測試賬號(hào)中,添加地址 https://play.google.com/apps/testing/包名
確認(rèn)賬號(hào)信息里可用于測試的Gmail賬號(hào)里瓶珊,已添加測試賬號(hào)啸箫。

錯(cuò)誤2:應(yīng)用內(nèi)無法查詢商品id,無法吊起支付窗口
一定要等你的應(yīng)用為Published狀態(tài)之后伞芹,并且創(chuàng)建了應(yīng)用內(nèi)商品為已激活狀態(tài)忘苛,在app里面才能查到商品id,執(zhí)行支付等操作,否則怎么樣都查不到

應(yīng)用已經(jīng)發(fā)布了扎唾,但是還是吊不起支付窗口
首先app需要安裝google三件套蜀肘,不知道怎么安裝的,可以安裝一個(gè)YouTube稽屏,進(jìn)入app后會(huì)自動(dòng)提示你需要安裝google play扮宠,需要vpn,然后一定注意了狐榔,需要在權(quán)限設(shè)置里面坛增,把google play的##允許應(yīng)用在后臺(tái)彈窗界面##這個(gè)權(quán)限打開,一定記得要打開

當(dāng)一切準(zhǔn)備就緒之后薄腻,報(bào):目前還無法在您所在的國家/地區(qū)購買Google Play中的內(nèi)容收捣。這個(gè)因?yàn)樵谥袊辉试S。
網(wǎng)頁登錄你的google賬戶:在設(shè)置里面庵楷,把你的地址改成美國或其他支持的國家罢艾,然后清除app內(nèi)google play的數(shù)據(jù),重新進(jìn)入尽纽,重新選擇地區(qū)(剛才你修改的地區(qū))咐蚯,選完之后會(huì)提示你切換到美國的商店,然后再添加付款信息(中國的卡就行弄贿,我用的是招商銀行的信用卡)春锋,這樣就萬事大吉了,之后就可以正常支付了差凹。

錯(cuò)誤3:In-app billing API version 3 is not supported on this device.
該手機(jī)登錄Google賬號(hào)的問題期奔,或者說是Google賬號(hào)的歸屬地問題,如果之前是ok的危尿,突然報(bào)這樣的的問題呐萌,重啟,重啟谊娇,重啟 7喂隆!邮绿!包括電腦渠旁。至于哪些地方不能使用,我沒有足夠的賬號(hào)數(shù)據(jù)支撐船逮」死埃或許咱們能做的是在產(chǎn)品角度,給出相應(yīng)提示挖胃,例如更換賬號(hào)啥的杂靶。

錯(cuò)誤4:signInResult:failed code=12501
先檢查網(wǎng)絡(luò)是否墻了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梆惯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吗垮,更是在濱河造成了極大的恐慌垛吗,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烁登,死亡現(xiàn)場離奇詭異怯屉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)饵沧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門锨络,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狼牺,你說我怎么就攤上這事羡儿。” “怎么了是钥?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵掠归,是天一觀的道長。 經(jīng)常有香客問我悄泥,道長虏冻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任码泞,我火速辦了婚禮兄旬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘余寥。我一直安慰自己,他們只是感情好悯森,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布宋舷。 她就那樣靜靜地躺著,像睡著了一般瓢姻。 火紅的嫁衣襯著肌膚如雪祝蝠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天幻碱,我揣著相機(jī)與錄音绎狭,去河邊找鬼。 笑死褥傍,一個(gè)胖子當(dāng)著我的面吹牛儡嘶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恍风,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蹦狂,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼誓篱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凯楔,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤窜骄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后摆屯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邻遏,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年虐骑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了党远。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡富弦,死狀恐怖沟娱,靈堂內(nèi)的尸體忽然破棺而出团搞,到底是詐尸還是另有隱情同蜻,我是刑警寧澤逝变,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布达皿,位于F島的核電站腾供,受9級(jí)特大地震影響疹启,放射性物質(zhì)發(fā)生泄漏磅网。R本人自食惡果不足惜虱岂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一唉铜、第九天 我趴在偏房一處隱蔽的房頂上張望台舱。 院中可真熱鬧,春花似錦潭流、人聲如沸竞惋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拆宛。三九已至,卻和暖如春讼撒,著一層夾襖步出監(jiān)牢的瞬間浑厚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工根盒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钳幅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓炎滞,卻偏偏與公主長得像敢艰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厂榛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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