iOS 解析 Stripe 集成

问题描述 投票:0回答:2

我对编程相当陌生,我创建了一个应用程序来向客户收费,并希望存储他们的 CC 信息并稍后收费。我已经阅读了所有教程和文档,但无法了解如何将其集成到我的应用程序中。我是否需要了解其他技术技能(例如 Rest API、Curl、Ruby 等)才能进行此设置?所有的指南和文档都指向这个方向。我不太明白 GET/POST 的用途以及它如何适合 iOS Objective-C 编程。

任何有关如何设置的指导将不胜感激。我已经被这个问题困扰了一段时间了。

ios parse-platform stripe-payments
2个回答
9
投票

Parse 的 stripe API 并不完整。有许多功能本身并不包含,但可以通过 HTTP 请求来完成。我必须学习一点 Javascript 和 HTTP 请求才能使许多功能正常工作。当然,您的第一直觉应该告诉您不要在任何设备上存储 CC 号码!每当您有用户输入 CC 号码时,立即获得一个令牌,然后这就是您需要使用的全部内容。

幸运的是,stripe 使您能够保存客户,并将 CC 附加到客户,然后在将来向该客户收费,而无需再次获取 CC 号码。 Parse 的 api 不处理向客户添加 CC,所以我自己添加了该功能。

所以步骤1和2使用Parse的API生成一个Customer,并使用Parse的API再次从他们输入的CC信息生成一个Token。如果您需要这方面的帮助以及所需的云代码,请告诉我。

步骤3 为客户添加CC。我正在使用自定义 Customer 对象,但您真正需要的主要内容是条带 customerId,即我的代码中的 customer.identifier,以及来自 CC 的 tokenID,在我的情况下是 token.tokenId。返回的响应将是带有卡信息的 JSON 字符串,我将其转换为字典,然后从字典创建 STPCard。我还展示了如何从客户那里删除卡。

iOS代码:

    +(void)addToken:(STPToken *)token toCustomerId:(NSString *)customerId completionHandler:(PFIdResultBlock)block
{
    [PFCloud callFunctionInBackground:@"stripeUpdateCustomer" withParameters:@{@"customerId":customerId,@"data":@{@"card":token.tokenId}} block:block];
}

