Some questions about Apple in-app purchases (IAP) and those pits

Source: Internet
Author: User
Tags response code

Recently in the study of Apple purchase function, so, on the Internet to find some information, to learn. However, the internal purchase function in the process of implementation, there are many pits, I really met a lot of ah, the following is their own internal purchase of some experience and experience it!

I said here may not be very detailed, so, I first see some of the online posts posted here, so that we do in-house shopping, convenient to find relevant information.

Here is a more comprehensive post, but did not write the middle problem processing: <ios development in the purchase of a full set of graphic tutorials >

Search on the Internet a number of related posts, a simple summary summed up, I think there is a forum called Teng of the world's great God, wrote three blog, written in detail:


"One of the IAP payments" In-app Purchase Walk Through the entire payment process

"IAP Payment II" in app purchase local purchase and server purchase two modes of purchase

"IAP payment three" Apple IAP Secure payment and Prevention receipt receipt verification

Before you make a purchase, we recommend a look!

However, after all, we developed the IAP to run on the Apple platform, so, if the English ability is good, it is best to go to the Apple official website without a look at <, which involves some of the Forum's posts did not mention the issues, and these content, it is likely to be ignored. The following is a Chinese translation of official < documents, which can be viewed against official documents. But sometimes there are problems associated with it. All right, nonsense, I'll start with the implementation of IAP and the specific problems, I may be involved in a lot of issues to be aware of, the flow of things will be less. Let's try to read some of the blogs above before reading the blog.

First, we're going to the itunes store to create a few products that we need to use in-store, remember that the product ID must be unique. Apple's official mentions that there are several types of IAP purchases:

  • Consumable Products: Consumer Product

  • non-consumable Products: non-expendable product

  • auto-renewable Subscriptions: Automatic Update Subscription Product

  • non-renewable subscriptions. Non-automatic Update subscription products

  • Free subscriptions. Free Subscription production

We usually play in the game currency is consumed products, racing tracks and other non-expendable products, usually these 2 kinds will be more common. I was using a consumer product.

Once the product is created, go to the itunes Store to apply for a test account and start writing the code. Before writing the code, the most important thing is to understand the process of the entire internal purchase implementation. Here is a better description of the < process of the post, the following is the flowchart:



In the final analysis, we have been dealing with the App Store, not with Apple's server, so we have to avoid this misunderstanding, and the app Store to deal with the Apple server, this layer, in fact, we do not need to consider the basic.

Process:

1. First, from the first step on the diagram, the client sends a request to its own server, requests the product list, and then our own server returns the identifiers to the client's product, which is the product ID that we set when we created the product, We need to request product details from the App store based on the identifiers obtained. However, for some applications, there may be no changes in the product category, so the direct integration of identifiers in the application, some directly placed in the Plist file, when needed, direct call, do not need to send a request to the server to obtain order information. But this also has the disadvantage, when the product changes, needs to release the new version, updates the application only then, therefore, does not recommend the use this kind of scheme.

2. After obtaining the product information, to refresh the UI, display to the user, let the user choose to buy that product, and then click the Buy button. When a user buys a product, our app sends a purchase request to the App store, the App Store receives it, the order is processed after the purchase request, and then returns the result of the purchase, and from the top we can see that Back to the client there is a receipt data, this thing is actually used to verify the certificate (in fact, a very long string, about 3,000 characters), to prevent someone using the jailbreak plugin, so that the repeated access to our products, especially like the gold coin.

3. After the client obtains the purchase result, sends the payment information (including the authentication certificate) to the server, the server initiates the authentication to the AppStore, this authentication must be the POST request, sends the data in the JSON format the past, simultaneously, receipt wants to carry on the Base64 encoding, when Apple confirms Will give us a status code that tells us if it was successful.


This is the official Apple given the central state value, the data returned by Apple is also in JSON format, there will be a national field, when it is 0, indicating success, we tested the interface is:https://sandbox.itunes.apple.com/ Verifyreceipt, the interface of the production environment is:https://buy.itunes.apple.com/verifyReceipt

