iOS內(nèi)購(gòu)(InAppPurchase)的一些操作筆記

1.蘋(píng)果官網(wǎng)的配置

a.創(chuàng)建一種商品類目,選擇對(duì)應(yīng)的價(jià)格,添加一種描述,這種描述在支付的時(shí)候會(huì)彈出,沙盒測(cè)試的時(shí)候可體驗(yàn),這種商品會(huì)有一個(gè)對(duì)應(yīng)的id

ipa2.png

b.添加一個(gè)沙盒賬號(hào),一般使用一個(gè)不常用的郵箱,這個(gè)郵箱和apple賬號(hào)無(wú)關(guān),只要這個(gè)郵箱能收到驗(yàn)證碼就能綁定成功,沙盒賬號(hào)就是這個(gè)郵箱,密碼自己隨便設(shè)置


ipa1.png

2.需要熟悉的一些流程上的東西(20210817補(bǔ)充)

1.用戶選擇商品
客戶端記錄用戶選擇的商品對(duì)應(yīng)的Apple的唯一標(biāo)識(shí)符并向自己公司的服務(wù)端請(qǐng)求接口來(lái)創(chuàng)建訂單,
請(qǐng)求參數(shù)是價(jià)格,和對(duì)應(yīng)的商品的在Apple端的唯一標(biāo)識(shí)
服務(wù)端返回的數(shù)據(jù)包含訂單號(hào)orderId,客戶端記錄這個(gè)orderId

2.客戶端檢測(cè)用戶當(dāng)前設(shè)備是否允許內(nèi)購(gòu)

3.客戶端將當(dāng)前App所有的商品類目列表信息發(fā)送給Apple服務(wù)端,request start,Apple服務(wù)端返回可用的商品列表,payment.applicationUsername最好使用的是自己服務(wù)器的orderId

4.客戶端遍歷Apple服務(wù)端返回的商品列表,判斷第1步中記錄的商品唯一標(biāo)識(shí)符是否存在于第3步Apple返回的商品列表中

5.客服端使用蘋(píng)果提供的方法發(fā)起購(gòu)買(mǎi)請(qǐng)求,這時(shí)候需要用戶輸入AppleID的賬號(hào)和密碼,輸入正確后會(huì)走到支付完成的回調(diào)中

6.客戶端檢查,客戶端根據(jù)蘋(píng)果返回的支付回調(diào)的購(gòu)買(mǎi)憑證通過(guò)接口請(qǐng)求向Apple端進(jìn)行驗(yàn)證

7.驗(yàn)證成功之后將購(gòu)買(mǎi)憑證通過(guò)接口發(fā)送給自己公司的服務(wù)端來(lái)表示當(dāng)前訂單已經(jīng)付款了

8.服務(wù)端收到這個(gè)驗(yàn)證請(qǐng)求,再次使用該購(gòu)買(mǎi)憑證向Apple端驗(yàn)證是否已經(jīng)付款

9.公司的服務(wù)端在通過(guò)Apple的服務(wù)端驗(yàn)證完成之后,表示用戶已經(jīng)完成了內(nèi)購(gòu)支付,做虛擬商品發(fā)放,做驗(yàn)證接口的返回處理操作.

需要考慮到的異常情況:
第5步執(zhí)行完之后,如果用戶沒(méi)有來(lái)的及檢查購(gòu)買(mǎi)狀態(tài)和進(jìn)行下一步的操作的時(shí)候,手機(jī)斷電等異常情況出現(xiàn)時(shí),下次打開(kāi)app或者進(jìn)入到充值頁(yè)面時(shí)候,應(yīng)當(dāng)自動(dòng)來(lái)檢測(cè)一下,當(dāng)前用戶是否有正在執(zhí)行中的支付訂單,如果有,則從第6步開(kāi)始繼續(xù)執(zhí)行支付流程

3.擼代碼

控制器里面導(dǎo)入

#import <StoreKit/StoreKit.h>

這里的URL分為兩個(gè),一個(gè)是沙盒用的,一個(gè)是正式用的

//#ifdef DEBUG
//#define yz_AppStore_URL @"https://sandbox.itunes.apple.com/verifyReceipt"
//#else
//#define yz_AppStore_URL @"https://buy.itunes.apple.com/verifyReceipt"
//#endif

