Xamarin.ios의 트랜잭션 및 확인Transactions and Verification in Xamarin.iOS

이전 트랜잭션 복원Restoring Past Transactions

응용 프로그램이 복원 가능한 제품 유형을 지 원하는 경우 사용자가 해당 구매를 복원할 수 있도록 일부 사용자 인터페이스 요소를 포함 해야 합니다.If your application supports product types that are restorable, you must include some user-interface elements to allow users to restore those purchases. 이 기능을 사용 하면 고객이 추가 장치에 제품을 추가 하거나 치료 또는 제거 후 앱을 다시 설치 하 여 동일한 장치로 제품을 복원할 수 있습니다.This functionality allows a customer to add the product to additional devices or to restore the product to the same device after being wiped clean or removing and re-installing the app. 다음 제품 유형은 복원 가능한입니다.The following product types are restorable:

  • 사용할 없는 제품Non-consumable products
  • 자동 갱신 가능한 구독Auto-renewable subscriptions
  • 무료 구독Free subscriptions

복원 프로세스는 제품을 충족 하기 위해 장치에 보관 하는 레코드를 업데이트 해야 합니다.The restore process should update the records you keep on the device to fulfill your products. 고객은 언제 든 지 모든 장치에서 복원 하도록 선택할 수 있습니다.The customer can choose to restore at any time, on any of their devices. 복원 프로세스는 해당 사용자에 대 한 모든 이전 트랜잭션을 다시 보냅니다. 그러면 응용 프로그램 코드에서 해당 정보를 사용 하 여 수행할 작업을 결정 해야 합니다. 예를 들어 장치에 해당 구매에 대 한 레코드가 이미 있는지 확인 하 고, 그렇지 않은 경우 구매 레코드를 만들고 해당 사용자에 대 한 제품을 사용 하도록 설정 합니다.The restore process re-sends all prior transactions for that user; the application code must then determine what action to take with that information (for example, checking if there is already a record of that purchase on the device, and if not, creating a record of the purchase and enabling the product for the user).

복원 구현Implementing Restore

사용자 인터페이스 복원 단추는 SKPaymentQueue에서 RestoreCompletedTransactions를 트리거하는 다음 메서드를 호출 합니다.The user interface Restore button calls the following method, which triggers RestoreCompletedTransactions on the SKPaymentQueue.

public void Restore()
{
   // theObserver will be notified of when the restored transactions start arriving <- AppStore
   SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();
}

기능 키트는 복원 요청을 Apple의 서버에 비동기적으로 보냅니다.StoreKit will send the restore request to Apple’s servers asynchronously.

CustomPaymentObserver은 트랜잭션 관찰자로 등록 되기 때문에 Apple의 서버가 응답할 때 메시지를 받게 됩니다.Because the CustomPaymentObserver is registered as a transaction observer, it will receive messages when Apple’s servers respond. 응답에는이 사용자가이 응용 프로그램에서 수행한 모든 트랜잭션 (모든 장치에서)이 포함 됩니다.The response will contain all the transactions this user has ever performed in this application (across all their devices). 이 코드는 각 트랜잭션을 반복 하 여 복원 된 상태를 검색 하 고 아래와 같이 UpdatedTransactions 메서드를 호출 하 여 처리 합니다.The code loops through each transaction, detects the Restored state and calls the UpdatedTransactions method to process it as shown below:

// called when the transaction status is updated
public override void UpdatedTransactions (SKPaymentQueue queue, SKPaymentTransaction[] transactions)
{
   foreach (SKPaymentTransaction transaction in transactions)
   {
       switch (transaction.TransactionState)
       {
       case SKPaymentTransactionState.Purchased:
          theManager.CompleteTransaction(transaction);
           break;
       case SKPaymentTransactionState.Failed:
          theManager.FailedTransaction(transaction);
           break;
       case SKPaymentTransactionState.Restored:
           theManager.RestoreTransaction(transaction);
           break;
default:
           break;
       }
   }
}

사용자에 대 한 복원 가능한 제품이 없으면 UpdatedTransactions가 호출 되지 않습니다.If there are no restorable products for the user, UpdatedTransactions is not called.

샘플에서 지정 된 트랜잭션을 복원 하는 가장 간단한 코드는 OriginalTransaction 속성이 제품 ID에 액세스 하는 데 사용 된다는 점을 제외 하 고는 구매가 수행 될 때와 동일한 작업을 수행 합니다.The simplest possible code to restore a given transaction in the sample does the same actions as when a purchase takes place, except that the OriginalTransaction property is used to access the Product ID:

