React-native-iap: finishTransactionIOS / finishTransaction ne fait rien pour iOS

Créé le 19 févr. 2020  ·  34Commentaires  ·  Source: dooboolab/react-native-iap

Version de react-native-iap

4.4.1

Version de react-native

0,60,4

Plateformes sur lesquelles vous avez rencontré l'erreur (IOS ou Android ou les deux?)

iOS

Comportement attendu

Lors de l'appel de finishTransactionIOS (purchaseId) ou finishTransaction (purchase) pour un abonnement, la transaction doit être terminée et ne pas être émise à nouveau vers l'application au prochain lancement. S'il y avait un problème avec cela, je m'attendrais à ce que quelque chose soit retourné à l'écouteur d'erreur ou dans une promesse de l'une des fonctions finishTransaction, rien ne se passe.

Android semble fonctionner correctement.

Comportement réel

La transaction est émise à chaque lancement, sauf si clearTransactionIOS est appelé, ce qui semble avoir d'autres effets secondaires.

Environnement testé (émulateur? Real Device?)

Appareil réel

Étapes pour reproduire le comportement

  • Créez un produit d'abonnement.
  • Achetez l'abonnement
  • Simuler la validation backend
  • Appelez finishTransactionIOS ou finishTransaction sur cet abonnement. N'a aucun effet.

J'ai essayé cette pile de différentes manières, et absolument rien ne semble fonctionner, quoi que je fasse, à part effacer les transactions, l'achat est à nouveau émis sur l'application à chaque lancement. Des idées sur ce qui se passe ou sur ce que je pourrais faire ou mal comprendre?

ℹ needs more info 📱 iOS 🙏 help wanted 🚶🏻 stale

Commentaire le plus utile

@hyochan une mise à jour sur ce problème? Nous sommes bloqués depuis un certain temps et incapables de publier notre application.

Tous les 34 commentaires

J'ai le même problème.

Pouvez-vous partager les ackResult ?

          try {
            const ackResult = await finishTransaction(purchase);
            console.log('ackResult', ackResult);
          } catch (ackErr) {
            console.warn('ackErr', ackErr);
          }

@hyochan
Dans mon cas:
ackResult undefined

@hyochan
Dans mon cas:
ackResult undefined

Pareil ici

Dans mon cas également, la valeur retournée n'est pas définie (appareil réel avec un utilisateur sandbox).

Il semble lié à # 366. Aussi pour ios finishTransaction ne retournera rien.
Pouvez-vous tous vous concentrer sur # 366 et revenir pour la mise à jour?

Il semble lié à # 366. Aussi pour ios finishTransaction ne retournera rien.
Pouvez-vous tous vous concentrer sur # 366 et revenir pour la mise à jour?

Juste pour clarifier - puisque le # 366 concerne les tests, suggérez-vous que cela devrait fonctionner correctement en production sans avoir besoin de clearTransactionIOS?

@hyochan Lorsque je teste la configuration de débogage avec un compte sandbox, je reçois essentiellement une notification du serveur au serveur (Apple) concernant un achat. Le problème est qu'après un certain temps, mon auditeur client reçoit une autre notification concernant l'achat, mais avec un identifiant de transaction différent, même lorsque l'action d'achat n'a eu lieu qu'une seule fois, il semble donc que le problème soit de terminer correctement la transaction précédente. Sur Android, tout fonctionne bien et je pense que ce n'est pas lié à # 366 car je n'ai aucun problème pour tester le processus d'achat avec un compte sandbox.

`` tsx
useEffect (() => {
purchaseUpdateSubscription.current = purchaseUpdatedListener (
async (achat: InAppPurchase | SubscriptionPurchase) => {
reçu de const = achat.transactionReceipt;
if (reçu) {
essayez {
attendez myBackendHandler ({
utilisateur,
achat,
});
résultat const = attendre RNIap.finishTransaction (achat, faux);
console.log ('résultat', résultat);
} catch (e) {
// À FAIRE
}
}
}
);
return () => {
if (purchaseUpdateSubscription.current) {
purchaseUpdateSubscription.current.remove ();
purchaseUpdateSubscription.current = null;
}
};
}, []);
`` ``

