├── .gitignore ├── Third Party Open Source Software Notice.docx ├── python27 ├── LICENSE ├── Push-CA-Root.pem ├── README.md ├── README_ZH.md ├── requirements.txt ├── setup.py ├── src │ ├── __init__.py │ └── push_admin │ │ ├── __init__.py │ │ ├── _app.py │ │ ├── _http.py │ │ ├── _message_serializer.py │ │ ├── _messages.py │ │ └── messaging.py └── test │ ├── __init__.py │ ├── push_env.py │ ├── send_apns_message.py │ ├── send_condition_message.py │ ├── send_data_message.py │ ├── send_instance_app_message.py │ ├── send_notify_message.py │ ├── send_test_message.py │ ├── send_topic_message.py │ └── send_webpush_message.py └── python37 ├── LICENSE ├── Push-CA-Root.pem ├── README.md ├── README_ZH.md ├── requirements.txt ├── setup.py ├── src └── push_admin │ ├── __init__.py │ ├── _app.py │ ├── _http.py │ ├── _message_serializer.py │ ├── _messages.py │ └── messaging.py └── test ├── push_env.py ├── send_apns_message.py ├── send_condition_message.py ├── send_data_message.py ├── send_instance_app_message.py ├── send_notify_message.py ├── send_test_message.py ├── send_topic_message.py └── send_webpush_message.py /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .settings/ 3 | logs/ 4 | log/ 5 | *.pyc 6 | *.jar 7 | */*.jar 8 | .idea 9 | *.iml 10 | .project -------------------------------------------------------------------------------- /Third Party Open Source Software Notice.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMS-Core/hms-push-serverdemo-python/8ce3533e89d37f645378be35293a70394ec1e622/Third Party Open Source Software Notice.docx -------------------------------------------------------------------------------- /python27/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 22 | 23 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 24 | 25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 26 | 27 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 28 | 29 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 30 | 31 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 32 | 33 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 34 | 35 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | You must cause any modified files to carry prominent notices stating that You changed the files; and 39 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 40 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 41 | 42 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 43 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 44 | 45 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 46 | 47 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 48 | 49 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 50 | 51 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 52 | 53 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /python27/Push-CA-Root.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 5 | QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT 6 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 7 | b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 8 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB 9 | CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 10 | nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 11 | 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P 12 | T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 13 | gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO 14 | BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR 15 | TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw 16 | DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr 17 | hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 18 | 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF 19 | PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls 20 | YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk 21 | CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= 22 | -----END CERTIFICATE----- 23 | 24 | -----BEGIN CERTIFICATE----- 25 | MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G 26 | A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp 27 | Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 28 | MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG 29 | A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI 30 | hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 31 | RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT 32 | gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm 33 | KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd 34 | QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ 35 | XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw 36 | DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o 37 | LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU 38 | RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp 39 | jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 40 | 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX 41 | mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs 42 | Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH 43 | WD9f 44 | -----END CERTIFICATE----- 45 | 46 | -------------------------------------------------------------------------------- /python27/README.md: -------------------------------------------------------------------------------- 1 | # HMS Pushkit Python Severdemo 2 | English| [中文](README_ZH.md) 3 | 4 | ## Table of Contents 5 | * [Introduction](#introduction) 6 | * [Installation](#installation) 7 | * [Configuration ](#configuration ) 8 | * [Supported Environments](#supported-environments) 9 | * [Sample Code](#sample-code) 10 | * [Libraries](#Libraries) 11 | * [License](#license) 12 | 13 | 14 | ## Introduction 15 | 16 | Python sample code encapsulates APIs of the HUAWEI Push Kit server. It provides many sample programs about quick access to HUAWEI Push Kit for your reference or usage. 17 | 18 | The following table describes packages of Python sample code. 19 | 20 | | Package | Description | 21 | | ---------- | ------------| 22 | | [test](test) | Sample code packages. Each package can run independently.| 23 | | [src/push_admin](src/push_admin) | Package where APIs of the HUAWEI Push Kit server are encapsulated.| 24 | 25 | ## Installation 26 | 27 | To install pushkit-python-sample, you should extract the compressed ZIP file, execute the following command in the unzipped directory: 28 | ``` 29 | python setup.py install 30 | ``` 31 | 32 | ## Supported Environments 33 | For pushkit-python-sample, We currently support Python 2.7/3.7 and JetBrains PyCharm are recommended. 34 | 35 | 36 | ## Configuration 37 | The following table describes parameters of the initialize_app method. 38 | 39 | | Parameter | Description | 40 | | ------------- | ------------------------------------------------------------------------- | 41 | | app_id | App ID, which is obtained from app information. | 42 | | app_secret | Secret access key of an app, which is obtained from app information. | 43 | | app_package_name | Appplication package name. | 44 | | token_server | URL for the Huawei OAuth 2.0 service to obtain a token, please refer to [Generating an App-Level Access Token](https://developer.huawei.com/consumer/en/doc/development/parts-Guides/generating_app_level_access_token). | 45 | | push_open_url | URL for accessing HUAWEI Push Kit, please refer to [Sending Messages](https://developer.huawei.com/consumer/en/doc/development/HMS-References/push-sendapi).|| 46 | 47 | 48 | ## Sample Code 49 | Download Python sample code in Downloading Server Sample Code. 50 | 51 | 52 | Python sample code uses the Messaging structure in the push_admin package as the entry. Each method in the Messaging 53 | structure calls an API of the HUAWEI Push Kit server. 54 | 55 | The following table describes methods in the Messaging structure. 56 | 57 | | Method | Description 58 | | ----------------- | --------------------------------------------------- | 59 | | send_message | Sends a message to a device. | 60 | | subscribe_topic | Subscribes to a topic. | 61 | | unsubscribe_topic | Unsubscribes from a topic. | 62 | | list_topics | Queries the list of topics subscribed by a device. | 63 | 64 | 65 | 1) Send an Android data message. 66 | Code location: [test/send_data_message.py](test/send_data_message.py) 67 | 68 | 2) Send an Android notification message. 69 | Code location: [test/send_notify_message.py](test/send_notify_message.py) 70 | 71 | 3) Send a message by topic. 72 | Code location: [test/send_topic_message.py](test/send_topic_message.py) 73 | 74 | 4) Send a message by conditions. 75 | Code location: [test/send_condition_message.py](test/send_condition_message.py) 76 | 77 | 5) Send a message to a Huawei quick app. 78 | Code location: [test/send_instance_app_message.py](test/send_instance_app_message.py) 79 | 80 | 6) Send a message through the WebPush agent. 81 | Code location: [test/send_webpush_message.py](test/send_webpush_message.py) 82 | 83 | 7) Send a message through the APNs agent. 84 | Code location: [test/send_apns_message.py](test/send_apns_message.py) 85 | 86 | 8) Send a test message. 87 | Code location: [test/send_test_message.py](test/send_test_message.py) 88 | 89 | ## Libraries 90 | | Library | Site 91 | | ----------------- | --------------------------------------------------- | 92 | | requests | https://requests.readthedocs.io/en/master/ | 93 | | six | https://six.readthedocs.io/ | 94 | 95 | ## Question or issues 96 | If you want to evaluate more about HMS Core, 97 | [r/HMSCore on Reddit](https://www.reddit.com/r/HuaweiDevelopers/) is for you to keep up with latest news about HMS Core, and to exchange insights with other developers. 98 | >>>>>>> afe8071b1b807b52ae92e6f1fd2255e0911150a9:README.md 99 | 100 | If you have questions about how to use HMS samples, try the following options: 101 | - [Stack Overflow](https://stackoverflow.com/questions/tagged/huawei-mobile-services) is the best place for any programming questions. Be sure to tag your question with 102 | `huawei-mobile-services`. 103 | - [Huawei Developer Forum](https://forums.developer.huawei.com/forumPortal/en/home?fid=0101187876626530001) HMS Core Module is great for general questions, or seeking recommendations and opinions. 104 | 105 | If you run into a bug in our samples, please submit an [issue](https://github.com/HMS-Core/hms-push-serverdemo-python/issues) to the Repository. Even better you can submit a [Pull Request](https://github.com/HMS-Core/hms-push-serverdemo-python/pulls) with a fix. 106 | 107 | ## License 108 | pushkit Python sample is licensed under the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 109 | -------------------------------------------------------------------------------- /python27/README_ZH.md: -------------------------------------------------------------------------------- 1 | ## 华为推送服务服务端Python示例代码 2 | [English](README.md) | 中文 3 | ## 目录 4 | * [简介](#简介) 5 | * [安装](#安装) 6 | * [环境要求](#环境要求) 7 | * [配置](#配置) 8 | * [示例代码](#示例代码) 9 | * [知识库](#知识库) 10 | * [授权许可](#授权许可) 11 | 12 | ## 简介 13 | 14 | Python示例代码对华为推送服务(HUAWEI Push Kit)服务端接口进行封装,包含丰富的示例程序,方便您参考或直接使用。 15 | 16 | 示例代码主要包括以下组件: 17 | 18 | | 包名 | 说明 | 19 | | ---------- | ------------| 20 | | [test](test) | 示例代码包,每个包都可以独立运行 | 21 | | [src/push_admin](src/push_admin) | 推送服务的服务端接口封装包 | 22 | 23 | ## 安装 24 | 25 | 安装本示例代码前,请解压zip文件包,并在解压后的文件目录中执行以下命令: 26 | ``` 27 | python setup.py install 28 | ``` 29 | 30 | ## 环境要求 31 | Python 2.7 32 | JetBrains PyCharm(推荐使用) 33 | 34 | 35 | ## 配置 36 | initialize_app方法包括如下参数: 37 | 38 | | 参数 | 说明 | 39 | | ------------- | ------------------------------------------------------------------------- | 40 | | app_id | 应用ID,从应用消息中获取 | 41 | | app_secret | 应用访问密钥,从应用信息中获取 | 42 | | app_package_name | 应用包名 | 43 | | token_server | 华为OAuth 2.0获取token的地址。具体请参考[基于OAuth 2.0开放鉴权-客户端模式](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/oauth2-0000001212610981)。| 44 | | push_open_url | 推送服务的访问地址。具体请参考[推送服务-下行消息](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-server-dev-0000001050040110?ha_source=hms1)。| 45 | 46 | 47 | ## 示例代码 48 | 49 | 本示例代码以push_admin包中的Messaging结构体为入口。Messaging结构体中的方法完成了对推送服务服务端接口的调用。 50 | 51 | Messaging包括如下方法: 52 | 53 | | 方法 | 说明 54 | | ----------------- | --------------------------------------------------- | 55 | | send_message | 向设备发送消息 | 56 | | subscribe_topic | 订阅主题 | 57 | | unsubscribe_topic | 退订主题 | 58 | | list_topics | 查询设备订阅的主题列表 | 59 | 60 | 61 | 1) 发送Android透传消息 62 | 代码位置: [test/send_data_message.py](test/send_data_message.py) 63 | 64 | 2) 发送Android通知栏消息 65 | 代码位置: [test/send_notify_message.py](test/send_notify_message.py) 66 | 67 | 3) 基于主题发送消息 68 | 代码位置: [test/send_topic_message.py](test/send_topic_message.py) 69 | 70 | 4) 基于条件发送消息 71 | 代码位置: [test/send_condition_message.py](test/send_condition_message.py) 72 | 73 | 5) 向华为快应用发送消息 74 | 代码位置: [test/send_instance_app_message.py](test/send_instance_app_message.py) 75 | 76 | 6) 基于WebPush代理发送消息 77 | 代码位置: [test/send_webpush_message.py](test/send_webpush_message.py) 78 | 79 | 7) 基于APNs代理发送消息 80 | 代码位置: [test/send_apns_message.py](test/send_apns_message.py) 81 | 82 | 8) 发送测试消息 83 | 代码位置: [test/send_test_message.py](test/send_test_message.py) 84 | 85 | ## 知识库 86 | | 知识库 | 地址 87 | | ----------------- | --------------------------------------------------- | 88 | | requests | https://requests.readthedocs.io/en/master/ | 89 | | six | https://six.readthedocs.io/ | 90 | 91 | ## 授权许可 92 | 华为推送服务Python示例代码经过[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0)授权许可。 93 | -------------------------------------------------------------------------------- /python27/requirements.txt: -------------------------------------------------------------------------------- 1 | requests >= 2.20.1 2 | six == 1.13.0 -------------------------------------------------------------------------------- /python27/setup.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # refer. https://wiki.python.org/moin/Distutils/Tutorial?highlight=%28setup.py%29 18 | # 19 | from setuptools import setup 20 | 21 | __version__ = '1.0.0' 22 | __title__ = 'hcm_admin' 23 | __author__ = 'Huawei' 24 | __license__ = 'Apache License 2.0' 25 | __url__ = 'https://developer.huawei.com/consumer/cn/' 26 | 27 | install_requires = ['requests>=2.20.1'] 28 | 29 | long_description = ('The Huawei Admin Python SDK enables server-side (backend) Python developers ' 30 | 'to integrate Huawei into their services and applications.') 31 | 32 | setup( 33 | name='huawei_push_admin', 34 | version='1.0.0', 35 | description='Huawei Admin Python SDK', 36 | long_description=long_description, 37 | url='https://developer.huawei.com/consumer/cn/', 38 | author='Huawei', 39 | license='Apache License 2.0', 40 | keywords='huawei cloud development', 41 | install_requires=install_requires, 42 | packages=['src/push_admin'], 43 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', 44 | classifiers=[ 45 | 'Development Status :: 5 - Production/Stable', 46 | 'Intended Audience :: Developers', 47 | 'Topic :: Software Development :: Build Tools', 48 | 'Programming Language :: Python :: 2', 49 | 'Programming Language :: Python :: 2.7', 50 | 'Programming Language :: Python :: 3', 51 | 'Programming Language :: Python :: 3.4', 52 | 'Programming Language :: Python :: 3.5', 53 | 'Programming Language :: Python :: 3.6', 54 | 'Programming Language :: Python :: 3.7', 55 | 'License :: OSI Approved :: Apache Software License', 56 | ], 57 | ) 58 | -------------------------------------------------------------------------------- /python27/src/__init__.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /python27/src/push_admin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Huawei Admin SDK for Python.""" 18 | 19 | import threading 20 | from src.push_admin import _app 21 | 22 | _apps = {} 23 | _apps_lock = threading.RLock() 24 | _DEFAULT_APP_NAME = 'DEFAULT' 25 | 26 | 27 | def initialize_app(appid, appsecret, appid_push=None, token_server='https://oauth-login.cloud.huawei.com/oauth2/v3/token', 28 | push_open_url='https://push-api.cloud.huawei.com'): 29 | """ 30 | Initializes and returns a new App instance. 31 | :param appid_at: appid parameters obtained by developer alliance applying for Push service 32 | :param appsecret_at: appsecret parameters obtained by developer alliance applying for Push service 33 | :param appid_push: the application Id in the URL 34 | :param token_server: Oauth server URL 35 | :param push_open_url: push open API URL 36 | """ 37 | app = _app.App(appid, appsecret, appid_push, token_server=token_server, push_open_url=push_open_url) 38 | 39 | with _apps_lock: 40 | if appid not in _apps: 41 | _apps[appid] = app 42 | 43 | """set default app instance""" 44 | if _apps.get(_DEFAULT_APP_NAME) is None: 45 | _apps[_DEFAULT_APP_NAME] = app 46 | 47 | 48 | def get_app(appid=None): 49 | """ 50 | get app instance 51 | :param appid: appid parameters obtained by developer alliance applying for Push service 52 | :return: app instance 53 | Raise: ValueError 54 | """ 55 | if appid is None: 56 | with _apps_lock: 57 | app = _apps.get(_DEFAULT_APP_NAME) 58 | if app is None: 59 | raise ValueError('The default Huawei app is not exists. ' 60 | 'This means you need to call initialize_app() it.') 61 | return app 62 | 63 | with _apps_lock: 64 | if appid not in _apps: 65 | raise ValueError('Huawei app id[{0}] is not exists. ' 66 | 'This means you need to call initialize_app() it.'.format(appid)) 67 | 68 | app = _apps.get(appid) 69 | if app is None: 70 | raise ValueError('The app id[{0}] is None.'.format(appid)) 71 | return app 72 | -------------------------------------------------------------------------------- /python27/src/push_admin/_app.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import urllib 18 | import json 19 | import time 20 | from src.push_admin import _http 21 | from src.push_admin import _message_serializer 22 | 23 | 24 | class App(object): 25 | """application for HW Cloud Message(HCM)""" 26 | 27 | JSON_ENCODER = _message_serializer.MessageSerializer() 28 | 29 | @classmethod 30 | def _send_to_server(cls, headers, body, url, verify_peer=False): 31 | try: 32 | msg_body = json.dumps(body) 33 | response = _http.post(url, msg_body, headers, verify_peer) 34 | 35 | if response.status_code is not 200: 36 | raise ApiCallError('http status code is {0} in send.'.format(response.status_code)) 37 | 38 | # json text to dict 39 | resp_dict = json.loads(response.text) 40 | return resp_dict 41 | 42 | except Exception as e: 43 | raise ApiCallError('caught exception when send. {0}'.format(e)) 44 | 45 | def __init__(self, appid_at, app_secret, appid_push, token_server='https://oauth-login.cloud.huawei.com/oauth2/v3/token', 46 | push_open_url='https://push-api.cloud.huawei.com'): 47 | """class init""" 48 | self.appid_at = appid_at 49 | self.app_secret_at = app_secret 50 | if appid_push is None: 51 | self.appid_push = appid_at 52 | else: 53 | self.appid_push = appid_push 54 | self.token_expired_time = 0 55 | self.access_token = None 56 | self.token_server = token_server 57 | self.push_open_url = push_open_url 58 | self.hw_push_server = self.push_open_url + "/v1/{0}/messages:send" 59 | self.hw_push_topic_sub_server = self.push_open_url + "/v1/{0}/topic:subscribe" 60 | self.hw_push_topic_unsub_server = self.push_open_url + "/v1/{0}/topic:unsubscribe" 61 | self.hw_push_topic_query_server = self.push_open_url + "/v1/{0}/topic:list" 62 | 63 | def _refresh_token(self, verify_peer=False): 64 | """refresh access token 65 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 66 | the server's TLS certificate, or a string, in which case it must be a path 67 | to a CA bundle to use. Defaults to ``True``. 68 | """ 69 | headers = dict() 70 | headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' 71 | 72 | params = dict() 73 | params['grant_type'] = 'client_credentials' 74 | params['client_secret'] = self.app_secret_at 75 | params['client_id'] = self.appid_at 76 | 77 | msg_body = urllib.urlencode(params) 78 | 79 | try: 80 | response = _http.post(self.token_server, msg_body, headers, verify_peer=verify_peer) 81 | 82 | if response.status_code is not 200: 83 | return False, 'http status code is {0} in get access token'.format(response.status_code) 84 | 85 | """ json string to directory """ 86 | response_body = json.loads(response.text) 87 | 88 | self.access_token = response_body.get('access_token') 89 | self.token_expired_time = long(round(time.time() * 1000)) + (long(response_body.get('expires_in')) - 5 * 60) * 1000 90 | 91 | return True, None 92 | except Exception as e: 93 | raise ApiCallError(format(repr(e))) 94 | 95 | def _is_token_expired(self): 96 | """is access token expired""" 97 | if self.access_token is None: 98 | """ need refresh token """ 99 | return True 100 | return long(round(time.time() * 1000)) >= self.token_expired_time 101 | 102 | def _update_token(self, verify_peer=False): 103 | if self._is_token_expired() is True: 104 | result, reason = self._refresh_token(verify_peer) 105 | if result is False: 106 | raise ApiCallError(reason) 107 | 108 | def _create_header(self): 109 | headers = dict() 110 | headers['Content-Type'] = 'application/json;charset=utf-8' 111 | headers['Authorization'] = 'Bearer {0}'.format(self.access_token) 112 | return headers 113 | 114 | def send(self, message, validate_only, **kwargs): 115 | """ 116 | Sends the given message Huawei Cloud Messaging (HCM) 117 | :param message: 118 | :param validate_only: 119 | :param kwargs: 120 | verify_peer: HTTPS server identity verification, use library 'certifi' 121 | :return: 122 | response dict: response body dict 123 | :raise: 124 | ApiCallError: failure reason 125 | """ 126 | verify_peer = kwargs['verify_peer'] 127 | self._update_token(verify_peer) 128 | headers = self._create_header() 129 | url = self.hw_push_server.format(self.appid_push) 130 | msg_body_dict = dict() 131 | msg_body_dict['validate_only'] = validate_only 132 | msg_body_dict['message'] = App.JSON_ENCODER.default(message) 133 | 134 | return App._send_to_server(headers, msg_body_dict, url, verify_peer) 135 | 136 | def subscribe_topic(self, topic, token_list): 137 | """ 138 | :param topic: The specific topic 139 | :param token_list: The token list to be added 140 | :return: 141 | """ 142 | self._update_token() 143 | headers = self._create_header() 144 | url = self.hw_push_topic_sub_server.format(self.appid_push) 145 | msg_body_dict = {'topic': topic, 'tokenArray': token_list} 146 | return App._send_to_server(headers, msg_body_dict, url) 147 | 148 | def unsubscribe_topic(self, topic, token_list): 149 | """ 150 | 151 | :param topic: The specific topic 152 | :param token_list: The token list to be deleted 153 | :return: 154 | """ 155 | self._update_token() 156 | headers = self._create_header() 157 | url = self.hw_push_topic_unsub_server.format(self.appid_push) 158 | msg_body_dict = {'topic': topic, 'tokenArray': token_list} 159 | return App._send_to_server(headers, msg_body_dict, url) 160 | 161 | def query_subscribe_list(self, token): 162 | """ 163 | :param token: The specific token 164 | :return: 165 | """ 166 | self._update_token() 167 | headers = self._create_header() 168 | url = self.hw_push_topic_query_server.format(self.appid_push) 169 | msg_body_dict = {'token': token} 170 | return App._send_to_server(headers, msg_body_dict, url) 171 | 172 | 173 | class ApiCallError(Exception): 174 | """Represents an Exception encountered while invoking the HCM API. 175 | 176 | Attributes: 177 | message: A error message string. 178 | detail: Original low-level exception. 179 | """ 180 | def __init__(self, message, detail=None): 181 | Exception.__init__(self, message) 182 | self.detail = detail 183 | -------------------------------------------------------------------------------- /python27/src/push_admin/_http.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import requests 18 | 19 | 20 | def post(url, req_body, headers=None, verify_peer=False): 21 | """ post http request to slb service 22 | :param url: url path 23 | :param req_body: http request body 24 | :param headers: http headers 25 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 26 | the server's TLS certificate, or a string, in which case it must be a path 27 | to a CA bundle to use. Defaults to ``True``. 28 | :return: 29 | success return response 30 | fali return None 31 | """ 32 | try: 33 | response = requests.post(url, data=req_body, headers=headers, timeout=10, verify=verify_peer) 34 | return response 35 | 36 | except Exception as e: 37 | raise ValueError('caught exception when post {0}. {1}'.format(url, e)) 38 | 39 | 40 | def _format_http_text(method, url, headers, body): 41 | """ 42 | print http head and body for request or response 43 | 44 | For examples: _format_http_text('', title, response.headers, response.text) 45 | """ 46 | result = method + ' ' + url + '\n' 47 | 48 | if headers is not None: 49 | for key, value in headers.items(): 50 | result = result + key + ': ' + value + '\n' 51 | 52 | result = result + body 53 | return result 54 | 55 | 56 | -------------------------------------------------------------------------------- /python27/src/push_admin/_message_serializer.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | from src.push_admin import _messages 19 | import six 20 | 21 | 22 | class MessageSerializer(json.JSONEncoder): 23 | """ 24 | Use https://docs.python.org/3/library/json.html to do serialization 25 | 26 | The serializer should serialize the following messages: 27 | _messages.Message 28 | _messages.Notification 29 | _messages.ApnsConfig 30 | _messages.WebPushConfig 31 | _messages.WebPushNotification 32 | _messages.WebPushNotificationAction 33 | _messages.WebPushHMSOptions 34 | _messages.AndroidConfig 35 | _messages.AndroidNotification 36 | _messages.AndroidClickAction 37 | _messages.BadgeNotification 38 | """ 39 | def default(self, message): 40 | """ 41 | :param message: The push message 42 | :return: formatted push messages 43 | """ 44 | result = { 45 | 'data': message.data, 46 | 'notification': MessageSerializer.encode_notification(message.notification), 47 | 'android': MessageSerializer.encode_android_config(message.android), 48 | 'apns': MessageSerializer.encode_apns_config(message.apns), 49 | 'webpush': MessageSerializer.encode_webpush_config(message.web_push), 50 | 'token': message.token, 51 | 'topic': message.topic, 52 | 'condition': message.condition 53 | } 54 | result = MessageSerializer.remove_null_values(result) 55 | return result 56 | 57 | @classmethod 58 | def remove_null_values(cls, dict_value): 59 | return {k: v for k, v in dict_value.items() if v not in [None, [], {}]} 60 | 61 | @classmethod 62 | def encode_notification(cls, notification): 63 | """ 64 | An example: 65 | { 66 | "title":"Big News", 67 | "body":"This is a Big News!", 68 | "image":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png" 69 | } 70 | :param notification: 71 | :return: 72 | """ 73 | if notification is None: 74 | return None 75 | 76 | if not isinstance(notification, _messages.Notification): 77 | raise ValueError('Message.notification must be an instance of Notification class.') 78 | 79 | result = { 80 | 'title': notification.title, 81 | 'body': notification.body, 82 | 'image': notification.image 83 | } 84 | return cls.remove_null_values(result) 85 | 86 | @classmethod 87 | def encode_android_config(cls, android_config): 88 | """ 89 | An example: 90 | { 91 | "android":{ 92 | "collapse_key":-1, 93 | "urgency":"HIGH", 94 | "ttl":"1448s", 95 | "bi_tag":"Trump", 96 | "fast_app_target":1, 97 | "notification": {} 98 | } 99 | :param android_config: 100 | :return: 101 | """ 102 | if android_config is None: 103 | return None 104 | 105 | if not isinstance(android_config, _messages.AndroidConfig): 106 | raise ValueError('Message.android must be an instance of AndroidConfig class.') 107 | 108 | result = { 109 | 'collapse_key': android_config.collapse_key, 110 | 'urgency': android_config.urgency, 111 | 'ttl': android_config.ttl, 112 | 'bi_tag': android_config.bi_tag, 113 | 'fast_app_target': android_config.fast_app_target, 114 | 'data': android_config.data, 115 | 'notification': MessageSerializer.encode_android_notification(android_config.notification) 116 | } 117 | return cls.remove_null_values(result) 118 | 119 | @classmethod 120 | def encode_android_notification(cls, notification): 121 | """ 122 | "notification":{ 123 | "title":"test title", 124 | "body":"test body", 125 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 126 | "color":"#AACCDD", 127 | "sound":"http://att.chinauui.com/day_120606/20120606_7fcf2235b44f1eab0b4dadtAkAGMTBHK.mp3", 128 | "default_sound":true, 129 | "tag":"tagBoom", 130 | "importance":"PRIORITY_HIGH", 131 | "click_action":{ 132 | "type":2, 133 | "url":"https://www.huawei.com" 134 | }, 135 | "body_loc_key":"M.String.body", 136 | "body_loc_args":[ 137 | "Boy", 138 | "Dog" 139 | ], 140 | "title_loc_key":"M.String.title", 141 | "title_loc_args":[ 142 | "Girl", 143 | "Cat" 144 | ], 145 | "channel_id":"RingRing", 146 | "notify_summary":"Some Summary", 147 | "style":2, 148 | "big_title":"Big Title", 149 | "big_body":"Big Body", 150 | "notify_id":123, 151 | "group":"spaceGroup", 152 | "badge":{ 153 | "add_num":99, 154 | "set_num":99, 155 | "class":"Classic" 156 | }, 157 | "ticker":"i am a ticker", 158 | "auto_cancel":false, 159 | "when":"2019-11-05", 160 | "use_default_vibrate":true, 161 | "use_default_light":false, 162 | "visibility":"PUBLIC", 163 | "vibrate_config":["1.5","2","3"], 164 | "light_settings":{ 165 | "color":{ 166 | "alpha":0, 167 | "red":0, 168 | "green":1, 169 | "blue":1 170 | }, 171 | "light_on_duration":"3.5", 172 | "light_off_duration":"5S" 173 | }, 174 | "foreground_show":true 175 | } 176 | :param notification: 177 | :return: 178 | """ 179 | if notification is None: 180 | return None 181 | 182 | if not isinstance(notification, _messages.AndroidNotification): 183 | raise ValueError('Message.AndroidConfig.notification must be an instance of AndroidNotification class.') 184 | 185 | result = { 186 | "title": notification.title, 187 | "body": notification.body, 188 | "icon": notification.icon, 189 | "color": notification.color, 190 | "sound": notification.sound, 191 | "default_sound": notification.default_sound, 192 | "tag": notification.tag, 193 | "importance": notification.importance, 194 | "multi_lang_key": notification.multi_lang_key, 195 | "click_action": MessageSerializer.encode_android_click_action(notification.click_action), 196 | "body_loc_key": notification.body_loc_key, 197 | "body_loc_args": notification.body_loc_args, 198 | "title_loc_key": notification.title_loc_key, 199 | "title_loc_args": notification.title_loc_args, 200 | "channel_id": notification.channel_id, 201 | "notify_summary": notification.notify_summary, 202 | "image": notification.image, 203 | "style": notification.style, 204 | "big_title": notification.big_title, 205 | "big_body": notification.big_body, 206 | "notify_id": notification.notify_id, 207 | "group": notification.group, 208 | "badge": MessageSerializer.encode_android_badge(notification.badge), 209 | "ticker": notification.ticker, 210 | "auto_cancel": notification.auto_cancel, 211 | "when": notification.when, 212 | "use_default_vibrate": notification.use_default_vibrate, 213 | "use_default_light": notification.use_default_light, 214 | "visibility": notification.visibility, 215 | "vibrate_config": notification.vibrate_config, 216 | "light_settings": MessageSerializer.encode_android_light_settings(notification.light_settings), 217 | "foreground_show": notification.foreground_show 218 | } 219 | result = cls.remove_null_values(result) 220 | return result 221 | 222 | @classmethod 223 | def encode_android_click_action(cls, click_action): 224 | """ 225 | "click_action":{ 226 | "type":2, 227 | "url":"https://www.huawei.com" 228 | } 229 | 230 | "click_action":{ 231 | "type":1, 232 | "intent":"https://www.huawei.com", 233 | "action":"" 234 | } 235 | 236 | :param click_action: _messages.AndroidClickAction 237 | :return: 238 | """ 239 | if click_action is None: 240 | return None 241 | 242 | if not isinstance(click_action, _messages.AndroidClickAction): 243 | raise ValueError('Message.AndroidConfig.AndroidNotification.click_action must be an instance\ 244 | of AndroidClickAction class.') 245 | 246 | result = { 247 | "type": click_action.action_type, 248 | "intent": click_action.intent, 249 | "url": click_action.url, 250 | "action": click_action.action 251 | } 252 | result = cls.remove_null_values(result) 253 | return result 254 | 255 | @classmethod 256 | def encode_android_badge(cls, badge): 257 | """ 258 | refer to: _messages.AndroidBadgeNotification 259 | 260 | "badge":{ 261 | "add_num":99, 262 | "set_num":99, 263 | "class":"Classic" 264 | } 265 | 266 | :param badge: 267 | :return: 268 | """ 269 | if badge is None: 270 | return None 271 | 272 | if not isinstance(badge, _messages.AndroidBadgeNotification): 273 | raise ValueError('Message.AndroidConfig.AndroidNotification.badge must be an instance\ 274 | of AndroidBadgeNotification class.') 275 | 276 | result = { 277 | "add_num": badge.add_num, 278 | "set_num": badge.set_num, 279 | "class": badge.clazz 280 | } 281 | result = cls.remove_null_values(result) 282 | return result 283 | 284 | @classmethod 285 | def encode_android_light_settings(cls, android_light_settings): 286 | """ 287 | refer to: _messages.AndroidLightSettings 288 | 289 | "light_settings":{ 290 | "color":{ 291 | "alpha":0, 292 | "red":0, 293 | "green":1, 294 | "blue":1 295 | }, 296 | "light_on_duration":"3.5", 297 | "light_off_duration":"5S" 298 | } 299 | 300 | :param android_light_settings: _messages.AndroidLightSettings 301 | :return: 302 | """ 303 | if android_light_settings is None: 304 | return None 305 | 306 | if not isinstance(android_light_settings, _messages.AndroidLightSettings): 307 | raise ValueError('Message.AndroidConfig.AndroidNotification.android_light_settings must be an instance\ 308 | of AndroidLightSettings class.') 309 | 310 | result = { 311 | "color": MessageSerializer.encode_android_light_settings_color(android_light_settings.color), 312 | "light_on_duration": android_light_settings.light_on_duration, 313 | "light_off_duration": android_light_settings.light_off_duration 314 | } 315 | result = cls.remove_null_values(result) 316 | return result 317 | 318 | @classmethod 319 | def encode_android_light_settings_color(cls, color): 320 | """ 321 | "color":{ 322 | "alpha":0, 323 | "red":0, 324 | "green":1, 325 | "blue":1 326 | } 327 | 328 | :param color: _messages.AndroidLightSettingsColor 329 | :return: 330 | """ 331 | if color is None: 332 | return None 333 | 334 | if not isinstance(color, _messages.AndroidLightSettingsColor): 335 | raise ValueError('Message.AndroidConfig.AndroidNotification.android_light_settings.color must be an instance\ 336 | of AndroidLightSettingsColor class.') 337 | result = { 338 | "alpha": color.alpha, 339 | "red": color.red, 340 | "green": color.green, 341 | "blue": color.blue 342 | } 343 | result = cls.remove_null_values(result) 344 | return result 345 | 346 | @classmethod 347 | def encode_webpush_config(cls, webpush_config): 348 | """ 349 | "webpush":{ 350 | "headers":{ 351 | ... 352 | }, 353 | "notification":{ 354 | ... 355 | }, 356 | "hms_options":{ 357 | ... 358 | } 359 | } 360 | :param webpush_config: refer to _messages.WebPushConfig 361 | :return: 362 | """ 363 | if webpush_config is None: 364 | return None 365 | 366 | if not isinstance(webpush_config, _messages.WebPushConfig): 367 | raise ValueError('Message.webpush must be an instance of WebPushConfig class.') 368 | 369 | result = { 370 | "headers": MessageSerializer.encode_webpush_config_headers(webpush_config.headers), 371 | "notification": MessageSerializer.encode_webpush_config_notification(webpush_config.notification), 372 | "hms_options": MessageSerializer.encode_webpush_config_hms_options(webpush_config.hms_options), 373 | } 374 | result = cls.remove_null_values(result) 375 | return result 376 | 377 | @classmethod 378 | def encode_webpush_config_headers(cls, webpush_headers): 379 | """ 380 | "headers":{ 381 | "ttl":"990", 382 | "urgency":"very-low", 383 | "topic":"12313ceshi" 384 | } 385 | 386 | :param webpush_headers: _messages.WebPushHeader 387 | :return: 388 | """ 389 | if webpush_headers is None: 390 | return None 391 | 392 | if not isinstance(webpush_headers, _messages.WebPushHeader): 393 | raise ValueError('Message.webpush.headers must be an instance of WebPushHeader class.') 394 | 395 | result = { 396 | "ttl": webpush_headers.ttl, 397 | "urgency": webpush_headers.urgency, 398 | "topic": webpush_headers.topic, 399 | } 400 | result = cls.remove_null_values(result) 401 | return result 402 | 403 | @classmethod 404 | def encode_webpush_config_notification(cls, webpush_notification): 405 | """ 406 | "notification":{ 407 | "title":"notication string", 408 | "body":"web push body", 409 | "actions":[ 410 | { 411 | "action":"", 412 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 413 | "title":"string" 414 | } 415 | ], 416 | "badge":"string", 417 | "dir":"auto", 418 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 419 | "image":"string", 420 | "lang":"string", 421 | "renotify":true, 422 | "requireInteraction":true, 423 | "silent":true, 424 | "tag":"string", 425 | "timestamp":1545201266, 426 | "vibrate":[1,2,3] 427 | } 428 | 429 | :param webpush_notification: refer to _messages.WebPushNotification 430 | :return: 431 | """ 432 | if webpush_notification is None: 433 | return None 434 | 435 | if not isinstance(webpush_notification, _messages.WebPushNotification): 436 | raise ValueError('Message.webpush.notification must be an instance of WebPushNotification class.') 437 | 438 | result = { 439 | "title": webpush_notification.title, 440 | "body": webpush_notification.body, 441 | "actions": [MessageSerializer.encode_webpush_notification_action(_) 442 | for _ in webpush_notification.actions], 443 | "badge": webpush_notification.badge, 444 | "dir": webpush_notification.dir, 445 | "icon": webpush_notification.icon, 446 | "image": webpush_notification.image, 447 | "lang": webpush_notification.lang, 448 | "renotify": webpush_notification.renotify, 449 | "require_interaction": webpush_notification.require_interaction, 450 | "silent": webpush_notification.silent, 451 | "tag": webpush_notification.tag, 452 | "timestamp": webpush_notification.timestamp, 453 | "vibrate": webpush_notification.vibrate 454 | } 455 | result = cls.remove_null_values(result) 456 | return result 457 | 458 | @classmethod 459 | def encode_webpush_notification_action(cls, webpush_notification_action): 460 | """ 461 | "actions":[ 462 | { 463 | "action":"", 464 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 465 | "title":"string" 466 | } 467 | ], 468 | :param webpush_notification_action: refer to _messages.WebPushNotificationAction 469 | :return: 470 | """ 471 | if webpush_notification_action is None: 472 | return None 473 | 474 | if not isinstance(webpush_notification_action, _messages.WebPushNotificationAction): 475 | raise ValueError('Message.webpush.notification.action must be an instance of \ 476 | WebPushNotificationAction class.') 477 | 478 | result = { 479 | "action": webpush_notification_action.action, 480 | "icon": webpush_notification_action.icon, 481 | "title": webpush_notification_action.title 482 | } 483 | result = cls.remove_null_values(result) 484 | return result 485 | 486 | @classmethod 487 | def encode_webpush_config_hms_options(cls, webpush_hms_options): 488 | """ 489 | "hms_options":{ 490 | "link":"https://www.huawei.com/" 491 | } 492 | 493 | :param webpush_hms_options: refer to _messages.WebPushHMSOptions 494 | :return: 495 | """ 496 | if webpush_hms_options is None: 497 | return None 498 | 499 | if not isinstance(webpush_hms_options, _messages.WebPushHMSOptions): 500 | raise ValueError('Message.webpush.hmsoptions must be an instance of \ 501 | WebPushHMSOptions class.') 502 | 503 | result = { 504 | "link": webpush_hms_options.link 505 | } 506 | result = cls.remove_null_values(result) 507 | return result 508 | 509 | @classmethod 510 | def encode_apns_config(cls, apns_config): 511 | """ 512 | Encode APNs config into JSON 513 | :param apns_config: 514 | :return: 515 | """ 516 | if apns_config is None: 517 | return None 518 | if not isinstance(apns_config, _messages.APNsConfig): 519 | raise ValueError('Message.apns_config must be an instance of _messages.APNsConfig class.') 520 | 521 | result = { 522 | 'headers': apns_config.headers, 523 | 'payload': cls.encode_apns_payload(apns_config.payload), 524 | 'hms_options': cls.encode_apns_hms_options(apns_config.apns_hms_options) 525 | } 526 | return cls.remove_null_values(result) 527 | 528 | @classmethod 529 | def encode_apns_payload(cls, apns_payload): 530 | """Encodes an ``APNSPayload`` instance into JSON.""" 531 | if apns_payload is None: 532 | return None 533 | if not isinstance(apns_payload, _messages.APNsPayload): 534 | raise ValueError('APNSConfig.payload must be an instance of _messages.APNsPayload class.') 535 | result = { 536 | 'aps': cls.encode_apns_payload_aps(apns_payload.aps) 537 | } 538 | for key, value in apns_payload.custom_data.items(): 539 | result[key] = value 540 | return cls.remove_null_values(result) 541 | 542 | @classmethod 543 | def encode_apns_payload_aps(cls, apns_payload_aps): 544 | """Encodes an ``Aps`` instance into JSON.""" 545 | if not isinstance(apns_payload_aps, _messages.APNsAps): 546 | raise ValueError('APNSPayload.aps must be an instance of _messages.APNsAps class.') 547 | 548 | result = { 549 | 'alert': cls.encode_apns_payload_alert(apns_payload_aps.alert), 550 | 'badge': apns_payload_aps.badge, 551 | 'sound': apns_payload_aps.sound, 552 | 'category': apns_payload_aps.category, 553 | 'thread-id': apns_payload_aps.thread_id 554 | } 555 | 556 | if apns_payload_aps.content_available is True: 557 | result['content-available'] = 1 558 | if apns_payload_aps.mutable_content is True: 559 | result['mutable-content'] = 1 560 | if apns_payload_aps.custom_data is not None: 561 | if not isinstance(apns_payload_aps.custom_data, dict): 562 | raise ValueError('Aps.custom_data must be a dict.') 563 | for key, val in apns_payload_aps.custom_data.items(): 564 | if key in result: 565 | raise ValueError('Multiple specifications for {0} in Aps.'.format(key)) 566 | result[key] = val 567 | return cls.remove_null_values(result) 568 | 569 | @classmethod 570 | def encode_apns_payload_alert(cls, apns_payload_alert): 571 | """Encodes an ``ApsAlert`` instance into JSON.""" 572 | if apns_payload_alert is None: 573 | return None 574 | if isinstance(apns_payload_alert, six.string_types): 575 | return apns_payload_alert 576 | if not isinstance(apns_payload_alert, _messages.APNsAlert): 577 | raise ValueError('Aps.alert must be a string or an instance of _messages.APNsAlert class.') 578 | result = { 579 | 'title': apns_payload_alert.title, 580 | 'body': apns_payload_alert.body, 581 | 'title-loc-key': apns_payload_alert.title_loc_key, 582 | 'title-loc-args': apns_payload_alert.title_loc_args, 583 | 'loc-key': apns_payload_alert.loc_key, 584 | 'loc-args': apns_payload_alert.loc_args, 585 | 'action-loc-key': apns_payload_alert.action_loc_key, 586 | 'launch-image': apns_payload_alert.launch_image 587 | } 588 | if result.get('loc-args') and not result.get('loc-key'): 589 | raise ValueError( 590 | 'ApsAlert.loc_key is required when specifying loc_args.') 591 | if result.get('title-loc-args') and not result.get('title-loc-key'): 592 | raise ValueError( 593 | 'ApsAlert.title_loc_key is required when specifying title_loc_args.') 594 | if apns_payload_alert.custom_data is not None: 595 | if not isinstance(apns_payload_alert.custom_data, dict): 596 | raise ValueError('ApsAlert.custom_data must be a dict.') 597 | for key, val in apns_payload_alert.custom_data.items(): 598 | result[key] = val 599 | return cls.remove_null_values(result) 600 | 601 | @classmethod 602 | def encode_apns_hms_options(cls, apns_hms_options): 603 | """ 604 | :param apns_hms_options: 605 | """ 606 | if apns_hms_options is None: 607 | return None 608 | if not isinstance(apns_hms_options, _messages.APNsHMSOptions): 609 | raise ValueError('Aps.alert must be a string or an instance of _messages.APNsHMSOptions class.') 610 | 611 | result = { 612 | 'target_user_type': apns_hms_options.target_user_type, 613 | } 614 | return cls.remove_null_values(result) 615 | -------------------------------------------------------------------------------- /python27/src/push_admin/messaging.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src.push_admin import _messages, _app 18 | from src import push_admin 19 | 20 | """HUAWEI Cloud Messaging module.""" 21 | 22 | """ General Data structure """ 23 | Message = _messages.Message 24 | Notification = _messages.Notification 25 | 26 | """ Web Push related data structure """ 27 | WebPushConfig = _messages.WebPushConfig 28 | WebPushHeader = _messages.WebPushHeader 29 | WebPushNotification = _messages.WebPushNotification 30 | WebPushNotificationAction = _messages.WebPushNotificationAction 31 | WebPushHMSOptions = _messages.WebPushHMSOptions 32 | 33 | """ Android Push related data structure """ 34 | AndroidConfig = _messages.AndroidConfig 35 | AndroidNotification = _messages.AndroidNotification 36 | AndroidClickAction = _messages.AndroidClickAction 37 | AndroidBadgeNotification = _messages.AndroidBadgeNotification 38 | AndroidLightSettings = _messages.AndroidLightSettings 39 | AndroidLightSettingsColor = _messages.AndroidLightSettingsColor 40 | 41 | """ APNS Push related data structure""" 42 | APNsConfig = _messages.APNsConfig 43 | APNsHeader = _messages.APNsHeader 44 | APNsPayload = _messages.APNsPayload 45 | APNsAps = _messages.APNsAps 46 | APNsAlert = _messages.APNsAlert 47 | APNsHMSOptions = _messages.APNsHMSOptions 48 | 49 | """Common exception definition""" 50 | ApiCallError = _app.ApiCallError 51 | 52 | 53 | def send_message(message, validate_only=False, app_id=None, verify_peer=False): 54 | """ 55 | Sends the given message Huawei Cloud Messaging (HCM) 56 | :param message: An instance of ``messaging.Message``. 57 | :param validate_only: A boolean indicating whether to run the operation in dry run mode (optional). 58 | :param app_id: app id parameters obtained by developer alliance applying for Push service (optional). 59 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 60 | the server's TLS certificate, or a string, in which case it must be a path 61 | to a CA bundle to use. Defaults to ``True``. 62 | :return: SendResponse 63 | Raises: 64 | ApiCallError: If an error occurs while sending the message to the HCM service. 65 | """ 66 | try: 67 | response = push_admin.get_app(app_id).send(message, validate_only, verify_peer=verify_peer) 68 | return SendResponse(response) 69 | except Exception as e: 70 | raise ApiCallError(repr(e)) 71 | 72 | 73 | def subscribe_topic(topic, token_list, app_id=None): 74 | """ 75 | :param topic: The specific topic 76 | :param token_list: The token list to be added 77 | :param app_id: application ID 78 | """ 79 | try: 80 | response = push_admin.get_app(app_id).subscribe_topic(topic, token_list) 81 | return TopicSubscribeResponse(response) 82 | except Exception as e: 83 | raise ApiCallError(repr(e)) 84 | 85 | 86 | def unsubscribe_topic(topic, token_list, app_id=None): 87 | """ 88 | :param topic: The specific topic 89 | :param token_list: The token list to be deleted 90 | :param app_id: application ID 91 | """ 92 | try: 93 | response = push_admin.get_app(app_id).unsubscribe_topic(topic, token_list) 94 | return TopicSubscribeResponse(response) 95 | except Exception as e: 96 | raise ApiCallError(repr(e)) 97 | 98 | 99 | def list_topics(token, app_id=None): 100 | """ 101 | :param token: The token to be queried 102 | :param app_id: application ID 103 | """ 104 | try: 105 | response = push_admin.get_app(app_id).query_subscribe_list(token) 106 | return TopicQueryResponse(response) 107 | except Exception as e: 108 | raise ApiCallError(repr(e)) 109 | 110 | 111 | class SendResponse(object): 112 | """ 113 | The response received from an send request to the HCM API. 114 | response: received http response body text from HCM. 115 | """ 116 | def __init__(self, response=None): 117 | try: 118 | self._msg = response['msg'] 119 | self._code = response['code'] 120 | self._requestId = response['requestId'] 121 | except Exception as e: 122 | raise ValueError(format(repr(e))) 123 | 124 | @property 125 | def code(self): 126 | """errcode""" 127 | return self._code 128 | 129 | @property 130 | def reason(self): 131 | """the description of errcode""" 132 | return self._msg 133 | 134 | @property 135 | def requestId(self): 136 | """A message ID string that uniquely identifies the message.""" 137 | return self._requestId 138 | 139 | 140 | class BaseTopicResponse(object): 141 | """ 142 | { 143 | "msg": "Success", 144 | "code": "80000000", 145 | "requestId": "157466304904000004000701" 146 | } 147 | """ 148 | def __init__(self, json_rsp=None): 149 | if json_rsp is None: 150 | self._msg = "" 151 | self._code = "" 152 | self._requestId = "" 153 | else: 154 | self._msg = json_rsp['msg'] 155 | self._code = json_rsp['code'] 156 | self._requestId = json_rsp['requestId'] 157 | 158 | @property 159 | def msg(self): 160 | return self._msg 161 | 162 | @property 163 | def code(self): 164 | return self._code 165 | 166 | @property 167 | def requestId(self): 168 | return self._requestId 169 | 170 | 171 | class TopicSubscribeResponse(BaseTopicResponse): 172 | """ 173 | { 174 | "msg": "Success", 175 | "code": "80000000", 176 | "requestId": "157466304904000004000701", 177 | "successCount": 2, 178 | "failureCount": 0, 179 | "errors": [] 180 | } 181 | """ 182 | def __init__(self, json_rsp=None): 183 | super(TopicSubscribeResponse, self).__init__(json_rsp=json_rsp) 184 | if json_rsp is None: 185 | self._successCount = 0 186 | self._failureCount = 0 187 | self._errors = [] 188 | else: 189 | self._successCount = json_rsp['successCount'] 190 | self._failureCount = json_rsp['failureCount'] 191 | self._errors = json_rsp['errors'] 192 | 193 | @property 194 | def successCount(self): 195 | return self._successCount 196 | 197 | @property 198 | def failureCount(self): 199 | return self._failureCount 200 | 201 | @property 202 | def errors(self): 203 | return self._errors 204 | 205 | 206 | class TopicQueryResponse(BaseTopicResponse): 207 | """ 208 | { 209 | "msg": "success", 210 | "code": "80000000", 211 | "requestId": "157466350121600008000701", 212 | "topics": [ 213 | { "name": "sports", 214 | "addDate": "2019-11-25" 215 | } ] 216 | } 217 | """ 218 | def __init__(self, json_rsp=None): 219 | super(TopicQueryResponse, self).__init__(json_rsp) 220 | self._topics = json_rsp['topics'] 221 | 222 | @property 223 | def topics(self): 224 | return self._topics 225 | -------------------------------------------------------------------------------- /python27/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | -------------------------------------------------------------------------------- /python27/test/push_env.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # Production ENV 19 | app_id = 'your aappId' 20 | app_secret = 'your appSecret' 21 | app_package_name = 'your packageName' 22 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 23 | push_open_api = 'https://push-api.cloud.huawei.com' 24 | 25 | # Production ENV 26 | app_id = 'your aappId' 27 | app_secret = 'your appSecret' 28 | app_package_name = 'your packageName' 29 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 30 | push_open_api = 'https://push-api.cloud.huawei.com' 31 | 32 | # Production EVN (instance APP) 33 | app_id = 'your aappId' 34 | app_secret = 'your appSecret' 35 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 36 | push_open_api = 'https://push-api.cloud.huawei.com' 37 | 38 | 39 | -------------------------------------------------------------------------------- /python27/test/send_apns_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | headers = {messaging.APNsHeader.HEAD_APNs_ID: "6532dc0e-f581-7bfb-e1ab-60ec3cecea73"} 23 | 24 | apns_alert = messaging.APNsAlert(title="HMS Push Title", 25 | body="HMS Push Body", 26 | launch_image="Default.png", 27 | custom_data={"k1": "v1", "k2": "v2"}) 28 | 29 | apns_payload_aps = messaging.APNsAps(alert=apns_alert, 30 | badge=1, 31 | sound="wtewt.mp4", 32 | content_available=True, 33 | category="category", 34 | thread_id="id") 35 | 36 | payload = messaging.APNsPayload(aps=apns_payload_aps, 37 | acme_account="jane.appleseed@apple.com", 38 | acme_message="message123456") 39 | 40 | apns_hms_options = messaging.APNsHMSOptions(target_user_type=1) 41 | 42 | apns_push_config = messaging.APNsConfig(headers=headers, 43 | payload=payload, 44 | apns_hms_options=apns_hms_options) 45 | 46 | 47 | def send_apns_push_message(): 48 | """ 49 | a sample to show hwo to send web push message 50 | :return: 51 | """ 52 | message = messaging.Message( 53 | apns=apns_push_config, 54 | # TODO 55 | token=['your token'] 56 | ) 57 | 58 | try: 59 | # Case 1: Local CA sample code 60 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 61 | # Case 2: No verification of HTTPS's certificate 62 | response = messaging.send_message(message) 63 | # Case 3: use certifi Library 64 | # import certifi 65 | # response = messaging.send_message(message, verify_peer=certifi.where()) 66 | print "response is ", json.dumps(vars(response)) 67 | assert (response.code == '80000000') 68 | except Exception as e: 69 | print repr(e) 70 | 71 | 72 | def init_app(): 73 | """init sdk app. The appID & app Secret use the Android's application ID and Secret under the same project, next version you can use 74 | the IOS application's own appId & secret! """ 75 | # TODO: 76 | app_id_at = "Your android application's app id" 77 | app_secret_at = "Your android application's app secret" 78 | app_id_push = "Your IOS application' app id " 79 | push_admin.initialize_app(app_id_at, app_secret_at, app_id_push) 80 | 81 | 82 | def main(): 83 | init_app() 84 | send_apns_push_message() 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /python27/test/send_condition_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["Girl", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title', 45 | big_body='Big Boom Body', 46 | auto_clear=86400000, 47 | notify_id=486, 48 | group='Group1', 49 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 50 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 51 | alpha=0, red=0, green=1, blue=1) 52 | , light_on_duration="3.5", light_off_duration="5S"), 53 | badge=messaging.AndroidBadgeNotification( 54 | add_num=1, clazz='Classic'), 55 | visibility=messaging.AndroidNotification.PUBLIC, 56 | foreground_show=True 57 | ) 58 | 59 | 60 | android = messaging.AndroidConfig( 61 | collapse_key=-1, 62 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 63 | ttl="10000s", 64 | bi_tag='the_sample_bi_tag_for_receipt_service', 65 | notification=android_notification, 66 | category=None 67 | ) 68 | 69 | 70 | def send_push_android_data_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | condition="'your topic' in topics" 80 | ) 81 | 82 | try: 83 | 84 | # Case 1: Local CA sample code 85 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 86 | # Case 2: No verification of HTTPS's certificate 87 | response = messaging.send_message(message) 88 | # Case 3: use certifi Library 89 | # import certifi 90 | # response = messaging.send_message(message, verify_peer=certifi.where()) 91 | print "response is ", json.dumps(vars(response)) 92 | assert (response.code == '80000000') 93 | except Exception as e: 94 | print repr(e) 95 | 96 | 97 | def init_app(): 98 | """init sdk app""" 99 | # TODO 100 | app_id = "Your android application's app id" 101 | app_secret = "Your android application's app secret" 102 | push_admin.initialize_app(app_id, app_secret) 103 | 104 | 105 | def main(): 106 | init_app() 107 | send_push_android_data_message() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /python27/test/send_data_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | """ 23 | [ANDROID] android 24 | """ 25 | android = messaging.AndroidConfig( 26 | collapse_key=-1, 27 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 28 | ttl="10000s", 29 | bi_tag='the_sample_bi_tag_for_receipt_service' 30 | ) 31 | 32 | 33 | def send_push_android_data_message(): 34 | """ 35 | a sample to show hwo to send web push message 36 | :return: 37 | """ 38 | message = messaging.Message( 39 | data="{'k1':'v1', 'k2':'v2'}", 40 | android=android, 41 | # TODO 42 | token=['your token'] 43 | ) 44 | 45 | try: 46 | # Case 1: Local CA sample code 47 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 48 | # Case 2: No verification of HTTPS's certificate 49 | response = messaging.send_message(message) 50 | # Case 3: use certifi Library 51 | # import certifi 52 | # response = messaging.send_message(message, verify_peer=certifi.where()) 53 | print "response is ", json.dumps(vars(response)) 54 | assert (response.code == '80000000') 55 | except Exception as e: 56 | print repr(e) 57 | 58 | 59 | def init_app(): 60 | """init sdk app""" 61 | # TODO 62 | app_id = "Your android application's app id" 63 | app_secret = "Your android application's app secret" 64 | push_admin.initialize_app(app_id, app_secret) 65 | 66 | 67 | def main(): 68 | init_app() 69 | send_push_android_data_message() 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | 75 | -------------------------------------------------------------------------------- /python27/test/send_instance_app_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | android = messaging.AndroidConfig( 22 | collapse_key=-1, 23 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 24 | ttl="10000s", 25 | bi_tag='the_sample_bi_tag_for_receipt_service', 26 | fast_app_target=1, 27 | category=None 28 | ) 29 | 30 | 31 | def send_push_android_data_message(): 32 | """ 33 | a sample to show hwo to send web push message 34 | :return: 35 | """ 36 | message = messaging.Message( 37 | # English sample 38 | # data = "{\"pushtype\":0,\"pushbody\":{\"title\":\"Welcome to use Huawei HMS Push Kit?\",\"description\":\"One " 39 | # + "of the best push platform on the planet!!!\",\"page\":\"/\",\"params\":{\"key1\":\"test1\",\"key2\":\"test2\"},\"ringtone\":" 40 | # + "{\"vibration\":\"true\",\"breathLight\":\"true\"}}}", 41 | # Chinese sample 42 | data = "{\"pushtype\":0,\"pushbody\":{\"title\":\"欢迎使用华为HMS Push Kit!\",\"description\":\"世界上最好," 43 | + "最优秀的推送平台!!!\",\"page\":\"/\",\"params\":{\"key1\":\"test1\",\"key2\":\"test2\"},\"ringtone\":" 44 | + "{\"vibration\":\"true\",\"breathLight\":\"true\"}}}", 45 | android=android, 46 | # TODO 47 | token=['your token'] 48 | ) 49 | 50 | try: 51 | # Case 1: Local CA sample code 52 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 53 | # Case 2: No verification of HTTPS's certificate 54 | response = messaging.send_message(message) 55 | # Case 3: use certifi Library 56 | # import certifi 57 | # response = messaging.send_message(message, verify_peer=certifi.where()) 58 | print "response is ", json.dumps(vars(response)) 59 | assert (response.code == '80000000') 60 | except Exception as e: 61 | print repr(e) 62 | 63 | 64 | def init_app(): 65 | """init sdk app""" 66 | # TODO 67 | app_id = "Your instance application's (not android app) app id" 68 | app_secret = "Your instance application's (not android app) app secret" 69 | push_admin.initialize_app(app_id, app_secret) 70 | 71 | 72 | def main(): 73 | init_app() 74 | send_push_android_data_message() 75 | 76 | 77 | if __name__ == '__main__': 78 | main() 79 | -------------------------------------------------------------------------------- /python27/test/send_notify_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body', 25 | image='https://www.huawei.com/path/icon.png' 26 | ) 27 | 28 | android_notification = messaging.AndroidNotification( 29 | icon='/raw/ic_launcher2', 30 | color='#AACCDD', 31 | sound='/raw/shake', 32 | default_sound=True, 33 | tag='tagBoom', 34 | click_action=messaging.AndroidClickAction( 35 | action_type=1, 36 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 37 | body_loc_key='M.String.body', 38 | body_loc_args=('boy', 'dog'), 39 | title_loc_key='M.String.title', 40 | title_loc_args=["Girl", "Cat"], 41 | channel_id='Your Channel ID', 42 | notify_summary='some summary', 43 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 44 | style=0, 45 | big_title='Big Boom Title', 46 | big_body='Big Boom Body', 47 | auto_clear=86400000, 48 | notify_id=4861, 49 | group='Group1', 50 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 51 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 52 | alpha=0, red=0, green=1, blue=1) 53 | , light_on_duration="3.5", light_off_duration="5S"), 54 | badge=messaging.AndroidBadgeNotification( 55 | add_num=1, clazz='Classic'), 56 | visibility=messaging.AndroidNotification.PUBLIC, 57 | foreground_show=True 58 | ) 59 | 60 | 61 | android = messaging.AndroidConfig( 62 | collapse_key=-1, 63 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 64 | ttl="10000s", 65 | bi_tag='the_sample_bi_tag_for_receipt_service', 66 | notification=android_notification 67 | ) 68 | 69 | 70 | def send_push_android_notify_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | token=['Your Token'] 80 | ) 81 | 82 | try: 83 | # Case 1: Local CA sample code 84 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 85 | # Case 2: No verification of HTTPS's certificate 86 | response = messaging.send_message(message) 87 | # Case 3: use certifi Library 88 | # import certifi 89 | # response = messaging.send_message(message, verify_peer=certifi.where()) 90 | print "response is ", json.dumps(vars(response)) 91 | assert (response.code == '80000000') 92 | except Exception as e: 93 | print repr(e) 94 | 95 | 96 | def init_app(): 97 | """init sdk app""" 98 | # TODO 99 | app_id = "Your android application's app id" 100 | app_secret = "Your android application's app secret" 101 | push_admin.initialize_app(app_id, app_secret) 102 | 103 | 104 | def main(): 105 | init_app() 106 | send_push_android_notify_message() 107 | 108 | 109 | if __name__ == '__main__': 110 | main() 111 | -------------------------------------------------------------------------------- /python27/test/send_test_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["jack", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title', 45 | big_body='Big Boom Body', 46 | auto_clear=86400000, 47 | group='Group1', 48 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 49 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 50 | alpha=0, red=0, green=1, blue=1) 51 | , light_on_duration="3.5", light_off_duration="5S"), 52 | badge=messaging.AndroidBadgeNotification( 53 | add_num=1, clazz='Classic'), 54 | visibility=messaging.AndroidNotification.PUBLIC, 55 | foreground_show=True 56 | ) 57 | 58 | 59 | android = messaging.AndroidConfig( 60 | collapse_key=-1, 61 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 62 | ttl="10000s", 63 | bi_tag='the_sample_bi_tag_for_receipt_service', 64 | notification=android_notification, 65 | category=None 66 | ) 67 | 68 | 69 | def send_push_android_data_message(): 70 | """ 71 | a sample to show hwo to send web push message 72 | :return: 73 | """ 74 | message = messaging.Message( 75 | notification=notification, 76 | android=android, 77 | # TODO 78 | token=['Your Token'] 79 | ) 80 | 81 | try: 82 | # Case 1: Local CA sample code 83 | # response = messaging.send_message(message, validate_only=True, verify_peer="../Push-CA-Root.pem") 84 | # Case 2: No verification of HTTPS's certificate 85 | response = messaging.send_message(message, validate_only=True) 86 | # Case 3: use certifi Library 87 | # import certifi 88 | # response = messaging.send_message(message, validate_only=True, verify_peer=certifi.where()) 89 | print "response is ", json.dumps(vars(response)) 90 | assert (response.code == '80000000') 91 | except Exception as e: 92 | print repr(e) 93 | 94 | 95 | def init_app(): 96 | """init sdk app""" 97 | # TODO 98 | app_id = "Your android application's app id" 99 | app_secret = "Your android application's app secret" 100 | push_admin.initialize_app(app_id, app_secret) 101 | 102 | 103 | def main(): 104 | init_app() 105 | send_push_android_data_message() 106 | 107 | 108 | if __name__ == '__main__': 109 | main() 110 | -------------------------------------------------------------------------------- /python27/test/send_topic_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src.push_admin import initialize_app 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["Girl", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title', 45 | big_body='Big Boom Body', 46 | auto_clear=86400000, 47 | notify_id=486, 48 | group='Group1', 49 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 50 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 51 | alpha=0, red=0, green=1, blue=1) 52 | , light_on_duration="3.5", light_off_duration="5S"), 53 | badge=messaging.AndroidBadgeNotification( 54 | add_num=1, clazz='Classic'), 55 | visibility=messaging.AndroidNotification.PUBLIC, 56 | foreground_show=True 57 | ) 58 | 59 | 60 | android = messaging.AndroidConfig( 61 | collapse_key=-1, 62 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 63 | ttl="10000s", 64 | bi_tag='the_sample_bi_tag_for_receipt_service', 65 | notification=android_notification, 66 | category=None 67 | ) 68 | 69 | 70 | def send_push_android_data_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | topic='Your topic' 80 | ) 81 | 82 | try: 83 | # Case 1: Local CA sample code 84 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 85 | # Case 2: No verification of HTTPS's certificate 86 | response = messaging.send_message(message) 87 | # Case 3: use certifi Library 88 | # import certifi 89 | # response = messaging.send_message(message, verify_peer=certifi.where()) 90 | print "response is ", json.dumps(vars(response)) 91 | assert (response.code == '80000000') 92 | except Exception as e: 93 | print repr(e) 94 | 95 | 96 | def init_app(): 97 | """init sdk app""" 98 | # TODO 99 | app_id = "Your android application's app id" 100 | app_secret = "Your android application's app secret" 101 | initialize_app(app_id, app_secret) 102 | 103 | 104 | def main(): 105 | init_app() 106 | send_push_android_data_message() 107 | 108 | 109 | if __name__ == '__main__': 110 | main() 111 | -------------------------------------------------------------------------------- /python27/test/send_webpush_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | from src import push_admin 19 | from src.push_admin import messaging 20 | 21 | web_push_headers = messaging.WebPushHeader(ttl="100") 22 | 23 | web_push_notification = messaging.WebPushNotification( 24 | title="中文推送", 25 | body="中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容", 26 | icon="https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/\ 27 | resources/images/icon_Promotion.png", 28 | actions=[messaging.WebPushNotificationAction(action="click", title="title", icon="https://developer-portalres-drcn.\ 29 | dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png")], 30 | badge="badge", 31 | data="data", 32 | dir="auto", 33 | image="image url", 34 | lang="en", 35 | renotify=False, 36 | require_interaction=False, 37 | silent=True, 38 | tag="tag", 39 | timestamp=32323, 40 | vibrate=[1, 2, 3]) 41 | 42 | web_push_config = messaging.WebPushConfig(headers=web_push_headers, notification=web_push_notification) 43 | 44 | 45 | def send_push_android_data_message(): 46 | """ 47 | a sample to show hwo to send web push message 48 | :return: 49 | """ 50 | message = messaging.Message( 51 | web_push=web_push_config, 52 | # TODO 53 | token=['your token'] 54 | ) 55 | 56 | try: 57 | # Case 1: Local CA sample code 58 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 59 | # Case 2: No verification of HTTPS's certificate 60 | response = messaging.send_message(message) 61 | # Case 3: use certifi Library 62 | # import certifi 63 | # response = messaging.send_message(message, verify_peer=certifi.where()) 64 | print "response is ", json.dumps(vars(response)) 65 | assert (response.code == '80000000') 66 | except Exception as e: 67 | print repr(e) 68 | 69 | 70 | def init_app(): 71 | """init sdk app 72 | The appID & app Secret use the Android's application ID and Secret under the same project, next version you can use 73 | the web application's own appId & secret! 74 | """ 75 | # TODO 76 | app_id_at = "Your android application's app id" 77 | app_secret_at = "Your android application's app secret" 78 | app_id_push = "Your Web application' app id " 79 | push_admin.initialize_app(app_id_at, app_secret_at, app_id_push) 80 | 81 | 82 | def main(): 83 | init_app() 84 | send_push_android_data_message() 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /python37/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 22 | 23 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 24 | 25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 26 | 27 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 28 | 29 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 30 | 31 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 32 | 33 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 34 | 35 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | You must cause any modified files to carry prominent notices stating that You changed the files; and 39 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 40 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 41 | 42 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 43 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 44 | 45 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 46 | 47 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 48 | 49 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 50 | 51 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 52 | 53 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /python37/Push-CA-Root.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 5 | QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT 6 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 7 | b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 8 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB 9 | CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 10 | nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 11 | 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P 12 | T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 13 | gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO 14 | BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR 15 | TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw 16 | DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr 17 | hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 18 | 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF 19 | PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls 20 | YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk 21 | CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= 22 | -----END CERTIFICATE----- 23 | 24 | -----BEGIN CERTIFICATE----- 25 | MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G 26 | A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp 27 | Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 28 | MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG 29 | A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI 30 | hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 31 | RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT 32 | gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm 33 | KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd 34 | QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ 35 | XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw 36 | DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o 37 | LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU 38 | RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp 39 | jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 40 | 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX 41 | mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs 42 | Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH 43 | WD9f 44 | -----END CERTIFICATE----- 45 | 46 | -------------------------------------------------------------------------------- /python37/README.md: -------------------------------------------------------------------------------- 1 | ## HMS PushKit Python Severdemo 2 | English | [中文](README_ZH.md) 3 | 4 | ## Table of Contents 5 | 6 | * [Introduction](#introduction) 7 | * [Installation](#installation) 8 | * [Configuration ](#configuration ) 9 | * [Supported Environments](#supported-environments) 10 | * [Sample Code](#sample-code) 11 | * [Libraries](#Libraries) 12 | * [License](#license) 13 | 14 | 15 | ## Introduction 16 | 17 | Python sample code encapsulates APIs of the HUAWEI Push Kit server. It provides many sample programs about quick access to HUAWEI Push Kit for your reference or usage. 18 | 19 | The following table describes packages of Python sample code. 20 | 21 | | Package | Description | 22 | | ---------- | ------------| 23 | | [test](test) | Sample code packages. Each package can run independently.| 24 | | [src/push_admin](src/push_admin) | Package where APIs of the HUAWEI Push Kit server are encapsulated.| 25 | 26 | ## Installation 27 | 28 | To install pushkit-python-sample, you should extract the compressed ZIP file, execute the following command in the unzipped directory: 29 | ``` 30 | python setup.py install 31 | ``` 32 | 33 | ## Supported Environments 34 | For pushkit-python-sample, We currently support Python 3.7 and JetBrains PyCharm are recommended. 35 | 36 | 37 | ## Configuration 38 | The following table describes parameters of the initialize_app method. 39 | 40 | | Parameter | Description | 41 | | ------------- | ------------------------------------------------------------------------- | 42 | | app_id | App ID, which is obtained from app information. | 43 | | app_secret | Secret access key of an app, which is obtained from app information. | 44 | | app_package_name | Appplication package name. | 45 | | token_server | URL for the Huawei OAuth 2.0 service to obtain a token, please refer to [Generating an App-Level Access Token](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/oauth2-0000001212610981). | 46 | | push_open_url | URL for accessing HUAWEI Push Kit, please refer to [Sending Messages](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/android-server-dev-0000001050040110?ha_source=hms1).|| 47 | 48 | 49 | ## Sample Code 50 | 51 | Python sample code uses the Messaging structure in the push_admin package as the entry. Each method in the Messaging 52 | structure calls an API of the HUAWEI Push Kit server. 53 | 54 | The following table describes methods in the Messaging structure. 55 | 56 | | Method | Description 57 | | ----------------- | --------------------------------------------------- | 58 | | send_message | Sends a message to a device. | 59 | | subscribe_topic | Subscribes to a topic. | 60 | | unsubscribe_topic | Unsubscribes from a topic. | 61 | | list_topics | Queries the list of topics subscribed by a device. | 62 | 63 | 1) Send an Android data message. 64 | Code location: [test/send_data_message.py](test/send_data_message.py) 65 | 66 | 2) Send an Android notification message. 67 | Code location: [test/send_notify_message.py](test/send_notify_message.py) 68 | 69 | 3) Send a message by topic. 70 | Code location: [test/send_topic_message.py](test/send_topic_message.py) 71 | 72 | 4) Send a message by conditions. 73 | Code location: [test/send_condition_message.py](test/send_condition_message.py) 74 | 75 | 5) Send a message to a Huawei quick app. 76 | Code location: [test/send_instance_app_message.py](test/send_instance_app_message.py) 77 | 78 | 6) Send a message through the WebPush agent. 79 | Code location: [test/send_webpush_message.py](test/send_webpush_message.py) 80 | 81 | 7) Send a message through the APNs agent. 82 | Code location: [test/send_apns_message.py](test/send_apns_message.py) 83 | 84 | 8) Send a test message. 85 | Code location: [test/send_test_message.py](test/send_test_message.py) 86 | 87 | ## Libraries 88 | | Library | Site 89 | | ----------------- | --------------------------------------------------- | 90 | | requests | https://requests.readthedocs.io/en/master/ | 91 | | six | https://six.readthedocs.io/ | 92 | ## License 93 | 94 | pushkit Python sample is licensed under the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 95 | -------------------------------------------------------------------------------- /python37/README_ZH.md: -------------------------------------------------------------------------------- 1 | ## 华为推送服务服务端Python示例代码 2 | [English](https://github.com/HMS-Core/hms-push-serverdemo-python/tree/master/python37) | 中文 3 | ## 目录 4 | * [简介](#简介) 5 | * [安装](#安装) 6 | * [环境要求](#环境要求) 7 | * [配置](#配置) 8 | * [示例代码](#示例代码) 9 | * [知识库](#知识库) 10 | * [授权许可](#授权许可) 11 | 12 | ## 简介 13 | 14 | Python示例代码对华为推送服务(HUAWEI Push Kit)服务端接口进行封装,包含丰富的示例程序,方便您参考或直接使用。 15 | 16 | 示例代码主要包括以下组件: 17 | 18 | | 包名 | 说明 | 19 | | ---------- | ------------| 20 | | [test](test) | 示例代码包,每个包都可以独立运行 | 21 | | [src/push_admin](src/push_admin) | 推送服务的服务端接口封装包 | 22 | 23 | ## 安装 24 | 25 | 安装本示例代码前,请解压zip文件包,并在解压后的文件目录中执行以下命令: 26 | ``` 27 | python setup.py install 28 | ``` 29 | 30 | ## 环境要求 31 | Python 2.7/3.7 32 | JetBrains PyCharm(推荐使用) 33 | 34 | 35 | ## 配置 36 | initialize_app方法包括如下参数: 37 | 38 | | 参数 | 说明 | 39 | | ------------- | ------------------------------------------------------------------------- | 40 | | app_id | 应用ID,从应用消息中获取。 | 41 | | app_secret | 应用访问密钥,从应用信息中获取。 | 42 | | app_package_name | 应用包名。 | 43 | | token_server | 华为OAuth 2.0获取token的地址。具体请参考[基于OAuth 2.0开放鉴权-客户端模式](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/oauth2-0000001212610981)。| 44 | | push_open_url | 推送服务的访问地址。具体请参考[推送服务-下行消息](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-server-dev-0000001050040110?ha_source=hms1)。| 45 | 46 | 47 | ## 示例代码 48 | 49 | 本示例代码以push_admin包中的Messaging结构体为入口。Messaging结构体中的方法完成了对推送服务服务端接口的调用。 50 | 51 | Messaging包括如下方法: 52 | 53 | | 方法 | 说明 54 | | ----------------- | --------------------------------------------------- | 55 | | send_message | 向设备发送消息 | 56 | | subscribe_topic | 订阅主题 | 57 | | unsubscribe_topic | 退订主题 | 58 | | list_topics | 查询设备订阅的主题列表 | 59 | 60 | 61 | 1) 发送Android透传消息 62 | 代码位置: [test/send_data_message.py](test/send_data_message.py) 63 | 64 | 2) 发送Android通知栏消息 65 | 代码位置: [test/send_notify_message.py](test/send_notify_message.py) 66 | 67 | 3) 基于主题发送消息 68 | 代码位置: [test/send_topic_message.py](test/send_topic_message.py) 69 | 70 | 4) 基于条件发送消息 71 | 代码位置: [test/send_condition_message.py](test/send_condition_message.py) 72 | 73 | 5) 向华为快应用发送消息 74 | 代码位置: [test/send_instance_app_message.py](test/send_instance_app_message.py) 75 | 76 | 6) 基于WebPush代理发送消息 77 | 代码位置: [test/send_webpush_message.py](test/send_webpush_message.py) 78 | 79 | 7) 基于APNs代理发送消息 80 | 代码位置: [test/send_apns_message.py](test/send_apns_message.py) 81 | 82 | 8) 发送测试消息 83 | 代码位置: [test/send_test_message.py](test/send_test_message.py) 84 | 85 | ## 知识库 86 | | 知识库 | 地址 87 | | ----------------- | --------------------------------------------------- | 88 | | requests | https://requests.readthedocs.io/en/master/ | 89 | | six | https://six.readthedocs.io/ | 90 | 91 | ## 授权许可 92 | 华为推送服务Python示例代码经过[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0)授权许可。 93 | -------------------------------------------------------------------------------- /python37/requirements.txt: -------------------------------------------------------------------------------- 1 | requests >= 2.20.1 2 | six >= 1.14.0 -------------------------------------------------------------------------------- /python37/setup.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # refer. https://wiki.python.org/moin/Distutils/Tutorial?highlight=%28setup.py%29 18 | # 19 | from setuptools import setup 20 | 21 | __version__ = '1.0.0' 22 | __title__ = 'hcm_admin' 23 | __author__ = 'Huawei' 24 | __license__ = 'Apache License 2.0' 25 | __url__ = 'https://developer.huawei.com/consumer/cn/' 26 | 27 | install_requires = ['requests>=2.20.1'] 28 | 29 | long_description = ('The Huawei Admin Python SDK enables server-side (backend) Python developers ' 30 | 'to integrate Huawei into their services and applications.') 31 | 32 | setup( 33 | name='huawei_push_admin', 34 | version='1.0.0', 35 | description='Huawei Admin Python SDK', 36 | long_description=long_description, 37 | url='https://developer.huawei.com/consumer/cn/', 38 | author='Huawei', 39 | license='Apache License 2.0', 40 | keywords='huawei cloud development', 41 | install_requires=install_requires, 42 | packages=['src/push_admin'], 43 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', 44 | classifiers=[ 45 | 'Development Status :: 5 - Production/Stable', 46 | 'Intended Audience :: Developers', 47 | 'Topic :: Software Development :: Build Tools', 48 | 'Programming Language :: Python :: 2', 49 | 'Programming Language :: Python :: 2.7', 50 | 'Programming Language :: Python :: 3', 51 | 'Programming Language :: Python :: 3.4', 52 | 'Programming Language :: Python :: 3.5', 53 | 'Programming Language :: Python :: 3.6', 54 | 'Programming Language :: Python :: 3.7', 55 | 'License :: OSI Approved :: Apache Software License', 56 | ], 57 | ) 58 | -------------------------------------------------------------------------------- /python37/src/push_admin/__init__.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Huawei Admin SDK for Python.""" 18 | 19 | import threading 20 | from src.push_admin import _app 21 | 22 | _apps = {} 23 | _apps_lock = threading.RLock() 24 | _DEFAULT_APP_NAME = 'DEFAULT' 25 | 26 | 27 | def initialize_app(appid_at, appsecret_at, appid_push=None, token_server='https://oauth-login.cloud.huawei.com/oauth2/v3/token', 28 | push_open_url='https://push-api.cloud.huawei.com'): 29 | """ 30 | Initializes and returns a new App instance. 31 | :param appid_at: appid parameters obtained by developer alliance applying for Push service 32 | :param appsecret_at: appsecret parameters obtained by developer alliance applying for Push service 33 | :param appid_push: the application Id in the URL 34 | :param token_server: Oauth server URL 35 | :param push_open_url: push open API URL 36 | """ 37 | app = _app.App(appid_at, appsecret_at, appid_push, token_server=token_server, push_open_url=push_open_url) 38 | 39 | with _apps_lock: 40 | if appid_at not in _apps: 41 | _apps[appid_at] = app 42 | 43 | """set default app instance""" 44 | if _apps.get(_DEFAULT_APP_NAME) is None: 45 | _apps[_DEFAULT_APP_NAME] = app 46 | 47 | 48 | def get_app(appid=None): 49 | """ 50 | get app instance 51 | :param appid: appid parameters obtained by developer alliance applying for Push service 52 | :return: app instance 53 | Raise: ValueError 54 | """ 55 | if appid is None: 56 | with _apps_lock: 57 | app = _apps.get(_DEFAULT_APP_NAME) 58 | if app is None: 59 | raise ValueError('The default Huawei app is not exists. ' 60 | 'This means you need to call initialize_app() it.') 61 | return app 62 | 63 | with _apps_lock: 64 | if appid not in _apps: 65 | raise ValueError('Huawei app id[{0}] is not exists. ' 66 | 'This means you need to call initialize_app() it.'.format(appid)) 67 | 68 | app = _apps.get(appid) 69 | if app is None: 70 | raise ValueError('The app id[{0}] is None.'.format(appid)) 71 | return app 72 | -------------------------------------------------------------------------------- /python37/src/push_admin/_app.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | import time 19 | import urllib 20 | import urllib.parse 21 | 22 | from src.push_admin import _http 23 | from src.push_admin import _message_serializer 24 | 25 | 26 | class App(object): 27 | """application for HW Cloud Message(HCM)""" 28 | 29 | JSON_ENCODER = _message_serializer.MessageSerializer() 30 | 31 | @classmethod 32 | def _send_to_server(cls, headers, body, url, verify_peer=False): 33 | try: 34 | msg_body = json.dumps(body) 35 | response = _http.post(url, msg_body, headers, verify_peer) 36 | 37 | if response.status_code is not 200: 38 | raise ApiCallError('http status code is {0} in send.'.format(response.status_code)) 39 | 40 | # json text to dict 41 | resp_dict = json.loads(response.text) 42 | return resp_dict 43 | 44 | except Exception as e: 45 | raise ApiCallError('caught exception when send. {0}'.format(e)) 46 | 47 | def __init__(self, appid_at, app_secret_at, appid_push, token_server='https://oauth-login.cloud.huawei.com/oauth2/v3/token', 48 | push_open_url='https://push-api.cloud.huawei.com'): 49 | """class init""" 50 | self.app_id_at = appid_at 51 | self.app_secret_at = app_secret_at 52 | if appid_push is None: 53 | self.appid_push = appid_at 54 | else: 55 | self.appid_push = appid_push 56 | self.token_expired_time = 0 57 | self.access_token = None 58 | self.token_server = token_server 59 | self.push_open_url = push_open_url 60 | self.hw_push_server = self.push_open_url + "/v1/{0}/messages:send" 61 | self.hw_push_topic_sub_server = self.push_open_url + "/v1/{0}/topic:subscribe" 62 | self.hw_push_topic_unsub_server = self.push_open_url + "/v1/{0}/topic:unsubscribe" 63 | self.hw_push_topic_query_server = self.push_open_url + "/v1/{0}/topic:list" 64 | 65 | def _refresh_token(self, verify_peer=False): 66 | """refresh access token 67 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 68 | the server's TLS certificate, or a string, in which case it must be a path 69 | to a CA bundle to use. Defaults to ``True``. 70 | """ 71 | headers = dict() 72 | headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' 73 | 74 | params = dict() 75 | params['grant_type'] = 'client_credentials' 76 | params['client_secret'] = self.app_secret_at 77 | params['client_id'] = self.app_id_at 78 | 79 | msg_body = urllib.parse.urlencode(params) 80 | 81 | try: 82 | response = _http.post(self.token_server, msg_body, headers, verify_peer=verify_peer) 83 | 84 | if response.status_code is not 200: 85 | return False, 'http status code is {0} in get access token'.format(response.status_code) 86 | 87 | """ json string to directory """ 88 | response_body = json.loads(response.text) 89 | 90 | self.access_token = response_body.get('access_token') 91 | self.token_expired_time = int(round(time.time() * 1000)) + (int(response_body.get('expires_in')) - 5 * 60) * 1000 92 | 93 | return True, None 94 | except Exception as e: 95 | raise ApiCallError(format(repr(e))) 96 | 97 | def _is_token_expired(self): 98 | """is access token expired""" 99 | if self.access_token is None: 100 | """ need refresh token """ 101 | return True 102 | return int(round(time.time() * 1000)) >= self.token_expired_time 103 | 104 | def _update_token(self, verify_peer=False): 105 | """ 106 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 107 | the server's TLS certificate, or a string, in which case it must be a path 108 | to a CA bundle to use. Defaults to ``True``. 109 | :return: 110 | """ 111 | if self._is_token_expired() is True: 112 | result, reason = self._refresh_token(verify_peer) 113 | if result is False: 114 | raise ApiCallError(reason) 115 | 116 | def _create_header(self): 117 | headers = dict() 118 | headers['Content-Type'] = 'application/json;charset=utf-8' 119 | headers['Authorization'] = 'Bearer {0}'.format(self.access_token) 120 | return headers 121 | 122 | def send(self, message, validate_only, **kwargs): 123 | """ 124 | Sends the given message Huawei Cloud Messaging (HCM) 125 | :param message: JSON format message 126 | :param validate_only: validate message format or not 127 | :param kwargs: 128 | verify_peer: HTTPS server identity verification, use library 'certifi' 129 | :return: 130 | response dict: response body dict 131 | :raise: 132 | ApiCallError: failure reason 133 | """ 134 | verify_peer = kwargs['verify_peer'] 135 | self._update_token(verify_peer) 136 | headers = self._create_header() 137 | url = self.hw_push_server.format(self.appid_push) 138 | msg_body_dict = dict() 139 | msg_body_dict['validate_only'] = validate_only 140 | msg_body_dict['message'] = App.JSON_ENCODER.default(message) 141 | 142 | return App._send_to_server(headers, msg_body_dict, url, verify_peer) 143 | 144 | def subscribe_topic(self, topic, token_list): 145 | """ 146 | :param topic: The specific topic 147 | :param token_list: The token list to be added 148 | :return: 149 | """ 150 | self._update_token() 151 | headers = self._create_header() 152 | url = self.hw_push_topic_sub_server.format(self.appid_push) 153 | msg_body_dict = {'topic': topic, 'tokenArray': token_list} 154 | return App._send_to_server(headers, msg_body_dict, url) 155 | 156 | def unsubscribe_topic(self, topic, token_list): 157 | """ 158 | 159 | :param topic: The specific topic 160 | :param token_list: The token list to be deleted 161 | :return: 162 | """ 163 | self._update_token() 164 | headers = self._create_header() 165 | url = self.hw_push_topic_unsub_server.format(self.appid_push) 166 | msg_body_dict = {'topic': topic, 'tokenArray': token_list} 167 | return App._send_to_server(headers, msg_body_dict, url) 168 | 169 | def query_subscribe_list(self, token): 170 | """ 171 | :param token: The specific token 172 | :return: 173 | """ 174 | self._update_token() 175 | headers = self._create_header() 176 | url = self.hw_push_topic_query_server.format(self.appid_push) 177 | msg_body_dict = {'token': token} 178 | return App._send_to_server(headers, msg_body_dict, url) 179 | 180 | 181 | class ApiCallError(Exception): 182 | """Represents an Exception encountered while invoking the HCM API. 183 | 184 | Attributes: 185 | message: A error message string. 186 | detail: Original low-level exception. 187 | """ 188 | def __init__(self, message, detail=None): 189 | Exception.__init__(self, message) 190 | self.detail = detail 191 | -------------------------------------------------------------------------------- /python37/src/push_admin/_http.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import requests 18 | 19 | 20 | def post(url, req_body, headers=None, verify_peer=False): 21 | """ post http request to slb service 22 | :param url: url path 23 | :param req_body: http request body 24 | :param headers: http headers 25 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 26 | the server's TLS certificate, or a string, in which case it must be a path 27 | to a CA bundle to use. Defaults to ``True``. 28 | :return: 29 | success return response 30 | fali return None 31 | """ 32 | try: 33 | response = requests.post(url, data=req_body, headers=headers, timeout=10, verify=verify_peer) 34 | return response 35 | 36 | except Exception as e: 37 | raise ValueError('caught exception when post {0}. {1}'.format(url, e)) 38 | 39 | 40 | def _format_http_text(method, url, headers, body): 41 | """ 42 | print http head and body for request or response 43 | 44 | For examples: _format_http_text('', title, response.headers, response.text) 45 | """ 46 | result = method + ' ' + url + '\n' 47 | 48 | if headers is not None: 49 | for key, value in headers.items(): 50 | result = result + key + ': ' + value + '\n' 51 | 52 | result = result + body 53 | return result 54 | 55 | 56 | -------------------------------------------------------------------------------- /python37/src/push_admin/_message_serializer.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | from src.push_admin import _messages 19 | import six 20 | 21 | 22 | class MessageSerializer(json.JSONEncoder): 23 | """ 24 | Use https://docs.python.org/3/library/json.html to do serialization 25 | 26 | The serializer should serialize the following messages: 27 | _messages.Message 28 | _messages.Notification 29 | _messages.ApnsConfig 30 | _messages.WebPushConfig 31 | _messages.WebPushNotification 32 | _messages.WebPushNotificationAction 33 | _messages.WebPushHMSOptions 34 | _messages.AndroidConfig 35 | _messages.AndroidNotification 36 | _messages.AndroidClickAction 37 | _messages.BadgeNotification 38 | """ 39 | def default(self, message): 40 | """ 41 | :param message: The push message 42 | :return: formatted push messages 43 | """ 44 | result = { 45 | 'data': message.data, 46 | 'notification': MessageSerializer.encode_notification(message.notification), 47 | 'android': MessageSerializer.encode_android_config(message.android), 48 | 'apns': MessageSerializer.encode_apns_config(message.apns), 49 | 'webpush': MessageSerializer.encode_webpush_config(message.web_push), 50 | 'token': message.token, 51 | 'topic': message.topic, 52 | 'condition': message.condition 53 | } 54 | result = MessageSerializer.remove_null_values(result) 55 | return result 56 | 57 | @classmethod 58 | def remove_null_values(cls, dict_value): 59 | return {k: v for k, v in dict_value.items() if v not in [None, [], {}]} 60 | 61 | @classmethod 62 | def encode_notification(cls, notification): 63 | """ 64 | An example: 65 | { 66 | "title":"Big News", 67 | "body":"This is a Big News!", 68 | "image":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2_0.png" 69 | } 70 | :param notification: 71 | :return: 72 | """ 73 | if notification is None: 74 | return None 75 | 76 | if not isinstance(notification, _messages.Notification): 77 | raise ValueError('Message.notification must be an instance of Notification class.') 78 | 79 | result = { 80 | 'title': notification.title, 81 | 'body': notification.body, 82 | 'image': notification.image 83 | } 84 | return cls.remove_null_values(result) 85 | 86 | @classmethod 87 | def encode_android_config(cls, android_config): 88 | """ 89 | An example: 90 | { 91 | "android":{ 92 | "collapse_key":-1, 93 | "urgency":"HIGH", 94 | "ttl":"1448s", 95 | "bi_tag":"Trump", 96 | "fast_app_target":1, 97 | "notification": {} 98 | } 99 | :param android_config: 100 | :return: 101 | """ 102 | if android_config is None: 103 | return None 104 | 105 | if not isinstance(android_config, _messages.AndroidConfig): 106 | raise ValueError('Message.android must be an instance of AndroidConfig class.') 107 | 108 | result = { 109 | 'collapse_key': android_config.collapse_key, 110 | 'urgency': android_config.urgency, 111 | 'ttl': android_config.ttl, 112 | 'bi_tag': android_config.bi_tag, 113 | 'fast_app_target': android_config.fast_app_target, 114 | 'data': android_config.data, 115 | 'notification': MessageSerializer.encode_android_notification(android_config.notification) 116 | } 117 | return cls.remove_null_values(result) 118 | 119 | @classmethod 120 | def encode_android_notification(cls, notification): 121 | """ 122 | "notification":{ 123 | "title":"Noti in Noti title", 124 | "body":"Noti in Noti body", 125 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 126 | "color":"#AACCDD", 127 | "default_sound":true, 128 | "tag":"tagBoom", 129 | "importance":"PRIORITY_HIGH", 130 | "click_action":{ 131 | "type":2, 132 | "url":"https://www.huawei.com" 133 | }, 134 | "body_loc_key":"M.String.body", 135 | "body_loc_args":[ 136 | "Boy", 137 | "Dog" 138 | ], 139 | "title_loc_key":"M.String.title", 140 | "title_loc_args":[ 141 | "Girl", 142 | "Cat" 143 | ], 144 | "channel_id":"RingRing", 145 | "notify_summary":"Some Summary", 146 | "style":2, 147 | "big_title":"Big Boom Title", 148 | "big_body":"Big Boom Body", 149 | "notify_id":486, 150 | "group":"Espace", 151 | "badge":{ 152 | "add_num":99, 153 | "set_num":99, 154 | "class":"Classic" 155 | }, 156 | "ticker":"i am a ticker", 157 | "auto_cancel":false, 158 | "when":"2019-11-05", 159 | "use_default_vibrate":true, 160 | "use_default_light":false, 161 | "visibility":"PUBLIC", 162 | "vibrate_config":["1.5","2","3"], 163 | "light_settings":{ 164 | "color":{ 165 | "alpha":0, 166 | "red":0, 167 | "green":1, 168 | "blue":1 169 | }, 170 | "light_on_duration":"3.5", 171 | "light_off_duration":"5S" 172 | }, 173 | "foreground_show":true 174 | } 175 | :param notification: 176 | :return: 177 | """ 178 | if notification is None: 179 | return None 180 | 181 | if not isinstance(notification, _messages.AndroidNotification): 182 | raise ValueError('Message.AndroidConfig.notification must be an instance of AndroidNotification class.') 183 | 184 | result = { 185 | "title": notification.title, 186 | "body": notification.body, 187 | "icon": notification.icon, 188 | "color": notification.color, 189 | "sound": notification.sound, 190 | "default_sound": notification.default_sound, 191 | "tag": notification.tag, 192 | "importance": notification.importance, 193 | "multi_lang_key": notification.multi_lang_key, 194 | "click_action": MessageSerializer.encode_android_click_action(notification.click_action), 195 | "body_loc_key": notification.body_loc_key, 196 | "body_loc_args": notification.body_loc_args, 197 | "title_loc_key": notification.title_loc_key, 198 | "title_loc_args": notification.title_loc_args, 199 | "channel_id": notification.channel_id, 200 | "notify_summary": notification.notify_summary, 201 | "image": notification.image, 202 | "style": notification.style, 203 | "big_title": notification.big_title, 204 | "big_body": notification.big_body, 205 | "notify_id": notification.notify_id, 206 | "group": notification.group, 207 | "badge": MessageSerializer.encode_android_badge(notification.badge), 208 | "ticker": notification.ticker, 209 | "auto_cancel": notification.auto_cancel, 210 | "when": notification.when, 211 | "use_default_vibrate": notification.use_default_vibrate, 212 | "use_default_light": notification.use_default_light, 213 | "visibility": notification.visibility, 214 | "vibrate_config": notification.vibrate_config, 215 | "light_settings": MessageSerializer.encode_android_light_settings(notification.light_settings), 216 | "foreground_show": notification.foreground_show 217 | } 218 | result = cls.remove_null_values(result) 219 | return result 220 | 221 | @classmethod 222 | def encode_android_click_action(cls, click_action): 223 | """ 224 | "click_action":{ 225 | "type":2, 226 | "url":"https://www.huawei.com" 227 | } 228 | 229 | "click_action":{ 230 | "type":1, 231 | "intent":"https://www.huawei.com", 232 | "action":"" 233 | } 234 | 235 | :param click_action: _messages.AndroidClickAction 236 | :return: 237 | """ 238 | if click_action is None: 239 | return None 240 | 241 | if not isinstance(click_action, _messages.AndroidClickAction): 242 | raise ValueError('Message.AndroidConfig.AndroidNotification.click_action must be an instance\ 243 | of AndroidClickAction class.') 244 | 245 | result = { 246 | "type": click_action.action_type, 247 | "intent": click_action.intent, 248 | "url": click_action.url, 249 | "action": click_action.action 250 | } 251 | result = cls.remove_null_values(result) 252 | return result 253 | 254 | @classmethod 255 | def encode_android_badge(cls, badge): 256 | """ 257 | refer to: _messages.AndroidBadgeNotification 258 | 259 | "badge":{ 260 | "add_num":99, 261 | "set_num":99, 262 | "class":"Classic" 263 | } 264 | 265 | :param badge: 266 | :return: 267 | """ 268 | if badge is None: 269 | return None 270 | 271 | if not isinstance(badge, _messages.AndroidBadgeNotification): 272 | raise ValueError('Message.AndroidConfig.AndroidNotification.badge must be an instance\ 273 | of AndroidBadgeNotification class.') 274 | 275 | result = { 276 | "add_num": badge.add_num, 277 | "set_num": badge.set_num, 278 | "class": badge.clazz 279 | } 280 | result = cls.remove_null_values(result) 281 | return result 282 | 283 | @classmethod 284 | def encode_android_light_settings(cls, android_light_settings): 285 | """ 286 | refer to: _messages.AndroidLightSettings 287 | 288 | "light_settings":{ 289 | "color":{ 290 | "alpha":0, 291 | "red":0, 292 | "green":1, 293 | "blue":1 294 | }, 295 | "light_on_duration":"3.5", 296 | "light_off_duration":"5S" 297 | } 298 | 299 | :param android_light_settings: _messages.AndroidLightSettings 300 | :return: 301 | """ 302 | if android_light_settings is None: 303 | return None 304 | 305 | if not isinstance(android_light_settings, _messages.AndroidLightSettings): 306 | raise ValueError('Message.AndroidConfig.AndroidNotification.android_light_settings must be an instance\ 307 | of AndroidLightSettings class.') 308 | 309 | result = { 310 | "color": MessageSerializer.encode_android_light_settings_color(android_light_settings.color), 311 | "light_on_duration": android_light_settings.light_on_duration, 312 | "light_off_duration": android_light_settings.light_off_duration 313 | } 314 | result = cls.remove_null_values(result) 315 | return result 316 | 317 | @classmethod 318 | def encode_android_light_settings_color(cls, color): 319 | """ 320 | "color":{ 321 | "alpha":0, 322 | "red":0, 323 | "green":1, 324 | "blue":1 325 | } 326 | 327 | :param color: _messages.AndroidLightSettingsColor 328 | :return: 329 | """ 330 | if color is None: 331 | return None 332 | 333 | if not isinstance(color, _messages.AndroidLightSettingsColor): 334 | raise ValueError('Message.AndroidConfig.AndroidNotification.android_light_settings.color must be an instance\ 335 | of AndroidLightSettingsColor class.') 336 | result = { 337 | "alpha": color.alpha, 338 | "red": color.red, 339 | "green": color.green, 340 | "blue": color.blue 341 | } 342 | result = cls.remove_null_values(result) 343 | return result 344 | 345 | @classmethod 346 | def encode_webpush_config(cls, webpush_config): 347 | """ 348 | "webpush":{ 349 | "headers":{ 350 | ... 351 | }, 352 | "notification":{ 353 | ... 354 | }, 355 | "hms_options":{ 356 | ... 357 | } 358 | } 359 | :param webpush_config: refer to _messages.WebPushConfig 360 | :return: 361 | """ 362 | if webpush_config is None: 363 | return None 364 | 365 | if not isinstance(webpush_config, _messages.WebPushConfig): 366 | raise ValueError('Message.webpush must be an instance of WebPushConfig class.') 367 | 368 | result = { 369 | "headers": MessageSerializer.encode_webpush_config_headers(webpush_config.headers), 370 | "notification": MessageSerializer.encode_webpush_config_notification(webpush_config.notification), 371 | "hms_options": MessageSerializer.encode_webpush_config_hms_options(webpush_config.hms_options), 372 | } 373 | result = cls.remove_null_values(result) 374 | return result 375 | 376 | @classmethod 377 | def encode_webpush_config_headers(cls, webpush_headers): 378 | """ 379 | "headers":{ 380 | "ttl":"990", 381 | "urgency":"very-low", 382 | "topic":"12313ceshi" 383 | } 384 | 385 | :param webpush_headers: _messages.WebPushHeader 386 | :return: 387 | """ 388 | if webpush_headers is None: 389 | return None 390 | 391 | if not isinstance(webpush_headers, _messages.WebPushHeader): 392 | raise ValueError('Message.webpush.headers must be an instance of WebPushHeader class.') 393 | 394 | result = { 395 | "ttl": webpush_headers.ttl, 396 | "urgency": webpush_headers.urgency, 397 | "topic": webpush_headers.topic, 398 | } 399 | result = cls.remove_null_values(result) 400 | return result 401 | 402 | @classmethod 403 | def encode_webpush_config_notification(cls, webpush_notification): 404 | """ 405 | "notification":{ 406 | "title":"notication string", 407 | "body":"web push body", 408 | "actions":[ 409 | { 410 | "action":"", 411 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 412 | "title":"string" 413 | } 414 | ], 415 | "badge":"string", 416 | "dir":"auto", 417 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 418 | "image":"string", 419 | "lang":"string", 420 | "renotify":true, 421 | "requireInteraction":true, 422 | "silent":true, 423 | "tag":"string", 424 | "timestamp":1545201266, 425 | "vibrate":[1,2,3] 426 | } 427 | 428 | :param webpush_notification: refer to _messages.WebPushNotification 429 | :return: 430 | """ 431 | if webpush_notification is None: 432 | return None 433 | 434 | if not isinstance(webpush_notification, _messages.WebPushNotification): 435 | raise ValueError('Message.webpush.notification must be an instance of WebPushNotification class.') 436 | 437 | result = { 438 | "title": webpush_notification.title, 439 | "body": webpush_notification.body, 440 | "actions": [MessageSerializer.encode_webpush_notification_action(_) 441 | for _ in webpush_notification.actions], 442 | "badge": webpush_notification.badge, 443 | "dir": webpush_notification.dir, 444 | "icon": webpush_notification.icon, 445 | "image": webpush_notification.image, 446 | "lang": webpush_notification.lang, 447 | "renotify": webpush_notification.renotify, 448 | "require_interaction": webpush_notification.require_interaction, 449 | "silent": webpush_notification.silent, 450 | "tag": webpush_notification.tag, 451 | "timestamp": webpush_notification.timestamp, 452 | "vibrate": webpush_notification.vibrate 453 | } 454 | result = cls.remove_null_values(result) 455 | return result 456 | 457 | @classmethod 458 | def encode_webpush_notification_action(cls, webpush_notification_action): 459 | """ 460 | "actions":[ 461 | { 462 | "action":"", 463 | "icon":"https://res.vmallres.com/pimages//common/config/logo/SXppnESYv4K11DBxDFc2.png", 464 | "title":"string" 465 | } 466 | ], 467 | :param webpush_notification_action: refer to _messages.WebPushNotificationAction 468 | :return: 469 | """ 470 | if webpush_notification_action is None: 471 | return None 472 | 473 | if not isinstance(webpush_notification_action, _messages.WebPushNotificationAction): 474 | raise ValueError('Message.webpush.notification.action must be an instance of \ 475 | WebPushNotificationAction class.') 476 | 477 | result = { 478 | "action": webpush_notification_action.action, 479 | "icon": webpush_notification_action.icon, 480 | "title": webpush_notification_action.title 481 | } 482 | result = cls.remove_null_values(result) 483 | return result 484 | 485 | @classmethod 486 | def encode_webpush_config_hms_options(cls, webpush_hms_options): 487 | """ 488 | "hms_options":{ 489 | "link":"https://www.huawei.com/" 490 | } 491 | 492 | :param webpush_hms_options: refer to _messages.WebPushHMSOptions 493 | :return: 494 | """ 495 | if webpush_hms_options is None: 496 | return None 497 | 498 | if not isinstance(webpush_hms_options, _messages.WebPushHMSOptions): 499 | raise ValueError('Message.webpush.hmsoptions must be an instance of \ 500 | WebPushHMSOptions class.') 501 | 502 | result = { 503 | "link": webpush_hms_options.link 504 | } 505 | result = cls.remove_null_values(result) 506 | return result 507 | 508 | @classmethod 509 | def encode_apns_config(cls, apns_config): 510 | """ 511 | Encode APNs config into JSON 512 | :param apns_config: 513 | :return: 514 | """ 515 | if apns_config is None: 516 | return None 517 | if not isinstance(apns_config, _messages.APNsConfig): 518 | raise ValueError('Message.apns_config must be an instance of _messages.APNsConfig class.') 519 | 520 | result = { 521 | 'headers': apns_config.headers, 522 | 'payload': cls.encode_apns_payload(apns_config.payload), 523 | 'hms_options': cls.encode_apns_hms_options(apns_config.apns_hms_options) 524 | } 525 | return cls.remove_null_values(result) 526 | 527 | @classmethod 528 | def encode_apns_payload(cls, apns_payload): 529 | """Encodes an ``APNSPayload`` instance into JSON.""" 530 | if apns_payload is None: 531 | return None 532 | if not isinstance(apns_payload, _messages.APNsPayload): 533 | raise ValueError('APNSConfig.payload must be an instance of _messages.APNsPayload class.') 534 | result = { 535 | 'aps': cls.encode_apns_payload_aps(apns_payload.aps) 536 | } 537 | for key, value in apns_payload.custom_data.items(): 538 | result[key] = value 539 | return cls.remove_null_values(result) 540 | 541 | @classmethod 542 | def encode_apns_payload_aps(cls, apns_payload_aps): 543 | """Encodes an ``Aps`` instance into JSON.""" 544 | if not isinstance(apns_payload_aps, _messages.APNsAps): 545 | raise ValueError('APNSPayload.aps must be an instance of _messages.APNsAps class.') 546 | 547 | result = { 548 | 'alert': cls.encode_apns_payload_alert(apns_payload_aps.alert), 549 | 'badge': apns_payload_aps.badge, 550 | 'sound': apns_payload_aps.sound, 551 | 'category': apns_payload_aps.category, 552 | 'thread-id': apns_payload_aps.thread_id 553 | } 554 | 555 | if apns_payload_aps.content_available is True: 556 | result['content-available'] = 1 557 | if apns_payload_aps.mutable_content is True: 558 | result['mutable-content'] = 1 559 | if apns_payload_aps.custom_data is not None: 560 | if not isinstance(apns_payload_aps.custom_data, dict): 561 | raise ValueError('Aps.custom_data must be a dict.') 562 | for key, val in apns_payload_aps.custom_data.items(): 563 | if key in result: 564 | raise ValueError('Multiple specifications for {0} in Aps.'.format(key)) 565 | result[key] = val 566 | return cls.remove_null_values(result) 567 | 568 | @classmethod 569 | def encode_apns_payload_alert(cls, apns_payload_alert): 570 | """Encodes an ``ApsAlert`` instance into JSON.""" 571 | if apns_payload_alert is None: 572 | return None 573 | if isinstance(apns_payload_alert, six.string_types): 574 | return apns_payload_alert 575 | if not isinstance(apns_payload_alert, _messages.APNsAlert): 576 | raise ValueError('Aps.alert must be a string or an instance of _messages.APNsAlert class.') 577 | result = { 578 | 'title': apns_payload_alert.title, 579 | 'body': apns_payload_alert.body, 580 | 'title-loc-key': apns_payload_alert.title_loc_key, 581 | 'title-loc-args': apns_payload_alert.title_loc_args, 582 | 'loc-key': apns_payload_alert.loc_key, 583 | 'loc-args': apns_payload_alert.loc_args, 584 | 'action-loc-key': apns_payload_alert.action_loc_key, 585 | 'launch-image': apns_payload_alert.launch_image 586 | } 587 | if result.get('loc-args') and not result.get('loc-key'): 588 | raise ValueError( 589 | 'ApsAlert.loc_key is required when specifying loc_args.') 590 | if result.get('title-loc-args') and not result.get('title-loc-key'): 591 | raise ValueError( 592 | 'ApsAlert.title_loc_key is required when specifying title_loc_args.') 593 | if apns_payload_alert.custom_data is not None: 594 | if not isinstance(apns_payload_alert.custom_data, dict): 595 | raise ValueError('ApsAlert.custom_data must be a dict.') 596 | for key, val in apns_payload_alert.custom_data.items(): 597 | result[key] = val 598 | return cls.remove_null_values(result) 599 | 600 | @classmethod 601 | def encode_apns_hms_options(cls, apns_hms_options): 602 | """ 603 | :param apns_hms_options: 604 | """ 605 | if apns_hms_options is None: 606 | return None 607 | if not isinstance(apns_hms_options, _messages.APNsHMSOptions): 608 | raise ValueError('Aps.alert must be a string or an instance of _messages.APNsHMSOptions class.') 609 | 610 | result = { 611 | 'target_user_type': apns_hms_options.target_user_type, 612 | } 613 | return cls.remove_null_values(result) 614 | -------------------------------------------------------------------------------- /python37/src/push_admin/messaging.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src.push_admin import _messages, _app 18 | from src import push_admin 19 | 20 | """HUAWEI Cloud Messaging module.""" 21 | 22 | """ General Data structure """ 23 | Message = _messages.Message 24 | Notification = _messages.Notification 25 | 26 | """ Web Push related data structure """ 27 | WebPushConfig = _messages.WebPushConfig 28 | WebPushHeader = _messages.WebPushHeader 29 | WebPushNotification = _messages.WebPushNotification 30 | WebPushNotificationAction = _messages.WebPushNotificationAction 31 | WebPushHMSOptions = _messages.WebPushHMSOptions 32 | 33 | """ Android Push related data structure """ 34 | AndroidConfig = _messages.AndroidConfig 35 | AndroidNotification = _messages.AndroidNotification 36 | AndroidClickAction = _messages.AndroidClickAction 37 | AndroidBadgeNotification = _messages.AndroidBadgeNotification 38 | AndroidLightSettings = _messages.AndroidLightSettings 39 | AndroidLightSettingsColor = _messages.AndroidLightSettingsColor 40 | 41 | """ APNS Push related data structure""" 42 | APNsConfig = _messages.APNsConfig 43 | APNsHeader = _messages.APNsHeader 44 | APNsPayload = _messages.APNsPayload 45 | APNsAps = _messages.APNsAps 46 | APNsAlert = _messages.APNsAlert 47 | APNsHMSOptions = _messages.APNsHMSOptions 48 | 49 | """Common exception definition""" 50 | ApiCallError = _app.ApiCallError 51 | 52 | 53 | def send_message(message, validate_only=False, app_id=None, verify_peer=False): 54 | """ 55 | Sends the given message Huawei Cloud Messaging (HCM) 56 | :param message: An instance of ``messaging.Message``. 57 | :param validate_only: A boolean indicating whether to run the operation in dry run mode (optional). 58 | :param app_id: app id parameters obtained by developer alliance applying for Push service (optional). 59 | :param verify_peer: (optional) Either a boolean, in which case it controls whether we verify 60 | the server's TLS certificate, or a string, in which case it must be a path 61 | to a CA bundle to use. Defaults to ``True``. 62 | :return: SendResponse 63 | Raises: 64 | ApiCallError: If an error occurs while sending the message to the HCM service. 65 | """ 66 | try: 67 | response = push_admin.get_app(app_id).send(message, validate_only, verify_peer=verify_peer) 68 | return SendResponse(response) 69 | except Exception as e: 70 | raise ApiCallError(repr(e)) 71 | 72 | 73 | def subscribe_topic(topic, token_list, app_id=None): 74 | """ 75 | :param topic: The specific topic 76 | :param token_list: The token list to be added 77 | :param app_id: application ID 78 | """ 79 | try: 80 | response = push_admin.get_app(app_id).subscribe_topic(topic, token_list) 81 | return TopicSubscribeResponse(response) 82 | except Exception as e: 83 | raise ApiCallError(repr(e)) 84 | 85 | 86 | def unsubscribe_topic(topic, token_list, app_id=None): 87 | """ 88 | :param topic: The specific topic 89 | :param token_list: The token list to be deleted 90 | :param app_id: application ID 91 | """ 92 | try: 93 | response = push_admin.get_app(app_id).unsubscribe_topic(topic, token_list) 94 | return TopicSubscribeResponse(response) 95 | except Exception as e: 96 | raise ApiCallError(repr(e)) 97 | 98 | 99 | def list_topics(token, app_id=None): 100 | """ 101 | :param token: The token to be queried 102 | :param app_id: application ID 103 | """ 104 | try: 105 | response = push_admin.get_app(app_id).query_subscribe_list(token) 106 | return TopicQueryResponse(response) 107 | except Exception as e: 108 | raise ApiCallError(repr(e)) 109 | 110 | 111 | class SendResponse(object): 112 | """ 113 | The response received from an send request to the HCM API. 114 | response: received http response body text from HCM. 115 | """ 116 | def __init__(self, response=None): 117 | try: 118 | self._code = response['code'] 119 | self._msg = response['msg'] 120 | self._requestId = response['requestId'] 121 | except Exception as e: 122 | raise ValueError(format(repr(e))) 123 | 124 | @property 125 | def code(self): 126 | """errcode""" 127 | return self._code 128 | 129 | @property 130 | def reason(self): 131 | """the description of errcode""" 132 | return self._msg 133 | 134 | @property 135 | def requestId(self): 136 | """A message ID string that uniquely identifies the message.""" 137 | return self._requestId 138 | 139 | 140 | class BaseTopicResponse(object): 141 | """ 142 | { 143 | "msg": "Success", 144 | "code": "80000000", 145 | "requestId": "157466304904000004000701" 146 | } 147 | """ 148 | def __init__(self, json_rsp=None): 149 | if json_rsp is None: 150 | self._msg = "" 151 | self._code = "" 152 | self._requestId = "" 153 | else: 154 | self._msg = json_rsp['msg'] 155 | self._code = json_rsp['code'] 156 | self._requestId = json_rsp['requestId'] 157 | 158 | @property 159 | def msg(self): 160 | return self._msg 161 | 162 | @property 163 | def code(self): 164 | return self._code 165 | 166 | @property 167 | def requestId(self): 168 | return self._requestId 169 | 170 | 171 | class TopicSubscribeResponse(BaseTopicResponse): 172 | """ 173 | { 174 | "msg": "Success", 175 | "code": "80000000", 176 | "requestId": "157466304904000004000701", 177 | "successCount": 2, 178 | "failureCount": 0, 179 | "errors": [] 180 | } 181 | """ 182 | def __init__(self, json_rsp=None): 183 | super(TopicSubscribeResponse, self).__init__(json_rsp=json_rsp) 184 | if json_rsp is None: 185 | self._successCount = 0 186 | self._failureCount = 0 187 | self._errors = [] 188 | else: 189 | self._successCount = json_rsp['successCount'] 190 | self._failureCount = json_rsp['failureCount'] 191 | self._errors = json_rsp['errors'] 192 | 193 | @property 194 | def successCount(self): 195 | return self._successCount 196 | 197 | @property 198 | def failureCount(self): 199 | return self._failureCount 200 | 201 | @property 202 | def errors(self): 203 | return self._errors 204 | 205 | 206 | class TopicQueryResponse(BaseTopicResponse): 207 | """ 208 | { 209 | "msg": "success", 210 | "code": "80000000", 211 | "requestId": "157466350121600008000701", 212 | "topics": [ 213 | { "name": "sports", 214 | "addDate": "2019-11-25" 215 | } ] 216 | } 217 | """ 218 | def __init__(self, json_rsp=None): 219 | super(TopicQueryResponse, self).__init__(json_rsp) 220 | self._topics = json_rsp['topics'] 221 | 222 | @property 223 | def topics(self): 224 | return self._topics 225 | -------------------------------------------------------------------------------- /python37/test/push_env.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | # Production ENV 19 | app_id = 'your aappId' 20 | app_secret = 'your appSecret' 21 | app_package_name = 'your packageName' 22 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 23 | push_open_api = 'https://push-api.cloud.huawei.com' 24 | 25 | # Production ENV 26 | app_id = 'your aappId' 27 | app_secret = 'your appSecret' 28 | app_package_name = 'your packageName' 29 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 30 | push_open_api = 'https://push-api.cloud.huawei.com' 31 | 32 | # Production EVN (instance APP) 33 | app_id = 'your aappId' 34 | app_secret = 'your appSecret' 35 | token_server = 'https://oauth-login.cloud.huawei.com/oauth2/v2/token' 36 | push_open_api = 'https://push-api.cloud.huawei.com' 37 | 38 | 39 | -------------------------------------------------------------------------------- /python37/test/send_apns_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | headers = {messaging.APNsHeader.HEAD_APNs_ID: "6532dc0e-f581-7bfb-e1ab-60ec3cecea73"} 23 | 24 | apns_alert = messaging.APNsAlert(title="HMS Push Title", 25 | body="HMS Push Body", 26 | launch_image="Default.png", 27 | custom_data={"k1": "v1", "k2": "v2"}) 28 | 29 | apns_payload_aps = messaging.APNsAps(alert=apns_alert, 30 | badge=1, 31 | sound="wtewt.mp4", 32 | content_available=True, 33 | category="category", 34 | thread_id="id") 35 | 36 | payload = messaging.APNsPayload(aps=apns_payload_aps, 37 | acme_account="jane.appleseed@apple.com", 38 | acme_message="message123456") 39 | 40 | apns_hms_options = messaging.APNsHMSOptions(target_user_type=1) 41 | 42 | apns_push_config = messaging.APNsConfig(headers=headers, 43 | payload=payload, 44 | apns_hms_options=apns_hms_options) 45 | 46 | 47 | def send_apns_push_message(): 48 | """ 49 | a sample to show hwo to send web push message 50 | :return: 51 | """ 52 | message = messaging.Message( 53 | apns=apns_push_config, 54 | # TODO: 55 | token=['your token'] 56 | ) 57 | 58 | try: 59 | # Case 1: Local CA sample code 60 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 61 | # Case 2: No verification of HTTPS's certificate 62 | response = messaging.send_message(message) 63 | # Case 3: use certifi Library 64 | # import certifi 65 | # response = messaging.send_message(message, verify_peer=certifi.where()) 66 | print("response is ", json.dumps(vars(response))) 67 | assert (response.code == '80000000') 68 | except Exception as e: 69 | print(repr(e)) 70 | 71 | 72 | def init_app(): 73 | """init sdk app. The appID & app Secret use the Android's application ID and Secret under the same project, next version you can use 74 | the IOS application's own appId & secret! """ 75 | # TODO: 76 | app_id_at = "Your android application's app id" 77 | app_secret_at = "Your android application's app secret" 78 | app_id_push = "Your IOS application' app id " 79 | push_admin.initialize_app(app_id_at, app_secret_at, app_id_push) 80 | 81 | 82 | def main(): 83 | init_app() 84 | send_apns_push_message() 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | -------------------------------------------------------------------------------- /python37/test/send_condition_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["Girl", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title(Topic)', 45 | big_body='Big Boom Body(Topic)', 46 | auto_clear=86400000, 47 | notify_id=486, 48 | group='Group1', 49 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 50 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 51 | alpha=0, red=0, green=1, blue=1) 52 | , light_on_duration="3.5", light_off_duration="5S"), 53 | badge=messaging.AndroidBadgeNotification( 54 | add_num=1, clazz='Classic'), 55 | visibility=messaging.AndroidNotification.PUBLIC, 56 | foreground_show=True 57 | ) 58 | 59 | 60 | android = messaging.AndroidConfig( 61 | collapse_key=-1, 62 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 63 | ttl="10000s", 64 | bi_tag='the_sample_bi_tag_for_receipt_service', 65 | notification=android_notification, 66 | category=None 67 | ) 68 | 69 | 70 | def send_push_android_data_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | condition="'your topic' in topics" 80 | ) 81 | 82 | try: 83 | # Case 1: Local CA sample code 84 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 85 | # Case 2: No verification of HTTPS's certificate 86 | response = messaging.send_message(message) 87 | # Case 3: use certifi Library 88 | # import certifi 89 | # response = messaging.send_message(message, verify_peer=certifi.where()) 90 | print("response is ", json.dumps(vars(response))) 91 | assert (response.code == '80000000') 92 | except Exception as e: 93 | print(repr(e)) 94 | 95 | 96 | def init_app(): 97 | """init sdk app""" 98 | # TODO 99 | app_id = "Your android application's app id" 100 | app_secret = "Your android application's app secret" 101 | push_admin.initialize_app(app_id, app_secret) 102 | 103 | 104 | def main(): 105 | init_app() 106 | send_push_android_data_message() 107 | 108 | 109 | if __name__ == '__main__': 110 | main() 111 | -------------------------------------------------------------------------------- /python37/test/send_data_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | """ 23 | [ANDROID] android 24 | """ 25 | android = messaging.AndroidConfig( 26 | collapse_key=-1, 27 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 28 | ttl="10000s", 29 | bi_tag='the_sample_bi_tag_for_receipt_service' 30 | ) 31 | 32 | 33 | def send_push_android_data_message(): 34 | """ 35 | a sample to show hwo to send web push message 36 | :return: 37 | """ 38 | message = messaging.Message( 39 | data="{'k1':'v1', 'k2':'v2'}", 40 | android=android, 41 | # TODO 42 | token=['your token'] 43 | ) 44 | 45 | try: 46 | # Case 1: Local CA sample code 47 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 48 | # Case 2: No verification of HTTPS's certificate 49 | response = messaging.send_message(message) 50 | # Case 3: use certifi Library 51 | # import certifi 52 | # response = messaging.send_message(message, verify_peer=certifi.where()) 53 | print("response is ", json.dumps(vars(response))) 54 | assert (response.code == '80000000') 55 | except Exception as e: 56 | print(repr(e)) 57 | 58 | 59 | def init_app(): 60 | """init sdk app""" 61 | # TODO 62 | app_id = "Your android application's app id" 63 | app_secret = "Your android application's app secret" 64 | push_admin.initialize_app(app_id, app_secret) 65 | 66 | 67 | def main(): 68 | init_app() 69 | send_push_android_data_message() 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | 75 | -------------------------------------------------------------------------------- /python37/test/send_instance_app_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | 19 | from src import push_admin 20 | from src.push_admin import messaging 21 | 22 | android = messaging.AndroidConfig( 23 | collapse_key=-1, 24 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 25 | ttl="10000s", 26 | bi_tag='the_sample_bi_tag_for_receipt_service', 27 | fast_app_target=1, 28 | category=None 29 | ) 30 | 31 | 32 | def send_push_android_data_message(): 33 | """ 34 | a sample to show hwo to send web push message 35 | :return: 36 | """ 37 | message = messaging.Message( 38 | # English sample 39 | # data = "{\"pushtype\":0,\"pushbody\":{\"title\":\"Welcome to use Huawei HMS Push Kit?\",\"description\":\"One " 40 | # + "of the best push platform on the planet!!!\",\"page\":\"/\",\"params\":{\"key1\":\"test1\",\"key2\":\"test2\"},\"ringtone\":" 41 | # + "{\"vibration\":\"true\",\"breathLight\":\"true\"}}}", 42 | # Chinese sample 43 | data = "{\"pushtype\":0,\"pushbody\":{\"title\":\"欢迎使用华为HMS Push Kit!\",\"description\":\"世界上最好," 44 | + "最优秀的推送平台!!!\",\"page\":\"/\",\"params\":{\"key1\":\"test1\",\"key2\":\"test2\"},\"ringtone\":" 45 | + "{\"vibration\":\"true\",\"breathLight\":\"true\"}}}", 46 | android=android, 47 | # TODO 48 | token=['your token'] 49 | ) 50 | 51 | try: 52 | # Case 1: Local CA sample code 53 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 54 | # Case 2: No verification of HTTPS's certificate 55 | response = messaging.send_message(message) 56 | # Case 3: use certifi Library 57 | # import certifi 58 | # response = messaging.send_message(message, verify_peer=certifi.where()) 59 | print("response is ", json.dumps(vars(response))) 60 | assert (response.code == '80000000') 61 | except Exception as e: 62 | print(repr(e)) 63 | 64 | 65 | def init_app(): 66 | """init sdk app""" 67 | # TODO 68 | app_id = "Your instance application's (not android app) app id" 69 | app_secret = "Your instance application's (not android app) app secret" 70 | push_admin.initialize_app(app_id, app_secret) 71 | 72 | 73 | def main(): 74 | init_app() 75 | send_push_android_data_message() 76 | 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /python37/test/send_notify_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body', 25 | image='https://www.huawei.com/path/icon.png' 26 | ) 27 | 28 | android_notification = messaging.AndroidNotification( 29 | icon='/raw/ic_launcher2', 30 | color='#AACCDD', 31 | sound='/raw/shake', 32 | default_sound=True, 33 | tag='tagBoom', 34 | click_action=messaging.AndroidClickAction( 35 | action_type=1, 36 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 37 | body_loc_key='M.String.body', 38 | body_loc_args=('boy', 'dog'), 39 | title_loc_key='M.String.title', 40 | title_loc_args=["Girl", "Cat"], 41 | channel_id='Your Channel ID', 42 | notify_summary='some summary', 43 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 44 | style=0, 45 | big_title='Big Boom Title', 46 | big_body='Big Boom Body', 47 | auto_clear=86400000, 48 | notify_id=4861, 49 | group='Group1', 50 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 51 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 52 | alpha=0, red=0, green=1, blue=1) 53 | , light_on_duration="3.5", light_off_duration="5S"), 54 | badge=messaging.AndroidBadgeNotification( 55 | add_num=1, clazz='Classic'), 56 | visibility=messaging.AndroidNotification.PUBLIC, 57 | foreground_show=True 58 | ) 59 | 60 | 61 | android = messaging.AndroidConfig( 62 | collapse_key=-1, 63 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 64 | ttl="10000s", 65 | bi_tag='the_sample_bi_tag_for_receipt_service', 66 | notification=android_notification 67 | ) 68 | 69 | 70 | def send_push_android_notify_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | token=['Your Token'] 80 | ) 81 | 82 | try: 83 | # TODO 84 | # Case 1: Local CA sample code 85 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 86 | # Case 2: No verification of HTTPS's certificate 87 | response = messaging.send_message(message) 88 | # Case 3: use certifi Library 89 | # import certifi 90 | # response = messaging.send_message(message, verify_peer=certifi.where()) 91 | print("response is ", json.dumps(vars(response))) 92 | assert (response.code == '80000000') 93 | except Exception as e: 94 | print(repr(e)) 95 | 96 | 97 | def init_app(): 98 | """init sdk app""" 99 | # TODO 100 | app_id = "Your android application's app id" 101 | app_secret = "Your android application's app secret" 102 | push_admin.initialize_app(app_id, app_secret) 103 | 104 | 105 | def main(): 106 | init_app() 107 | send_push_android_notify_message() 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /python37/test/send_test_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from src import push_admin 18 | import json 19 | from src.push_admin import messaging 20 | 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["jack", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title', 45 | big_body='Big Boom Body', 46 | auto_clear=86400000, 47 | group='Group1', 48 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 49 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 50 | alpha=0, red=0, green=1, blue=1) 51 | , light_on_duration="3.5", light_off_duration="5S"), 52 | badge=messaging.AndroidBadgeNotification( 53 | add_num=1, clazz='Classic'), 54 | visibility=messaging.AndroidNotification.PUBLIC, 55 | foreground_show=True 56 | ) 57 | 58 | 59 | android = messaging.AndroidConfig( 60 | collapse_key=-1, 61 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 62 | ttl="10000s", 63 | bi_tag='the_sample_bi_tag_for_receipt_service', 64 | notification=android_notification, 65 | category=None 66 | ) 67 | 68 | 69 | def send_push_android_data_message(): 70 | """ 71 | a sample to show hwo to send web push message 72 | :return: 73 | """ 74 | message = messaging.Message( 75 | notification=notification, 76 | android=android, 77 | # TODO 78 | token=['Your Token'] 79 | ) 80 | 81 | try: 82 | # Case 1: Local CA sample code 83 | # response = messaging.send_message(message, validate_only=True, verify_peer="../Push-CA-Root.pem") 84 | # Case 2: No verification of HTTPS's certificate 85 | response = messaging.send_message(message, validate_only=True) 86 | # Case 3: use certifi Library 87 | # import certifi 88 | # response = messaging.send_message(message, validate_only=True, verify_peer=certifi.where()) 89 | print("response is ", json.dumps(vars(response))) 90 | assert (response.code == '80000000') 91 | except Exception as e: 92 | print(repr(e)) 93 | 94 | 95 | def init_app(): 96 | """init sdk app""" 97 | # TODO 98 | app_id = "Your android application's app id" 99 | app_secret = "Your android application's app secret" 100 | push_admin.initialize_app(app_id, app_secret) 101 | 102 | 103 | def main(): 104 | init_app() 105 | send_push_android_data_message() 106 | 107 | 108 | if __name__ == '__main__': 109 | main() 110 | -------------------------------------------------------------------------------- /python37/test/send_topic_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | 19 | from src.push_admin import initialize_app 20 | from src.push_admin import messaging 21 | 22 | notification = messaging.Notification( 23 | title='sample title', 24 | body='sample message body' 25 | ) 26 | 27 | android_notification = messaging.AndroidNotification( 28 | icon='/raw/ic_launcher2', 29 | color='#AACCDD', 30 | sound='/raw/shake', 31 | default_sound=True, 32 | tag='tagBoom', 33 | click_action=messaging.AndroidClickAction( 34 | action_type=1, 35 | intent="intent://com.huawei.codelabpush/deeplink?#Intent;scheme=pushscheme;launchFlags=0x4000000;i.age=180;S.name=abc;end"), 36 | body_loc_key='M.String.body', 37 | body_loc_args=('boy', 'dog'), 38 | title_loc_key='M.String.title', 39 | title_loc_args=["Girl", "Cat"], 40 | channel_id='Your Channel ID', 41 | notify_summary='some summary', 42 | multi_lang_key={"title_key": {"en": "value1"}, "body_key": {"en": "value2"}}, 43 | style=1, 44 | big_title='Big Boom Title', 45 | big_body='Big Boom Body', 46 | auto_clear=86400000, 47 | notify_id=486, 48 | group='Group1', 49 | importance=messaging.AndroidNotification.PRIORITY_HIGH, 50 | light_settings=messaging.AndroidLightSettings(color=messaging.AndroidLightSettingsColor( 51 | alpha=0, red=0, green=1, blue=1) 52 | , light_on_duration="3.5", light_off_duration="5S"), 53 | badge=messaging.AndroidBadgeNotification( 54 | add_num=1, clazz='Classic'), 55 | visibility=messaging.AndroidNotification.PUBLIC, 56 | foreground_show=True 57 | ) 58 | 59 | 60 | android = messaging.AndroidConfig( 61 | collapse_key=-1, 62 | urgency=messaging.AndroidConfig.HIGH_PRIORITY, 63 | ttl="10000s", 64 | bi_tag='the_sample_bi_tag_for_receipt_service', 65 | notification=android_notification, 66 | category=None 67 | ) 68 | 69 | 70 | def send_push_android_data_message(): 71 | """ 72 | a sample to show hwo to send web push message 73 | :return: 74 | """ 75 | message = messaging.Message( 76 | notification=notification, 77 | android=android, 78 | # TODO 79 | topic='Your topic' 80 | ) 81 | 82 | try: 83 | # Case 1: Local CA sample code 84 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 85 | # Case 2: No verification of HTTPS's certificate 86 | response = messaging.send_message(message) 87 | # Case 3: use certifi Library 88 | # import certifi 89 | # response = messaging.send_message(message, verify_peer=certifi.where()) 90 | print("response is ", json.dumps(vars(response))) 91 | assert (response.code == '80000000') 92 | except Exception as e: 93 | print(repr(e)) 94 | 95 | 96 | def init_app(): 97 | """init sdk app""" 98 | # TODO 99 | app_id = "Your android application's app id" 100 | app_secret = "Your android application's app secret" 101 | initialize_app(app_id, app_secret) 102 | 103 | 104 | def main(): 105 | init_app() 106 | send_push_android_data_message() 107 | 108 | 109 | if __name__ == '__main__': 110 | main() 111 | -------------------------------------------------------------------------------- /python37/test/send_webpush_message.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # 3 | # Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import json 18 | from src import push_admin 19 | from src.push_admin import messaging 20 | 21 | web_push_headers = messaging.WebPushHeader(ttl="100") 22 | 23 | web_push_notification = messaging.WebPushNotification( 24 | title="中文推送", 25 | body="中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容中文推送内容", 26 | icon="https://developer-portalres-drcn.dbankcdn.com/system/modules/org.opencms.portal.template.core/\ 27 | resources/images/icon_Promotion.png", 28 | actions=[messaging.WebPushNotificationAction(action="click", title="title", icon="https://developer-portalres-drcn.\ 29 | dbankcdn.com/system/modules/org.opencms.portal.template.core/resources/images/icon_Promotion.png")], 30 | badge="badge", 31 | data="data", 32 | dir="auto", 33 | image="image url", 34 | lang="en", 35 | renotify=False, 36 | require_interaction=False, 37 | silent=True, 38 | tag="tag", 39 | timestamp=32323, 40 | vibrate=[1, 2, 3]) 41 | 42 | web_push_config = messaging.WebPushConfig(headers=web_push_headers, notification=web_push_notification) 43 | 44 | 45 | def send_push_android_data_message(): 46 | """ 47 | a sample to show hwo to send web push message 48 | :return: 49 | """ 50 | message = messaging.Message( 51 | web_push=web_push_config, 52 | # TODO 53 | token=['your token'] 54 | ) 55 | 56 | try: 57 | # Case 1: Local CA sample code 58 | # response = messaging.send_message(message, verify_peer="../Push-CA-Root.pem") 59 | # Case 2: No verification of HTTPS's certificate 60 | response = messaging.send_message(message) 61 | # Case 3: use certifi Library 62 | # import certifi 63 | # response = messaging.send_message(message, verify_peer=certifi.where()) 64 | print("response is ", json.dumps(vars(response))) 65 | assert (response.code == '80000000') 66 | except Exception as e: 67 | print(repr(e)) 68 | 69 | 70 | def init_app(): 71 | """init sdk app 72 | The appID & app Secret use the Android's application ID and Secret under the same project, next version you can use 73 | the web application's own appId & secret! 74 | """ 75 | # TODO 76 | app_id_at = "Your android application's app id" 77 | app_secret_at = "Your android application's app secret" 78 | app_id_push = "Your Web application' app id " 79 | push_admin.initialize_app(app_id_at, app_secret_at, app_id_push) 80 | 81 | 82 | def main(): 83 | init_app() 84 | send_push_android_data_message() 85 | 86 | 87 | if __name__ == '__main__': 88 | main() 89 | --------------------------------------------------------------------------------