public void RestoreTransaction (SKPaymentTransaction transaction)
{
   // Restored Transactions always have an 'original transaction' attached
   var productId = transaction.OriginalTransaction.Payment.ProductIdentifier;
   // Register the purchase, so it is remembered for next time
   PhotoFilterManager.Purchase(productId); // it's as though it was purchased again
   FinishTransaction(transaction, true);
}

보다 정교한 구현은 원래 날짜 및 수신 번호와 같은 다른 transaction.OriginalTransaction 속성을 확인할 수 있습니다.A more sophisticated implementation may check other transaction.OriginalTransaction properties, such as the original date and receipt number. 이 정보는 일부 제품 유형 (예: 구독)에 유용 합니다.This information will be useful for some product types (such as subscriptions).

복원 완료Restore Completion

CustomPaymentObserver에는 다음과 같은 두 가지 추가 메서드가 있습니다. 복원 프로세스가 완료 되 면 (성공 또는 실패) 다음이 표시 됩니다.The CustomPaymentObserver has two additional methods that will be called by StoreKit when the restore process has completed (either successfully or with a failure), shown below:

public override void PaymentQueueRestoreCompletedTransactionsFinished (SKPaymentQueue queue)
{
   Console.WriteLine(" ** RESTORE Finished ");
}
public override void RestoreCompletedTransactionsFailedWithError (SKPaymentQueue queue, NSError error)
{
   Console.WriteLine(" ** RESTORE FailedWithError " + error.LocalizedDescription);
}

예제에서 이러한 메서드는 아무 작업도 수행 하지 않지만 실제 응용 프로그램은 사용자 또는 다른 기능에 메시지를 구현 하도록 선택할 수 있습니다.In the example these methods do nothing, however a real application may choose to implement a message to the user or some other functionality.

구매 보안Securing Purchases

이 문서의 두 예제에서는 NSUserDefaults를 사용 하 여 구매를 추적 합니다.The two examples in this document use NSUserDefaults to track purchases:

소모품 – 크레딧 구매의 ' 잔액 '은 각 구매와 함께 증가 하는 간단한 NSUserDefaults 정수 값입니다.Consumables – the ‘balance’ of credit purchases is a simple NSUserDefaults integer value that is incremented with each purchase.

비 소비 -각 사진 필터 구매는 NSUserDefaults에 키-값 쌍으로 저장 됩니다.Non-Consumables – each photo filter purchase is stored as a key-value pair in NSUserDefaults.

NSUserDefaults를 사용 하 여 예제 코드를 간단 하 게 유지 하지만 기술적으로 관심이 있는 사용자가 설정을 업데이트 (지불 메커니즘 바이패스) 할 수 있으므로 매우 안전한 솔루션을 제공 하지는 않습니다.Using NSUserDefaults keeps the example code simple, but does not offer a very secure solution as it may be possible for technically-minded users to update the settings (bypassing the payment mechanism).

참고: 실제 응용 프로그램은 사용자 변조의 영향을 받지 않는 구매 된 콘텐츠를 저장 하는 보안 메커니즘을 채택 해야 합니다.Note: Real-world applications should adopt a secure mechanism for storing purchased content that is not subject to user tampering. 여기에는 암호화 및/또는 원격 서버 인증을 비롯 한 다른 방법이 포함 될 수 있습니다.This may involve encryption and/or other techniques including remote-server authentication.

또한이 메커니즘은 iOS, iTunes 및 iCloud의 기본 제공 백업 및 복구 기능을 활용 하도록 설계 되어야 합니다.The mechanism should also be designed to take advantage of the built-in backup and recovery features of iOS, iTunes and iCloud. 이렇게 하면 사용자가 백업을 복원한 후 이전 구매를 즉시 사용할 수 있게 됩니다.This will ensure that after a user restores a backup their previous purchases will be immediately available.

자세한 iOS 관련 지침은 Apple의 보안 코딩 가이드를 참조 하세요.Refer to Apple’s Secure Coding Guide for more iOS-specific guidelines.

수신 확인 및 서버에서 제공 하는 제품Receipt Verification and Server-Delivered Products

