Verwenden von Notofication Hubs mit Python

Sie können von einem Java-/PHP-/Python-/Ruby-Back-End aus über die REST-Schnittstelle für Notification Hubs, die im MSDN-Artikel REST-APIs für Benachrichtigungshubs beschrieben ist, auf alle Notification Hub-Funktionen zugreifen.

Hinweis

Dies ist eine beispielhafte Referenzimplementierung für die Implementierung der Benachrichtigungsübermittlung in Python und nicht der offiziell unterstützte Notification Hub Python SDK. Das Beispiel wurde mit Python 3.4 erstellt.

In diesem Artikel lernen Sie Folgendes:

  • Erstellen eines REST-Clients für Notification Hubs-Features in Python.
  • Senden von Benachrichtigungen über die Python-Schnittstelle an die Notification Hub-REST-APIs.
  • Abrufen eines Abbilds der HTTP-REST-Anforderung/Antwort zu Debugging-/Lernzwecken.

Führen Sie die Schritte im Lernprogramm Erste Schritte mit Notification Hubs aus, und implementieren Sie den Back-End-Teil in Python.

Hinweis

Das Beispiel ist auf das Senden von Benachrichtigungen begrenzt und enthält keine Registrierungsverwaltung.

Clientschnittstelle

Über die Hauptclientschnittstelle können dieselben Methoden bereitgestellt werden, die im .NET Notification Hubs SDKverfügbar sind. Mithilfe dieser Schnittstelle können Sie alle Tutorials und Beispiele, die derzeit auf dieser Website verfügbar sind und die von der Community im Internet beigesteuert werden, direkt umsetzen.

Den gesamten verfügbaren Code finden Sie im Beispiel für Python-REST-Wrapper.

So erstellen Sie beispielsweise einen Client:

isDebug = True
hub = NotificationHub("myConnectionString", "myNotificationHubName", isDebug)

So senden Sie eine Windows-Popupbenachrichtigung

wns_payload = """<toast><visual><binding template=\"ToastText01\"><text id=\"1\">Hello world!</text></binding></visual></toast>"""
hub.send_windows_notification(wns_payload)

Implementierung

Führen Sie, sofern nicht bereits geschehen, das Tutorial Erste Schritte mit Notification Hubs bis zum letzten Abschnitt aus, in dem Sie das Back-End implementieren müssen.

Alle Details für das Implementieren eines vollständigen REST-Wrappers finden sich auf MSDN. In diesem Abschnitt wird die Python-Implementierung mit den Hauptschritten beschrieben, die für den Zugriff auf REST-Endpunkte von Notification Hubs und für das Senden von Benachrichtigungen erforderlich sind.

  1. Analysieren der Verbindungszeichenfolge
  2. Generieren des Authentifizierungstokens
  3. Senden einer Benachrichtigung über die HTTP-REST-API

Analysieren der Verbindungszeichenfolge

Dies hier ist die Hauptklasse, die den Client implementiert, dessen Konstruktor die Verbindungszeichenfolge analysiert:

class NotificationHub:
    API_VERSION = "?api-version=2013-10"
    DEBUG_SEND = "&test"

    def __init__(self, connection_string=None, hub_name=None, debug=0):
        self.HubName = hub_name
        self.Debug = debug

        # Parse connection string
        parts = connection_string.split(';')
        if len(parts) != 3:
            raise Exception("Invalid ConnectionString.")

        for part in parts:
            if part.startswith('Endpoint'):
                self.Endpoint = 'https' + part[11:].lower()
            if part.startswith('SharedAccessKeyName'):
                self.SasKeyName = part[20:]
            if part.startswith('SharedAccessKey'):
                self.SasKeyValue = part[16:]

Erstellen des Sicherheitstokens

Einzelheiten zum Erstellen des Sicherheitstokens finden Sie hier. Fügen Sie der Klasse NotificationHub die folgenden Methoden hinzu, um das Token basierend auf dem URI der aktuellen Anforderung und den Anmeldeinformationen, die aus der Verbindungszeichenfolge extrahiert wurden, zu erstellen.

@staticmethod
def get_expiry():
    # By default returns an expiration of 5 minutes (=300 seconds) from now
    return int(round(time.time() + 300))


@staticmethod
def encode_base64(data):
    return base64.b64encode(data)


