Skip to content
forked from paulskeie/PyAPNs2

Python library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol

Notifications You must be signed in to change notification settings

qustodio/PyAPNs2

 
 

Repository files navigation

PyAPNs2

A modern Python library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol using httpx with full async support.

  • HTTP/2 Support: Native HTTP/2 with httpx for optimal performance
  • Async/Await: Full async support with sync wrapper for compatibility
  • Batch Processing: Efficient batch notification sending with HTTP/2 multiplexing
  • Token & Certificate Auth: Both JWT token and certificate authentication
  • Modern Python: Python 3.12+ with full type hints
  • High Performance: Optimized for high-throughput scenarios
  • Comprehensive Testing: High test coverage with 60+ comprehensive tests
  • Production Ready: Battle-tested with proper error handling

Quick Start

Certificate Authentication

from apns2.client import APNsClient
from apns2.payload import Payload

# Initialize client with certificate
client = APNsClient('path/to/cert.pem', use_sandbox=True)

# Create payload
payload = Payload(
    alert="Hello World!",
    sound="default",
    badge=1,
    custom={"user_id": 123}
)

# Send notification
token = 'device_token_hex_string'
topic = 'com.example.App'
result = client.send_notification(token, payload, topic)
print(f"Notification result: {result}")

JWT Token Authentication

from apns2.client import APNsClient
from apns2.credentials import TokenCredentials
from apns2.payload import Payload

# Initialize with JWT token credentials
credentials = TokenCredentials(
    auth_key_path='path/to/AuthKey_XXXXXXXXXX.p8',
    auth_key_id='XXXXXXXXXX',
    team_id='XXXXXXXXXX'
)
client = APNsClient(credentials=credentials, use_sandbox=True)

# Send notification
payload = Payload(alert="Hello from JWT!")
result = client.send_notification(token, payload, topic)

Batch Notifications

from apns2.client import APNsClient, Notification
from apns2.payload import Payload

client = APNsClient('cert.pem', use_sandbox=True)

# Create multiple notifications
notifications = [
    Notification(token='token1', payload=Payload(alert="Message 1")),
    Notification(token='token2', payload=Payload(alert="Message 2")),
    Notification(token='token3', payload=Payload(alert="Message 3")),
]

# Send batch (uses HTTP/2 multiplexing for efficiency)
results = client.send_notification_batch(notifications, topic='com.example.App')

# Process results
for token, result in results.items():
    if result == "Success":
        print(f"✅ {token}: Delivered")
    else:
        print(f"❌ {token}: {result}")

Async Usage

import asyncio
from apns2.client import APNsClient
from apns2.payload import Payload


async def send_notifications():
    client = APNsClient('cert.pem', use_sandbox=True)
    payload = Payload(alert="Async notification!")

    # Send single notification asynchronously
    result = await client.asend_notification(token, payload, topic)

    # Send batch asynchronously
    results = await client.asend_notification_batch(notifications, topic)

    return results


# Run async function
results = asyncio.run(send_notifications())

Advanced Payload Configuration

from apns2.payload import Payload, PayloadAlert

# Rich alert with title and subtitle
alert = PayloadAlert(
    title="New Message",
    subtitle="From John Doe",
    body="Hey, how are you doing?",
    title_localized_key="NEW_MESSAGE_TITLE",
    title_localized_args=["John Doe"]
)

payload = Payload(
    alert=alert,
    badge=5,
    sound="custom_sound.caf",
    category="MESSAGE_CATEGORY",
    thread_id="conversation_123",
    mutable_content=True,
    content_available=True,
    custom={
        "user_info": {"user_id": 12345},
        "deep_link": "app://conversation/123"
    }
)

Push Type Configuration

from apns2.client import APNsClient, NotificationPriority, NotificationType

client = APNsClient('cert.pem')

# VoIP notification
result = client.send_notification(
    token=voip_token,
    notification=payload,
    topic='com.example.App.voip',
    push_type=NotificationType.VoIP,
    priority=NotificationPriority.Immediate
)

