itenfay / Unity-iOS-InAppPurchase

Unity实现苹果iOS的应用内购买( Unity implements Apple's in-app purchases for iOS.)。
Other
12 stars 1 forks source link

购买非消耗类型的物品后,调用初始化后.就会进入交易成功. #2

Open corle-bell opened 3 weeks ago

corle-bell commented 3 weeks ago

购买非消耗类型的物品后,重新启动应用。 调用初始化后.就会进入交易成功的状态是为什么?

QQ截图20240618103718

itenfay commented 2 weeks ago

付款完成,交易票据验证通过拿到server响应后,客户端要调用以下方法关闭此次交易,不然每次启动苹果server会通知客户端还有交易未完成,另外非消耗产品需要提供额外的恢复购买的按钮提供用户使用。

// Completes a pending transaction.
[DllImport("__Internal")]
private static extern void DYFFinishTransaction(string transactionId, string originalTransactionId);

// Completes a pending transaction.
[DllImport("__Internal")]
private static extern void DYFFinishTransaction_(string transactionId);
corle-bell commented 2 weeks ago

我在验证成功之后调用的关闭交易,调用了关闭交易还是存在这个问题。 无法正确的关闭时因为transactionId不正确么,我在恢复购买后,进行验证。然后再下行信息里拿到的transactionId和 初始化后弹出的交易里的transactionId并不一样。但是他们的originalTransactionId是一样的。当然他们都是同一个商品。

itenfay commented 1 week ago

你看一下 UnityIAPConnector.mm 文件这段代码。因为非消耗型产品,在恢复购买后,transactionId与之前不一样,但originalTransactionId是一样的,导致传新的transactionId找不到Restored transaction

/// Completes a pending transaction.
void DYFFinishTransaction(const char* transactionId, const char* originalTransactionId)
{
    NSString *transactionIdentifier = __OBJC_STRING(transactionId);
    NSString *orgTransactionIdentifier = __OBJC_STRING(originalTransactionId);

    DYFStore *store = DYFStore.defaultStore;
    SKPaymentTransaction *pt = [store extractPurchasedTransaction:transactionIdentifier];
    if (pt) {
        [DYFStore.defaultStore finishTransaction:pt];
    } else {
        SKPaymentTransaction *rt = [store extractRestoredTransaction:transactionIdentifier];
        [DYFStore.defaultStore finishTransaction:rt];
    }
    DYFStoreUserDefaultsPersistence *persister = [[DYFStoreUserDefaultsPersistence alloc] init];
    [persister removeTransaction:transactionIdentifier];

    if (orgTransactionIdentifier) {
        [persister removeTransaction:orgTransactionIdentifier];
    }
}
itenfay commented 1 week ago
- (SKPaymentTransaction *)extractRestoredTransaction:(NSString *)transactionIdentifier
{
    __block SKPaymentTransaction *transaction = nil;
    if (!transactionIdentifier || transactionIdentifier.length == 0) {
        return transaction;
    }

    [self.restoredTranscations enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SKPaymentTransaction *tempTransaction = obj;
        NSString *id = tempTransaction.transactionIdentifier;
        NSString *originalId = tempTransaction.originalTransaction.transactionIdentifier;
        DYFStoreLog(@"index: %zi, transactionId: %@, originalTransactionId: %@", idx, id, originalId);

        if ([id isEqualToString:transactionIdentifier]) {
            transaction = tempTransaction;
        }
    }];

    return transaction;
}

你过滤一下日志,看一下这段代码的日志打印的是什么,在这里回复我一下,我看到后分析定位问题所在,然后进行修复。

corle-bell commented 1 week ago
- (SKPaymentTransaction *)extractRestoredTransaction:(NSString *)transactionIdentifier
{
    __block SKPaymentTransaction *transaction = nil;
    if (!transactionIdentifier || transactionIdentifier.length == 0) {
        return transaction;
    }

    [self.restoredTranscations enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SKPaymentTransaction *tempTransaction = obj;
        NSString *id = tempTransaction.transactionIdentifier;
        NSString *originalId = tempTransaction.originalTransaction.transactionIdentifier;
        DYFStoreLog(@"index: %zi, transactionId: %@, originalTransactionId: %@", idx, id, originalId);

        if ([id isEqualToString:transactionIdentifier]) {
            transaction = tempTransaction;
        }
    }];

    return transaction;
}

你过滤一下日志,看一下这段代码的日志打印的是什么,在这里回复我一下,我看到后分析定位问题所在,然后进行修复。

这里是log,初始化后processPurchaseNotification这里收到的是DYFStorePurchaseStateSucceeded,而不是Restore image

e1faff28cdeba57b8957b1ba92d1e684