沙盒用的驗(yàn)證:就是可以用沙盒賬號(hào)來(lái)購(gòu)買(mǎi),不用實(shí)際話費(fèi)金額,就直接走了購(gòu)買(mǎi)成功的流程

正式用的:需要實(shí)際現(xiàn)金支付

這里要特別注意,一定要保證給AppleStore審核人員用的是用沙盒驗(yàn)證的而不是正式的

而且服務(wù)端的驗(yàn)證方式也需要和移動(dòng)端的驗(yàn)證方式一致

這里說(shuō)下當(dāng)前我們的處理邏輯:

進(jìn)入付款流程的時(shí)候先默認(rèn)是正式的驗(yàn)證url,然后進(jìn)行接口請(qǐng)求,接口返回一個(gè)版本號(hào),這個(gè)版本號(hào)和當(dāng)前的app里面的版本號(hào)做對(duì)比,如果版本號(hào)一致,那么久將驗(yàn)證地址的url改為沙盒的

這樣當(dāng)提交一個(gè)新的版本給蘋(píng)果審核的時(shí)候,將app審核過(guò)后自動(dòng)發(fā)布改為手動(dòng)發(fā)布.

等蘋(píng)果那邊審核通過(guò)之后,先讓服務(wù)端將接口返回的版本號(hào)改成0.0.0(只要不一致就行了)

然后再進(jìn)行手動(dòng)發(fā)布新版本,這樣就保證用戶手里的一定是正式的,審核人員用的就是沙盒的

獲取版本號(hào),對(duì)比之后看是否需要開(kāi)啟沙盒模式驗(yàn)證

基礎(chǔ)操作:


- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    _appleUrl = @"https://buy.itunes.apple.com/verifyReceipt";
    NSString * vFromSelfServer = [self getAppleInfoFromSelfServer];
    NSString * vCurrIPA = @"當(dāng)前安裝包的版本號(hào)";
    if([vFromSelfServer isEqualToString:vCurrIPA]){
//      當(dāng)前安裝包的版本號(hào)和服務(wù)端返回的版本號(hào)一致,就將appleUrl的值改為沙盒驗(yàn)證,因?yàn)檫@種情況下表示app正在被審核中
        _appleUrl = @"https://sandbox.itunes.apple.com/verifyReceipt";
    }

    
//    添加交易監(jiān)聽(tīng)
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    
    [self.view addSubview:self.payLab];

    
}
#pragma mark --------- self server request

/**
 * 用接口從自己服務(wù)器獲取版本號(hào)
 *    1.發(fā)布更新提交審核時(shí)候,從itunes中選項(xiàng)改為手動(dòng)發(fā)布
 *    2.讓服務(wù)端將getAppleInfoFromSelfServer這個(gè)接口返回的版本號(hào)和發(fā)布給蘋(píng)果審核的版本號(hào)一致
 *    3.等待蘋(píng)果審核通過(guò),先讓服務(wù)端將getAppleInfoFromSelfServer的值改一下成無(wú)限大(這里只要不等于線上所有用戶的版本號(hào),也不等于當(dāng)前已審核通過(guò)的版本號(hào)即可)
 *    4.itunes手動(dòng)發(fā)布已審核通過(guò)的ipa包
 */
-(NSString *)getAppleInfoFromSelfServer {
    
    return @"自己服務(wù)器返回的一個(gè)版本號(hào)";
}

當(dāng)用戶點(diǎn)擊了購(gòu)買(mǎi)某個(gè)商品的時(shí)候,調(diào)用自己服務(wù)端接口進(jìn)行訂單創(chuàng)建


-(void)clickPayAction {
//            自己在蘋(píng)果商城申請(qǐng)的類別的ID列表為
           //  bundleid+xxx 就是你添加內(nèi)購(gòu)條目設(shè)置的產(chǎn)品ID
//            zydj.product.pay_6  6元4.2豆
//            zydj.product.pay_40 40元28豆
//            zydj.product.pay_60 60元48豆
//            假設(shè)選中了6元4.2豆則通過(guò)zydj_product_pay_6在自己服務(wù)端創(chuàng)建訂單
            
            self.currentProducId = @"zydj.product.pay_6";
            
            NSString * orderId =  [self creatOrderFromSelfServer:self.currentProducId];
      
            self.orderId = orderId;
            
            [self startInAppPay];
}

