iOS IAP應(yīng)用內(nèi)購(gòu)詳細(xì)步驟和問(wèn)題總結(jié)指南

最近公司在做APP內(nèi)購(gòu)會(huì)員功能 遇到了很多問(wèn)題 總結(jié)記錄一下 首先一定要區(qū)分Apple pay 和IAP內(nèi)購(gòu)的區(qū)別
可以先去看一下官方文檔地址 有每個(gè)步驟的詳細(xì)解釋
本篇文章分為:
1、 內(nèi)購(gòu)支付流程;
2、開(kāi)發(fā)集成步驟;
3、問(wèn)題(遇坑)記錄解決方式

之前沒(méi)看官方文檔走了很多彎路 網(wǎng)上博客并不系統(tǒng) 強(qiáng)烈建議先過(guò)一遍官方文檔

先看一下IAP內(nèi)購(gòu)支付流程(官方)

官方流程圖
  1. 程序向服務(wù)器發(fā)送請(qǐng)求,獲得一份產(chǎn)品列表。
  2. 服務(wù)器返回包含產(chǎn)品標(biāo)識(shí)符的列表。
  3. 程序向App Store發(fā)送請(qǐng)求,得到產(chǎn)品的信息。
  4. App Store返回產(chǎn)品信息。
  5. 程序把返回的產(chǎn)品信息顯示給用戶(App的store界面)
  6. 用戶選擇某個(gè)產(chǎn)品
  7. 程序向App Store發(fā)送支付請(qǐng)求
  8. App Store處理支付請(qǐng)求并返回交易完成信息。
  9. 程序從信息中獲得數(shù)據(jù),并發(fā)送至服務(wù)器。
  10. 服務(wù)器紀(jì)錄數(shù)據(jù),并進(jìn)行審(我們的)查。
  11. 服務(wù)器將數(shù)據(jù)發(fā)給App Store來(lái)驗(yàn)證該交易的有效性。
  12. App Store對(duì)收到的數(shù)據(jù)進(jìn)行解析,返回該數(shù)據(jù)和說(shuō)明其是否有效的標(biāo)識(shí)。
  13. 服務(wù)器讀取返回的數(shù)據(jù),確定用戶購(gòu)買的內(nèi)容。
  14. 服務(wù)器將購(gòu)買的內(nèi)容傳遞給程序。

第一步:內(nèi)購(gòu)賬戶稅務(wù)協(xié)議、銀行卡綁定相關(guān)

一般都是運(yùn)營(yíng)或者產(chǎn)品經(jīng)理處理這步 這篇文章圖文步驟比較詳細(xì) 處理稅務(wù)銀行相關(guān)設(shè)置 IAP,In App Purchases-在APP內(nèi)部支付

第二步:Xcode設(shè)置相關(guān)

打開(kāi)In-App Purchase開(kāi)關(guān) 對(duì)應(yīng)在開(kāi)發(fā)者證書中心的項(xiàng)目證書中顯示應(yīng)該也是可用狀態(tài)

屏幕快照 2018-08-22 下午6.00.11.png

屏幕快照 2018-08-22 下午6.01.35.png

第三步:在App Store Content -> 我的APP 添加內(nèi)購(gòu)項(xiàng)目商品

  1. 首頁(yè)上,點(diǎn)按“我的 App”,然后選擇與該 App 內(nèi)購(gòu)買項(xiàng)目相關(guān)聯(lián)的 App。
  2. 在工具欄中,點(diǎn)按“功能”,然后在左列中點(diǎn)按“App 內(nèi)購(gòu)買項(xiàng)目”。
  3. 若要添加 App 內(nèi)購(gòu)買項(xiàng)目,請(qǐng)前往“App 內(nèi)購(gòu)買項(xiàng)目”,并點(diǎn)按“添加”按鈕(+)。

屏幕快照 2018-08-23 上午10.06.23.png

選擇功能 添加內(nèi)購(gòu)項(xiàng)目商品
選擇功能Tab

