Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Alibaba Cloud Push Notification Service Integration Guide

Tech May 14 1

Push Notification Service

A cloud-to-device messaging solution that delivers notifications and messages to mobile endpoints, supporting both Android and iOS platforms through dedicated channels.

Notification vs Message Delivery

Notifications appear automatically in the device's status bar. Users can interact with or dismiss them. On iOS, notifications route through Apple's APNs infrastructure. Android notifications utilize the push service's proprietary channel.

Messages remain invisible in the notification drawer and require in-app handling to display. Both iOS and Android messages travel through the push service's internal channel.

Delivery Methods

Push targeting options include device-based delivery. Retrieve the device identifier on the client using the appropriate SDK method, then submit targets via console or OpenAPI endpoints.

Key Terminology

AppKey: A unique identifier assigned to each application within the push service. Required during SDK initialization and API calls. Obtain from the application credentials section in the console's app list.

AppSecret: The application's authentication key. Needed for SDK initialization. Fetch from the same credentials panel as AppKey.

AccessKeyId and AccessKeySecret: Credentials for authenticating OpenAPI calls. Acquire from the Alibaba Cloud console at https://ak-console.aliyun.com/#/accesskey.

ResponseId: A unique identifier returned by OpenAPI push requests. Useful when troubleshooting requires support assistance.

MessageId: An identifier for a specific push operation. Findable in notification or message delivery logs within the console.

DeviceId: A 32-character alphanumeric string serving as the device's push identifier. Fetch programmatically: Android uses CloudPushService.getDeviceId(), iOS uses CloudPushSDK.getDeviceId().

DeviceToken: A 64-character identifier issued by Apple's servers during device registration. iOS devices maintain both DeviceId and DeviceToken—these serve different purposes.

Account: A user-associated label assignable to devices. Each device accepts one account, while one account may reference multiple devices.

Alias: A custom label for targeting devices. Up to 128 aliases can bind to a single device, and up to 128 devices can share an alias.

Tag: Categorization labels for grouping devices. Each app supports up to 10,000 tags with no device limit per tag. Tag names must not exceed 128 characters.

Usage Constraints

Batch operations support a maximum of 1,000 targets when pushing by alias or device (comma-separated list). Account-based pushes accommodate 100 targets maximum. Tags are capped at 10,000 per application.

Initial Setup

Android Configuration

Enable Android support and provide the PackageName. This value must match your application's applicationId in the build configuration. Each application requires a unique package name, as the push SDK uses this identifier for routing. Misconfiguration may cause messages to reach unintended applications.

Retrieving AppKey and Secret

Navigate to the product list, select a specific product, access the app list, and click the credential viewing option to display AppKey and Secret values.

Device Association Operations

Operation Funcsion
QueryAliases Retrieve alias bindings
BindAlias Establish alias connection
UnbindAlias Remove alias binding
QueryTags Search tag assignments
ListTags Enumerate available tags
BindTag Create tag association
UnbindTag Remove tag assignment
RemoveTag Delete tag entirely

Common Request Parameters

Every API call requires these parameters:

Parameter Type Required Description
Format String No Response format: JSON or XML (default: XML)
RegionId String Yes Set to cn-hangzhou
Version String Yes API version in YYYY-MM-DD format
AccessKeyId String Yes User access key identifier
Signature String Yes Computed request signature
SignatureMethod String Yes HMAC-SHA1
Timestamp String Yes ISO 8601 UTC timestamp (YYYY-MM-DDThh:mm:ssZ)
SignatureVersion String Yes Signature algorithm version (1.0)
SignatureNonce String Yes Unique random value per request

Request Example

https://cloudpush.aliyuncs.com/
?Format=XML
&RegionId=cn-hangzhou
&Version=2016-08-01
&AccessKeyId=testid
&Signature=Pc5WB8gokVn0xfeu%2FZV%2BiNM1dgI%3D
&SignatureMethod=HMAC-SHA1
&SignatureNonce=15215528852396
&SignatureVersion=1.0
&Timestamp=2016-02-25T12:00:00Z
&<operation-specific-parameters>

