12

我正在尝试使用 Python 向 iPhone 发送推送通知。我已将我的证书和私钥从钥匙串访问导出到 p12 文件中,然后使用以下命令将其转换为 pem 文件:

openssl pkcs12 -in cred.p12 -out cert.pem -nodes -clcerts

我在 Python 中使用APNSWrapper进行连接。

我运行以下代码:

deviceToken = '群\xaa\xd ... c0\x9c\xf6\xca'

# 创建包装器
wrapper = APNSNotificationWrapper('/path/to/cert/cert.pem', True)

# 创建消息
消息 = APNSNotification()
message.token(deviceToken)
message.badge(5)

# 将消息添加到元组并将其发送到 APNS 服务器
wrapper.append(消息)
wrapper.notify()

然后我收到错误消息:

ssl.SSLError: (1, '_ssl.c:485:
错误:14094416:SSL 例程:SSL3_READ_BYTES:sslv3 警报证书未知')

谁能帮我解决这个问题?

4

5 回答 5

8

我最近使用 Django 做了这个 - http://leecutsco.de/2009/07/14/push-on-the-iphone/

可能有用吗?除了已经包含在 Python 中的库之外,它没有使用任何额外的库。提取 send_message() 方法不需要太多。

于 2009-08-10T09:58:26.183 回答
2

你考虑过Twisted包吗?下面的代码取自这里

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory

APNS_SERVER_HOSTNAME = "<insert the push hostname from your iPhone developer portal>"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):
    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32cH%dc" % len(payload)
        command = 0
        msg = struct.pack(fmt, command, deviceToken,
                          len(payload), payload)
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME, 
                       APNS_SERVER_PORT,
                       APNSClientFactory(), 
                       APNSClientContextFactory())
    reactor.run()
于 2009-07-23T18:00:23.670 回答
2

最初发布的代码中有一些错误,所以这里有一个适合我的更正版本。

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory
import binascii
import struct

APNS_SERVER_HOSTNAME = "gateway.sandbox.push.apple.com"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"
DEVICE_TOKEN = "<hexlified device token>"
MESSAGE = '{"aps":{"alert":"twisted test"}}'

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):

    def connectionMade(self):
        print "connection made"
        self.sendMessage(binascii.unhexlify(DEVICE_TOKEN), MESSAGE)
        self.transport.loseConnection()

    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32sH%ds" % len(payload)
        command = '\x00'
        msg = struct.pack(fmt, command, 32, deviceToken,
                          len(payload), payload)
        print "%s: %s" %(binascii.hexlify(deviceToken), binascii.hexlify(msg))
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME,
                       APNS_SERVER_PORT,
                       APNSClientFactory(),
                       APNSClientContextFactory())
    reactor.run()
于 2009-08-15T18:59:00.063 回答
1

尝试更新到最新的 APNSWrapper 版本 (0.4)。现在内置了对 openssl 命令行工具 (openssl s_client) 的支持。

于 2009-11-17T00:33:04.620 回答
0

我尝试了APNSWrapperLee Peckham 的代码,但无法让它在 Snow Leopard 和 Python 2.6 下工作。经过大量的试验和错误,它终于可以使用pyOpenSSL.

我已经在此处发布了包含详细信息和代码片段的帖子,因此我将在此处向您推荐。

于 2009-09-09T09:44:32.477 回答