內(nèi)購(gòu)商品對(duì)應(yīng)四種類型 消耗型、非消耗型、自動(dòng)續(xù)訂訂閱型、非續(xù)訂訂閱型
官方文檔

  1. 選擇“消耗型項(xiàng)目”、“非消耗型項(xiàng)目”或“非續(xù)訂訂閱”,并點(diǎn)按“創(chuàng)建”。有關(guān)自動(dòng)續(xù)訂訂閱的信息,請(qǐng)參見(jiàn)創(chuàng)建自動(dòng)續(xù)期訂閱。
  2. 添加參考名稱、產(chǎn)品 ID 和本地化顯示名稱。
  3. 點(diǎn)按“存儲(chǔ)”或“提交以供審核”。
您可以在創(chuàng)建您的 App 內(nèi)購(gòu)買項(xiàng)目時(shí)輸入所有的元數(shù)據(jù),或稍后輸入您的 App 內(nèi)購(gòu)買項(xiàng)目信息。
屏幕快照 2018-08-23 上午10.09.34.png

添加一個(gè)測(cè)試商品 其他屬性都可以隨意填寫 產(chǎn)品ID一定要認(rèn)真填寫 項(xiàng)目中需要根據(jù)ID獲取商品信息 價(jià)格有不同的等級(jí)可以選 最低備用等級(jí)1 == 1元
填寫完成之后儲(chǔ)存 就完成了一個(gè)內(nèi)購(gòu)商品的添加

屏幕快照 2018-08-23 上午10.16.31.png

第四步:沙盒環(huán)境測(cè)試賬號(hào)

因?yàn)樯婕暗藉X相關(guān) 總不能直接用money去支付吧 所以需要你去添加一個(gè)沙盒技術(shù)測(cè)試人員的賬號(hào) (這個(gè)賬號(hào)是虛擬的) 付款不會(huì)扣你
看第三步那張圖 在App Store Content 選擇用戶和職能 進(jìn)入下面頁(yè)面 選擇沙箱技術(shù)測(cè)試員 添加測(cè)試賬號(hào)

屏幕快照 2018-08-23 上午11.02.26.png
屏幕快照 2018-08-23 上午11.05.28.png

Tips:Q:為什么添加沙箱技術(shù)測(cè)試員 注冊(cè)不成功 Unknown Email xxxxxx
首先這里有個(gè)坑 郵箱只要符合格式就可以 虛假郵箱也可以 但密碼必須符合正式的要求要有大小寫和字符 復(fù)雜就好 例如:Lh123456*

第五步:代碼實(shí)現(xiàn)(初步,未進(jìn)行優(yōu)化 有什么問(wèn)題可以在評(píng)論中跟我溝通)

.h文件

typedef void(^XSProductStatusBlock)(BOOL isStatus);

@interface XSApplePayManager : NSObject


+ (instancetype)shareManager;

/** 檢測(cè)客戶端與服務(wù)器漏單情況處理*/
+ (void)checkOrderStatus;


/**
  根據(jù)商品ID請(qǐng)求支付信息


 @param orderId 訂單號(hào)
 @param productId 商品號(hào)
 @param statusBlock 回掉block
 */
- (void)requestProductWithOrderId:(NSString *)orderId
                        productId:(NSString *)productId
                      statusBlock:(XSProductStatusBlock)statusBlock;

.m文件

#import <StoreKit/StoreKit.h>
#import "APIManager.h"
#import "UIAlertView+AABlock.h"

@interface XSApplePayManager ()<SKProductsRequestDelegate,SKPaymentTransactionObserver>

@property (nonatomic, copy) NSString *orderId;
@property (nonatomic, copy) XSProductStatusBlock statusBlcok;

@end

@implementation XSApplePayManager

+ (instancetype)shareManager
{
    static dispatch_once_t onceToken;
    static XSApplePayManager *manager = nil;
    dispatch_once(&onceToken, ^{
        manager = [[XSApplePayManager alloc]init];
    });
    return manager;
}