Response Structure

Every API response includes a RequestId for tracking purposes, regardless of success or failure.

{
    "RequestId": "4C467B38-3910-447D-87BC-AC049166F216"
}

Endpoint Details

Service Endpoint: cloudpush.aliyuncs.com

Each request must specify an Action parameter (such as Push) along with common parameters and operation-specific parameters. All communication uses UTF-8 encoding.

Python Implementation

# -*- coding: utf-8 -*-

import os
import re
import configparser
from datetime import timedelta
from aliyunsdkpush.request.v20160801 import PushRequest
from aliyunsdkcore import client
from Config import ConfigPath

class PushNotificationClient:
    
    MAX_TAG_OPERATIONS = 50
    NOTIFICATION_TEMPLATES = {
        "INIT": "Processing started for entity {0}",
        "UPDATE": "Status changed for entity {0}",
        "RETRY": "Operation restart for entity {0}"
    }

    def __init__(self, target_type, target_value):
        self._target_type = target_type
        self._target_value = target_value
        
        config = configparser.ConfigParser()
        config.read(ConfigPath)
        
        self._ak_id = os.getenv('PUSH_ACCESS_KEY_ID', 
                               config.get("push_config", "PUSH_ACCESS_KEY_ID"))
        self._ak_secret = os.getenv('PUSH_ACCESS_KEY_SECRET', 
                                   config.get("push_config", "PUSH_ACCESS_KEY_SECRET"))
        self._region = os.getenv('PUSH_REGION_ID', 
                                config.get("push_config", "PUSH_REGION_ID"))
        self._app_key = os.getenv('PUSH_APP_KEY', 
                                 config.get("push_config", "PUSH_APP_KEY"))

        self._client = client.AcsClient(self._ak_id, self._ak_secret, self._region)
        self._request = PushRequest.PushRequest()
        self._request.set_AppKey(self._app_key)

    async def send_notification(self, subject, content):
        if not subject or not content:
            return None
            
        self._request.set_Target(self._target_type)
        self._request.set_TargetValue(self._target_value)
        self._request.set_DeviceType("ANDROID")
        self._request.set_PushType("MESSAGE")
        self._request.set_Title(subject)
        self._request.set_Body(content)
        
        schedule_time = datetime.utcnow() + timedelta(seconds=5)
        expiration = datetime.utcnow() + timedelta(hours=24)
        
        self._request.set_PushTime(schedule_time.strftime("%Y-%m-%dT%XZ"))
        self._request.set_ExpireTime(expiration.strftime("%Y-%m-%dT%XZ"))
        self._request.set_StoreOffline(True)
        
        result = self._client.do_action(self._request)
        result = result.decode('unicode_escape')
        msg_id = re.findall("<MessageId>(.*)?</MessageId>", result)
        return msg_id

Push Invocation Example

target_tags = {
    "and": [
        { "tag": current_entity_code },
        { "or": list(map(lambda x: {"tag": x}, filtered_list)) }
    ]
}
print(target_tags)

push_client = PushNotificationClient("TAG", target_tags)

if job_type == JobTypes.INITIAL:
    notification_title = "INIT"
    notification_body = {
        "type": 0,
        "message": PushNotificationClient.NOTIFICATION_TEMPLATES["INIT"].format(current_entity_code)
    }
elif job_type == JobTypes.SYNC:
    notification_title = "UPDATE"
    notification_body = {
        "type": 0,
        "message": PushNotificationClient.NOTIFICATION_TEMPLATES["UPDATE"].format(current_entity_code)
    }
else:
    continue

attempt = 1
success = False
while not success and attempt <= 3:
    try:
        await push_client.send_notification(notification_title, notification_body)
        success = True
    except Exception as error:
        attempt += 1
    if attempt > 3:
        raise Exception("Failed to deliver notification after 3 attempts")

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.