itenfay commented 1 week ago
- (SKPaymentTransaction *)extractRestoredTransaction:(NSString *)transactionIdentifier
{
    __block SKPaymentTransaction *transaction = nil;
    if (!transactionIdentifier || transactionIdentifier.length == 0) {
        return transaction;
    }

    [self.restoredTranscations enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SKPaymentTransaction *tempTransaction = obj;
        NSString *id = tempTransaction.transactionIdentifier;
        NSString *originalId = tempTransaction.originalTransaction.transactionIdentifier;
        DYFStoreLog(@"index: %zi, transactionId: %@, originalTransactionId: %@", idx, id, originalId);

        if ([id isEqualToString:transactionIdentifier]) {
            transaction = tempTransaction;
        }
    }];

    return transaction;
}

你过滤一下日志,看一下这段代码的日志打印的是什么,在这里回复我一下,我看到后分析定位问题所在,然后进行修复。

这里是log,初始化后processPurchaseNotification这里收到的是DYFStorePurchaseStateSucceeded,而不是Restore image

e1faff28cdeba57b8957b1ba92d1e684

  1. 红框标记和下面遍历Purchased Transcations都对得上。
  2. 看完log,发现调用完成交易的方法传入的交易id是null或是空的,你看下C#那边传的参数什么?
  3. 调用完成交易会进入下面的方法,检查一下交易id和原始交易id。

    /// Completes a pending transaction.
    void DYFFinishTransaction(const char* transactionId, const char* originalTransactionId)
    {
    NSString *transactionIdentifier = __OBJC_STRING(transactionId);
    NSString *orgTransactionIdentifier = __OBJC_STRING(originalTransactionId);
    
    DYFStore *store = DYFStore.defaultStore;
    SKPaymentTransaction *pt = [store extractPurchasedTransaction:transactionIdentifier];
    if (pt) {
        [DYFStore.defaultStore finishTransaction:pt];
    } else {
        SKPaymentTransaction *rt = [store extractRestoredTransaction:transactionIdentifier];
        [DYFStore.defaultStore finishTransaction:rt];
    }
    DYFStoreUserDefaultsPersistence *persister = [[DYFStoreUserDefaultsPersistence alloc] init];
    [persister removeTransaction:transactionIdentifier];
    
    if (orgTransactionIdentifier) {
        [persister removeTransaction:orgTransactionIdentifier];
    }
    }
corle-bell commented 1 week ago
- (SKPaymentTransaction *)extractRestoredTransaction:(NSString *)transactionIdentifier
{
    __block SKPaymentTransaction *transaction = nil;
    if (!transactionIdentifier || transactionIdentifier.length == 0) {
        return transaction;
    }

    [self.restoredTranscations enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SKPaymentTransaction *tempTransaction = obj;
        NSString *id = tempTransaction.transactionIdentifier;
        NSString *originalId = tempTransaction.originalTransaction.transactionIdentifier;
        DYFStoreLog(@"index: %zi, transactionId: %@, originalTransactionId: %@", idx, id, originalId);

        if ([id isEqualToString:transactionIdentifier]) {
            transaction = tempTransaction;
        }
    }];

    return transaction;
}

你过滤一下日志,看一下这段代码的日志打印的是什么,在这里回复我一下,我看到后分析定位问题所在,然后进行修复。

这里是log,初始化后processPurchaseNotification这里收到的是DYFStorePurchaseStateSucceeded,而不是Restore image e1faff28cdeba57b8957b1ba92d1e684

  1. 红框标记和下面遍历Purchased Transcations都对得上。
  2. 看完log,发现调用完成交易的方法传入的交易id是null或是空的,你看下C#那边传的参数什么?
  3. 调用完成交易会进入下面的方法,检查一下交易id和原始交易id。
/// Completes a pending transaction.
void DYFFinishTransaction(const char* transactionId, const char* originalTransactionId)
{
    NSString *transactionIdentifier = __OBJC_STRING(transactionId);
    NSString *orgTransactionIdentifier = __OBJC_STRING(originalTransactionId);

    DYFStore *store = DYFStore.defaultStore;
    SKPaymentTransaction *pt = [store extractPurchasedTransaction:transactionIdentifier];
    if (pt) {
        [DYFStore.defaultStore finishTransaction:pt];
    } else {
        SKPaymentTransaction *rt = [store extractRestoredTransaction:transactionIdentifier];
        [DYFStore.defaultStore finishTransaction:rt];
    }
    DYFStoreUserDefaultsPersistence *persister = [[DYFStoreUserDefaultsPersistence alloc] init];
    [persister removeTransaction:transactionIdentifier];

    if (orgTransactionIdentifier) {
        [persister removeTransaction:orgTransactionIdentifier];
    }
}

调用传入的transactionIdentifier是正确的,最后的log是在这里输出的。 image 这里使用的值是 传入的SKPaymentTransaction中的字段 ,如果在上一步没有找到正确的SKPaymentTransaction这里就会出现空的字符串。和C# 传入的值没关系。