/** 檢測(cè)客戶端與服務(wù)器漏單情況處理*/
+ (void)checkOrderStatus
{
    NSDictionary *orderInfo = [XSApplePayManager getReceiptData];
    if (orderInfo != nil) {
        
        NSString *orderId = orderInfo[@"orderId"];
        NSString *receipt = orderInfo[@"receipt"];
        
        [[XSApplePayManager shareManager] verifyPurchaseForServiceWithOrderId:orderId receipt:receipt];
    }
}

#pragma mark -- 結(jié)束上次未完成的交易
-(void)removeAllUncompleteTransactionsBeforeNewPurchase{
    
    NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
    
    if (transactions.count >= 1) {
        
        for (SKPaymentTransaction* transaction in transactions) {
            if (transaction.transactionState == SKPaymentTransactionStatePurchased ||
                transaction.transactionState == SKPaymentTransactionStateRestored) {
                [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
            }
        }
        
    }else{
        NSLog(@"沒(méi)有歷史未消耗訂單");
    }
}


/** 檢測(cè)權(quán)限 添加支付監(jiān)測(cè) 開(kāi)始支付流程*/
- (void)requestProductWithOrderId:(NSString *)orderId
                        productId:(NSString *)productId
                      statusBlock:(XSProductStatusBlock)statusBlock

{
    
    if (orderId == nil || productId == nil) {
        [AAProgressManager showFinishWithStatus:@"訂單號(hào)/商品號(hào)有誤"];
        return;
    }
    
    if ([[XZDeviceManager didRoot] isEqualToString:@"didRoot"]) {//寫自己的越獄判斷方法
        [AAProgressManager showFinishWithStatus:@"越獄手機(jī)不支持內(nèi)購(gòu)"];
        return;
    }
    
    
    if([SKPaymentQueue canMakePayments]){
        
        [self removeAllUncompleteTransactionsBeforeNewPurchase];
        
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

        self.orderId = orderId;
        self.statusBlcok = statusBlock;
        [self requestProductData:productId];
        
    }else{
        [AAProgressManager showFinishWithStatus:L(@"請(qǐng)打開(kāi)應(yīng)用內(nèi)支付功能")];
    }
}

/** 去Apple IAP Service 根據(jù)商品ID請(qǐng)求商品信息*/
- (void)requestProductData:(NSString *)type{
    
    [AAProgressManager showWithStatus:@"正在請(qǐng)求..."];
    NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
    
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;
    [request start];
}


#pragma mark -- SKProductsRequestDelegate
//收到產(chǎn)品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSArray *product = response.products;
    if([product count] == 0){
        [AAProgressManager showFinishWithStatus:L(@"無(wú)法獲取商品信息,請(qǐng)重新嘗試購(gòu)買")];
        return;
    }
    
    NSLog(@"產(chǎn)品付費(fèi)數(shù)量:%ld",product.count);
    
    SKProduct *p = product.firstObject;
    
    SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:p];
    payment.quantity = (NSInteger)p.price;//購(gòu)買次數(shù)=價(jià)錢
    if (payment.quantity == 0) {
        payment.quantity = 1;
    }
    payment.applicationUsername = self.orderId;//[NSString stringWithFormat:@"%@",[[AAUserManager shareManager] getUID]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}

//請(qǐng)求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"------------------錯(cuò)誤-----------------:%@", error);
    if (self.statusBlcok) {
        self.statusBlcok(NO);
    }
    [AAProgressManager showFinishWithStatus:L(@"從Apple獲取商品信息失敗")];

}

- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"------------反饋信息結(jié)束-----------------%@",request);
}