지금까지이 문서의 예제는 앱 스토어 서버와 직접 통신 하 여 앱에 이미 코딩 된 기능 또는 기능의 잠금을 해제 하는 응용 프로그램 으로만 이루어져 있습니다.The examples in this document so far have consisted solely of the application communicating directly with the App Store servers to conduct purchase transactions, which unlock features or capabilities already coded into the app.

Apple은 다른 서버에서 구매 확인을 독립적으로 확인할 수 있도록 하 여 추가 수준의 구매 보안을 제공 합니다 .이를 통해 구매의 일부로 디지털 콘텐츠를 전달 하기 전에 요청을 유효성 검사 하는 데 유용할 수 있습니다 (예: 디지털 설명서 또는 잡지).Apple provides for an additional level of purchase security by allowing purchase receipts to be independently verified by another server, which can be useful to validate a request before delivering digital content as part of a purchase (such as a digital book or magazine).

기본 제공 제품 –이 문서의 예제와 같이 구매한 제품은 응용 프로그램과 함께 제공 되는 기능으로 존재 합니다.Built-In Products – Like the examples in this document, the product being purchased exists as functionality shipped with the application. 앱 내 구매를 통해 사용자는 기능에 액세스할 수 있습니다.An in-app purchase enables the user to access the functionality. 제품 Id는 하드 코드 되어 있습니다.Product IDs are hardcoded.

서버에서 제공 하는 제품 –이 제품은 성공적인 트랜잭션으로 인해 콘텐츠가 다운로드 될 때까지 원격 서버에 저장 된 다운로드 가능한 콘텐츠로 구성 됩니다.Server-Delivered Products – The product consists of downloadable content that is stored on a remote server until a successful transaction causes the content to be downloaded. 예제에는 책 또는 잡지 문제가 포함 될 수 있습니다.Examples might include books or magazine issues. 제품 Id는 일반적으로 외부 서버에서 소싱 됩니다 (제품 콘텐츠도 호스트 됨).Product IDs are usually sourced from an external server (where the product content is also hosted). 응용 프로그램은 트랜잭션이 완료 된 시기를 기록 하는 강력한 방법을 구현 해야 하므로 콘텐츠 다운로드에 실패 하면 사용자를 혼동 하지 않고 다시 시도할 수 있습니다.Applications must implement a robust way of recording when a transaction has completed, so that if content download fails it can be re-attempted without confusing the user.

서버에서 제공 하는 제품Server-Delivered Products

책, 잡지 (또는 게임 수준)와 같은 일부 제품 콘텐츠는 구매 프로세스 중에 원격 서버에서 다운로드 해야 합니다.Some product’s content, such as books and magazines (or even a game level) need to be downloaded from a remote server during the purchase process. 즉, 제품 콘텐츠를 구매한 후 저장 하 고 배달 하려면 추가 서버가 필요 합니다.This means an additional server is required to store and deliver the product content after it is purchased.

서버에서 제공 하는 제품 가격 얻기Getting Prices for Server-Delivered Products

제품이 원격으로 전달 되기 때문에 책을 추가 하거나 잡지의 새로운 문제를 추가 하는 등, 시간에 따라 제품을 더 추가할 수 있습니다 (앱 코드를 업데이트 하지 않고).Because the products are remotely delivered, it is also possible to add more products over time (without updating the app code), such as adding more books or new issues of a magazine. 응용 프로그램이 이러한 뉴스 제품을 검색 하 여 사용자에 게 표시할 수 있도록 추가 서버는이 정보를 저장 하 고 제공 해야 합니다.So that the application can discover these news products and display them to the user, the additional server should store and deliver this information.

  1. 제품 정보는 서버와 iTunes Connect에서 여러 위치에 저장 해야 합니다.Product information must be stored in multiple places: on your server and in iTunes Connect. 또한 각 제품에는 연결 된 콘텐츠 파일이 있습니다.In addition, each product will have content files associated with it. 이러한 파일은 성공적으로 구매한 후에 배달 됩니다.These files will be delivered after a successful purchase.

  2. 사용자가 제품을 구입 하려는 경우 응용 프로그램에서 사용할 수 있는 제품을 결정 해야 합니다.When the user wishes to purchase a product, the application must determine what products are available. 이 정보는 캐시 될 수 있지만, 제품의 마스터 목록이 저장 된 원격 서버에서 배달 되어야 합니다.This information may be cached, but should be delivered from a remote server where the master list of products is stored.

  3. 서버는 구문 분석할 응용 프로그램의 제품 Id 목록을 반환 합니다.The server returns a list of Product IDs for the application to parse.

  4. 그런 다음 응용 프로그램은이 제품 Id 중에서 지 수 키트에 전송 하 여 가격 및 설명을 검색 합니다.The application then determines which of these Product IDs to send to StoreKit to retrieve prices and descriptions.

  5. 서버 키트는 Apple의 서버에 제품 Id 목록을 보냅니다.StoreKit sends the list of Product IDs to Apple’s servers.

  6. ITunes 서버는 유효한 제품 정보 (설명 및 현재 가격)를 사용 하 여 응답 합니다.The iTunes servers respond with valid product information (description and current price).

  7. 응용 프로그램의 SKProductsRequestDelegate는 사용자에 게 표시 하기 위해 제품 정보를 전달 합니다.The application’s SKProductsRequestDelegate is passed the product information for display to the user.