def sign_string(self, to_sign):
    key = self.SasKeyValue.encode('utf-8')
    to_sign = to_sign.encode('utf-8')
    signed_hmac_sha256 = hmac.HMAC(key, to_sign, hashlib.sha256)
    digest = signed_hmac_sha256.digest()
    encoded_digest = self.encode_base64(digest)
    return encoded_digest


def generate_sas_token(self):
    target_uri = self.Endpoint + self.HubName
    my_uri = urllib.parse.quote(target_uri, '').lower()
    expiry = str(self.get_expiry())
    to_sign = my_uri + '\n' + expiry
    signature = urllib.parse.quote(self.sign_string(to_sign))
    auth_format = 'SharedAccessSignature sig={0}&se={1}&skn={2}&sr={3}'
    sas_token = auth_format.format(signature, expiry, self.SasKeyName, my_uri)
    return sas_token

Senden einer Benachrichtigung über die HTTP-REST-API

Hinweis

Der Microsoft-Pushbenachrichtigungsdienst (MPNS) ist veraltet und wird nicht mehr unterstützt.

Lassen Sie uns zuerst eine Klasse definieren, die eine Benachrichtigung darstellt.

class Notification:
    def __init__(self, notification_format=None, payload=None, debug=0):
        valid_formats = ['template', 'apple', 'gcm',
                         'windows', 'windowsphone', "adm", "baidu"]
        if not any(x in notification_format for x in valid_formats):
            raise Exception(
                "Invalid Notification format. " +
                "Must be one of the following - 'template', 'apple', 'gcm', 'windows', 'windowsphone', 'adm', 'baidu'")

        self.format = notification_format
        self.payload = payload

        # array with keynames for headers
        # Note: Some headers are mandatory: Windows: X-WNS-Type, WindowsPhone: X-NotificationType
        # Note: For Apple you can set Expiry with header: ServiceBusNotification-ApnsExpiry
        # in W3C DTF, YYYY-MM-DDThh:mmTZD (for example, 1997-07-16T19:20+01:00).
        self.headers = None

Diese Klasse ist ein Container für einen nativen Benachrichtigungstext oder einen Satz von Eigenschaften einer Benachrichtigungsvorlage sowie ein Satz von Headern, der ein Format (native Plattform oder Vorlage) und plattformspezifische Eigenschaften (wie die Apple-Ablaufeigenschaft und WNS-Header) enthält.

Alle verfügbaren Optionen finden Sie in der Dokumentation der REST-APIs für Notification Hubs und unter den Formaten der einzelnen Benachrichtigungsplattformen.

Mit dieser Klasse können Sie jetzt die Methoden zum Senden von Benachrichtigungen innerhalb der Klasse NotificationHub schreiben.

def make_http_request(self, url, payload, headers):
    parsed_url = urllib.parse.urlparse(url)
    connection = http.client.HTTPSConnection(
        parsed_url.hostname, parsed_url.port)

    if self.Debug > 0:
        connection.set_debuglevel(self.Debug)
        # adding this querystring parameter gets detailed information about the PNS send notification outcome
        url += self.DEBUG_SEND
        print("--- REQUEST ---")
        print("URI: " + url)
        print("Headers: " + json.dumps(headers, sort_keys=True,
                                       indent=4, separators=(' ', ': ')))
        print("--- END REQUEST ---\n")

    connection.request('POST', url, payload, headers)
    response = connection.getresponse()

    if self.Debug > 0:
        # print out detailed response information for debugging purpose
        print("\n\n--- RESPONSE ---")
        print(str(response.status) + " " + response.reason)
        print(response.msg)
        print(response.read())
        print("--- END RESPONSE ---")

    elif response.status != 201:
        # Successful outcome of send message is HTTP 201 - Created
        raise Exception(
            "Error sending notification. Received HTTP code " + str(response.status) + " " + response.reason)

    connection.close()


def send_notification(self, notification, tag_or_tag_expression=None):
    url = self.Endpoint + self.HubName + '/messages' + self.API_VERSION

    json_platforms = ['template', 'apple', 'gcm', 'adm', 'baidu']

    if any(x in notification.format for x in json_platforms):
        content_type = "application/json"
        payload_to_send = json.dumps(notification.payload)
    else:
        content_type = "application/xml"
        payload_to_send = notification.payload

    headers = {
        'Content-type': content_type,
        'Authorization': self.generate_sas_token(),
        'ServiceBusNotification-Format': notification.format
    }

    if isinstance(tag_or_tag_expression, set):
        tag_list = ' || '.join(tag_or_tag_expression)
    else:
        tag_list = tag_or_tag_expression

    # add the tags/tag expressions to the headers collection
    if tag_list != "":
        headers.update({'ServiceBusNotification-Tags': tag_list})

    # add any custom headers to the headers collection that the user may have added
    if notification.headers is not None:
        headers.update(notification.headers)

    self.make_http_request(url, payload_to_send, headers)