#pragma mark -- 監(jiān)聽(tīng)AppStore支付狀態(tài)
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    
    NSLog(@"監(jiān)聽(tīng)AppStore支付狀態(tài)");
    dispatch_async(dispatch_get_main_queue(), ^{
        for(SKPaymentTransaction *tran in transaction){
            switch (tran.transactionState) {
                case SKPaymentTransactionStatePurchased:
                {
                    // 發(fā)送到蘋果服務(wù)器驗(yàn)證憑證
                    [self verifyPurchaseWithPaymentTransaction];
                    [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                }
                    break;
                case SKPaymentTransactionStatePurchasing:
                    NSLog(@"商品添加進(jìn)列表");
                    break;
                case SKPaymentTransactionStateRestored:
                {
                    [AAProgressManager showFinishWithStatus:L(@"已經(jīng)購(gòu)買過(guò)商品")];
                    [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                }
                    break;
                case SKPaymentTransactionStateFailed:
                {
                    if (self.statusBlcok) {
                        self.statusBlcok(NO);
                    }
                    NSLog(@"交易失敗");

                    [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                }
                    break;
                case SKPaymentTransactionStateDeferred:
                {
                    [AAProgressManager showFinishWithStatus:L(@"最終狀態(tài)未確定")];
                }
                    break;
                default:
                    break;
            }
        }
    });
    
}

#pragma mark -- 驗(yàn)證
/**驗(yàn)證購(gòu)買,避免越獄軟件模擬蘋果請(qǐng)求達(dá)到非法購(gòu)買問(wèn)題*/
-(void)verifyPurchaseWithPaymentTransaction{
    
    //從沙盒中獲取交易憑證并且拼接成請(qǐng)求體數(shù)據(jù)
    NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
    NSString *receiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    [self saveReceiptData:@{@"receipt":receiptString,
                            @"orderId":self.orderId}];
    
  
    [self verifyPurchaseForServiceWithOrderId:self.orderId
                                      receipt:receiptString];
}

- (void)verifyPurchaseForServiceWithOrderId:(NSString *)orderId
                                    receipt:(NSString *)receiptString
{
    if (orderId == nil && receiptString == nil) {
        if (self.statusBlcok) {
            self.statusBlcok(NO);
        }
        [AAProgressManager showFinishWithStatus:@"訂單號(hào)/憑證無(wú)效"];
        return;
    }
    
    [self removeTransaction];

    [AAProgressManager showWithStatus:@"正在驗(yàn)證服務(wù)器..."];
    
    WS(weakSelf);
    [[APIManager sharedInstance] verifyPurchaseWithOrderID:orderId
                                                    params:@{@"ceceipt-data":receiptString}
                                                   success:^(id response)
     {
         dispatch_async(dispatch_get_main_queue(), ^{
             [AAProgressManager dismiss];
             [AAProgressManager showFinishWithStatus:L(@"交易完成")];
             [weakSelf removeLocReceiptData];
             if (weakSelf.statusBlcok) {
                 weakSelf.statusBlcok(YES);
             }
         });
         
     } failure:^(NSError *error) {
         dispatch_async(dispatch_get_main_queue(), ^{
             
             [CommonFunction showError:error];
             [weakSelf verifyPurchaseFail];
         });
     }];
}

- (void)verifyPurchaseFail
{
    WS(weakSelf);
    UIAlertView *altert =[UIAlertView alertViewWithTitle:@"服務(wù)器驗(yàn)證失敗"
                                                 message:@"賬單在驗(yàn)證服務(wù)器過(guò)程中出現(xiàn)錯(cuò)誤,\n請(qǐng)檢查網(wǎng)絡(luò)環(huán)境是否可以再次驗(yàn)證\n如果取消可在網(wǎng)絡(luò)環(huán)境良好的情況下重新啟動(dòng)行者可再次繼續(xù)驗(yàn)證支付"
                                       cancelButtonTitle:L(@"取消")
                                       otherButtonTitles:@[L(@"再次驗(yàn)證")]
                                               onDismiss:^(NSInteger buttonIndex)
                          {
                              dispatch_async(dispatch_get_main_queue(), ^
                                             {
                                                 [XSApplePayManager checkOrderStatus];
                                             });           ;
                              
                          } onCancel:^{
                              dispatch_async(dispatch_get_main_queue(), ^{
                                  
                                  if (weakSelf.statusBlcok) {
                                      weakSelf.statusBlcok(NO);
                                  }
                                  [PromptInfo showWithText:@"可在網(wǎng)絡(luò)環(huán)境良好的情況下重新啟動(dòng)行者可再次繼續(xù)驗(yàn)證支付"];
                                  
                              });
                          }];
    [altert show];
}

//交易結(jié)束
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void)removeTransaction
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

#pragma mark -- 本地保存一次支付憑證
static NSString *const kSaveReceiptData = @"kSaveReceiptData";

- (void)saveReceiptData:(NSDictionary *)receiptData
{
    [[NSUserDefaults standardUserDefaults] setValue:receiptData forKey:kSaveReceiptData];
    [[NSUserDefaults standardUserDefaults]synchronize];
}

+ (NSDictionary *)getReceiptData
{
    return [[NSUserDefaults standardUserDefaults] valueForKey:kSaveReceiptData];
}

- (void)removeLocReceiptData
{
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:kSaveReceiptData];
    [[NSUserDefaults standardUserDefaults] synchronize];
}
第六步:IAP支付流程 & 服務(wù)器驗(yàn)證流程