Hé équipe, merci pour tout le travail acharné sur cette bibliothèque, cela nous facilite vraiment la vie. Je commente parce que ce problème n'a pas été résolu et je ne vois pas à quel point les anciennes transactions non compensées ont quelque chose à voir avec # 366.

Mon cas d'utilisation est

  1. L'utilisateur 1 effectue l'achat et l'avantage premium appliqué à son compte.
  2. L'utilisateur 1 se déconnecte
  3. L'utilisateur 2 se connecte

Résultat attendu:

  • Les transactions de l'utilisateur 1 ne sont pas émises via l'écouteur d'achat

Résultat actuel

  • Les transactions de l'utilisateur 1 ne sont PAS effacées et sont à nouveau émises. Même si un nouvel utilisateur s'est connecté, ce qui entraîne de mauvaises données.

Ceci n'est qu'un exemple de la raison pour laquelle il est important que cette question soit priorisée. Merci d'avoir lu ce long commentaire ...

pareil ici

exactement le même problème que ci-dessus, on dirait que la pile n'est pas du tout effacée, même après avoir déconnecté le compte sandbox / itunes, redémarrer l'appareil, réinstaller l'application ..: /

Pouvez-vous vérifier que le finishTransaction ne fait vraiment rien dans le fichier RNIapIos.m ?
Je viens de le vérifier et il termine correctement sa transaction.

Veuillez vérifier la méthode clearTransaction ou finishTransactionWithIdentifier et essayez de mettre des journaux à l'intérieur. Essayez de trouver les codes ci-dessous.

