如何在Objective-C中从APNS反馈服务器接收数据

3

你好,我想做一件相当简单的事情。 我制作了一个Cocoa应用程序,使用APNS发送数据,并从我的数据库中获取令牌,一切都设置好了,运行得非常完美。

现在,我想检查APNS反馈服务器并删除从我的数据库中收到的任何令牌。 我在php、javascript等语言中找到了许多示例,但没有Objective C的示例。我已经阅读了苹果的编程指南,但无法弄清楚如何实现它。

我正在与APNS反馈建立连接,但不知道如何读取数据。 我是Cocoa新手,请详细说明:)

这是我连接到反馈服务器的方式,与发送时连接方式相同,只是使用另一个主机。

- (void)connectToFeedBackServer
{
    if(self.certificate == nil)
    {
    return;
}

    NSString *feedBackHost = @"feedback.push.apple.com";
    const char *cHost = [feedBackHost UTF8String];
    NSLog(@"The size of cHost is: %lu", strlen(cHost));


    NSLog(@"Host is: %s", cHost);
// Define result variable.
OSStatus result;

// Establish connection to server.
PeerSpec peer;
result = MakeServerConnection(cHost, 2196, &socket, &peer);
    //NSLog(@"MakeServerConnection(): %d", result);

// Create new SSL context.
result = SSLNewContext(false, &context); //NSLog(@"SSLNewContext(): %d", result);

// Set callback functions for SSL context.
result = SSLSetIOFuncs(context, SocketRead, SocketWrite);
    // NSLog(@"SSLSetIOFuncs(): %d", result);

// Set SSL context connection.
result = SSLSetConnection(context, socket);
    // NSLog(@"SSLSetConnection(): %d", result);

// Set server domain name.
//result = SSLSetPeerDomainName(context, cHost, sizeof(cHost));
    NSLog(@"SSLSetPeerDomainName(): %d", result);
    result = SSLSetPeerDomainName(context, cHost, strlen(cHost));


    result = SecIdentityCopyCertificate(_theIdentity, &(certificate));

// Set client certificate.
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)&_theIdentity, 1, NULL);
result = SSLSetCertificate(context, certificates);// NSLog(@"SSLSetCertificate(): %d", result);
CFRelease(certificates);

// Perform SSL handshake.
do 
    {
    result = SSLHandshake(context); NSLog(@"SSLHandshake(): %d", result);
} while(result == errSSLWouldBlock);
}

我尝试读取数据并将接收到的令牌保存在一个数组中。

- (NSMutableArray *)CheckFeedBackServer
{
    char feedback[38];
    size_t feedBackSize = sizeof(feedback);
    size_t processed = 0;

    NSMutableData *feedbackData = [[NSMutableData alloc]init];
    NSString *token = [[NSString alloc]init];
    NSMutableArray *tokenArray = [[NSMutableArray alloc]init];

    [self connectToFeedBackServer];
    while ([self getSSLContext])
    {
        int bytesLength = SSLRead([self getSSLContext], &feedback, feedBackSize, &processed);

        [feedbackData appendBytes:feedback length:bytesLength];

        while ([feedbackData length] > 38)
        {
            NSData *deviceToken = [NSData dataWithBytes:[feedbackData bytes] + 6 length:32];

            token = [self deviceTokenToString:deviceToken];

            [tokenArray addObject:token];

            [feedbackData replaceBytesInRange: NSMakeRange(0, 38) withBytes: "" length: 0];
        }
    }
    return tokenArray;
}

- (NSString *)deviceTokenToString: (NSData *)deviceToken;
{
    NSString *tmpToken = [NSString stringWithFormat:@"%@", deviceToken];
    NSUInteger loc_begin = [tmpToken rangeOfString: @"<"].location+1;
    NSUInteger loc_end = [tmpToken rangeOfString: @">"].location-1;
    return [tmpToken substringWithRange: NSMakeRange(loc_begin, loc_end)];
}

你在用Objective-C进行服务器编程吗?我认为这有点不寻常。你能发布一下连接到APNS获取反馈的代码吗? - bdesham
我已经编辑了我的问题并包含了代码。 - John Smith
反馈应该在APNS的服务器端处理,而不是在你的应用程序中处理。你想要实现什么? - Baby Groot
该应用程序是在OSX上运行的工具,用于向iOS设备发送PUSH消息,而不是iOS设备上的应用程序。我想从APNS反馈服务器获取流数据,并告诉我的数据库删除令牌。但问题是它正在从反馈服务器获取令牌。 - John Smith
SSLRead() 返回的是 OSStatus 结果,而不是 bytesLength - Davyd Geyl
1个回答

2

如果有人需要做类似的事情,我是这样解决我的问题的。

我使用了苹果的ioSock类,并通过调用钥匙串在我的代码中设置了证书。

首先,我使用以下代码连接到反馈服务器:

- (void)connectToFeedBackServer
{
    if(self.certificate == nil)
    {
    return;
}

    // Get the global variable feedbackHost and make it to a char
    const char *cHost = [feedbackHost UTF8String];
    NSLog(@"The size of cHost is: %lu", strlen(cHost));

    NSLog(@"Host is: %s", cHost);
    // Define result variable.
    OSStatus result;

    // Establish connection to server.
    PeerSpec peer;
    result = MakeServerConnection(cHost, 2196, &socket, &peer); 

    // Create new SSL context.
    result = SSLNewContext(false, &context); 

    // Set callback functions for SSL context.
    result = SSLSetIOFuncs(context, SocketRead, SocketWrite);

    // Set SSL context connection.
    result = SSLSetConnection(context, socket);

    // Set server domain name.
    result = SSLSetPeerDomainName(context, cHost, strlen(cHost));

    result = SecIdentityCopyCertificate(_theIdentity, &(certificate));

    // Set client certificate.
    CFArrayRef certificates = CFArrayCreate(NULL, (const void **)&_theIdentity, 1, NULL);
    result = SSLSetCertificate(context, certificates);
    CFRelease(certificates);

    do
    {
        result = SSLHandshake(context); NSLog(@"SSLHandshake(): %d", result);
    } while(result == errSSLWouldBlock);

}

然后我读取反馈数据并将令牌添加到数组中,就像这样

- (NSMutableArray *)CheckFeedBackServer
{
    OSStatus result;

    NSMutableArray *feedbackTokens = [[NSMutableArray alloc]init];

    // Retrieve message from SSL.
    size_t processed = 0;
    char buffer[38];
    do
    {
        // Fetch the next item
        result = SSLRead(context, buffer, 38, &processed);
        if (result) break;

        char *b = buffer;

        // Recover Device ID
        NSMutableString *deviceID = [NSMutableString string];
        b += 6;
        for (int i = 0; i < 32; i++)
        {
            [deviceID appendFormat:@"%02x", (unsigned char)b[i]];
        }
        [feedbackTokens addObject:deviceID];

    } while (processed > 0);

    return feedbackTokens;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接