整個(gè)支付流程如下:
1.客戶端向Appstore請(qǐng)求購(gòu)買產(chǎn)品(假設(shè)產(chǎn)品信息已經(jīng)取得),Appstore驗(yàn)證產(chǎn)品成功后,從用戶的Apple賬戶余額中扣費(fèi)。
2.Appstore向客戶端返回一段receipt-data,里面記錄了本次交易的證書和簽名信息。
3.客戶端向我們可以信任的服務(wù)器提供receipt-data
4.服務(wù)器對(duì)receipt-data進(jìn)行一次base64編碼
5.服務(wù)器把編碼后的receipt-data發(fā)往itunes.appstore進(jìn)行驗(yàn)證
6.itunes.appstore返回驗(yàn)證結(jié)果給服務(wù)器
7.服務(wù)器對(duì)商品購(gòu)買狀態(tài)以及商品類型,向客戶端發(fā)放相應(yīng)的道具與推送數(shù)據(jù)更新通知

漏單處理 確保receipt-data的成功提交與異常處理

建立在IAP Server Model的基礎(chǔ)上,并且我們知道手機(jī)網(wǎng)絡(luò)是不穩(wěn)定的,在付款成功后不能確保把receipt-data一定提交到服務(wù)器。如果出現(xiàn)了這樣的情況,那就意味著玩家被appstore扣費(fèi)了,卻沒(méi)收到服務(wù)器發(fā)放的道具。
漏單處理:
解決這個(gè)問(wèn)題的方法是在客戶端提交receipt-data給我們的服務(wù)器,讓我們的服務(wù)器向蘋果服務(wù)器發(fā)送驗(yàn)證請(qǐng)求,驗(yàn)證這個(gè)receipt-data賬單的有效性. 在沒(méi)有收到回復(fù)之前,客戶端必須要把receipt-data保存好,并且定期或在合理的UI界面觸發(fā)向服務(wù)端發(fā)起請(qǐng)求,直至收到服務(wù)端的回復(fù)后刪除客戶端的receipt賬單記錄。
如果是客戶端沒(méi)成功提交receipt-data,那怎么辦?就是玩家被扣費(fèi)了,也收到appstore的消費(fèi)收據(jù)了,卻依然沒(méi)收到游戲道具,于是投訴到游戲客服處。

