从验证收据中检查自动续订订阅到期日期

Posted

技术标签:

【中文标题】从验证收据中检查自动续订订阅到期日期【英文标题】:Check auto-renewable subscription expire date from validate receipt 【发布时间】:2017-08-10 13:17:01 【问题描述】:

我正在应用程序委托中调用收据验证方法来检查可更新过程。它在开发模式下工作正常,但从应用商店发布后它总是返回是,即使用户没有购买该产品。请建议我做错了什么。在沙盒模式下它工作正常,但在发布后我发现它总是返回 true 的问题。为了验证收据,我使用以下代码

// 验证收据

+(BOOL ) getStoreReceipt:(BOOL)sandbox andTrasaction:(SKPaymentTransaction *)tractaion

    NSArray *objects;
    NSArray *keys;
    NSDictionary *dictionary;

    BOOL gotreceipt = false;

    @try 

        NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];

        if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptUrl path]]) 

            NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];

            NSString *receiptString = [self base64forData:receiptData];
            NSLog(@"receiptString Value---->= %@",receiptString);

            NSString *encReceipt = [receiptData base64EncodedStringWithOptions:0];
            NSLog(@"receiptString Value ======>= %@",encReceipt);
            if (receiptString != nil) 
                NSString *strSharedSecrect = @"MY_Secrect_Key";
                objects = [[NSArray alloc] initWithObjects:receiptString,strSharedSecrect, nil];
                keys = [[NSArray alloc] initWithObjects:@"receipt-data",@"password", nil];
                dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];

                NSString *postData = [self getJsonStringFromDictionary:dictionary];
                NSLog(@"postData Value---->= %@",receiptString);
                NSString *urlSting = @"https://buy.itunes.apple.com/verifyReceipt";
               // if (sandbox) urlSting = @"https://sandbox.itunes.apple.com/verifyReceipt";

                dictionary = [self getJsonDictionaryWithPostFromUrlString:urlSting andDataString:postData];
                  NSLog(@"dictionary Value for receipt---->= %@",dictionary);
                if ([dictionary objectForKey:@"status"] != nil) 

                    if ([[dictionary objectForKey:@"status"] intValue] == 0) 

                        gotreceipt = true;

                    
                

            

        //623065

     @catch (NSException * e) 
        gotreceipt = false;
        return NO;
         NSLog(@"NSException---->= %@",e);
    

    if (!gotreceipt) 
          NSLog(@"Not gotreceipt---->=");
        objects = [[NSArray alloc] initWithObjects:@"-1", nil];
        keys = [[NSArray alloc] initWithObjects:@"status", nil];
        dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
        return NO;
    else
        BOOL isPurchased = [self PurchasedSubscriptionStatues:dictionary];
         return isPurchased;
    
    return NO;

正在检查是否有待续订...

+(BOOL)PurchasedSubscriptionStatues:(NSDictionary *)transactionReceipt

    if ([[transactionReceipt allKeys] containsObject:@"pending_renewal_info"]) 

        NSArray *arrData = [transactionReceipt objectForKey:@"pending_renewal_info"];
        NSDictionary *dicPendinRenew = [arrData objectAtIndex:0];
        if ([[dicPendinRenew allKeys] containsObject:@"expiration_intent"] || [[dicPendinRenew objectForKey:@"auto_renew_status"] integerValue]==0) 
            return NO;
        else if ([[dicPendinRenew objectForKey:@"auto_renew_status"] integerValue]==1) 

            return YES;
        else
           return NO;
        
    else
        return YES;
    

    return NO;

字符串转字典

+(NSString *)getJsonStringFromDictionary:(NSDictionary *)dicVal

    NSError *error = nil;
    NSData *postData = [NSJSONSerialization dataWithJSONObject:dicVal options:NSJSONWritingPrettyPrinted error:&error];
    NSString *postString = @"";
    if (! postData) 
        NSLog(@"Got an error: %@", error);
        return nil;
    
    else  postString = [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding];
        return postString;
    

Convert  Dictionary to string
+(NSDictionary *) getJsonDictionaryWithPostFromUrlString:(NSString *)urlString andDataString:(NSString *)dataString 
    NSString *jsonString = [self getStringWithPostFromUrlString:urlString andDataString:dataString];
    NSLog(@"getJsonDictionaryWithPostFromUrlString-->%@", jsonString); // see what the response looks like
    return [self getDictionaryFromJsonString:jsonString];



+ (NSDictionary *) getDictionaryFromJsonString:(NSString *)jsonstring 
    NSError *jsonError;
    NSDictionary *dictionary = (NSDictionary *) [NSJSONSerialization JSONObjectWithData:[jsonstring dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&jsonError];
    if (jsonError) 
        dictionary = [[NSDictionary alloc] init];
    
    return dictionary;

//请求post方法获取recipt

+ (NSString *) getStringWithPostFromUrlString:(NSString *)urlString andDataString:(NSString *)dataString 
    NSString *s = @"";
    @try 
        NSData *postdata = [dataString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
        NSString *postlength = [NSString stringWithFormat:@"%d", [postdata length]];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
        [request setURL:[NSURL URLWithString:urlString]];
        [request setTimeoutInterval:60];
        [request setHTTPMethod:@"POST"];
        [request setValue:postlength forHTTPHeaderField:@"Content-Length"];
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:postdata];
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
        if (data != nil) 
            s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
    
    @catch (NSException *exception) 
        s = @"";
    
    return s;



// from https://***.com/questions/2197362/converting-nsdata-to-base64
+ (NSString*)base64forData:(NSData*)theData 
    const uint8_t* input = (const uint8_t*)[theData bytes];
    NSInteger length = [theData length];
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;
    NSInteger i;
    for (i=0; i < length; i += 3) 
        NSInteger value = 0;
        NSInteger j;
        for (j = i; j < (i + 3); j++) 
            value <<= 8;

            if (j < length) 
                value |= (0xFF & input[j]);
            
        
        NSInteger theIndex = (i / 3) * 4;
        output[theIndex + 0] =                    table[(value >> 18) & 0x3F];
        output[theIndex + 1] =                    table[(value >> 12) & 0x3F];
        output[theIndex + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[theIndex + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    
    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];



------------------------------------------------------------------------

【问题讨论】:

你的问题格式很糟糕;请修复它 【参考方案1】:

我认为您的PurchasedSubscriptionStatues 方法有错误:如果收据不包含pending_renewal_info 键,则返回YES。尝试创建一个新的沙盒用户并查看收据是否包含此密钥,如果没有,则此方法应在这种情况下返回 NO

另外,您可以尝试使用一些可以管理 InApp 购买的库,例如 RMStore,以简化收据验证。

【讨论】:

以上是关于从验证收据中检查自动续订订阅到期日期的主要内容,如果未能解决你的问题,请参考以下文章

如何更新自动更新订阅收据

iOS 7 自动续订订阅到期

应用购买iphone中的自动续订验证

iOS收据验证 - 自动续订订阅

如何为 iOS 应用实现 iOS 自动续订订阅收据验证

iOS可续订到期日期字段