/**
 * 創(chuàng)建訂單
 */
-(NSString *)creatOrderFromSelfServer:(NSString *)priceID {
    return @"服務(wù)端根據(jù)priceID返回的一個(gè)orderId";
}

先驗(yàn)證用戶當(dāng)前使用的設(shè)備是否支持內(nèi)購(gòu),允許就走到productsRequest


/**
 * Apple Operation
 */
-(void)startInAppPay {
    //判斷是否允許內(nèi)購(gòu)
    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"用戶允許內(nèi)購(gòu)");
        //bundleid+xxx 就是你添加內(nèi)購(gòu)條目設(shè)置的產(chǎn)品ID
        NSArray *product = [[NSArray alloc] initWithObjects:@"zydj.product.pay_6",@"zydj.product.pay_40",@"tv.zydj.app_pay_6",@"zydj.product.pay_60", nil];
        NSSet *nsset = [NSSet setWithArray:product];
        
        //初始化請(qǐng)求
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
        request.delegate = self;
        
        //開(kāi)始請(qǐng)求
        [request start];
        
//        注意,這里請(qǐng)求成功之后,會(huì)走到)productsRequest:
        
        
    }else{
       //  NSLog(@"用戶不允許內(nèi)購(gòu)");
//        [ToastUtils showMessage:@"當(dāng)前設(shè)備不允許內(nèi)購(gòu)" duration:1 position:Toast_Point_Center];
    }
}

接收到產(chǎn)品的返回信息,然后用返回的商品信息進(jìn)行發(fā)起購(gòu)買(mǎi)請(qǐng)求

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response NS_AVAILABLE_IOS(3_0)
{
    NSArray *product = response.products;

    //如果蘋(píng)果服務(wù)器沒(méi)有產(chǎn)品,那就return
    if([product count] == 0){
        NSLog(@"沒(méi)有該商品");
        return;
    }
    
    SKProduct *requestProduct = nil;

    NSString * currentProducId = self.currentProducId;
    
    for (SKProduct *pro in product) {
        
        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);
        
        //如果后臺(tái)消費(fèi)條目的ID與我這里需要請(qǐng)求的一樣(用于確保訂單的正確性)
        if([pro.productIdentifier isEqualToString:currentProducId]){
//            到這一步就說(shuō)明商品存在,開(kāi)始發(fā)送購(gòu)買(mǎi)請(qǐng)求
            requestProduct = pro;
            SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:requestProduct];
            payment.applicationUsername = self.orderId;//可以是userId础米,也可以是訂單id分苇,跟你自己需要而定
            [[SKPaymentQueue defaultQueue] addPayment:payment];
            // 如果請(qǐng)求成功就會(huì)彈出輸入密碼等頁(yè)面,輸入完密碼之后會(huì)出現(xiàn)一個(gè)支付成功的彈窗,點(diǎn)擊了彈窗之后會(huì)進(jìn)入paymentQueue:方法中
        }
    }
}

paymentQueue:方法監(jiān)聽(tīng),有兩種方式會(huì)進(jìn)入這個(gè)方法回調(diào)中,
方式1:正常流程,用戶輸入密碼,支付成功之后,點(diǎn)擊了系統(tǒng)彈出的支付成功彈窗,就會(huì)進(jìn)入這個(gè)方法回調(diào)中,
方式2:異常流程,當(dāng)用戶輸入完密碼之后,蘋(píng)果實(shí)際扣款成功,用戶手機(jī)異常退出(閃退或者直接殺掉APP,斷電等情況異常離開(kāi)app),下次打開(kāi)APP進(jìn)入到充值頁(yè)面之后,viewDidLoad中添加了支付回調(diào)監(jiān)聽(tīng)之后,也會(huì)進(jìn)這個(gè)方法回調(diào)中

- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
    
    dispatch_async(dispatch_get_main_queue(), ^{
        for(SKPaymentTransaction *tran in transactions){
            switch (tran.transactionState) {
                case SKPaymentTransactionStatePurchased:{
                    NSLog(@"交易完成");
//                    接下來(lái)的流程
                    [self completeTransaction:tran];
                }
                    break;
                case SKPaymentTransactionStatePurchasing:
                    
                    NSLog(@"商品添加進(jìn)列表");
                    break;
                case SKPaymentTransactionStateRestored:
                    
                    NSLog(@"已經(jīng)購(gòu)買(mǎi)過(guò)商品");
                    //[[SKPaymentQueue defaultQueue] finishTransaction:tran]; 消耗型商品不用寫(xiě)
                    break;
                case SKPaymentTransactionStateFailed:{
                    //這里說(shuō)明支付失敗了啊.密碼輸入錯(cuò)誤或者沒(méi)扣款成功,那就finish掉這筆交易
                    [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                    NSLog(@"交易失敗");
                }
                    break;
                default:
                    break;
            }
        }

    });
}

交易結(jié)束,當(dāng)交易結(jié)束后還要去appstore上驗(yàn)證支付信息是否都正確,只有所有都正確后,我們就可以給用戶方法我們的虛擬物品了。為了防止上一步的方式2進(jìn)入這個(gè)方法中所需要的操作,存入identifier和recepit信息, NSData * data = [NSKeyedArchiver archivedDataWithRootObject:model];和 SAVEDEFAULTS(data, transaction.transactionIdentifier);整體實(shí)現(xiàn)如下

- (void)completeTransaction:(SKPaymentTransaction *)transaction
{

    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.orderId.length != 0) {
//            這里需要展示一個(gè)加載框,展示出來(lái)之后要禁止掉用戶的點(diǎn)擊其他view區(qū)域的操作,包括左滑返回也給禁止掉
//            [MBProgressHUD showLoadHUD:@"加載中..." toView:self.view];
        }
        // appStoreReceiptURL iOS7.0增加的屁桑,購(gòu)買(mǎi)交易完成后医寿,會(huì)將憑據(jù)存放在該地址
        // 驗(yàn)證憑據(jù),獲取到蘋(píng)果返回的交易憑據(jù)
        NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
        // 從沙盒中獲取到購(gòu)買(mǎi)憑據(jù)
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
        //發(fā)送POST請(qǐng)求蘑斧,對(duì)購(gòu)買(mǎi)憑據(jù)進(jìn)行驗(yàn)證
        
        NSLog(@"before = %@",receiptURL);
        
        NSURL *url = [NSURL URLWithString:_appleUrl];
        
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f];
        urlRequest.HTTPMethod = @"POST";
        NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        _receipt = encodeStr;
        
        //防止異常退出做的操作
    if (self.orderId.length != 0) {
        YZChargeDefaultsModel * model = [[YZChargeDefaultsModel alloc] init];
        model.orderId = self.orderId;
        model.receipt = encodeStr;
        NSData * data = [NSKeyedArchiver archivedDataWithRootObject:model];
        SAVEDEFAULTS(data, transaction.transactionIdentifier);
//        這里存到userdefaults
    }
        NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
        NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
        urlRequest.HTTPBody = payloadData;
        
        NSURLSessionTask *task =   [[NSURLSession sharedSession] dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//            [MBProgressHUD hideHUD];
            if (data == nil) {
                NSLog(@"驗(yàn)證失敗");
                return;
            }
            
            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
            NSLog(@"請(qǐng)求成功后的數(shù)據(jù):%@",dic);
            //這里可以通過(guò)判斷 state == 0 驗(yàn)證憑據(jù)成功靖秩,然后進(jìn)入自己服務(wù)器二次驗(yàn)證须眷,,也可以直接進(jìn)行服務(wù)器邏輯的判斷。
            //本地服務(wù)器驗(yàn)證成功之后別忘了 [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
            NSString *productId = transaction.payment.productIdentifier;
            NSString *applicationUsername = transaction.payment.applicationUsername;
            
            NSLog(@"applicationUsername++++%@",applicationUsername);
            NSLog(@"payment.productIdentifier++++%@",productId);

            
            if (dic != nil) {
                
                NSLog(@"order id == null");
                
                NSArray * array = dic[@"receipt"][@"in_app"];
                if (array.count <= 0) {
                    return;
                }
                self.orderId = applicationUsername;
                //服務(wù)器二次驗(yàn)證
                NSLog(@"%@",transaction);
                
                for (int i = 0; i < array.count; i ++) {
                    NSDictionary * dic = array[i];
                    NSString * transaction_id = dic[@"transaction_id"];
                    if ([transaction.transactionIdentifier isEqualToString:transaction_id]) {
                        if (self.orderId.length != 0) {
                                [self vertifyApplePayRequestWith:transaction receipt:self.receipt transactionOrderId:self.orderId];
                        }else {
                            NSData * data = GETDEFAULTS(transaction.transactionIdentifier);
                            YZChargeDefaultsModel * model = [NSKeyedUnarchiver unarchiveObjectWithData:data];
                            if (model.orderId.length != 0 && model.receipt.length != 0) {
                                [self vertifyApplePayRequestWith:transaction receipt:model.receipt transactionOrderId:model.orderId];
                            }else {
                                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                            }
                        }
                    }
                }

            }
        }];
        [task resume];
    });
}