def send_apple_notification(self, payload, tags=""):
    nh = Notification("apple", payload)
    self.send_notification(nh, tags)


def send_google_notification(self, payload, tags=""):
    nh = Notification("gcm", payload)
    self.send_notification(nh, tags)


def send_adm_notification(self, payload, tags=""):
    nh = Notification("adm", payload)
    self.send_notification(nh, tags)


def send_baidu_notification(self, payload, tags=""):
    nh = Notification("baidu", payload)
    self.send_notification(nh, tags)


def send_mpns_notification(self, payload, tags=""):
    nh = Notification("windowsphone", payload)

    if "<wp:Toast>" in payload:
        nh.headers = {'X-WindowsPhone-Target': 'toast',
                      'X-NotificationClass': '2'}
    elif "<wp:Tile>" in payload:
        nh.headers = {'X-WindowsPhone-Target': 'tile',
                      'X-NotificationClass': '1'}

    self.send_notification(nh, tags)


def send_windows_notification(self, payload, tags=""):
    nh = Notification("windows", payload)

    if "<toast>" in payload:
        nh.headers = {'X-WNS-Type': 'wns/toast'}
    elif "<tile>" in payload:
        nh.headers = {'X-WNS-Type': 'wns/tile'}
    elif "<badge>" in payload:
        nh.headers = {'X-WNS-Type': 'wns/badge'}

    self.send_notification(nh, tags)


def send_template_notification(self, properties, tags=""):
    nh = Notification("template", properties)
    self.send_notification(nh, tags)

Diese Methoden senden eine HTTP-POST-Anforderung mit dem ordnungsgemäßen Text und Headern zum Senden der Benachrichtigung an den „/messages“-Endpunkt des Benachrichtigungs-Hubs.

Aktivieren der ausführlichen Protokollierung mithilfe der Debug-Eigenschaft

Durch das Aktivieren der Debug-Eigenschaft während der Initialisierung des Notification Hubs werden detaillierte Protokollinformationen zu HTTP-Anforderung und -Antwort sowie ein detailliertes Sendeergebnis für die Benachrichtigungsnachricht geschrieben. Die „TestSend“-Eigenschaft für Notification Hubs gibt ausführliche Informationen zum Sendeergebnis der Benachrichtigung zurück. Wenn Sie diese Eigenschaft verwenden möchten, initialisieren Sie mit dem folgenden Code:

hub = NotificationHub("myConnectionString", "myNotificationHubName", isDebug)

Der HTTP-URL der Sendeanforderung des Notification Hubs wird eine Testabfragezeichenfolge als Ergebnis angehängt.

Tutorial abschließen

Sie können jetzt das Lernprogramm "Erste Schritte" abschließen, indem Sie die Benachrichtigung von einem Python-Back-End aus senden.

Initialisieren Sie Ihren Notification Hubs-Client (ersetzen Sie die Verbindungszeichenfolge und den Hubnamen wie im Erste Schritte mit Notification Hubsbeschrieben):

hub = NotificationHub("myConnectionString", "myNotificationHubName")

Fügen Sie dann den Sendecode je nach mobiler Zielplattform hinzu. Mit diesem Beispiel werden außerdem Methoden auf höherer Ebene hinzugefügt, um das Senden von Benachrichtigungen auf Plattformbasis zu aktivieren, z.B. „send_windows_notification“ (für Windows), „send_apple_notification“ (für Apple) usw.

Windows Store und Windows Phone 8.1 (nicht Silverlight)

wns_payload = """<toast><visual><binding template=\"ToastText01\"><text id=\"1\">Test</text></binding></visual></toast>"""
hub.send_windows_notification(wns_payload)

Windows Phone 8.0 und 8.1 Silverlight

hub.send_mpns_notification(toast)

iOS

alert_payload = {
    'data':
        {
            'msg': 'Hello!'
        }
}
hub.send_apple_notification(alert_payload)

Android

gcm_payload = {
    'data':
        {
            'msg': 'Hello!'
        }
}
hub.send_google_notification(gcm_payload)