+ (void)removeCard:(STPCard *)card FromCustomer:(ELCustomer *)customer completion:(STPCardDeletionBlock)handler
{
    if (!customer ||!customer.identifier || !card || !card.identifier || !handler) [NSException raise:@"RequiredParameter" format:@"Required Parameter Missing for deleting card from customer"];

    [PFCloud callFunctionInBackground:@"stripeDeleteCardFromCustomer" withParameters:@{@"cardId":card.identifier,@"customerId":customer.identifier} block:^(id object, NSError *error)
    {
            NSDictionary *dict = nil;
            NSError *jsonError = nil;

            if (object && [object isKindOfClass:[NSString class]] && !error) {
                dict = [NSJSONSerialization JSONObjectWithData:[object dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&jsonError];
            }
            if (!jsonError && dict) {
                handler(dict[@"id"],[dict[@"deleted"] boolValue],error);
            }
            else if(jsonError) handler(nil,NO,jsonError);
            else handler(nil,NO,error);
    }];
}

需要云代码:

Parse.Cloud.define("stripeUpdateCustomer", function(request, response) 
{
        Stripe.Customers.update
    (
        request.params["customerId"],
        request.params["data"],
        {
            success:function(results)
            {
                console.log(results["id"]);
                response.success(results);
            },
            error:function(error)
            {
                response.error("Error:" +error); 
            }
        }
    );
});

Parse.Cloud.define("stripeDeleteCardFromCustomer", function(request, response) 
{
        Stripe.initialize(STRIPE_SECRET_KEY);
        Parse.Cloud.httpRequest({
                method:"DELETE",
                //STRIPE_SECRET_KEY will be your stripe secrect key obviously, this is different from the public key that you will use in your iOS/Android side.
                // STRIPE_API_BASE_URL = 'api.stripe.com/v1'
                url: "https://" + STRIPE_SECRET_KEY + ':@' + STRIPE_API_BASE_URL + "/customers/" + request.params.customerId + "/cards/" + request.params.cardId,
                success: function(httpResponse) {
                response.success(httpResponse.text);
                },
                error: function(httpResponse) {
                response.error('Request failed with response code ' + httpResponse.status);
                }
        });
});

向客户或代币收取费用的 iOS 代码请注意,字典中所需的参数是以美分而非美元为单位的金额、一种货币,然后是客户或 tokenId。请注意,客户可以拥有多张信用卡,但其中一张是有效信用卡。活动卡是您向客户收费时将被扣款的卡:

//Will attempt to charge customer, if no customer exists, or it fails to charge the custoemr it will attempt to charge a card token directly;
//*********Warning: This is the final step it will APPLY A CHARGE TO THE ACCOUNT.***************

-(void)processChargeThroughStripeWithCompletionHandler:(STPChargeCompletionHandler)handler
{
    if (![self validForCardProcessing] && ![self validForCustomerProcessing]) {
        handler(nil,[NSError errorWithDomain:MY_ERROR_DOMAIN code:elErrorCodeNoCustomerOrTokenID userInfo:[NSDictionary dictionary]]);
        return;
    }
    [self processChargeThroughStripeUsingCustomerWithCompletionHandler:^(STPCharge *charge, NSError *error)
    {
        if (!error) handler(charge,error);
        else{
            [self processChargeThroughStripeUsingCardWithCompletionHandler:^(STPCharge *charge, NSError *error) {
                handler(charge, error);
            }];
        }
    }];
}

//Process payment using a customer to their active card. No token is required if customer exists with a card on record.
//*********Warning: This is the final step it will APPLY A CHARGE TO THE ACCOUNT.***************

-(void)processChargeThroughStripeUsingCustomerWithCompletionHandler:(STPChargeCompletionHandler)handler
{
    if (!self.validForCustomerProcessing)
    {
        handler(self,[NSError errorWithDomain:MY_ERROR_DOMAIN code:elErrorCodeNoCustomerID userInfo:[NSDictionary dictionary]]);
        return;
    }
    [PFCloud callFunctionInBackground:@"chargeToken" withParameters:[STPCharge dictionaryFromSTPChargeForProccessingUsingCustomer:self] block:^(id object, NSError *error)
    {
        if (!error)
        {
            [self initSelfWithDictionary:object];
            NSLog(@"object:%@",object);
        }
        handler(self,error);
    }];
}

//Process payment using a token that is attached to the charge, when complete self will be updated with the new charge information
//*********Warning: This is the final step it will APPLY A CHARGE TO THE ACCOUNT.***************

-(void)processChargeThroughStripeUsingCardWithCompletionHandler:(STPChargeCompletionHandler)handler
{
    if (!self.validForCardProcessing)
    {
        handler(self,[NSError errorWithDomain:MY_ERROR_DOMAIN code:elErrorCodeNoTokenID userInfo:[NSDictionary dictionary]]);
        return;
    }
    [PFCloud callFunctionInBackground:@"chargeToken" withParameters:[STPCharge dictionaryFromSTPChargeForProccessingUsingCard:self] block:^(id object, NSError *error)
     {
         if (!error)
         {
             [self initSelfWithDictionary:object];
         }
         handler(self,error);
     }];
}
+ (NSDictionary *)dictionaryFromSTPChargeForProccessingUsingCard:(STPCharge *)charge
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    dictionary[@"amount"] = charge.amountInCents;
    dictionary[@"currency"] = charge.currency;
    dictionary[@"card"] = charge.token.tokenId;
    return dictionary;
}
+ (NSDictionary *)dictionaryFromSTPChargeForProccessingUsingCustomer:(STPCharge *)charge
{
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    dictionary[@"amount"] = charge.amountInCents;
    dictionary[@"currency"] = charge.currency;
    dictionary[@"customer"] = charge.customer.identifier;
    return dictionary;
}

用于向客户/令牌收费的云代码:

Parse.Cloud.define("chargeToken",function(request,response)
{
    Stripe.initialize(STRIPE_SECRET_KEY);
    Stripe.Charges.create
    (
        request.params,
        {
            success:function(results)
            {
                response.success(results);
            },
            error:function(error)
            {
                response.error("Error:" +error); 
            }
        }
    );
});

1
投票

您如何存储他们的 CC 信息以便稍后充电?在继续之前,您需要知道它是否符合 PCI 标准。最多,您应该存储的唯一内容是到期日期、最后 4 位数字以及 Parse Stripe 为您提供的与该 CC 相对应的关联记录对象。不要尝试存储完整的 CC。

关于您的其他问题:

通常您需要了解网络语言才能执行此类操作。这是我在这种情况下见过的可能堆栈的示例:

iOS 应用程序 -> 向服务器发送请求(rails、python、php 等)-> 将请求发送到第 3 方站点

第 3 方站点响应 -> 服务器 -> iOS 应用程序。

服务器的重点是拦截从移动应用程序到 Parse 的调用,以及从 Parse 返回到移动应用程序的响应。这样做的原因是,您可以拥有交易/状态的“主”数据库,并且如果应用程序重新安装在用户的手机上,则可以恢复。它还可以让您在解析条带上存储指向用户 CC 的标识符(我假设)。

您应该真正了解 GET/POST,因为它们正在成为任何 iOS 应用程序的一个非常基本的功能。它们只是您从服务器获取/插入记录的方式。考虑到几乎所有流行的应用程序都嵌入了某种网络连接,在我看来,它确实是 iOS 编程的核心部分。

© www.soinside.com 2019 - 2024. All rights reserved.