上面代碼中的遍歷和二次處理,方式1直接發(fā)起驗(yàn)證請(qǐng)求,方式2從本地拿到一些信息數(shù)據(jù),向服務(wù)端發(fā)起驗(yàn)證請(qǐng)求

                for (int i = 0; i < array.count; i ++) {
                    NSDictionary * dic = array[i];
                    NSString * transaction_id = dic[@"transaction_id"];
                    if ([transaction.transactionIdentifier isEqualToString:transaction_id]) {
                        if (self.orderId.length != 0) {
                                [self vertifyApplePayRequestWith:transaction receipt:self.receipt transactionOrderId:self.orderId];
                        }else {
                            NSData * data = GETDEFAULTS(transaction.transactionIdentifier);
                            YZChargeDefaultsModel * model = [NSKeyedUnarchiver unarchiveObjectWithData:data];
                            if (model.orderId.length != 0 && model.receipt.length != 0) {
                                [self vertifyApplePayRequestWith:transaction receipt:model.receipt transactionOrderId:model.orderId];
                            }else {
                                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                            }
                        }
                    }
                }

根據(jù)一些參數(shù),向服務(wù)端請(qǐng)求驗(yàn)證當(dāng)前訂單是否支付

transaction.transactionIdentifier 唯一的
receipt 一般這個(gè)數(shù)據(jù)很長(zhǎng)很長(zhǎng)很長(zhǎng), md5一下,傳輸方便
orderId

服務(wù)端的一些處理

先判斷這個(gè)transaction.transactionIdentifier對(duì)應(yīng)的訂單是否支付成功且發(fā)放了虛擬物品
如果是就直接返回一個(gè)狀態(tài)比如狀態(tài)1
客戶端在狀態(tài)1的處理就是直接finish掉這筆交易

如果發(fā)送虛擬物品的記錄中沒(méi)有這條記錄,那么先通過(guò)transaction.transactionIdentifier向apple再次驗(yàn)證一下是否支付成功,如果支付成功,那么就發(fā)放虛擬物品給用戶,并在當(dāng)前接口中返回狀態(tài)2
客戶端在狀態(tài)2的處理就是 finish掉這筆交易,并刪除本地的transactionIdentifier對(duì)應(yīng)的YZChargeDefaultsModel,并記錄一下transactionIdentifierd對(duì)應(yīng)的交易已經(jīng)成功,為了應(yīng)對(duì)狀態(tài)1的情況

如果發(fā)送虛擬物品的記錄中沒(méi)有這條記錄,那么先通過(guò)transaction.transactionIdentifier向apple再次驗(yàn)證一下是否支付成功,如果支付失敗,那么返回狀態(tài)3給客戶端,然后什么都不用記錄
客戶端在狀態(tài)3的處理就是直接finish掉這筆交易,因?yàn)榉?wù)端驗(yàn)證獲取到的信息是用戶支付的資金沒(méi)有到賬

/**
 * 驗(yàn)證訂單
 */