這種情況在以往的經(jīng)驗(yàn)中也會(huì)出現(xiàn),常見(jiàn)的玩家和游戲運(yùn)營(yíng)商發(fā)生的糾紛。游戲客服向玩家索要游戲賬號(hào)和appstore的收據(jù)單號(hào),通過(guò)查詢itunes-connect看是否確有這筆訂單。如果訂單存在,則要聯(lián)系研發(fā)方去查詢游戲服務(wù)器,看訂單號(hào)與玩家名是否對(duì)應(yīng),并且是否已經(jīng)被使用了,做這一點(diǎn)檢查的目的是 為了防止惡意玩家利用已經(jīng)使用過(guò)了的訂單號(hào)進(jìn)行欺騙(已驗(yàn)證的賬單是可以再次請(qǐng)求驗(yàn)證的,曾經(jīng)為了測(cè)試,將賬單手動(dòng)發(fā)給服務(wù)器處理并成功),謊稱自己沒(méi)收到商品。這就是上面一節(jié)IAP Server Model中紅字所提到的安全邏輯的目的。當(dāng)然了,如果查不到這個(gè)訂單號(hào),就意味著這個(gè)訂單確實(shí)還沒(méi)使用過(guò),手動(dòng)給玩家補(bǔ)發(fā)商品即可。

更多可以查看這篇博文蘋果IAP安全支付與防范 receipt收據(jù)驗(yàn)證

遇到的坑

Q:21004 你提供的共享密鑰和賬戶的共享密鑰不一致 什么是共享密鑰? 共享密鑰從哪里獲取?

A:先看一下官方文檔怎么說(shuō)生成收據(jù)驗(yàn)證代碼
為了在驗(yàn)證自動(dòng)續(xù)期訂閱時(shí)提高您的 App 與 Apple 服務(wù)器交易的安全性,您可以在收據(jù)中包含一個(gè) 32 位隨機(jī)生成的字母數(shù)字字符串,作為共享密鑰。
在 App Store Connect 中生成共享密鑰。您可以生成一個(gè)主共享密鑰,作為您所有 App 的單一代碼,或作為針對(duì)單個(gè) App 的 App 專用共享密鑰。您也可以針對(duì)您的部分 App 使用主共享密鑰,其他 App 使用 App 專用共享密鑰。
點(diǎn)擊下面展開(kāi)就可以看到共享密鑰生成的方式

Q:沙箱技術(shù)測(cè)試人員添加不成功 總是提示郵箱錯(cuò)誤

A: 沙箱技術(shù)測(cè)試賬號(hào)用于付款測(cè)試 任意未創(chuàng)建過(guò)Apple ID 的郵箱都可以 假的郵箱也可以 重要的是密碼格式一定要包含大小寫 跟正式賬號(hào)注冊(cè)規(guī)則一樣 (例如:Lh123456*)

Q:自己服務(wù)器向蘋果服務(wù)器驗(yàn)證收據(jù)/憑證參數(shù)是什么?向status code 驗(yàn)證apple iap sever的狀態(tài)碼代表什么意思?

A:21002、21003、21004、21005、21006、21007... 具體可以查看這篇文檔用App Store驗(yàn)證收據(jù)

Q:Apple 和IAP的區(qū)別

A:IAP是鏈接App store的內(nèi)購(gòu)服務(wù) 一般是虛擬商品需要走的通道(比如會(huì)員功能)
Apple Pay是蘋果跟各大銀行合作的卡包形式的類似于刷卡支付服務(wù) 一般用于現(xiàn)實(shí)場(chǎng)景
這兩個(gè)一定別搞混了

Q:怎么通過(guò)itunes-connect查看具體訂單,itunes-connect中無(wú)法直接看到訂單信息,可以用以下方法來(lái)查詢

1.可以通過(guò)賬單向蘋果發(fā)送賬單驗(yàn)證,有效可以手動(dòng)補(bǔ)發(fā)
2 .用自己的服務(wù)器的記錄賬單列表對(duì)比
3.利用第三方的TalkingData等交易函數(shù),會(huì)自動(dòng)記錄賬單數(shù)據(jù)

還有一些問(wèn)題可以借鑒一下這篇博文iOS之你一定要看的內(nèi)購(gòu)破解-越獄篇 他遇到的實(shí)際問(wèn)題比較多 按需借鑒

覺(jué)得有幫助可以關(guān)注我 后續(xù)繼續(xù)補(bǔ)充....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容