RCT_EXPORT_METHOD(clearTransaction) {
    NSArray *pendingTrans = [[SKPaymentQueue defaultQueue] transactions];
    NSLog(@"\n\n\n  ***  clear remaining Transactions. Call this before make a new transaction   \n\n.");
    for (int k = 0; k < pendingTrans.count; k++) {
        [[SKPaymentQueue defaultQueue] finishTransaction:pendingTrans[k]];
    }
-(void)finishTransactionWithIdentifier:(NSString *)transactionIdentifier {
    SKPaymentQueue *queue = [SKPaymentQueue defaultQueue];
    for(SKPaymentTransaction *transaction in queue.transactions) {
        if([transaction.transactionIdentifier isEqualToString:transactionIdentifier]) {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
    }
}

Je ne peux pas faire avancer ce problème car je n'ai aucune idée de ce qui se passe. J'espère que quelqu'un pourra déboguer des choses dans son environnement et partager 🙏

une mise à jour sur ce problème?

up, je rencontre ce problème aussi.

idem ici finishTransactionIOS / finishTransaction cela ne fonctionne pas sous IOS

J'ai l'impression de vivre la même chose.
L'achat d'IAP se termine avec succès, mais l'appel final à finishTransaction renvoie undefined .

// Finish transaction
const ackResult = await finishTransaction(purchase);
console.log("Ack result: ", ackResult); // Ack result: undefined

_Appareil réel "iPhone 6s" utilisant l'environnement Sandbox de l'App Store._

Quel est le résultat attendu de finishTransaction? Est-ce que undefined un bon résultat ou dois-je m'attendre à autre chose?

Je rencontre également ce problème sur iOS, où ni finishTransactionIOS ni finishTransaction ne suppriment réellement ces transactions, ce qui m'empêche de publier l'application. Toute mise à jour?

@hyochan Bien que je ne parle certainement pas couramment Objective-C, j'ai ajouté quelques journaux dans finishTransaction et finishTransactionWithIdentifier et il semble qu'ils fonctionnent correctement (l'id est passé et mis en correspondance). La seule chose à laquelle je peux penser est que [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; ne se connecte pas réellement à StoreKit et ne termine pas la transaction? Je ne sais pas vraiment où aller à partir de là, mais j'espère que cela vous sera utile lors du débogage

Traitez-vous également les notifications de statut d'abonnement depuis l'App Store? Dans mon cas, j'ai eu ce problème jusqu'à ce que je m'assure que mon serveur gère correctement tous les événements de notification et répond avec un 200.

@espenjanson Intéressant. Non, je ne l'étais pas. Mais en fait, je viens de passer hier au module InAppPurchases d'expo et tout fonctionne très bien maintenant.

@lachlanglen Nevermind. C'était juste un coup de chance (?) Ou autre chose. Construit une autre version de l'application et le problème est de nouveau là. Pensant faire de même mais un peu inquiet que le repo expo ne soit pas très bien entretenu.

J'y étais en train de regarder et il est correct qu'il retourne undefined puisque l'appel finishTransactions n'est pas destiné à renvoyer quoi que ce soit dans obj-c.
J'ai fait quelques tests et dans mon cas, cela semble les terminer correctement (test simple, pull pendingTransactions, s'il n'y a rien, ça marche bien)

@espenjanson Je ne sais pas ce qui vous fait penser que les packages Expo ne sont pas bien entretenus. Je pense qu'Expo a sorti son module iap assez récemment. Si je savais qu'expo avait le module iap au moment où j'implémentais iap, j'aurais choisi expo sans réfléchir à deux fois.

Y a-t-il un moyen de résoudre ce problème?
J'ai testé cela sur TestFlight même avec un nouvel utilisateur de sandbox et cela continue toujours de se produire.

Mon purchaseUpdateListener continue de recevoir des "anciennes" transactions.
J'appelle finishTransaction(purchase,false) car j'utilise des abonnements autorenouvelables.
Le résultat de l'appel est undefined .

Quelqu'un peut-il proposer une solution de contournement ou une explication de ce problème?

@zatloeri C'est apparemment un comportement souhaité. Il m'a fallu un certain temps pour m'en rendre compte. L'App Store mettra un nouveau reçu de renouvellement dans StoreKit, ce qui déclenchera l'observateur. Vous devez traiter ce reçu et terminer la transaction.

https://developer.apple.com/videos/play/wwdc2018/705/
https://developer.apple.com/videos/play/wwdc2020/10671

(regardez dans Safari pour la qualité HD)

@ziyoshams Merci pour la réponse rapide et pour les ressources que je vais parcourir un peu.

Mais d'abord, je veux juste souligner une chose parce que je ne pense pas l'avoir rendue apparente.
Ce que vous décrivez me semble logique et je m'attendais à ce que cela se produise, mais ce qui me laisse perplexe, c'est ceci:

Le produit A a expiré, comme vérifié par receipt validation .
Je reçois une ancienne transaction (de la veille) pour le produit A lorsque je lance ou mets au premier plan l'application.
Ensuite, la prochaine fois que je mets au premier plan l'application, je reçois une autre transaction ancienne (peut-être un peu plus récente que la précédente, pas sûr) pour le produit A.
Sur un autre premier plan peut-être un autre et ainsi de suite.

Je m'attendrais à les obtenir tous sur une seule application si l'abonnement est déjà après son expiration.
Est-ce également un comportement attendu ou y a-t-il quelque chose de louche?

@zatloeri Chaque transaction non terminée apparaîtra dans cette file d'attente, même si elle a expiré. Pour les abonnements mensuels, vous devriez recevoir ce reçu toutes les 5 minutes environ. Par exemple, si vous achetez quelque chose et revenez à l'application le lendemain, vous obtiendrez 5 à 6 reçus en même temps. Je recommande vivement de regarder ces vidéos WWDC. Ils sont si utiles.

J'ai le même problème sur iOS, la transaction ne se termine pas, la file d'attente ne se vide pas et le reçu réapparaît à chaque fois que l'application est lancée. J'ai vérifié la réception côté serveur, puis la transaction terminée. Veuillez jeter un œil à mon code ci-dessous

J'ai mentionné quelques extraits de mon code ci-dessous ...

''
importer RNIap, {
InAppPurchase,
Produit,
PurchaseError,
Abonnement,
AbonnementAchat,
finitionTransaction,
finishTransactionIOS,
purchaseErrorListener,
purchaseUpdatedListener,
clearTransactionIOS,
} de 'react-native-iap';

async componentDidMount () {
résultat const = attendre RNIap.initConnection ();
const itemSubs = Platform.select ({
Android: [
get (this.props, 'subscriptionStore.subscription.android_product_id', null)
],
ios: [
get (this.props, 'subscriptionStore.subscription.ios_product_id', null)
]
});

abonnements const = attendre RNIap.getSubscriptions (itemSubs);
purchaseUpdateSubscription = purchaseUpdatedListener (
async (achat) => {
reçu de const = achat.transactionReceipt;
laissez abonnement = {
subscription_id: get (this.props, 'subscriptionStore.subscription.id', null)
};
if (Platform.OS === 'ios') {
abonnement = {
...abonnement,
order_id: get (achat, 'transactionId', null),
achat_token: get (achat, 'originalTransactionIdentifierIOS', null),
reçu: get (achat, 'transactionReceipt', null), // (Stockez-le dans TEXT)
os: 'IOS'
}
} else if (Platform.OS === 'android') {
const data = JSON.parse (reçu);
abonnement = {
...abonnement,
order_id: get (données, 'orderId', null),
buy_token: get (données, 'purchaseToken', null),
os: 'ANDROID'
}
}
essayez {
finishTransaction (achat, faux); // c'est ici pour temp, il sera placé sur le succès plus tard.
this.props.notificationStore.showToast ('Abonné avec succès. Veuillez patienter ...', 'succès', 5000);
const resp = wait this.props.subscriptionStore.onPurchase (abonnement); // vérification des transactions côté serveur.
if (resp.success) {// réponse de succès
this.props.userStore.setUser ({is_premium: 1});
this.props.navigation.replace ('FixFooter');
}
} catch (erreur) {
console.log ("ERREUR API onPurchase:", erreur);
}
}
)

purchaseErrorSubscription = purchaseErrorListener (
async (erreur) => {
console.log ('erreur d'achat:', erreur);
}
)
}

/ * Bouton onPurchase * /
async onPurchase () {
essayez {
const request = attendre RNIap.requestSubscription (Platform.OS === 'android'?
get (this.props, 'subscriptionStore.subscription.android_product_id', null):
get (this.props, 'subscriptionStore.subscription.ios_product_id', null))
} catch (erreur) {
console.log ('erreur:', erreur)
}
}

@ sufyan297 pouvez-vous s'il vous plaît partager un extrait de votre code côté serveur? J'essaie également de mettre en place un truc de vérification des reçus, mais le document d'Apple est extrêmement déroutant

@ziyoshams Obtenez -vous null également en utilisant la méthode finishTransaction du module expo iap?

@bcbcbcbcbcl Je n'utilise pas le module expo.

+1 pour moi il renvoie undefined

@hyochan une mise à jour sur ce problème? Nous sommes bloqués depuis un certain temps et incapables de publier notre application.

Salut, il semble qu'il n'y ait eu aucune activité sur ce problème récemment. Le problème a-t-il été résolu ou nécessite-t-il toujours l'attention de la communauté? Ce problème peut être résolu si aucune autre activité ne se produit. Vous pouvez également étiqueter ce problème comme "Pour discussion" ou "Bon premier numéro" et je le laisserai ouvert. Merci pour vos contributions.

Cette page vous a été utile?
0 / 5 - 0 notes