-(void)vertifyApplePayRequestWith:(SKPaymentTransaction *)transaction receipt:(NSString *)receipt transactionOrderId:(NSString *)orderId{
//    NSMutableDictionary * dic = [NSMutableDictionary dictionary];
//    [dic setObject:receipt forKey:@"receipt_data"];
//    NSString * alltransId = [NSString stringWithFormat:@"%@%@",YZ_Transaction_ID,transaction.transactionIdentifier];
//    NSString * needtransID = [alltransId md5String];
//    [dic setObject:orderPhpId forKey:@"orderNum"];
//    [dic setObject:needtransID forKey:@"transactionID"];
   
    NSInteger status = 0;
        if(status == 1){
            [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
        }else if (status == 2){
            [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
        }else if(status == 3) {
            [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
        }
            if (self.orderId.length != 0) {
//                [ToastUtils showMessage:responseObjc[@"msg"] duration:1 position:Toast_Point_Center];
                self.orderId = @"";
                [[NSUserDefaults standardUserDefaults] removeObjectForKey:transaction.transactionIdentifier];
            }

        
}

整體流程大概是這樣實(shí)現(xiàn)的,Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沟突,一起剝皮案震驚了整個(gè)濱河市花颗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惠拭,老刑警劉巖扩劝,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異职辅,居然都是意外死亡棒呛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)域携,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)簇秒,“玉大人,你說(shuō)我怎么就攤上這事涵亏≡姿” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵气筋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我旋圆,道長(zhǎng)宠默,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任灵巧,我火速辦了婚禮搀矫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刻肄。我一直安慰自己瓤球,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布敏弃。 她就那樣靜靜地躺著卦羡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪麦到。 梳的紋絲不亂的頭發(fā)上绿饵,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音瓶颠,去河邊找鬼拟赊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛粹淋,可吹牛的內(nèi)容都是我干的吸祟。 我是一名探鬼主播指黎,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼冷溶!你這毒婦竟也來(lái)了抖剿?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炒瘟,失蹤者是張志新(化名)和其女友劉穎吹埠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體疮装,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缘琅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了廓推。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刷袍。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖樊展,靈堂內(nèi)的尸體忽然破棺而出呻纹,到底是詐尸還是另有隱情,我是刑警寧澤专缠,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布雷酪,位于F島的核電站,受9級(jí)特大地震影響涝婉,放射性物質(zhì)發(fā)生泄漏哥力。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一墩弯、第九天 我趴在偏房一處隱蔽的房頂上張望吩跋。 院中可真熱鬧,春花似錦渔工、人聲如沸锌钮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梁丘。三九已至,卻和暖如春脓魏,著一層夾襖步出監(jiān)牢的瞬間兰吟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工茂翔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混蔼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓珊燎,卻偏偏與公主長(zhǎng)得像惭嚣,于是被迫代替她去往敵國(guó)和親遵湖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • 自己開(kāi)發(fā)的視頻直播項(xiàng)目晚吞,牽涉到充值金幣延旧,用到了蘋(píng)果公司的內(nèi)購(gòu),趴坑了兩天槽地,這里總結(jié)下實(shí)現(xiàn)蘋(píng)果內(nèi)購(gòu)迁沫。 一. 創(chuàng)建測(cè)試...
    Leo丶Dicaprio閱讀 3,365評(píng)論 8 7
  • 一.總說(shuō)內(nèi)購(gòu)的內(nèi)容 協(xié)議、稅務(wù)和銀行業(yè)務(wù) 信息填寫(xiě) 內(nèi)購(gòu)商品的添加 添加沙盒測(cè)試賬號(hào) 內(nèi)購(gòu)代碼的具體實(shí)現(xiàn) 內(nèi)購(gòu)的注...
    默默_David閱讀 3,643評(píng)論 0 6
  • iOS應(yīng)用如果涉及到支付功能捌蚊,分為兩類:第三方支付和蘋(píng)果內(nèi)購(gòu)集畅。那么什么情況下選擇使用第三方支付,又在什么情況下選擇...
    ZfRee閱讀 38,821評(píng)論 36 66
  • - 消耗型項(xiàng)目 就像你玩游戲需要買(mǎi)金幣缅糟,買(mǎi)鉆石等挺智,只要花錢(qián)就可以無(wú)限次的購(gòu)買(mǎi) - 非消耗型項(xiàng)目 就像你在App S...
    tiger2016閱讀 650評(píng)論 0 1
  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來(lái)的情緒窗宦。表情可以傳達(dá)很多信息赦颇。高興了當(dāng)然就笑了,難過(guò)就哭了赴涵。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,432評(píng)論 2 7