# Background notification
background_payload = Payload(content_available=True)
result = client.send_notification(
    token=token,
    notification=background_payload,
    topic='com.example.App',
    push_type=NotificationType.Background
)

Error Handling

from apns2.client import APNsClient
from apns2.payload import Payload

client = APNsClient('cert.pem')
payload = Payload(alert="Test")

result = client.send_notification(token, payload, topic)

if result == "Success":
    print("✅ Notification sent successfully")
elif result == "BadDeviceToken":
    print("❌ Invalid device token")
elif result == "PayloadTooLarge":
    print("❌ Payload exceeds 4KB limit")
elif isinstance(result, tuple) and result[0] == "Unregistered":
    print(f"❌ Device unregistered at timestamp: {result[1]}")
else:
    print(f"❌ Error: {result}")

Requirements

  • Python: 3.12+ (with full type hints support)
  • httpx: 0.28.1+ with HTTP/2 support (automatically configured)
  • cryptography: 1.7.2+ for certificate handling
  • PyJWT: 2.0.0+ for token authentication

Configuration Options

Client Configuration

client = APNsClient(
    credentials='cert.pem',  # Certificate path or credentials object
    use_sandbox=True,  # Use sandbox APNs server
    use_alternative_port=False,  # Use port 2197 instead of 443
    json_encoder=CustomEncoder,  # Custom JSON encoder class
    password='cert_password',  # Certificate password
    proxy_host='proxy.example.com',  # Proxy configuration
    proxy_port=8080
)

Connection Settings

The client automatically configures optimal settings for APNs:

  • HTTP/2: Enabled by default for multiplexing
  • Connection pooling: Up to 1500 concurrent connections
  • Keep-alive: 600 seconds for connection reuse
  • Timeouts: Optimized for APNs (10s connect, 30s read)

Development

This project uses Poetry for dependency management and modern Python tooling.

Setup Development Environment

# Clone the repository
git clone https://github.com/Pr0Ger/PyAPNs2.git
cd PyAPNs2

# Install Poetry (if not already installed)
curl -sSL https://install.python-poetry.org | python3 -

# Install dependencies
poetry install --with test,dev

Running Tests

# Run all tests
poetry run pytest

# Run with coverage
poetry run coverage run -m pytest && poetry run coverage report

# Run specific test file
poetry run pytest test/test_client.py

# Run async tests only
poetry run pytest -k "async"

Code Quality

# Run pre-commit hooks
poetry run pre-commit run --all-files

# Type checking with mypy
poetry run mypy apns2/

# Format code
poetry run ruff format

# Lint code
poetry run ruff check --fix

Performance

PyAPNs2 is optimized for high-performance scenarios:

  • HTTP/2 Multiplexing: Send multiple notifications concurrently over a single connection
  • Async Support: Non-blocking I/O for maximum throughput
  • Connection Reuse: Efficient connection pooling and keep-alive
  • Batch Processing: Optimized batch sending with proper error handling

Migration from hyper-based versions

If migrating from older hyper-based versions:

  1. Update Python: Minimum Python 3.12+
  2. Install new version: poetry add apns2 or pip install apns2
  3. Update imports: Same API, no changes needed
  4. Async support: New asend_notification and asend_notification_batch methods
  5. Improved performance: Automatic HTTP/2 multiplexing

Contributing

Contributions are welcome! Please read our contributing guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run tests and linting (poetry run pre-commit run --all-files)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Create a Pull Request

Development Guidelines

  • Type hints: All code must have proper type annotations
  • Tests: Maintain 90%+ coverage for new code
  • Documentation: Update README and docstrings
  • Code style: Follow PEP 8 with ruff formatting

License

PyAPNs2 is distributed under the terms of the MIT license.

See LICENSE file for the complete license details.

Further Reading

About

Python library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 98.1%
  • Jsonnet 1.9%