서버에서 제공 하는 제품 구매Purchasing Server-Delivered Products

원격 서버에서 콘텐츠 요청이 유효한 지 확인 하는 몇 가지 방법이 필요 하기 때문에 (ie .는에 대해 지불 됨) 확인 정보는 인증을 위해 함께 전달 됩니다.Because the remote server requires some way of validating that a content request is valid (ie. has been paid for), the receipt information is passed along for authentication. 원격 서버는 확인을 위해 해당 데이터를 iTunes에 전달 하 고 성공 하면 응용 프로그램에 대 한 응답에 제품 콘텐츠를 포함 합니다.The remote server forwards that data to iTunes for verification and, if successful, includes the product content in the response to the application.

  1. 앱이 큐에 SKPayment를 추가 합니다.The app adds an SKPayment to the queue. 필요한 경우 사용자에 게 Apple ID를 입력 하 라는 메시지가 표시 되 고 지불을 확인 하 라는 메시지가 표시 됩니다.If required the user will be prompted for their Apple ID, and asked to confirm the payment.

  2. 서버를 처리 하기 위해 서버에 요청을 보냅니다.StoreKit sends the request to the server for processing.

  3. 트랜잭션이 완료 되 면 서버는 트랜잭션 수신으로 응답 합니다.When the transaction is complete, the server responds with a transaction receipt.

  4. SKPaymentTransactionObserver 서브 클래스는 수신을 수신 하 고 처리 합니다.The SKPaymentTransactionObserver subclass receives the receipt and processes it. 제품을 서버에서 다운로드 해야 하기 때문에 응용 프로그램은 원격 서버에 대 한 네트워크 요청을 시작 합니다.Because the product must be downloaded from a server, the application initiates a network request to the remote server.

  5. 다운로드 요청은 원격 서버에서 콘텐츠에 액세스할 수 있는 권한이 있는지 확인할 수 있도록 수신 데이터와 함께 제공 됩니다.The download request is accompanied by the receipt data so that the remote server can verify it is authorized to access the content. 응용 프로그램의 네트워크 클라이언트는이 요청에 대 한 응답을 기다립니다.The application’s network client waits for a response to this request.

  6. 서버는 콘텐츠에 대 한 요청을 받으면 수신 데이터를 구문 분석 하 고 iTunes 서버에 직접 요청을 보내 올바른 트랜잭션에 대 한 수신 인지 확인 합니다.When the server receives a request for content, it parses out the receipt data and sends a request directly to the iTunes servers to verify the receipt is for a valid transaction. 서버는 일부 논리를 사용 하 여 프로덕션 또는 샌드박스 URL에 요청을 보낼지 여부를 결정 해야 합니다.The server should use some logic to determine whether to send the request to the production or sandbox URL. Apple은 항상 프로덕션 URL을 사용 하 고 수신 상태 21007 (샌드박스 확인이 프로덕션 서버에 전송 된 경우)로 전환 하는 것을 제안 합니다.Apple suggests always using the production URL and switching to sandbox if your receive status 21007 (sandbox receipt sent to production server). 자세한 내용은 Apple의 수신 확인 프로그래밍 가이드 를 참조 하세요.Refer to Apple's Receipt Validation Programming Guide for more details.

  7. iTunes는 수신 확인을 확인 하 고 유효한 경우 상태를 0으로 반환 합니다.iTunes will check the receipt and return a status of zero if it is valid.

  8. 서버에서 iTunes 응답을 기다립니다.The server waits for iTunes’ response. 유효한 응답을 수신 하는 경우 코드는 응용 프로그램에 대 한 응답에 포함할 연결 된 제품 콘텐츠 파일을 찾습니다.If it receives a valid response, the code should locate the associated product content file to include in the response to the application.

  9. 응용 프로그램은 응답을 받아서 구문 분석 하 여 제품 콘텐츠를 장치의 파일 시스템에 저장 합니다.The application receives and parses the response, saving the product content to the device’s filesystem.

  10. 이 응용 프로그램은 제품을 사용 하도록 설정한 다음, FinishTransaction을 호출 합니다.The application enables the product, and then calls StoreKit’s FinishTransaction. 그런 다음 응용 프로그램은 구매 된 콘텐츠를 선택적으로 표시할 수 있습니다. 예를 들어 구매한 책 또는 잡지 문제의 첫 번째 페이지를 표시 합니다.The application may then optionally display the purchased content (for example, show the first page of a purchased book or magazine issue).