Kindle Fire

adm_payload = {
    'data':
        {
            'msg': 'Hello!'
        }
}
hub.send_adm_notification(adm_payload)

Baidu

baidu_payload = {
    'data':
        {
            'msg': 'Hello!'
        }
}
hub.send_baidu_notification(baidu_payload)

Beim Ausführen des Python-Codes sollte eine Benachrichtigung erstellt und auf dem Zielgerät angezeigt werden.

Beispiele

Aktivieren der Eigenschaft debug

Wenn Sie beim Initialisieren von „NotificationHub“ das Flag „debug“ aktivieren, werden die detaillierte HTTP-Anforderung und -Antwort sowie das Benachrichtigungsergebnis wie folgt angezeigt. Dabei können Sie erkennen, welche HTTP-Header in der Anforderung übergeben werden und welche HTTP-Antwort vom Notification Hub empfangen wurde:

Screenshot einer Konsole mit den Details der HTTP-Anforderung und -Antwort sowie den Meldungen mit dem Benachrichtigungsergebnis (rot umrandet).

Das detaillierte Ergebnis des Notification Hubs wird angezeigt, z.B.

  • wenn die Nachricht erfolgreich zum Pushbenachrichtigungsdienst gesendet wurde.
    <Outcome>The Notification was successfully sent to the Push Notification System</Outcome>
    
  • Wenn für eine Pushbenachrichtigung keine Ziele gefunden wurden, wird wahrscheinlich die folgende Ausgabe in der Antwort angezeigt (dies besagt, dass keine Registrierungen zum Übermitteln der Benachrichtigung gefunden wurden, möglicherweise aufgrund nicht übereinstimmender Registrierungs-Tags).
    '<NotificationOutcome xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect" xmlns:i="https://www.w3.org/2001/XMLSchema-instance"><Success>0</Success><Failure>0</Failure><Results i:nil="true"/></NotificationOutcome>'
    

Broadcast-Popupbenachrichtigung an Windows

Beachten Sie die Header, die beim Senden einer Broadcast-Popupbenachrichtigung an einen Windows-Client gesendet werden.

hub.send_windows_notification(wns_payload)

Screenshot einer Konsole mit den Details der HTTP-Anforderung und dem Service Bus-Benachrichtigungsformat sowie den XWNS-Typwerten (rot umrandet).

Senden einer Benachrichtigung mit Angabe eines Tags (oder Tag-Ausdrucks)

Beachten Sie den HTTP-Header des Tags, der der HTTP-Anforderung hinzugefügt wird (im folgenden Beispiel wird die Benachrichtigung nur an Registrierungen mit der „payload“ des Typs „sports“ gesendet).

hub.send_windows_notification(wns_payload, "sports")

Screenshot einer Konsole mit den Details der HTTP-Anforderung, dem Service Bus-Benachrichtigungsformat, dem Service Bus-Benachrichtigungstag sowie den XWNS-Typwerten (rot umrandet).

Senden einer Benachrichtigung mit Angabe mehrerer Tags

Beachten Sie, wie sich der HTTP-Header der Tags ändert, wenn mehrere Tags gesendet werden.

tags = {'sports', 'politics'}
hub.send_windows_notification(wns_payload, tags)

Screenshot einer Konsole mit den Details der HTTP-Anforderung, dem Service Bus-Benachrichtigungsformat, mehreren Service Bus-Benachrichtigungstags sowie den XWNS-Typwerten (rot umrandet).

Auf Vorlagen basierende Benachrichtigung

Beachten Sie, dass sich der Format-HTTP-Header ändert und der "payload"-Text als Teil des HTTP-Anforderungstexts gesendet wird:

Clientseitig (registrierte Vorlage):

var template = @"<toast><visual><binding template=""ToastText01""><text id=""1"">$(greeting_en)</text></binding></visual></toast>";

Serverseitig (Senden der Nutzlast):

template_payload = {'greeting_en': 'Hello', 'greeting_fr': 'Salut'}
hub.send_template_notification(template_payload)

Screenshot einer Konsole mit den Details der HTTP-Anforderung, dem Inhaltstyp und den Werten für das Service Bus-Benachrichtigungsformat (rot umrandet).

Nächste Schritte

In diesem Artikel haben wir gezeigt, wie Sie einen Python-REST-Client für Notification Hubs erstellen. Hier können Sie folgende Aktionen ausführen: