La mise en œuvre de la Réception de la Validation de Swift 3
Je développe une application iOS dans Swift 3 et tentent de mettre en œuvre la réception de validation suivant ce tutoriel: http://savvyapps.com/blog/how-setup-test-auto-renewable-subscription-ios-app. Cependant, le tutoriel semble avoir été écrit à l'aide d'une version antérieure de Swift, donc j'ai eu à faire plusieurs changements. Voici mon receiptValidation() fonction:
func receiptValidation() {
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let receiptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
let postString = "receipt-data=" + receiptString! + "&password=" + SUBSCRIPTION_SECRET
let storeURL = NSURL(string:"https://sandbox.itunes.apple.com/verifyReceipt")!
let storeRequest = NSMutableURLRequest(url: storeURL as URL)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = postString.data(using: .utf8)
let session = URLSession(configuration:URLSessionConfiguration.default)
let task = session.dataTask(with: storeRequest as URLRequest) { data, response, error in
do{
let jsonResponse:NSDictionary = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
let expirationDate:NSDate = self.expirationDateFromResponse(jsonResponse: jsonResponse)!
self.updateIAPExpirationDate(date: expirationDate)
}
catch{
print("ERROR: " + error.localizedDescription)
}
}
task.resume()
}
}
Le problème s'affiche lorsque j'essaie d'appeler le expirationDateFromResponse() la méthode. Il s'avère que le jsonResponse qui est transmis à cette méthode contient: status = 21002;
. J'ai regardé et il signifie "les données de La réception de données de propriété a été mal formé ou manquant." Cependant, l'appareil je suis en essais sur dispose d'un sandbox de l'abonnement pour le produit, et l'abonnement semble fonctionner correctement à côté de cette question. Est-il autre chose que je besoin de le faire pour s'assurer que le receiptData valeur sera lu et codé correctement, ou de quelque autre problème qui peut être à l'origine de ce problème?
EDIT:
J'ai essayé une autre façon de mettre en storeRequest.httpBody:
func receiptValidation() {
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let receiptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) //.URLEncoded
let dict = ["receipt-data":receiptString, "password":SUBSCRIPTION_SECRET] as [String : Any]
var jsonData:Data?
do{
jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let storeURL = NSURL(string:"https://sandbox.itunes.apple.com/verifyReceipt")!
let storeRequest = NSMutableURLRequest(url: storeURL as URL)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = jsonData!
let session = URLSession(configuration:URLSessionConfiguration.default)
let task = session.dataTask(with: storeRequest as URLRequest) { data, response, error in
do{
let jsonResponse:NSDictionary = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
let expirationDate:NSDate = self.expirationDateFromResponse(jsonResponse: jsonResponse)!
self.updateIAPExpirationDate(date: expirationDate)
}
catch{
print("ERROR: " + error.localizedDescription)
}
}
task.resume()
}
}
Cependant, lorsque je lance l'application du présent code, il se bloque au moment d'atteindre la ligne jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
. Il n'a même pas le bloc catch, il s'arrête juste rien faire. De ce que j'ai vu en ligne, d'autres personnes semblent avoir de la difficulté à utiliser JSONSerialization.données pour la définition de la demande httpBody dans Swift 3.
J'ai changé mon code pour faire cette modification pour les receiptString juste après sa déclaration, mais je suis toujours de voir la même erreur. Aussi, quand j'imprime le receiptString, je remarque qu'il contient beaucoup de caractères "/" séparant le long de la base de 64 chaînes. Est-ce la façon dont il est censé le regarder quand il est correctement codé?
Je devrais aussi mentionner que j'ai essayé de supprimer les caractères"/", mais je vois encore le 21002 état.
J'ai mis à jour mon Essentiel de montrer le code que j'utilise pour récupérer de la réception et de coder les données base64. Dans mon cas, c'est envoyé de mon code php qui envoie sur les serveurs Apple pour gist.github.com/paulw11/fa76e10f785e055338ce06673787c6d2
En regardant le code, les données que vous envoyez n'est pas correct. Vous êtes l'envoi, la réception et le mot de passe que les données POST, mais vous avez besoin d'envoyer un objet JSON qui contient votre reçu et votre mot de passe. Si vous le faites, alors vous ne devriez pas avoir à vous soucier de l' % de l'encodage, c'était quelque chose dont j'avais besoin pour fonctionner avec mon PHP.
OriginalL'auteur user3726962 | 2016-09-26
Vous devez vous connecter pour publier un commentaire.
Son travail correctement avec Swift 4
C'-ce que pour renouvellement automatiques ? ou des régulièrement des achats in-app?
OriginalL'auteur Yasin Aktimur
J'ai mis à jour le @user3726962 du code, supprimant les NS es et "crash opérateurs". Il devrait ressembler à Swift 3 maintenant.
Avant d'utiliser ce code averti qu'Apple ne recommande pas de faire direct [périphérique] <-> [serveur Apple] validation et lui demande de le faire [périphérique] <-> [votre serveur] <-> [serveur Apple]. À utiliser uniquement si vous n'avez pas peur d'avoir de vos Achats Dans l'Application piraté.
Mise à JOUR: la fonction universelle: il va tenter de valider la réception de la Production tout d'abord, si omet - il de répéter avec bac à sable. C'est un peu encombrant, mais devrait être tout à fait autonome et indépendante, à partir de la 3e parties.
Cela fonctionne pour les abonnements renouvelables automatiquement. N'ai pas testé avec d'autres types d'abonnements encore. Laisser un commentaire si cela fonctionne pour vous avec un autre type d'abonnement.
Son un code, peut être placé n'importe où. Dans mon cas, c'est une partie d'un IAPHelper classe, qui à son tour est conservé comme une instance statique de IAPProducts struct nommé "magasin". De sorte qu'à partir AppDelegate il est appelé comme IAPProducts.magasin.tryCheckValidateReceiptAndUpdateexpirationdate() à chaque fois que j'en ai besoin.
Ah oui je comprends, je l'ai mis dans mon PEI service de classe que j'ai créé, et l'appel de cette méthode n'importe où je veux sur mon objet. Je vous remercie il travaille maintenant
Juste une dernière question, quand je soumettre mon application sur l'App Store, il tourne en mode de Production, dois-je changer cette url suivante: sandbox.itunes.apple.com/verifyReceipt par: buy.itunes.apple.com/verifyReceipt. Dans d'autres cas, devrait-je changer de "bac à sable" par "acheter" dans cette url avant de mettre mon application sur l'AppStore?
bonne question. Bref, la réponse est OUI. Mais vous pouvez également vérifier les mises à jour de code dans ma réponse ici, il prend soin au sujet de "bac à sable vs Production" problème, attendent et de la manipulation de la 21007 code, qui signifie "que la réception est à partir de bac à sable, aller vérifier là, mec". P. S. désolé de son encore sur Swift 3, espère que son cabriolet à 4.
OriginalL'auteur Vitalii
J'ai eu du mal de ma tête avec le même problème. Le problème est que cette ligne:
Renvoie une OPTION et
ne peut pas gérer les options. Donc, pour le fixer, il vous suffit de remplacer la première ligne de code:
Et tout fonctionnera comme un charme!
à la question d'origine de la receiptData est facultatif et il ne peut pas être passé à JSONSerialization.de données(...). Peut-être que votre problème en est une autre.
Votre suggestion de code utilise .lineLength64Characters. J'ai vérifié que l'obtention de la Chaîne à partir de Données avec cette option produit une erreur 21002 pour moi. Je suis d'accord que le code d'origine avait Facultatif (j'ai clairement vu lors du débogage) mais j'ai été également surpris de voir que cela fonctionnait correctement pour moi en quelque sorte. J'ai donc fini par utiliser le codage par défaut de la méthode receiptData.base64EncodedString(options: []). Voir le code complet dans ma réponse ci-dessous.
Où placer ce morceau de code? Dans AppDelegate.swift? Parce que dans mon ViewController.swift je ne peux pas trouver un moyen de faire cela fonctionne.
lire la question d'origine. Le code d'origine est: savvyapps.com/blog/...
OriginalL'auteur Pablo Romeu
Finalement, j'ai été en mesure de résoudre le problème en faisant de mon appli appeler une fonction Lambda écrit en Python, comme indiqué dans cette réponse. Je ne suis toujours pas sûr de ce qui n'allait pas avec mon code Swift ou la façon de le faire entièrement en Swift 3, mais la fonction Lambda obtenu le résultat souhaité, en tout cas.
OriginalL'auteur user3726962
//trop faible rep de commentaire
Yasin Aktimur, merci pour votre réponse, c'est génial. Cependant, en regardant la documentation d'Apple sur ce, ils disent de se connecter à iTunes sur une autre File d'attente. Donc, il devrait ressembler à ceci:
Ok ce que je peux demander à mon ami Google, aide-moi à faire une phrase, mon anglais est si mauvais, et le traducteur ne peut pas trouver un moyen de m'aider
Serez-vous l'appel de la fonction de plus d'une classe? Si donc, assurez-ce de la fonction publique dans un fichier séparé de garder tout propre. Si ce n'est pas que juste le mettre dans votre classe et de l'appeler une fois qu'un achat est effectué
OriginalL'auteur Not Batman
J'ai bien aimé votre réponse, et j'ai juste réécrit en C# pour ceux qui sont comme moi, comme je n'ai pas trouvé une bonne source pour trouver la solution.
Merci Encore
Pour les Consommables PEI
OriginalL'auteur Mohammad Khalifeh