매우 큰 제품 콘텐츠 파일의 대체 구현에는 트랜잭션이 신속 하 게 완료 될 수 있도록 #9 단계에서 트랜잭션 수신 확인을 저장 하 고 사용자가 실제 제품 콘텐츠를 다운로드할 수 있는 사용자 인터페이스를 제공 하는 것만 포함 될 수 있습니다. 나중에An alternative implementation for very large product content files could involve simply storing the transaction receipt in step #9 so that the transaction can be quickly completed, and providing a user-interface for the user to download the actual product content at some later time. 후속 다운로드 요청은 저장 된 수신 확인을 다시 전송 하 여 필요한 제품 콘텐츠 파일에 액세스할 수 있습니다.The subsequent download request can re-send the stored receipt to access the required product content file.

서버 쪽 수신 확인 코드 작성Writing Server-Side Receipt Verification Code

서버 쪽 코드에서 수신 확인은 워크플로 다이어그램의 #8를 통해 #5 단계를 포함 하는 간단한 HTTP POST 요청/응답을 사용 하 여 수행할 수 있습니다.Validating a receipt in server-side code can be done with a simple HTTP POST request/response that encompasses steps #5 through #8 in the workflow diagram.

앱에서 SKPaymentTansaction.TransactionReceipt 속성을 추출 합니다.Extract the SKPaymentTansaction.TransactionReceipt property in the app. 확인을 위해 iTunes로 보내야 하는 데이터입니다 (단계 #5).This is the data that needs to be sent to iTunes for verification (step #5).

트랜잭션 수신 데이터 (단계 #5 또는 #6)를 Base64로 인코딩합니다.Base64-encode the transaction receipt data (either in step #5 or #6).

다음과 같이 간단한 JSON 페이로드를 만듭니다.Create a simple JSON payload like this:

{
   "receipt-data" : "(base-64 encoded receipt here)"
}

프로덕션 또는 테스트 https://sandbox.itunes.apple.com/verifyReceipt 에 대 한 https://buy.itunes.apple.com/verifyReceipt JSON을 게시 합니다.HTTP POST the JSON to https://buy.itunes.apple.com/verifyReceipt for production or https://sandbox.itunes.apple.com/verifyReceipt for testing.

JSON 응답에는 다음 키가 포함 됩니다.The JSON response will contain the following keys:

{
   "status" : 0,
   "receipt" : { (receipt repeated here) }
}

상태 0은 올바른 수신 여부를 나타냅니다.A status of zero indicates a valid receipt. 서버에서 구매한 제품의 콘텐츠를 계속 처리할 수 있습니다.Your server can proceed to fulfill the purchased product’s content. 수신 키에는 앱에서 받은 SKPaymentTransaction 개체와 동일한 속성을 포함 하는 JSON 사전이 포함 되어 있으므로 서버 코드는이 사전을 쿼리하여 구매 수량 및 product_id 같은 정보를 검색할 수 있습니다.The receipt key contains a JSON dictionary with the same properties as the SKPaymentTransaction object that was received by the app, so the server code can query this dictionary to retrieve information such as the product_id and quantity of the purchase.

자세한 내용은 Apple의 영수증 유효성 검사 프로그래밍 가이드 설명서를 참조 하세요.See Apple’s Receipt Validation Programming Guide documentation for additional information.