, so we have to distinguish between the two interfaces. 21007 means that the test environment to get receipt sent to the production environment, 21008 means that the production environment receipt sent to the test environment, the other return value, should all indicate that the validation failed, but, what is specific, I also do not know, English good, you can translate it yourself, and then, Tell me. Here is the < Apple official authentication document, you can view this, write out the client-side validation code. Because I do not do the service side, so do not know how to write service-side verification, but, the two should be interlinked, you can write a comment below to discuss together.

4. When the server obtains the return status from the AppStore, determines whether the purchase record, if any, updates the server-side database, indicates that the item has been purchased, and then sends the purchase result to the client. Here said AppStore, I found a lot of information on the Internet, are so said, but I think the Apple server to provide the interface, just for convenience, so, in the drawing, it is painted to the App Store to send verification, in fact, here is an interface provided by Apple server.

The author of the company at that time used is rmstore this open source library, this use is very convenient, so, we can also try, but do not guarantee completely no problem, because I in the process of use, in fact, also encountered some difficult problems. We can also write their own payment of this module, in fact, the normal process is not very troublesome, first the basic process, and then consider the possible problems, will be much better. I quoted in the above several links inside, some links inside the specific code, we can refer to.

In the case of Rmstore, the main thing is to call such a method:

-(void) Addpayment: (nsstring*) productidentifier              User: (nsstring*) Useridentifier           success: (void (^) ( Skpaymenttransaction *transaction)) Successblock           failure: (void (^) (skpaymenttransaction *transaction, NSError * Error)) Failureblock;

Let's talk about these parameters first. First, the first parameter, which is the identifier of the product we have acquired, is the unique identifier of the product to be purchased, and then the user, which is a custom object, can be a user's UUID or other information, and this is a great use. will be mentioned in the following: Here the success block, the actual payment after the success of the callback content, as long as the success of the operation after writing in the inside can be, but, because of the success, the need for a lot of operation, we must put the operation package, in the call, otherwise, the logic will be very messy, and , the following failure block also to judge and deal with many anomalies, one of which is "unable to connect to the itunes Store", this problem is very troublesome, will be specific later. In general, if you do not consider the user variable, you can use the following method directly:

-(void) Addpayment: (nsstring*) Productidentifier           success: (void (^) (skpaymenttransaction *transaction)) Successblock           failure: (void (^) (skpaymenttransaction *transaction, Nserror *error)) Failureblock;
This method calls the method above, but the user defaults to nil.


The payment process looks like this, it feels simple, but the problem is really big. Above is only in all normal state, will walk the process, but, if considering the network problems, broken network, application flash back, there are jailbreak plug-ins and other problems, the problem is troublesome, this process, each process needs to consider the problem, in fact, still a lot of. OK, so let's start with the various pits in the IAP implementation. First, bring the picture back above.

First, the first step:



This step is still very easy, we to the server to obtain product identifiers, because of the need for network requests, but also to pay, so, we must take off the network into consideration, this is necessary, then, in this step, we have to judge, when no data is obtained, To prompt users not to get product list information, this part is actually OK, do not need to consider too much.

After some of the process, it is more complex, think of things will be more. First take the rest of the pieces:


This part of the problem is a lot, and the need for logic is complex. First of all, the seventh step, this part, in the application, when the click on the purchase, will pop up the input box, ask to enter the account and password, when the click Cancel, will actually call failure block. When calling failure block, Will get a payment information transaction and an error, we can judge the transaction of the relevant information, to determine the cancellation status,

if (Transaction.error.code = = skerrorpaymentcancelled)
This is the code value of the error that determines the order information, and this is the cancellation state. But in fact, this is a more common state. When the user re-purchase process, if in the process, the sudden disconnection of the network, or the request to pay the status of the order of the problem, that is, the above process ⑦ a problem, it will trigger the other states, this time, if only the output order failure information, there will be "unable to connect to the itunes store", It's a very frustrating situation because you don't know exactly what the problem is and how you can't connect to the itunes store. I was also trapped by the problem, and later found out that this was actually a request failure, similar to skerrorpaymentcancelled. Skerrorpaymentcancelled and several other states are actually enumerated types:

Ns_assume_nonnull_beginsk_extern NSString * Const Skerrordomain Ns_available_ios (3_0);//error codes for the Skerrordomainenum {    Skerrorunknown,    skerrorclientinvalid,               //client is not allowed to issue the request, etc.    skerrorpaymentcancelled,            //user cancelled the request, etc.    Skerrorpaymentinvalid,              //Purchase identifier was invalid, etc.    skerrorpaymentnotallowed,           //This device isn't allowed to make the payment    skerrorstoreproductnotavailable,< c10/>//Product isn't available in the current storefront}; Ns_assume_nonnull_end

The same kind of problem, which is said above can not connect to the itunes store, although aware of these kinds of States, but, still do not know what these states represent what. So I went to the Apple development document and looked at it,

Constantsskerrorunknownindicates that's an unknown or unexpected error occurred. Available in IOS 3.0 and later. Skerrorclientinvalidindicates that the client isn't allowed to perform the attempted action. Available in IOS 3.0 and later. Skerrorpaymentcancelledindicates that the user cancelled a payment request. Available in IOS 3.0 and later. Skerrorpaymentinvalidindicates that one of the payment parameters is not recognized by the Apple App store.available in I OS 3.0 and later. Skerrorpaymentnotallowedindicates the user is not allowed to authorize payments. Available in IOS 3.0 and later. Skerrorstoreproductnotavailableindicates that the requested product isn't available in the store. Available in IOS 6.0 and later.

This is an official explanation, and you can try translating it to understand what the representative means. Later on the online search for a related article, only found one, said < can not connect to itunes Store>, but there are several states written here, and not all covered, and then I found a bit on the Internet, the following is I gave to the itunes Store can not connect to the processing:

    if (transaction.error! = nil) {switch (transaction.error.code) {case Skerrorunknow                N:nslog (@ "Skerrorunknown");                Detail = @ "Unknown error, you may be using jailbreak phone";                            Break                Case Skerrorclientinvalid:nslog (@ "Skerrorclientinvalid");                Detail = @ "Current Apple account is not able to purchase goods (if in doubt, ask Apple customer service)";                            Break                Case Skerrorpaymentcancelled:nslog (@ "skerrorpaymentcancelled");                Detail = @ "Order cancelled";            Break                Case Skerrorpaymentinvalid:nslog (@ "Skerrorpaymentinvalid");                Detail = @ "The order is invalid (if in doubt, you can ask Apple customer service)";                            Break                Case Skerrorpaymentnotallowed:nslog (@ "skerrorpaymentnotallowed");                Detail = @ "The current Apple device is unable to purchase the product (if in doubt, ask Apple customer service)";                            Break CaseSkerrorstoreproductnotavailable:nslog (@ "skerrorstoreproductnotavailable");                Detail = @ "Current item not available";                            Break                Default:nslog (@ "No Match Found for error");                Detail = @ "Unknown error";        Break }    }


This skerrorunknown is really difficult to deal with, I looked for a lot of posts, including StackOverflow, also did not see too many statements, some say it may be jailbroken mobile phone, will appear this state, in the test, we usually encounter this problem. When testing, we need to apply for a test account with itunes Connect, sometimes the test account is out of order, or the test account has been canceled, no longer used, and when the payment is still using this test account, this time, also will appear unknown state.

Of course, there are a number of failures, which are not connected to the itunes store, not a network issue. The above mentioned failure, there will be transaction and error two return value, when the network has a problem, error.code is negative. At this time, success, without this error message, then, we can determine exactly what is going on, when the error returned, First judge whether the transaction.error is empty, not empty, the above switch judgment, for empty words, stating that the order information of the transaction is not a problem, at this time, just the network problem, the user is prompted to network anomalies.

When we send a request to AppStore, if the AppStore transaction is completed, that is, the above successful success block, we first have to save the order information to the local, and then send to our own server, when our server gave us back information, We then update the UI and delete the locally saved order information. This order information, can be saved in the database, can also be saved in the file, however, Apple is recommended to save in the file, with nscoding encoding to save, this will be better.

If you send a message to your server, there are a lot of things to watch out for. This also includes some of Afnetworking's problems. But I don't know if this is an occasional thing. The problems that arose at the time were this:ErrorDomain=com. Alamofire.error.serialization.responseCode=-1016 "Request failed:unacceptable content-type:text/html"

Error domain=com.alamofire.error.serialization.response code=-1016 "Request failed:unacceptable content-type:text/ html
I did not know what was going on, and later found some information on the Internet, only to understand that this is afnetworking to the network request data type of a support problem, the following in a post, tell us how to solve the problem:
 Error domain=com.alamofire.error.serialization.response code=-1016 "Request failed:unacceptable con

When this problem occurs, the order information will not be uploaded to their own server, this time, there is a problem, the user has paid, the money has been deducted, but our server does not have order information, so, can not give the user the goods, similar to harm the interests of users is absolutely not allowed. So, you can avoid this problem by changing the request type and adding support for text/html according to the above post. In addition, when our own server error, when the user intends to upload the order information to our server, at this time, the server may return some of our pre-set status code, for this state, we also have to make appropriate judgment on the client, when encountering such a problem, the prompt with the server error, Quickly contact our customer service, to solve the problem.


As mentioned above, when we send payment request to the App Store, when the payment is completed, the server will return the order to us, this time, the first thing we should do is to save the order information to the local, and then send the order information to our own server, when the server gives us feedback information, After notifying us of success, delete the locally saved order information. If it fails, we will set up a timer here to submit the unfinished failed order to our server and get the product we want to buy. But what if I don't have a network? This is where we have to query for unfinished order information each time the app is opened, and then upload the order information to the server to get the goods we want to buy.

After this state has been processed, there are other states, for example, when the network status is not good, when we launched the order request to the App store, the request was successful, but when the App store returned to our order, the network was disconnected, or, at this point, exiting the app, and applying the flash back, What should we do then? In fact, Apple has already figured out the solution to this problem for us. We just have to set up the agent when the app starts, that's it, < official document, we need to set the proxy method for Skpaymentqueue when the app starts

[[Skpaymentqueue Defaultqueue] addtransactionobserver:self];
and implement the Proxy method
-(BOOL) Application: (UIApplication *) application didfinishlaunchingwithoptions: (nsdictionary *) launchOptions{    Attach an observer to the payment queue    [[Skpaymentqueue Defaultqueue] addtransactionobserver:self];    return YES;} Called when the application are about to terminate-(void) Applicationwillterminate: (uiapplication *) application{     / /REMOVE The Observer    [[Skpaymentqueue Defaultqueue] removetransactionobserver:self];}
When the order status occurs, this method is called asynchronously, notifying us to update the order, and uploading the order information to the server for delivery to the user. If we use Rmstore, we actually do not need to implement manually, because Rmstore is the observe, so, when the application starts, we should be the Rmsotre this singleton initialization.

Here's how to do the following:

-(void) Addpayment: (nsstring*) productidentifier              User: (nsstring*) Useridentifier           success: (void (^) ( Skpaymenttransaction *transaction)) Successblock           failure: (void (^) (skpaymenttransaction *transaction, NSError * Error)) Failureblock;
In this method, there is a user attribute, which is used to customize the field, when we send a payment request, after sending this field, when the successful payment request is obtained, the field will return unchanged. This field is very useful when we log in to 2 different accounts with the same phone. Under normal circumstances, when we get the payment order information, to upload the order information to their own server, then, how to determine which is the user, by default, we will save the local user account, but also return to their own server. However, we assume such a situation: we now have a mobile phone, a in the above orders, the order has been sent to the App Store, this time, the network has not received the App Store feedback back payment results, this time, a quit the account, after a while, there is network, b login, At this point, if the order is returned, we will need to upload the order to our server in a normal state. So, the problem comes, we can't at this time or get the user information of a to place an order. If still according to the default state, at this time, the account information of B will be sent to our server together, so that the error, a buy things, did not get, B did not buy, but got. This is unreasonable. So, we have to send a payment request to the App Store, together with the order of the user information sent past, that is, the value of the users stored on the above, when the App Store feedback, then the user information together, and then sent to the server, so, There's no such thing as that.

The above is my recent development of some of the problems encountered in the resolution, there is not comprehensive and wrong place, but also ask you to criticize the guidance.






Some questions about Apple in-app purchases (IAP) and those pits

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.