diff --git a/.classpath b/.classpath deleted file mode 100644 index dce4385f..00000000 --- a/.classpath +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000..126ba84c --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,35 @@ +name: Publish package to the Maven Central Repository +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Build with Maven + run: mvn -B clean package -Dmaven.test.skip + + - name: Set up Apache Maven Central + uses: actions/setup-java@v1 + with: # running setup-java again overwrites the settings.xml + java-version: 1.8 + server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml + server-username: MAVEN_USERNAME # env variable for username in deploy + server-password: MAVEN_PASSWORD # env variable for token in deploy + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import + gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase + + - name: Publish to Apache Maven Central + run: mvn deploy -Dmaven.test.skip + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 998ec3c7..5dd802ea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ bin/ target/ test-output/ .idea/ +.classpath *.class *.project @@ -12,6 +13,5 @@ test-output/ *.ear *.iml -pom.xml.releaseBackup -release.properties - +*.releaseBackup +release.properties \ No newline at end of file diff --git a/.project b/.project deleted file mode 100644 index 577a5514..00000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - jpush-api - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7db7478d..00000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: java - -jdk: - - oraclejdk7 - - oraclejdk8 - - openjdk6 - - openjdk7 - -#branches: -# only: -# - master - - diff --git a/README.md b/README.md index 4f1f4078..185e9c2e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,15 @@ -[![Build Status](https://travis-ci.org/jpush/jpush-api-java-client.svg?branch=master)](https://travis-ci.org/jpush/jpush-api-java-client) -[![Dependency Status](https://www.versioneye.com/user/projects/53eff13a13bb06f0bb000518/badge.svg?style=flat)](https://www.versioneye.com/user/projects/53eff13a13bb06f0bb000518) +# 新版 SDK +欢迎使用新一代 [jiguang-sdk-java](https://github.com/jpush/jiguang-sdk-java)!这个 SDK 旨在提供更好的性能、更多功能和更好的用户体验。 + +为什么升级? +* 性能优化:新版本经过优化,运行更快,消耗更少的资源。 +* 功能增强:引入了许多新功能和改进,使您的开发工作更加高效。 +* Bug 修复:解决了上个版本存在的问题,提高了稳定性和可靠性。 + +> 极光已推出新版本的 SDK 供广大用户使用,当前版本后续将不推荐使用,请移步仓库 [jiguang-sdk-java](https://github.com/jpush/jiguang-sdk-java) 了解更多。 + +# ~~旧版 SDK~~ + [![GitHub version](https://badge.fury.io/gh/jpush%2Fjpush-api-java-client.svg)](http://badge.fury.io/gh/jpush%2Fjpush-api-java-client) # JPush API Java Library @@ -8,30 +18,17 @@ 这是 JPush REST API 的 Java 版本封装开发包,是由极光推送官方提供的,一般支持最新的 API 功能。 -对应的 REST API 文档: - -本开发包 Javadoc:[API Docs](http://jpush.github.io/jpush-api-java-client/apidocs/) +对应的 REST API 文档:[REST API - Push](https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/), [REST API - Report](https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/). 版本更新:[Release页面](https://github.com/jpush/jpush-api-java-client/releases)。下载更新请到这里。 +> 非常欢迎各位开发者提交代码,贡献一份力量,review过有效的代码将会合入本项目。 -## 安装 - -### maven 方式 -将下边的依赖条件放到你项目的 maven pom.xml 文件里。 - -``` - - cn.jpush.api - jpush-client - 3.2.6 - -``` -### jar 包方式 -请到 [Release页面](https://github.com/jpush/jpush-api-java-client/releases)下载相应版本的发布包。 +## 安装 ### 依赖包 +* [jiguang-java-client-common](https://github.com/jpush/jiguang-java-client-common) / 极光 Java client 的公共封装开发包,必须依赖,v1.1.11 为例,查看[最新版本](https://github.com/jpush/jiguang-java-client-common/releases) * [slf4j](http://www.slf4j.org/) / log4j (Logger) * [gson](https://code.google.com/p/google-gson/) (Google JSON Utils) @@ -39,40 +36,64 @@ 如果使用 Maven 构建项目,则需要在你的项目 pom.xml 里增加: -``` - - com.google.code.gson - gson - 2.2.4 - - - org.slf4j - slf4j-api - 1.7.5 - - - - - org.slf4j - slf4j-log4j12 - 1.7.5 - - - log4j - log4j - 1.2.16 - - - +```Java + + cn.jpush.api + jiguang-common + 1.1.11 + + + io.netty + netty-all + 4.1.6.Final + compile + + + com.google.code.gson + gson + 2.3 + + + org.slf4j + slf4j-api + 1.7.7 + + + + + org.slf4j + slf4j-log4j12 + 1.7.7 + + + log4j + log4j + 1.2.17 + ``` 如果不使用 Maven 构建项目,则项目 libs/ 目录下有依赖的 jar 可复制到你的项目里去。 +## 编译源码 + +> 如果开发者想基于本项目做一些扩展的开发,或者想了解本项目源码,可以参考此章,否则可略过此章。 + +### 导入本项目 + +* 可以采用 `git clone https://github.com/jpush/jpush-api-java-client.git jpush-api-src` 命令下载源码 +* 如果不使用git,请到[Release页面](https://github.com/jpush/jpush-api-java-client/releases)下载源码包并解压 +* 采用eclipse导入下载的源码工程,推荐采用maven的方式,方便依赖包的管理 +* 假如采用导入普通项目的方式,项目报错,检查Build Path,Libraries + * 依赖jar包都在libs目录下可以找到,没有加入的请添加到Build Path,Libraries + * 默认采用了log4j做日志框架,开发者可根据自己需求替换logback、commons-logging等日志框架 + * 极个别情况下,如果test目录报错,请手动添加test的依赖jar包mockwebserver-2.0.0.jar、okhttp-2.0.0.jar、okio-1.0.0.jar +* 开发者需要注意,将本项目的编码格式设置为UTF-8 + ### 构建本项目 可以用 Eclipse 类 IDE 导出 jar 包。建议直接使用 maven,执行命令: - maven package + mvn package ### 自动化测试 @@ -81,13 +102,28 @@ mvn test ## 使用样例 +如果使用 NettyHttpClient(v3.2.15 版本新增),需要在响应返回后手动调用一下 NettyHttpClient 中的 close 方法,否则进程不会退出。代码示例: +``` +... +try { + PushResult result = jpushClient.sendPush(payload); + LOG.info("Got result - " + result); + Thread.sleep(5000); +    // 请求结束后,调用 NettyHttpClient 中的 close 方法,否则进程不会退出。 +    jpushClient.close(); +} catch(InterruptedException e) { + e.printStackTrace(); +} +``` + +3.2.17 版本后,在 PushClient 中添加了 setHttpClient(IHttpClient client) 方法,用户可以自由切换 ApacheHttpClient,NettyHttpClient 或是 NativeHttpClient。 ### 推送样例 > 以下片断来自项目代码里的文件:example / cn.jpush.api.examples.PushExample ```Java - JPushClient jpushClient = new JPushClient(masterSecret, appKey, 3); + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance()); // For push, all you need do is to build PushPayload object. PushPayload payload = buildPushObject_all_all_alert(); @@ -95,7 +131,7 @@ try { PushResult result = jpushClient.sendPush(payload); LOG.info("Got result - " + result); - + } catch (APIConnectionException e) { // Connection error, should retry later LOG.error("Connection error, should retry later", e); @@ -143,7 +179,7 @@ } ``` -* 构建推送对象:平台是 iOS,推送目标是 "tag1", "tag_all" 的并集,推送内容同时包括通知与消息 - 通知信息是 ALERT,角标数字为 5,通知声音为 "happy",并且附加字段 from = "JPush";消息内容是 MSG_CONTENT。通知是 APNs 推送通道的,消息是 JPush 应用内消息通道的。APNs 的推送环境是“生产”(如果不显式设置的话,Library 会默认指定为开发) +* 构建推送对象:平台是 iOS,推送目标是 "tag1", "tag_all" 的交集,推送内容同时包括通知与消息 - 通知信息是 ALERT,角标数字为 5,通知声音为 "happy",并且附加字段 from = "JPush";消息内容是 MSG_CONTENT。通知是 APNs 推送通道的,消息是 JPush 应用内消息通道的。APNs 的推送环境是“生产”(如果不显式设置的话,Library 会默认指定为开发) ```Java public static PushPayload buildPushObject_ios_tagAnd_alertWithExtrasAndMessage() { @@ -166,7 +202,7 @@ } ``` -* 构建推送对象:平台是 Andorid 与 iOS,推送目标是 ("tag1" 与 "tag2" 的交集)并("alias1" 与 "alias2" 的交集),推送内容是 - 内容为 MSG_CONTENT 的消息,并且附加字段 from = JPush。 +* 构建推送对象:平台是 Andorid 与 iOS,推送目标是 ("tag1" 与 "tag2" 的并集)交("alias1" 与 "alias2" 的并集),推送内容是 - 内容为 MSG_CONTENT 的消息,并且附加字段 from = JPush。 ```Java public static PushPayload buildPushObject_ios_audienceMore_messageWithExtras() { @@ -184,6 +220,30 @@ } ``` +* 构建推送对象:推送内容包含SMS信息 + +```Java + public static void testSendWithSMS() { + JPushClient jpushClient = new JPushClient(masterSecret, appKey); + try { + SMS sms = SMS.newBuilder() + .setDelayTime(1000) + .setTempID(2000) + .addPara("Test", 1) + .build(); + PushResult result = jpushClient.sendAndroidMessageWithAlias("Test SMS", "test sms", sms, "alias1"); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } +``` + ### 统计获取样例 > 以下片断来自项目代码里的文件:example / cn.jpush.api.examples.ReportsExample @@ -211,6 +271,7 @@ > 以下片断来自项目代码里的文件:example / cn.jpush.api.examples.DeviceExample +* 获取Tag Alias ```Java try { TagAliasResult result = jpushClient.getDeviceTagAlias(REGISTRATION_ID1); @@ -227,6 +288,22 @@ } ``` +* 绑定手机号 + +```Java + try { + DefaultResult result = jpushClient.bindMobile(REGISTRATION_ID1, "13000000000"); + LOG.info("Got result " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } +``` + ### Schedule 样例 > 以下片断来自项目代码里的文件:example / cn.jpush.api.examples.ScheduleExample @@ -248,3 +325,99 @@ LOG.info("Error Message: " + e.getErrorMessage()); } ``` + +### Custom Client 样例 + +> 以下片断来自项目代码里面的文件:example / cn.jpush.api.examples.ClientExample + +* 配置的SSLVersion表示指定至少支持的协议版本,也可能支持其他多个协议版本,最终支持的协议版本列表取决于JRE和运行环境 +```Java + public static void testCustomClient() { + ClientConfig config = ClientConfig.getInstance(); + config.setMaxRetryTimes(5); + config.setConnectionTimeout(10 * 1000); // 10 seconds + config.setSSLVersion("TLSv1.1"); // JPush server supports SSLv3, TLSv1, TLSv1.1, TLSv1.2 + + JPushClient jPushClient = new JPushClient(masterSecret, appKey, null, config); + } + + public static void testCustomPushClient() { + ClientConfig config = ClientConfig.getInstance(); + config.setApnsProduction(false); // development env + config.setTimeToLive(60 * 60 * 24); // one day + + // config.setGlobalPushSetting(false, 60 * 60 * 24); // development env, one day + + JPushClient jPushClient = new JPushClient(masterSecret, appKey, null, config); // JPush client + + // PushClient pushClient = new PushClient(masterSecret, appKey, null, config); // push client only + + } +``` + +### Image Client 样例 + +> 以下片断来自项目代码里面的文件:example / cn.jpush.api.examples.ImageExample +* 支持通过URL或者文件来上传图片 +```Java + public static void testUploadImageByUrl() throws APIConnectionException, APIRequestException { + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageUrlPayload payload = ImageUrlPayload.newBuilder() + .setImageType(ImageType.LARGE_ICON) + .setImageUrl("http://xxx.com/image/a.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + String mediaId = imageUploadResult.getMediaId(); + } + + public static void testUploadImageByFile() { + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageFilePayload payload = ImageFilePayload.newBuilder() + .setImageType(ImageType.BIG_PICTURE) + // 本地文件路径 + .setOppoFileName("/MyDir/a.jpg") + .setXiaomiFileName("/MyDir/a.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + String mediaId = imageUploadResult.getMediaId(); + } +``` + +### Weblogic 使用Java SDK + +Weblogic在使用jpush-api-java-client时需要注意的一些事项。 + +#### 注意事项 + +本文档基于weblogic 10.3.6 版本,12版本请自己对应配置路径。 + +极个别时候,证书会有版本升级等情况,所以一定要验证当前使用的证书和官方证书的指纹是否一致。 + +**Weblogic console 设置** + ++ 【主机名验证】设置为无,否则默认使用weblogic.security.SSL.HostnameVerifier进行主机名验证,导致Hostname验证失败 + + 配置路径 Weblogic Console > 服务器设置 > SSL > 高级 > 主机名验证 ++ 选择【使用 JSSE SSL】,因为Weblogic默认的加密算法和Java标准的加密算法不一样 + + 配置路径 Weblogic Console > 服务器设置 > SSL > 高级 > 使用 JSSE SSL + +**证书配置** + ++ 检查Weblogic使用的信任密钥库的位置 + + 默认使用的文件是 JRE目录下面的 jre\lib\security\cacerts 文件 + + 有些开发者可能会改为自定义的信任密钥库 ++ 检查对应的信任库是否包含了Geo Trust的根证书或者Geo Trust SSL二级 证书 + + 举例:keytool -list -keystore cacerts + + 此过程需要信任库的密码(默认changeit) + + 如果包含这两个证书中任意一个,调用JPush接口都可以调用通过 ++ 如果信任库不包含上述证书,需要导入公钥到对应的信任库 + + 打开jpush.cn,导出公钥(可以是Geo Trust根证书、Geo Trust SSL 或者 *.jpush.cn 三个任意一个,具体导出方法请百度) + + 将导出的公钥证书导入到步骤1对应的信任库 + + 举例:keytool -import -alias geotrustssl -keystore cacerts -file GeoTrustSSL.cer + + 此过程需要信任库的密码(默认changeit) + +**证书对比方式** + ++ 执行 keytool -list -keystore mykey.jks 命令列出信任库里的所有公钥,观察对应证书的指纹 ++ 检查官网证书,观察对应证书的指纹 ++ 比较两个指纹是否一致,如下图所示 +![jpush_weblogic](https://docs.jiguang.cn/jpush/server/3rd/image/weblogic.png) diff --git a/example/main/java/cn/jpush/api/examples/ClientExample.java b/example/main/java/cn/jpush/api/examples/ClientExample.java new file mode 100644 index 00000000..99f1073c --- /dev/null +++ b/example/main/java/cn/jpush/api/examples/ClientExample.java @@ -0,0 +1,52 @@ +package cn.jpush.api.examples; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import cn.jiguang.common.ClientConfig; +import cn.jpush.api.JPushClient; + +public class ClientExample { + protected static final Logger LOG = LoggerFactory.getLogger(ClientExample.class); + + private static final String appKey = "dd1066407b044738b6479275"; + private static final String masterSecret = "e8cc9a76d5b7a580859bcfa7"; + + public static void main(String[] args) { +// testDefaultClient(); +// testCustomClient(); +// testCustomPushClient(); + } + + public static void testDefaultClient() { + JPushClient client = new JPushClient(masterSecret, appKey); + + // JPushClient client1 = new JPushClient(masterSecret, appKey, null, ClientConfig.getInstance()); + } + + public static void testCustomClient() { + ClientConfig config = ClientConfig.getInstance(); + config.setMaxRetryTimes(5); + config.setConnectionTimeout(10 * 1000); // 10 seconds + config.setSSLVersion("TLSv1.1"); // JPush server supports SSLv3, TLSv1, TLSv1.1, TLSv1.2 + + JPushClient jPushClient = new JPushClient(masterSecret, appKey, null, config); + } + + public static void testCustomPushClient() { + ClientConfig config = ClientConfig.getInstance(); + + config.setApnsProduction(false); // development env + config.setTimeToLive(60 * 60 * 24); // one day + + // config.setGlobalPushSetting(false, 60 * 60 * 24); // development env, one day + + JPushClient jPushClient = new JPushClient(masterSecret, appKey, null, config); // JPush client + + // PushClient pushClient = new PushClient(masterSecret, appKey, null, config); // push client only + + } + +} + + diff --git a/example/main/java/cn/jpush/api/examples/DevcieExample.java b/example/main/java/cn/jpush/api/examples/DevcieExample.java deleted file mode 100644 index 2ad18316..00000000 --- a/example/main/java/cn/jpush/api/examples/DevcieExample.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.jpush.api.examples; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import cn.jpush.api.JPushClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.device.TagAliasResult; - -public class DevcieExample { - protected static final Logger LOG = LoggerFactory.getLogger(DevcieExample.class); - - private static final String appKey = "dd1066407b044738b6479275"; - private static final String masterSecret = "2b38ce69b1de2a7fa95706ea"; - private static final String TAG1 = "tag1"; - private static final String ALIAS1 = "alias1"; - private static final String ALIAS2 = "alias2"; - private static final String REGISTRATION_ID1 = "0900e8d85ef"; - private static final String REGISTRATION_ID2 = "0a04ad7d8b4"; - - private static JPushClient jpushClient = new JPushClient(masterSecret, appKey); - - public static void main(String[] args) { - testGetDeviceTagAlias(); - } - - public static void testGetDeviceTagAlias() { - try { - TagAliasResult result = jpushClient.getDeviceTagAlias(REGISTRATION_ID1); - - LOG.info(result.alias); - LOG.info(result.tags.toString()); - - } catch (APIConnectionException e) { - LOG.error("Connection error. Should retry later. ", e); - - } catch (APIRequestException e) { - LOG.error("Error response from JPush server. Should review and fix it. ", e); - LOG.info("HTTP Status: " + e.getStatus()); - LOG.info("Error Code: " + e.getErrorCode()); - LOG.info("Error Message: " + e.getErrorMessage()); - } - } - -} - - diff --git a/example/main/java/cn/jpush/api/examples/DeviceExample.java b/example/main/java/cn/jpush/api/examples/DeviceExample.java new file mode 100644 index 00000000..a66bce77 --- /dev/null +++ b/example/main/java/cn/jpush/api/examples/DeviceExample.java @@ -0,0 +1,102 @@ +package cn.jpush.api.examples; + +import java.util.HashSet; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.DefaultResult; +import cn.jpush.api.JPushClient; +import cn.jpush.api.device.OnlineStatus; +import cn.jpush.api.device.TagAliasResult; + +public class DeviceExample { + protected static final Logger LOG = LoggerFactory.getLogger(DeviceExample.class); + + private static final String appKey = "7b4b94cca0d185d611e53cca"; + private static final String masterSecret = "860803cf613ed54aa3b941a8"; + private static final String TAG1 = "tag1"; + private static final String ALIAS1 = "alias1"; + private static final String ALIAS2 = "alias2"; + private static final String REGISTRATION_ID1 = "160a3797c856951a397"; + private static final String REGISTRATION_ID2 = "0a04ad7d8b4"; + + private static JPushClient jpushClient = new JPushClient(masterSecret, appKey); + + public static void main(String[] args) { +// testGetDeviceTagAlias(); +// testGetUserOnlineStatus(); + testUpdateDeviceTagAlias(); + } + + public static void testUpdateDeviceTagAlias() { + HashSet tagSet = new HashSet(); + tagSet.add("hhh"); + try { + DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID1, null, tagSet, null); + LOG.info("Got result " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testGetDeviceTagAlias() { + try { + TagAliasResult result = jpushClient.getDeviceTagAlias(REGISTRATION_ID1); + + LOG.info(result.alias); + LOG.info(result.tags.toString()); + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testGetUserOnlineStatus() { + try { + Map result = jpushClient.getUserOnlineStatus(REGISTRATION_ID1, REGISTRATION_ID2); + + LOG.info(result.get(REGISTRATION_ID1).toString()); + LOG.info(result.get(REGISTRATION_ID2).toString()); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testBindMobile() { + try { + DefaultResult result = jpushClient.bindMobile(REGISTRATION_ID1, "13000000000"); + LOG.info("Got result " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + +} + + diff --git a/example/main/java/cn/jpush/api/examples/ImageExample.java b/example/main/java/cn/jpush/api/examples/ImageExample.java new file mode 100644 index 00000000..a29ad866 --- /dev/null +++ b/example/main/java/cn/jpush/api/examples/ImageExample.java @@ -0,0 +1,56 @@ +package cn.jpush.api.image; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.image.model.ImageFilePayload; +import cn.jpush.api.image.model.ImageType; +import cn.jpush.api.image.model.ImageUploadResult; +import cn.jpush.api.image.model.ImageUrlPayload; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ImageExample { + protected static final Logger LOG = LoggerFactory.getLogger(ImageExample.class); + + // demo App defined in resources/jpush-api.conf + protected static final String APP_KEY = "e4ceeaf7a53ad745dd4728f2"; + protected static final String MASTER_SECRET = "1582b986adeaf48ceec1e354"; + protected static final String GROUP_PUSH_KEY = "2c88a01e073a0fe4fc7b167c"; + protected static final String GROUP_MASTER_SECRET = "b11314807507e2bcfdeebe2e"; + + public static final String TITLE = "Test from API example"; + public static final String ALERT = "Test from API Example - alert"; + public static final String MSG_CONTENT = "Test from API Example - msgContent"; + public static final String REGISTRATION_ID = "0900e8d85ef"; + public static final String TAG = "tag_api"; + public static long sendCount = 0; + private static long sendTotalTime = 0; + + public static void main(String[] args) throws APIConnectionException, APIRequestException { + testUploadImageByFile(); + testUploadImageByUrl(); + } + + public static void testUploadImageByUrl() throws APIConnectionException, APIRequestException { + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageUrlPayload payload = ImageUrlPayload.newBuilder() + .setImageType(ImageType.LARGE_ICON) + .setImageUrl("http://xxx.com/image/a.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + String mediaId = imageUploadResult.getMediaId(); + } + + public static void testUploadImageByFile() { + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageFilePayload payload = ImageFilePayload.newBuilder() + .setImageType(ImageType.BIG_PICTURE) + // 本地文件路径 + .setOppoFileName("/MyDir/a.jpg") + .setXiaomiFileName("/MyDir/a.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + String mediaId = imageUploadResult.getMediaId(); + } +} + diff --git a/example/main/java/cn/jpush/api/examples/PushExample.java b/example/main/java/cn/jpush/api/examples/PushExample.java index 77150e42..37a3c9ba 100644 --- a/example/main/java/cn/jpush/api/examples/PushExample.java +++ b/example/main/java/cn/jpush/api/examples/PushExample.java @@ -1,69 +1,275 @@ package cn.jpush.api.examples; -import cn.jpush.api.common.ClientConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.connection.NettyHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; import cn.jpush.api.JPushClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; +import cn.jpush.api.push.CIDResult; +import cn.jpush.api.push.GroupPushClient; +import cn.jpush.api.push.GroupPushResult; import cn.jpush.api.push.PushResult; -import cn.jpush.api.push.model.Message; -import cn.jpush.api.push.model.Options; -import cn.jpush.api.push.model.Platform; -import cn.jpush.api.push.model.PushPayload; +import cn.jpush.api.push.model.*; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.audience.AudienceTarget; -import cn.jpush.api.push.model.notification.AndroidNotification; -import cn.jpush.api.push.model.notification.IosNotification; -import cn.jpush.api.push.model.notification.Notification; +import cn.jpush.api.push.model.notification.*; +import cn.jpush.api.report.GroupMessageDetailResult; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import io.netty.handler.codec.http.HttpMethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; public class PushExample { protected static final Logger LOG = LoggerFactory.getLogger(PushExample.class); - // demo App defined in resources/jpush-api.conf - private static final String appKey ="e5c0d34f58732cf09b2d4d74"; - private static final String masterSecret = "4cdda6d3c8b029941dbc5cb3"; - - public static final String TITLE = "Test from API example"; + /** + * Change the app key and master secret to your own account + * If you want to use push by group, please enter your own group push key and group master secret. + */ + protected static final String APP_KEY = "8f02a4fa717a6235734d92de"; + protected static final String MASTER_SECRET = "cf6de29f9e66432ba4ac1c32"; + protected static final String GROUP_PUSH_KEY = "2c88a01e073a0fe4fc7b167c"; + protected static final String GROUP_MASTER_SECRET = "b11314807507e2bcfdeebe2e"; + + public static final String TITLE = "Test from API example"; public static final String ALERT = "Test from API Example - alert"; public static final String MSG_CONTENT = "Test from API Example - msgContent"; public static final String REGISTRATION_ID = "0900e8d85ef"; public static final String TAG = "tag_api"; + public static long sendCount = 0; + private static long sendTotalTime = 0; + + public static void main(String[] args) { + + // 回调参数可参考下面方法 +// testSendPushWithCustom(); +// testSendPushWithCustomField(); +// testBatchSend(); +// testSendPushWithCustomConfig(); +// testSendIosAlert(); + + // 目前推荐这个方法进行测试 + testSendPush(); +// testSendGroupPush(); + + +// testGetCidList(); +// testSendPushes(); +// testSendPush_fromJSON(); +// testSendPushWithCallback(); +// testSendPushWithCid(); +// testSendWithSMS(); + } + + // 使用 NettyHttpClient 异步接口发送请求 + public static void testSendPushWithCallback() { + ClientConfig clientConfig = ClientConfig.getInstance(); + String host = (String) clientConfig.get(ClientConfig.PUSH_HOST_NAME); + final NettyHttpClient client = new NettyHttpClient(ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET), + null, clientConfig); + try { + URI uri = new URI(host + clientConfig.get(ClientConfig.PUSH_PATH)); + PushPayload payload = buildPushObject_all_alias_alert(); + client.sendRequest(HttpMethod.POST, payload.toString(), uri, new NettyHttpClient.BaseCallback() { + @Override + public void onSucceed(ResponseWrapper responseWrapper) { + LOG.info("Got result: " + responseWrapper.responseContent); + } + }); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + public static void testSendPush() { + ClientConfig clientConfig = ClientConfig.getInstance(); + final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); +// String authCode = ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET); + // Here you can use NativeHttpClient or NettyHttpClient or ApacheHttpClient. + // Call setHttpClient to set httpClient, + // If you don't invoke this method, default httpClient will use NativeHttpClient. + +// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig); +// NettyHttpClient httpClient =new NettyHttpClient(authCode, null, clientConfig); +// jpushClient.getPushClient().setHttpClient(httpClient); - public static void main(String[] args) { - testSendPushWithCustomConfig(); - } - - - public static void testSendPush() { - // HttpProxy proxy = new HttpProxy("localhost", 3128); - // Can use this https proxy: https://github.com/Exa-Networks/exaproxy - JPushClient jpushClient = new JPushClient(masterSecret, appKey, 3); - // For push, all you need do is to build PushPayload object. - PushPayload payload = buildPushObject_all_all_alert(); - + final PushPayload payload = buildPushObject_android_and_ios(); + +// PushPayload payload = buildPushObject_all_alias_alert(); + try { + PushResult result = jpushClient.sendPush(payload); + LOG.info("Got result - " + result); + System.out.println(result); + // 如果使用 NettyHttpClient,需要手动调用 close 方法退出进程 + // If uses NettyHttpClient, call close when finished sending request, otherwise process will not exit. + // jpushClient.close(); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); + } + } + + public static void testSendPushWithEncrypt() { + ClientConfig clientConfig = ClientConfig.getInstance(); + clientConfig.setEncryptType(EncryptKeys.ENCRYPT_SMS2_TYPE); + final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); +// String authCode = ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET); + // Here you can use NativeHttpClient or NettyHttpClient or ApacheHttpClient. + // Call setHttpClient to set httpClient, + // If you don't invoke this method, default httpClient will use NativeHttpClient. + +// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig); +// NettyHttpClient httpClient =new NettyHttpClient(authCode, null, clientConfig); +// jpushClient.getPushClient().setHttpClient(httpClient); + final PushPayload payload = buildPushObject_android_and_ios(); +// // For push, all you need do is to build PushPayload object. +// PushPayload payload = buildPushObject_all_alias_alert(); try { PushResult result = jpushClient.sendPush(payload); LOG.info("Got result - " + result); - + System.out.println(result); + // 如果使用 NettyHttpClient,需要手动调用 close 方法退出进程 + // If uses NettyHttpClient, call close when finished sending request, otherwise process will not exit. + // jpushClient.close(); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); + } + } + + //use String to build PushPayload instance + public static void testSendPush_fromJSON() { + ClientConfig clientConfig = ClientConfig.getInstance(); + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); + Gson gson = new GsonBuilder() + .registerTypeAdapter(PlatformNotification.class, new InterfaceAdapter()) + .create(); + // Since the type of DeviceType is enum, thus the value should be uppercase, same with the AudienceType. + String payloadString = "{\"platform\":{\"all\":false,\"deviceTypes\":[\"IOS\"]},\"audience\":{\"all\":true,\"targets\":[{\"audienceType\":\"TAG_AND\",\"values\":[\"tag1\",\"tag_all\"]}]},\"notification\":{\"notifications\":[{\"soundDisabled\":false,\"badgeDisabled\":false,\"sound\":\"happy\",\"badge\":\"5\",\"contentAvailable\":false,\"alert\":\"Test from API Example - alert\",\"extras\":{\"from\":\"JPush\"},\"type\":\"cn.jpush.api.push.model.notification.IosNotification\"}]},\"message\":{\"msgContent\":\"Test from API Example - msgContent\"},\"options\":{\"sendno\":1429488213,\"overrideMsgId\":0,\"timeToLive\":-1,\"apnsProduction\":true,\"bigPushDuration\":0}}"; + PushPayload payload = gson.fromJson(payloadString, PushPayload.class); + try { + PushResult result = jpushClient.sendPush(payloadString); + LOG.info("Got result - " + result); + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + // LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + //LOG.error("Sendno: " + payload.getSendno()); + } + } + + /** + * 测试多线程发送 2000 条推送耗时 + */ + public static void testSendPushes() { + ClientConfig clientConfig = ClientConfig.getInstance(); + final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); + String authCode = ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET); + // Here you can use NativeHttpClient or NettyHttpClient or ApacheHttpClient. + NativeHttpClient httpClient = new NativeHttpClient(authCode, null, clientConfig); + // Call setHttpClient to set httpClient, + // If you don't invoke this method, default httpClient will use NativeHttpClient. +// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig); + jpushClient.getPushClient().setHttpClient(httpClient); + final PushPayload payload = buildPushObject_ios_tagAnd_alertWithExtrasAndMessage(); + for (int i = 0; i < 10; i++) { + Thread thread = new Thread() { + public void run() { + for (int j = 0; j < 200; j++) { + long start = System.currentTimeMillis(); + try { + PushResult result = jpushClient.sendPush(payload); + LOG.info("Got result - " + result); + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); + } + + System.out.println("耗时" + (System.currentTimeMillis() - start) + "毫秒 sendCount:" + (++sendCount)); + } + } + }; + thread.start(); + } + } + + public static void testSendGroupPush() { + GroupPushClient groupPushClient = new GroupPushClient(GROUP_MASTER_SECRET, GROUP_PUSH_KEY); + final PushPayload payload = buildPushObject_android_and_ios(); + try { + GroupPushResult groupPushResult = groupPushClient.sendGroupPush(payload); + Map result = groupPushResult.getAppResultMap(); + for (Map.Entry entry : result.entrySet()) { + PushResult pushResult = entry.getValue(); + PushResult.Error error = pushResult.error; + if (error != null) { + LOG.info("Group_msgid: " + groupPushResult.getGroupMsgId() + " AppKey: " + entry.getKey() + " error code : " + error.getCode() + " error message: " + error.getMessage()); + } else { + LOG.info("Group_msgid: " + groupPushResult.getGroupMsgId() + " AppKey: " + entry.getKey() + " sendno: " + pushResult.sendno + " msg_id:" + pushResult.msg_id); + } + + } } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); - + LOG.error("Sendno: " + payload.getSendno()); + } catch (APIRequestException e) { LOG.error("Error response from JPush server. Should review and fix it. ", e); LOG.info("HTTP Status: " + e.getStatus()); LOG.info("Error Code: " + e.getErrorCode()); LOG.info("Error Message: " + e.getErrorMessage()); LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); } - } - - public static PushPayload buildPushObject_all_all_alert() { - return PushPayload.alertAll(ALERT); - } - + } + + public static PushPayload buildPushObject_all_all_alert() { + return PushPayload.alertAll(ALERT); + } + public static PushPayload buildPushObject_all_alias_alert() { return PushPayload.newBuilder() .setPlatform(Platform.all()) @@ -71,7 +277,7 @@ public static PushPayload buildPushObject_all_alias_alert() { .setNotification(Notification.alert(ALERT)) .build(); } - + public static PushPayload buildPushObject_android_tag_alertWithTitle() { return PushPayload.newBuilder() .setPlatform(Platform.android()) @@ -79,23 +285,92 @@ public static PushPayload buildPushObject_android_tag_alertWithTitle() { .setNotification(Notification.android(ALERT, TITLE, null)) .build(); } - + + /** + * Could modify the contents for pushing + * The comments are showing how to use it + * @return + */ public static PushPayload buildPushObject_android_and_ios() { + Map extras = new HashMap(); + extras.put("test", "https://community.jiguang.cn/push"); + // you can set anything you want in this builder, read the document to avoid collision. return PushPayload.newBuilder() + .setPlatform(Platform.android_ios()) + .setAudience(Audience.all()) +// .setMessage(Message.newBuilder() +// .setMsgContent("Hi, JPush") +// .build()) + .setNotification(Notification.newBuilder() + .setAlert("testing alert content") + .addPlatformNotification(AndroidNotification.newBuilder() + .setTitle("Android Title") + .addExtras(extras).build()) + .addPlatformNotification(IosNotification.newBuilder() + .incrBadge(1) + .addExtra("extra_key", "extra_value").build()) + .build()) +// .setSMS(SMS.newBuilder() +// .setDelayTime(1000) +// .setTempID(2000) +// .addPara("Test", 1) +// .setActiveFilter(true) +// .build()) +// .setNotification3rd(Notification3rd.newBuilder() +// .setContent("Hi, JPush") +// .setTitle("msg testing") +// .setChannelId("channel1001") +// .setUriActivity("cn.jpush.android.ui.OpenClickActivity") +// .setUriAction("cn.jpush.android.intent.CONNECTION") +// .setBadgeAddNum(1) +// .setBadgeClass("com.test.badge.MainActivity") +// .setSound("sound") +// .addExtra("news_id", 124) +// .addExtra("my_key", "a value") +// .build()) + .setOptions(Options.newBuilder() + .setApnsProduction(false) + .setTimeToLive(43200) + .build()) + .build(); + } + + public static void buildPushObject_with_extra() { + + JsonObject jsonExtra = new JsonObject(); + jsonExtra.addProperty("extra1", 1); + jsonExtra.addProperty("extra2", false); + + Map extras = new HashMap(); + extras.put("extra_1", "val1"); + extras.put("extra_2", "val2"); + + PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.android_ios()) .setAudience(Audience.tag("tag1")) .setNotification(Notification.newBuilder() - .setAlert("alert content") - .addPlatformNotification(AndroidNotification.newBuilder() - .setTitle("Android Title").build()) - .addPlatformNotification(IosNotification.newBuilder() - .incrBadge(1) - .addExtra("extra_key", "extra_value").build()) - .build()) + .setAlert("alert content") + .addPlatformNotification(AndroidNotification.newBuilder() + .setTitle("Android Title") + .addExtras(extras) + .addExtra("booleanExtra", false) + .addExtra("numberExtra", 1) + .addExtra("jsonExtra", jsonExtra) + .build()) + .addPlatformNotification(IosNotification.newBuilder() + .incrBadge(1) + .addExtra("extra_key", "extra_value").build()) + .build()) .build(); + + System.out.println(payload.toJSON()); } - + public static PushPayload buildPushObject_ios_tagAnd_alertWithExtrasAndMessage() { + JsonObject sound = new JsonObject(); + sound.add("critical", new JsonPrimitive(1)); + sound.add("name", new JsonPrimitive("default")); + sound.add("volume", new JsonPrimitive(0.2)); return PushPayload.newBuilder() .setPlatform(Platform.ios()) .setAudience(Audience.tag_and("tag1", "tag_all")) @@ -103,17 +378,56 @@ public static PushPayload buildPushObject_ios_tagAnd_alertWithExtrasAndMessage() .addPlatformNotification(IosNotification.newBuilder() .setAlert(ALERT) .setBadge(5) - .setSound("happy") + .setMutableContent(false) +// .setSound("happy") + .setSound(sound) .addExtra("from", "JPush") .build()) .build()) - .setMessage(Message.content(MSG_CONTENT)) - .setOptions(Options.newBuilder() - .setApnsProduction(true) - .build()) - .build(); + .setMessage(Message.content(MSG_CONTENT)) + .setOptions(Options.newBuilder() + .setApnsProduction(true) + .build()) + .build(); + } + + public static PushPayload buildPushObject_android_newly_support() { + + JsonObject inbox = new JsonObject(); + inbox.add("line1", new JsonPrimitive("line1 string")); + inbox.add("line2", new JsonPrimitive("line2 string")); + inbox.add("contentTitle", new JsonPrimitive("title string")); + inbox.add("summaryText", new JsonPrimitive("+3 more")); + + JsonObject intent = new JsonObject(); + intent.add("url", new JsonPrimitive("intent:#Intent;component=com.jiguang.push/com.example.jpushdemo.SettingActivity;end")); + + Notification notification = Notification.newBuilder() + .addPlatformNotification(AndroidNotification.newBuilder() + .setAlert(ALERT) + .setBigPicPath("path to big picture") + .setBigText("long text") + .setBuilderId(1) + .setCategory("CATEGORY_SOCIAL") + .setInbox(inbox) + .setStyle(1) + .setTitle("Alert test") + .setPriority(1) + .setLargeIcon("http://www.jiguang.cn/largeIcon.jpg") + .setIntent(intent) + .build()) + .build(); + return PushPayload.newBuilder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setNotification(notification) + .setOptions(Options.newBuilder() + .setApnsProduction(true) + .setSendno(ServiceHelper.generateSendno()) + .build()) + .build(); } - + public static PushPayload buildPushObject_ios_audienceMore_messageWithExtras() { return PushPayload.newBuilder() .setPlatform(Platform.android_ios()) @@ -128,12 +442,41 @@ public static PushPayload buildPushObject_ios_audienceMore_messageWithExtras() { .build(); } + public static PushPayload buildPushObject_all_tag_not() { + return PushPayload.newBuilder() + .setPlatform(Platform.all()) + .setAudience(Audience.tag_not("abc", "123")) + .setNotification(Notification.alert(ALERT)) + .build(); + } + + public static PushPayload buildPushObject_android_cid() { + Collection list = new LinkedList(); + list.add("1507bfd3f79558957de"); + list.add("1507bfd3f79554957de"); + list.add("1507bfd3f79555957de"); + list.add("1507bfd3f79556957de"); + list.add("1507ffd3f79545957de"); + list.add("1507ffd3f79457957de"); + list.add("1507ffd3f79456757de"); + list.add("zzzzzzzz"); + + + return PushPayload.newBuilder() + .setPlatform(Platform.android()) +// .setAudience(Audience.registrationId("1507bfd3f79558957de")) + .setAudience(Audience.registrationId(list)) + .setNotification(Notification.alert(ALERT)) + .setCid("cid") + .build(); + } + public static void testSendPushWithCustomConfig() { ClientConfig config = ClientConfig.getInstance(); // Setup the custom hostname config.setPushHostName("https://api.jpush.cn"); - JPushClient jpushClient = new JPushClient(masterSecret, appKey, 3, null, config); + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, config); // For push, all you need do is to build PushPayload object. PushPayload payload = buildPushObject_all_all_alert(); @@ -154,5 +497,233 @@ public static void testSendPushWithCustomConfig() { } } + public static void testSendIosAlert() { + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); + + IosAlert alert = IosAlert.newBuilder() + .setTitleAndBody("test alert", "subtitle", "test ios alert json") + .setActionLocKey("PLAY") + .build(); + try { + PushResult result = jpushClient.sendIosNotificationWithAlias(alert, new HashMap(), "alias1"); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testSendWithSMS() { + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); + try { +// SMS sms = SMS.content(1, 10); + SMS sms = SMS.newBuilder() + .setDelayTime(1000) + .setTempID(2000) + .addPara("Test", 1) + .setActiveFilter(false) + .build(); + PushResult result = jpushClient.sendAndroidMessageWithAlias("Test SMS", "test sms", sms, "alias1"); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testGetCidList() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + try { + CIDResult result = jPushClient.getCidList(3, "push"); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + public static void testSendPushWithCid() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + PushPayload pushPayload = buildPushObject_android_cid(); + try { + PushResult result = jPushClient.sendPush(pushPayload); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + /** + * 批量单推接口 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#vip + */ + public static void testBatchSend() { + + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + try { + { + List pushPayloadList = new ArrayList<>(); + PushPayload.Builder builder1 = PushPayload.newBuilder(); + builder1.setMessage(Message.content("content1 by alias")) + .setNotification(Notification.alert(ALERT)) + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setOptions(Options.sendno()) + .setTarget("1507ffd3f79456757de"); + pushPayloadList.add(builder1.build()); + + PushPayload.Builder builder2 = PushPayload.newBuilder(); + builder2.setMessage(Message.content("content2 by alias")) + .setNotification(Notification.alert(ALERT)) + .setPlatform(Platform.android()) + .setAudience(Audience.all()) + .setOptions(Options.sendno()) + .setTarget("1507ffd3f79456757de"); + pushPayloadList.add(builder2.build()); + + BatchPushResult result = jPushClient.batchSendPushByAlias(pushPayloadList); + LOG.info("batchSendPushByAlias param: {}, result: {}", pushPayloadList, new Gson().toJson(result.getBatchPushResult())); + } + +// { +// List pushPayloadList = new ArrayList<>(); +// PushPayload.Builder builder1 = PushPayload.newBuilder(); +// builder1.setMessage(Message.content("content1 by regId")) +// .setNotification(Notification.alert(ALERT)) +// .setPlatform(Platform.android()) +// .setAudience(Audience.all()) +// .setOptions(Options.sendno()) +// .setTarget("1507ffd3f79456757de"); +// pushPayloadList.add(builder1.build()); +// +// PushPayload.Builder builder2 = PushPayload.newBuilder(); +// builder2.setMessage(Message.content("content2 by regId")) +// .setNotification(Notification.alert(ALERT)) +// .setAudience(Audience.all()) +// .setPlatform(Platform.ios()) +// .setOptions(Options.sendno()) +// .setTarget("1507ffd3f79456757de"); +// pushPayloadList.add(builder2.build()); +// +// BatchPushResult result = jPushClient.batchSendPushByRegId(pushPayloadList); +// LOG.info("batchSendPushByRegId param: {}, result: {}", pushPayloadList, new Gson().toJson(result.getBatchPushResult())); +// } + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + /** + * 自定义发送参数名称, 华为客户可参考该方法 + */ + public static void testSendPushWithCustomField() { + + ClientConfig config = ClientConfig.getInstance(); + // Setup the custom hostname + config.setPushHostName("https://api.jpush.cn"); + + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, config); + + Notification notification = Notification.newBuilder() + .addPlatformNotification(AndroidNotification.newBuilder() + .setAlert(ALERT) + .setTitle("Alert test") + .setLargeIcon("http://www.jiguang.cn/largeIcon.jpg") + .addCustom("uri_activity", "uri_activity") + .addCustom("uri_flag", "uri_flag") + .addCustom("uri_action", "uri_action") + .build()) + .build(); + + PushPayload.Builder payloadBuilder = new PushPayload.Builder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setNotification(notification); + + try { + PushResult result = jpushClient.sendPush(payloadBuilder.build()); + LOG.info("Got result - " + result); + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + + /** + * 回调参数示例 + */ + public static void testSendPushWithCustom() { + + ClientConfig config = ClientConfig.getInstance(); + // Setup the custom hostname + config.setPushHostName("https://api.jpush.cn"); + + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, config); + + Notification notification = Notification.newBuilder() + .addPlatformNotification(AndroidNotification.newBuilder() + .setAlert(ALERT) + .setTitle("Alert test") + .build()) + .build(); + + JsonObject callback = new JsonObject(); + callback.addProperty("url", "https://www.jiguagn.cn/callback"); + JsonObject params = new JsonObject(); + params.addProperty("name", "joe"); + params.addProperty("age", 26); + callback.add("params", params); + callback.addProperty("type", 3); + + PushPayload.Builder payloadBuilder = new PushPayload.Builder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setNotification(notification) + .addCustom("callback", callback); + + try { + PushResult result = jpushClient.sendPush(payloadBuilder.build()); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + } diff --git a/example/main/java/cn/jpush/api/examples/ReportsExample.java b/example/main/java/cn/jpush/api/examples/ReportsExample.java index 2482f7bb..e97cf3f3 100644 --- a/example/main/java/cn/jpush/api/examples/ReportsExample.java +++ b/example/main/java/cn/jpush/api/examples/ReportsExample.java @@ -1,35 +1,52 @@ package cn.jpush.api.examples; +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.JPushClient; +import cn.jpush.api.report.*; +import cn.jpush.api.report.model.CheckMessagePayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import cn.jpush.api.JPushClient; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.report.MessagesResult; -import cn.jpush.api.report.ReceivedsResult; -import cn.jpush.api.report.UsersResult; +import java.util.Map; public class ReportsExample { protected static final Logger LOG = LoggerFactory.getLogger(ReportsExample.class); - // demo App defined in resources/jpush-api.conf - private static final String appKey = "dd1066407b044738b6479275"; - private static final String masterSecret = "2b38ce69b1de2a7fa95706ea"; + + /** + * Change the app key and master secret to your own account + * If you want to use push by group, please enter your own group push key and group master secret. + */ + protected static final String appKey = "8f02a4fa717a6235734d92de"; + protected static final String masterSecret = "cf6de29f9e66432ba4ac1c32"; + protected static final String GROUP_PUSH_KEY = "2c88a01e073a0fe4fc7b167c"; + protected static final String GROUP_MASTER_SECRET = "b11314807507e2bcfdeebe2e"; + + + public static final String REGISTRATION_ID1 = "0900e8d85ef"; + public static final String REGISTRATION_ID2 = "0a04ad7d8b4"; + public static final String REGISTRATION_ID3 = "18071adc030dcba91c0"; public static void main(String[] args) { - testGetReport(); - testGetMessages(); - testGetUsers(); + +// testGetReceivedDetail(); +// testGetMessagesDetail(); +// testGetReport(); +// testGetMessages(); +// testGetUsers(); +// testGetMessageStatus(); + testGetGroupMessagesDetail(); +// testGetGroupUsers(); } public static void testGetReport() { JPushClient jpushClient = new JPushClient(masterSecret, appKey); try { - ReceivedsResult result = jpushClient.getReportReceiveds("1942377665"); - LOG.debug("Got result - " + result); + ReceivedsResult result = jpushClient.getReportReceiveds("2252035206045707"); + LOG.info("Got result - " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); @@ -42,11 +59,15 @@ public static void testGetReport() { } } + /** + * 用户统计 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/#vip_2 + */ public static void testGetUsers() { JPushClient jpushClient = new JPushClient(masterSecret, appKey); try { UsersResult result = jpushClient.getReportUsers(TimeUnit.DAY, "2014-06-10", 3); - LOG.debug("Got result - " + result); + LOG.info("Got result - " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); @@ -76,5 +97,114 @@ public static void testGetMessages() { } } + public static void testGetMessageStatus() { + JPushClient jPushClient = new JPushClient(masterSecret, appKey); + CheckMessagePayload payload = CheckMessagePayload.newBuilder() + .setMsgId(3993287034L) + .addRegistrationIds(REGISTRATION_ID1, REGISTRATION_ID2, REGISTRATION_ID3) + .setDate("2017-08-08") + .build(); + try { + Map map = jPushClient.getMessageStatus(payload); + for (Map.Entry entry : map.entrySet()) { + LOG.info("registrationId: " + entry.getKey() + " status: " + entry.getValue().getStatus()); + } + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + /** + * 消息统计 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/#vip + */ + public static void testGetMessagesDetail() { + + JPushClient jPushClient = new JPushClient(masterSecret, appKey); +// String msgIds = "3993287034,3993287035,3993287036"; + String msgIds = "38280839685161019"; + try { + MessageDetailResult result = jPushClient.getMessagesDetail(msgIds); + LOG.info("msgIds: {}, MessageDetail: {}", msgIds, result.received_list); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + + } + + /** + * 送达详情 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/#_7 + */ + public static void testGetReceivedDetail() { + + JPushClient jPushClient = new JPushClient(masterSecret, appKey); + String msgIds = "3993287034,3993287035,3993287036"; + try { + ReceivedsResult result = jPushClient.getReceivedsDetail(msgIds); + LOG.info("msgIds: {}, ReceivedsDetail: {}", msgIds, result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + /** + * 分组统计-消息统计 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/#-vip + */ + public static void testGetGroupMessagesDetail() { + + JPushClient jPushClient = new JPushClient(GROUP_MASTER_SECRET, GROUP_PUSH_KEY); + String groupMsgIds = "c4hmbne09s6bbaca91vg"; + try { + GroupMessageDetailResult result = jPushClient.getGroupMessagesDetail(groupMsgIds); + LOG.info("group_msgIds: {}, MessageDetail: {}", groupMsgIds, result.received_list); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + + } + + /** + * 分组统计-用户统计 + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_report/#-vip_1 + */ + public static void testGetGroupUsers() { + JPushClient jpushClient = new JPushClient(GROUP_MASTER_SECRET, GROUP_PUSH_KEY); + try { + GroupUsersResult result = jpushClient.getGroupReportUsers(TimeUnit.DAY, "2021-08-21", 3); + LOG.debug("Got result - " + result); + + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + } diff --git a/example/main/java/cn/jpush/api/examples/ScheduleExample.java b/example/main/java/cn/jpush/api/examples/ScheduleExample.java index de4df8c4..80bde327 100644 --- a/example/main/java/cn/jpush/api/examples/ScheduleExample.java +++ b/example/main/java/cn/jpush/api/examples/ScheduleExample.java @@ -1,40 +1,49 @@ package cn.jpush.api.examples; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.Week; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.JPushClient; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.common.Week; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.schedule.ScheduleListResult; +import cn.jpush.api.schedule.ScheduleMsgIdsResult; import cn.jpush.api.schedule.ScheduleResult; import cn.jpush.api.schedule.model.SchedulePayload; import cn.jpush.api.schedule.model.TriggerPayload; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ScheduleExample { protected static final Logger LOG = LoggerFactory.getLogger(ScheduleExample.class); - private static final String appKey ="e5c0d34f58732cf09b2d4d74"; - private static final String masterSecret = "4cdda6d3c8b029941dbc5cb3"; - public static void main(String[] args) { + /** + * Change it to your own appKey and masterSecret if you want to try the demo + */ + private static final String appKey ="7b4b94cca0d185d611e53cca"; + private static final String masterSecret = "860803cf613ed54aa3b941a8"; + + public static void main(String[] args) { + testCreateSingleSchedule(); +// testCreateDailySchedule(); // testDeleteSchedule(); - testGetScheduleList(); +// testGetScheduleList(); // testUpdateSchedule(); - testGetSchedule(); +// testGetSchedule(); +// testGetScheduleMsgIds(); } public static void testCreateSingleSchedule() { JPushClient jpushClient = new JPushClient(masterSecret, appKey); String name = "test_schedule_example"; - String time = "2016-07-30 12:30:25"; - PushPayload push = PushPayload.alertAll("test schedule example."); + String time = "2021-08-11 15:36:10"; + PushPayload push = PushPayload.alertAll("test schedule example"); try { - ScheduleResult result = jpushClient.createSingleSchedule(name, time, push); + ScheduleResult result = jpushClient.createSingleSchedule(name, time, push, masterSecret, appKey); LOG.info("schedule result is " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); @@ -49,12 +58,12 @@ public static void testCreateSingleSchedule() { public static void testCreateDailySchedule() { JPushClient jPushClient = new JPushClient(masterSecret, appKey); String name = "test_daily_schedule"; - String start = "2015-08-06 12:16:13"; - String end = "2115-08-06 12:16:13"; + String start = "2019-08-06 12:16:13"; + String end = "2020-08-06 12:16:13"; String time = "14:00:00"; PushPayload push = PushPayload.alertAll("test daily example."); try { - ScheduleResult result = jPushClient.createDailySchedule(name, start, end, time, push); + ScheduleResult result = jPushClient.createDailySchedule(name, start, end, time, push, masterSecret, appKey); LOG.info("schedule result is " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); @@ -75,7 +84,7 @@ public static void testCreateWeeklySchedule() { Week[] days = {Week.MON, Week.FRI}; PushPayload push = PushPayload.alertAll("test weekly example."); try { - ScheduleResult result = jPushClient.createWeeklySchedule(name, start, end, time, days, push); + ScheduleResult result = jPushClient.createWeeklySchedule(name, start, end, time, days, push, masterSecret, appKey); LOG.info("schedule result is " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later. ", e); @@ -96,7 +105,7 @@ public static void testCreateMonthlySchedule() { String[] points = {"01", "02"}; PushPayload push = PushPayload.alertAll("test monthly example."); try { - ScheduleResult result = jPushClient.createMonthlySchedule(name, start, end, time, points, push); + ScheduleResult result = jPushClient.createMonthlySchedule(name, start, end, time, points, push, masterSecret, appKey); LOG.info("schedule result is " + result); } catch (APIConnectionException e) { LOG.error("Connection error. Should retry later.", e); @@ -170,7 +179,7 @@ public static void testUpdateSchedule() { } public static void testGetSchedule() { - String scheduleId = "95bbd066-3a88-11e5-8e62-0021f652c102"; + String scheduleId = "13573bfa-cf5a-11e8-bd7f-0021f6b55802"; JPushClient jpushClient = new JPushClient(masterSecret, appKey); try { @@ -185,6 +194,23 @@ public static void testGetSchedule() { LOG.info("Error Message: " + e.getErrorMessage()); } } + + public static void testGetScheduleMsgIds() { + String scheduleId = "63db10a0-cf5b-11e8-ac2f-0021f6b55802"; + JPushClient jpushClient = new JPushClient(masterSecret, appKey); + + try { + ScheduleMsgIdsResult result = jpushClient.getScheduleMsgIds(scheduleId); + LOG.info("scheduleMsgIds :" + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } } diff --git a/example/main/java/cn/jpush/api/examples/adminExample.java b/example/main/java/cn/jpush/api/examples/adminExample.java new file mode 100644 index 00000000..a6f5bd86 --- /dev/null +++ b/example/main/java/cn/jpush/api/examples/adminExample.java @@ -0,0 +1,43 @@ +package cn.jpush.api.examples; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.admin.AdminClient; +import cn.jpush.api.file.model.FileType; +import cn.jpush.api.file.model.FileUploadResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class adminExample { + + protected static final Logger LOG = LoggerFactory.getLogger(DeviceExample.class); + + + /** + * Change the Dev key and Dev secret to your own account + * base64_auth_string 生成规则是:base64(dev_key:dev_secret), dev_key 及 dev_secret 请登录官网在开发者帐号页面获取; + */ + protected static final String DEV_KEY = "b924003f73a21f28b238fb12"; + protected static final String DEV_SECRET = "666a4a8284e62eef3b7aaf51"; + protected static final String APP_KEY = "e9fcfcf59eb3adb7e4dda56d"; + + public static void main(String[] args) { + testUploadCertificate(); + } + + public static void testUploadCertificate() { + AdminClient adminClient = new AdminClient(DEV_KEY, DEV_SECRET); + + try { + adminClient.uploadCertificate(APP_KEY, "test_push_cert.p12", "123456", null, null); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } +} diff --git a/pom.xml b/pom.xml index 5dd458ea..7a3330df 100644 --- a/pom.xml +++ b/pom.xml @@ -3,20 +3,12 @@ cn.jpush.api jpush-client - 3.2.6-SNAPSHOT + 3.7.8 jar https://github.com/jpush/jpush-api-java-client JPush API Java Client JPush's officially supported Java client library for accessing JPush APIs. - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - github UTF-8 @@ -35,11 +27,37 @@ https://github.com/jpush/jpush-api-java-client scm:git:git@github.com:jpush/jpush-api-java-client.git scm:git:git@github.com:jpush/jpush-api-java-client.git - v3.1.1 + v3.3.12 + + + + org.projectlombok + lombok + 1.18.6 + provided + + + + cn.jpush.api + jiguang-common + 1.2.7 + + org.apache.httpcomponents + httpclient + 4.5.3 + compile + + + io.netty + netty-all + 4.1.6.Final + compile + + com.google.code.gson gson 2.3 @@ -67,10 +85,22 @@ test - + + org.bouncycastle + bcprov-jdk15on + 1.60 + + + org.bouncycastle + bcpkix-jdk15on + 1.60 + + + + junit junit - 4.11 + 4.13.1 test @@ -79,147 +109,18 @@ 2.0.0 test + + org.mockito + mockito-core + 1.10.19 + test + + + org.hamcrest + hamcrest-core + 2.2 + test + - - - - maven-compiler-plugin - 3.1 - - ${jdkVersion} - ${jdkVersion} - 1.5 - true - true - true - true - - -Xlint:unchecked - - - - - - org.apache.maven.plugins - maven-release-plugin - 2.5.1 - - - org.apache.maven.plugins - maven-scm-plugin - 1.9.2 - - - - deploy,site - false - true - true - v@{project.version} - - - - - com.github.github - site-maven-plugin - 0.9 - - Creating site for ${project.version} - github - - - - - site - - site - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.17 - - UTF-8 - cn.jpush.api.FastTests - -Dfile.encoding=UTF-8 - - **/mock/*Test.java - - - - - org.apache.maven.surefire - surefire-junit47 - 2.17 - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.17 - - UTF-8 - cn.jpush.api.SlowTests - -Dfile.encoding=UTF-8 - - **/mock/*Test.java - - - - - - integration-test - verify - - - - **/*.class - - - - - - - org.apache.maven.surefire - surefire-junit47 - 2.17 - - - - - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.7 - - - - dependencies - license - scm - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - resources/javadoc-overview.html - - - - - diff --git a/src/main/java/cn/jpush/api/JPushClient.java b/src/main/java/cn/jpush/api/JPushClient.java index 270df3b1..e0b132b7 100644 --- a/src/main/java/cn/jpush/api/JPushClient.java +++ b/src/main/java/cn/jpush/api/JPushClient.java @@ -1,67 +1,100 @@ package cn.jpush.api; +import java.util.List; import java.util.Map; import java.util.Set; -import cn.jpush.api.common.ClientConfig; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.common.Week; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.BooleanResult; -import cn.jpush.api.common.resp.DefaultResult; +import cn.jiguang.common.resp.*; +import cn.jpush.api.push.CIDResult; +import cn.jpush.api.push.model.*; +import cn.jpush.api.push.model.live_activity.LiveActivity; +import cn.jpush.api.report.*; +import cn.jpush.api.report.model.CheckMessagePayload; +import com.google.gson.JsonObject; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.Week; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.connection.HttpProxy; import cn.jpush.api.device.AliasDeviceListResult; import cn.jpush.api.device.DeviceClient; +import cn.jpush.api.device.OnlineStatus; import cn.jpush.api.device.TagAliasResult; import cn.jpush.api.device.TagListResult; import cn.jpush.api.push.PushClient; import cn.jpush.api.push.PushResult; -import cn.jpush.api.push.model.Message; -import cn.jpush.api.push.model.Platform; -import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.push.model.audience.Audience; +import cn.jpush.api.push.model.notification.IosAlert; import cn.jpush.api.push.model.notification.Notification; -import cn.jpush.api.report.MessagesResult; -import cn.jpush.api.report.ReceivedsResult; -import cn.jpush.api.report.ReportClient; -import cn.jpush.api.report.UsersResult; import cn.jpush.api.schedule.ScheduleClient; import cn.jpush.api.schedule.ScheduleListResult; +import cn.jpush.api.schedule.ScheduleMsgIdsResult; import cn.jpush.api.schedule.ScheduleResult; import cn.jpush.api.schedule.model.SchedulePayload; import cn.jpush.api.schedule.model.TriggerPayload; -import cn.jpush.api.utils.Preconditions; /** * The global entrance of JPush API library. */ public class JPushClient { private final PushClient _pushClient; - private final ReportClient _reportClient; - private final DeviceClient _deviceClient; + private final ReportClient _reportClient; + private final DeviceClient _deviceClient; private final ScheduleClient _scheduleClient; - - /** - * Create a JPush Client. - * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. - */ - public JPushClient(String masterSecret, String appKey) { - _pushClient = new PushClient(masterSecret, appKey); - _reportClient = new ReportClient(masterSecret, appKey); - _deviceClient = new DeviceClient(masterSecret, appKey); + + /** + * Create a JPush Client. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + */ + public JPushClient(String masterSecret, String appKey) { + _pushClient = new PushClient(masterSecret, appKey); + _reportClient = new ReportClient(masterSecret, appKey); + _deviceClient = new DeviceClient(masterSecret, appKey); _scheduleClient = new ScheduleClient(masterSecret, appKey); - } - - public JPushClient(String masterSecret, String appKey, int maxRetryTimes) { + } + + /** + * Create a JPush Client by custom Client configuration. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param proxy The proxy, if there is no proxy, should be null. + * @param conf The client configuration. Can use ClientConfig.getInstance() as default. + */ + public JPushClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { + _pushClient = new PushClient(masterSecret, appKey, proxy, conf); + _reportClient = new ReportClient(masterSecret, appKey, proxy, conf); + _deviceClient = new DeviceClient(masterSecret, appKey, proxy, conf); + _scheduleClient = new ScheduleClient(masterSecret, appKey, proxy, conf); + } + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The max retry times. + */ + @Deprecated + public JPushClient(String masterSecret, String appKey, int maxRetryTimes) { _pushClient = new PushClient(masterSecret, appKey, maxRetryTimes); _reportClient = new ReportClient(masterSecret, appKey, maxRetryTimes); _deviceClient = new DeviceClient(masterSecret, appKey, maxRetryTimes); _scheduleClient = new ScheduleClient(masterSecret, appKey, maxRetryTimes); - } - + } + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The max retry times. + * @param proxy The proxy, if there is no proxy, should be null. + */ + @Deprecated public JPushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { _pushClient = new PushClient(masterSecret, appKey, maxRetryTimes, proxy); _reportClient = new ReportClient(masterSecret, appKey, maxRetryTimes, proxy); @@ -71,148 +104,231 @@ public JPushClient(String masterSecret, String appKey, int maxRetryTimes, HttpPr /** * Create a JPush Client by custom Client configuration. - * + *

* If you are using JPush privacy cloud, maybe this constructor is what you needed. + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. * @param maxRetryTimes Client request retry times. - * @param proxy The proxy, if there is no proxy, should be null. - * @param conf The client configuration. Can use ClientConfig.getInstance() as default. + * @param proxy The proxy, if there is no proxy, should be null. + * @param conf The client configuration. Can use ClientConfig.getInstance() as default. */ + @Deprecated public JPushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf) { - _pushClient = new PushClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _reportClient = new ReportClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _deviceClient = new DeviceClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _scheduleClient = new ScheduleClient(masterSecret, appKey, maxRetryTimes, proxy, conf); + conf.setMaxRetryTimes(maxRetryTimes); + + _pushClient = new PushClient(masterSecret, appKey, proxy, conf); + _reportClient = new ReportClient(masterSecret, appKey, proxy, conf); + _deviceClient = new DeviceClient(masterSecret, appKey, proxy, conf); + _scheduleClient = new ScheduleClient(masterSecret, appKey, proxy, conf); + } /** * Create a JPush Client by custom Client configuration with global settings. - * + *

* If you are using JPush privacy cloud, and you want different settings from default globally, * maybe this constructor is what you needed. + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setGlobalPushSetting} instead of this constructor. * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. - * @param maxRetryTimes Client request retry times. - * @param proxy The proxy, if there is no proxy, should be null. - * @param conf The client configuration. Can use ClientConfig.getInstance() as default. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes Client request retry times. + * @param proxy The proxy, if there is no proxy, should be null. + * @param conf The client configuration. Can use ClientConfig.getInstance() as default. * @param apnsProduction Global APNs environment setting. It will override PushPayload Options. - * @param timeToLive Global time_to_live setting. It will override PushPayload Options. + * @param timeToLive Global time_to_live setting. It will override PushPayload Options. */ + @Deprecated public JPushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf, boolean apnsProduction, long timeToLive) { - _pushClient = new PushClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _reportClient = new ReportClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _deviceClient = new DeviceClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _scheduleClient = new ScheduleClient(masterSecret, appKey, maxRetryTimes, proxy, conf); - _pushClient.setDefaults(apnsProduction, timeToLive); - } - - /** - * Create a JPush Client with global settings. - * - * If you want different settings from default globally, this constructor is what you needed. - * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. - * @param apnsProduction Global APNs environment setting. It will override PushPayload Options. - * @param timeToLive Global time_to_live setting. It will override PushPayload Options. - */ + conf.setMaxRetryTimes(maxRetryTimes); + conf.setApnsProduction(apnsProduction); + conf.setTimeToLive(timeToLive); + _pushClient = new PushClient(masterSecret, appKey, proxy, conf); + _reportClient = new ReportClient(masterSecret, appKey, proxy, conf); + _deviceClient = new DeviceClient(masterSecret, appKey, proxy, conf); + _scheduleClient = new ScheduleClient(masterSecret, appKey, proxy, conf); + } + + /** + * Create a JPush Client with global settings. + *

+ * If you want different settings from default globally, this constructor is what you needed. + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setGlobalPushSetting} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param apnsProduction Global APNs environment setting. It will override PushPayload Options. + * @param timeToLive Global time_to_live setting. It will override PushPayload Options. + */ + @Deprecated public JPushClient(String masterSecret, String appKey, boolean apnsProduction, long timeToLive) { - _pushClient = new PushClient(masterSecret, appKey, apnsProduction, timeToLive); + ClientConfig conf = ClientConfig.getInstance(); + conf.setApnsProduction(apnsProduction); + conf.setTimeToLive(timeToLive); + _pushClient = new PushClient(masterSecret, appKey); _reportClient = new ReportClient(masterSecret, appKey); _deviceClient = new DeviceClient(masterSecret, appKey); _scheduleClient = new ScheduleClient(masterSecret, appKey); } - - + + public PushClient getPushClient() { + return _pushClient; + } + // ----------------------------- Push API /** * Send a push with PushPayload object. - * - * @param pushPayload payload object of a push. + * + * @param pushPayload payload object of a push. * @return PushResult The result object of a Push. Can be printed to a JSON. - * @throws APIConnectionException - * @throws APIRequestException - */ - public PushResult sendPush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { - return _pushClient.sendPush(pushPayload); - } - - /** - * Send a push with JSON string. - * - * You can send a push JSON string directly with this method. - * - * Attention: globally settings cannot be affect this type of Push. - * - * @param payloadString payload of a push. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendPush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { + return _pushClient.sendPush(pushPayload); + } + + /** + * Send a push with JSON string. + *

+ * You can send a push JSON string directly with this method. + *

+ * Attention: globally settings cannot be affect this type of Push. + * + * @param payloadString payload of a push. * @return PushResult. Can be printed to a JSON. - * @throws APIConnectionException - * @throws APIRequestException - */ + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ public PushResult sendPush(String payloadString) throws APIConnectionException, APIRequestException { return _pushClient.sendPush(payloadString); } - + + /** + * Send a file push with PushPayload object. + * + * @param pushPayload payload object of a push. + * @return PushResult The result object of a Push. Can be printed to a JSON. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendFilePush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { + return _pushClient.sendFilePush(pushPayload); + } + /** * Validate a push action, but do NOT send it actually. - * - * @param paylaod - * @return - * @throws APIConnectionException - * @throws APIRequestException + * + * @param payload payload of a push. + * @return PushResult. Can be printed to a JSON. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendPushValidate(PushPayload paylaod) throws APIConnectionException, APIRequestException { - return _pushClient.sendPushValidate(paylaod); + public PushResult sendPushValidate(PushPayload payload) throws APIConnectionException, APIRequestException { + return _pushClient.sendPushValidate(payload); } public PushResult sendPushValidate(String payloadString) throws APIConnectionException, APIRequestException { - return _pushClient.sendPushValidate(payloadString); + return _pushClient.sendPushValidate(payloadString); + } + + public BatchPushResult batchSendPushByRegId(List pushPayloadList) throws APIConnectionException, APIRequestException { + return _pushClient.batchSendPushByRegId(pushPayloadList); } - + public BatchPushResult batchSendPushByAlias(List pushPayloadList) throws APIConnectionException, APIRequestException { + return _pushClient.batchSendPushByAlias(pushPayloadList); + } + + /** + * Get cid list, the data form of cid is appKey-uuid. + * + * @param count the count of cid list, from 1 to 1000. default is 1. + * @param type default is push, option: schedule + * @return CIDResult, an array of cid + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public CIDResult getCidList(int count, String type) throws APIConnectionException, APIRequestException { + return _pushClient.getCidList(count, type); + } + + // ------------------------------- Report API /** - * Get received report. - * + * Get received report. + * * @param msgIds 100 msgids to batch getting is supported. * @return ReceivedResult. Can be printed to JSON. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ReceivedsResult getReportReceiveds(String msgIds) throws APIConnectionException, APIRequestException { - return _reportClient.getReceiveds(msgIds); - } - + return _reportClient.getReceiveds(msgIds); + } + public UsersResult getReportUsers(TimeUnit timeUnit, String start, int duration) throws APIConnectionException, APIRequestException { return _reportClient.getUsers(timeUnit, start, duration); } - + public MessagesResult getReportMessages(String msgIds) throws APIConnectionException, APIRequestException { return _reportClient.getMessages(msgIds); } - - + + public Map getMessageStatus(CheckMessagePayload payload) + throws APIConnectionException, APIRequestException { + return _reportClient.getMessagesStatus(payload); + } + + public ReceivedsResult getReceivedsDetail(String msgIds) + throws APIConnectionException, APIRequestException { + return _reportClient.getReceivedsDetail(msgIds); + } + + public MessageDetailResult getMessagesDetail(String msgIds) + throws APIConnectionException, APIRequestException { + return _reportClient.getMessagesDetail(msgIds); + } + + public GroupMessageDetailResult getGroupMessagesDetail(String groupMsgIds) + throws APIConnectionException, APIRequestException { + return _reportClient.getGroupMessagesDetail(groupMsgIds); + } + + public GroupUsersResult getGroupReportUsers(TimeUnit timeUnit, String start, int duration) throws APIConnectionException, + APIRequestException { + return _reportClient.getGroupUsers(timeUnit, start, duration); + } + // ------------------------------ Shortcuts - notification - - /** - * Shortcut - */ + public PushResult sendNotificationAll(String alert) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.alertAll(alert); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send a notification to all. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The notification content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @return push result + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendAndroidNotificationWithAlias(String title, String alert, - Map extras, String... alias) + public PushResult sendNotificationAll(String alert, SMS sms) throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.alertAll(alert, sms); + return _pushClient.sendPush(payload); + } + + public PushResult sendAndroidNotificationWithAlias(String title, String alert, + Map extras, String... alias) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.android()) @@ -221,26 +337,163 @@ public PushResult sendAndroidNotificationWithAlias(String title, String alert, .build(); return _pushClient.sendPush(payload); } - + + /** + * Send a notification to Android with alias. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The notification title. + * @param alert The notification content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra parameter. + * @param alias The users' alias. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendAndroidNotificationWithAlias(String title, String alert, SMS sms, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.android(alert, title, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendAndroidNotificationWithRegistrationID(String title, String alert, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.android(alert, title, extras)) + .build(); + return _pushClient.sendPush(payload); + } + /** - * Shortcut + * Send a notification to Android with RegistrationID. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The notification title. + * @param alert The notification content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra parameter. + * @param registrationID The registration id generated by JPush. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendAndroidNotificationWithRegistrationID(String title, String alert, - Map extras, String... registrationID) + public PushResult sendAndroidNotificationWithRegistrationID(String title, String alert, SMS sms, + Map extras, String... registrationID) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.android()) .setAudience(Audience.registrationId(registrationID)) .setNotification(Notification.android(alert, title, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendIosNotificationWithAlias(String alert, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.ios(alert, extras)) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send a notification to iOS with alias. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The notification content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra parameter. + * @param alias The users' alias. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithAlias(String alert, SMS sms, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with alias. + * If you want to send alert as a Json object, maybe this method is what you needed. + * + * @param alert The wrapper of APNs alert. + * @param extras The extra params. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithAlias(IosAlert alert, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.ios(alert, extras)) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with alias. + * If you want to send alert as a Json object, maybe this method is what you needed. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The wrapper of APNs alert. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra params. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithAlias(IosAlert alert, SMS sms, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) .build(); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send an iOS notification with alias. + * If you want to send alert as a Json object, maybe this method is what you needed. + * + * @param alert The JSON object of APNs alert. + * @param extras The extra params. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendIosNotificationWithAlias(String alert, - Map extras, String... alias) + public PushResult sendIosNotificationWithAlias(JsonObject alert, + Map extras, String... alias) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.ios()) @@ -249,12 +502,80 @@ public PushResult sendIosNotificationWithAlias(String alert, .build(); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send an iOS notification with alias. + * If you want to send alert as a Json object, maybe this method is what you needed. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The JSON object of APNs alert. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra params. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendIosNotificationWithRegistrationID(String alert, - Map extras, String... registrationID) + public PushResult sendIosNotificationWithAlias(JsonObject alert, SMS sms, + Map extras, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendIosNotificationWithRegistrationID(String alert, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.ios(alert, extras)) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with registrationIds. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The notification content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra params. + * @param registrationID The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithRegistrationID(String alert, SMS sms, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with registrationIds. + * If you want to send alert as a Json object, maybe this method is what you needed. + * + * @param alert The wrapper of APNs alert. + * @param extras The extra params. + * @param registrationID The registration ids. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithRegistrationID(IosAlert alert, + Map extras, String... registrationID) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.ios()) @@ -264,21 +585,102 @@ public PushResult sendIosNotificationWithRegistrationID(String alert, return _pushClient.sendPush(payload); } - - // ---------------------- shortcuts - message - /** - * Shortcut + * Send an iOS notification with registrationIds. + * If you want to send alert as a Json object, maybe this method is what you needed. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The wrapper of APNs alert. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra params. + * @param registrationID The registration ids. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ + public PushResult sendIosNotificationWithRegistrationID(IosAlert alert, SMS sms, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with registrationIds. + * If you want to send alert as a Json object, maybe this method is what you needed. + * + * @param alert The wrapper of APNs alert. + * @param extras The extra params. + * @param registrationID The registration ids. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithRegistrationID(JsonObject alert, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.ios(alert, extras)) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS notification with registrationIds. + * If you want to send alert as a Json object, maybe this method is what you needed. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param alert The JSON object of APNs alert. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param extras The extra params. + * @param registrationID The registration ids. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosNotificationWithRegistrationID(JsonObject alert, SMS sms, + Map extras, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setNotification(Notification.ios(alert, extras)) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + + // ---------------------- shortcuts - message + public PushResult sendMessageAll(String msgContent) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.messageAll(msgContent); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send a message to all + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendAndroidMessageWithAlias(String title, String msgContent, String... alias) + public PushResult sendMessageAll(String msgContent, SMS sms) throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.messageAll(msgContent, sms); + return _pushClient.sendPush(payload); + } + + public PushResult sendAndroidMessageWithAlias(String title, String msgContent, String... alias) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.android()) @@ -290,11 +692,34 @@ public PushResult sendAndroidMessageWithAlias(String title, String msgContent, S .build(); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send an Android message with alias. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The message title. + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendAndroidMessageWithRegistrationID(String title, String msgContent, String... registrationID) + public PushResult sendAndroidMessageWithAlias(String title, String msgContent, SMS sms, String... alias) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.alias(alias)) + .setMessage(Message.newBuilder() + .setTitle(title) + .setMsgContent(msgContent) + .build()) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendAndroidMessageWithRegistrationID(String title, String msgContent, String... registrationID) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.android()) @@ -306,11 +731,34 @@ public PushResult sendAndroidMessageWithRegistrationID(String title, String msgC .build(); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send an Android message with registration id. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The message title. + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param registrationID The registration id list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendIosMessageWithAlias(String title, String msgContent, String... alias) + public PushResult sendAndroidMessageWithRegistrationID(String title, String msgContent, SMS sms, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.registrationId(registrationID)) + .setMessage(Message.newBuilder() + .setTitle(title) + .setMsgContent(msgContent) + .build()) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendIosMessageWithAlias(String title, String msgContent, String... alias) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.ios()) @@ -322,14 +770,76 @@ public PushResult sendIosMessageWithAlias(String title, String msgContent, Strin .build(); return _pushClient.sendPush(payload); } - + /** - * Shortcut + * Send an iOS message with alias. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The message title. + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param alias The alias list. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendIosMessageWithRegistrationID(String title, String msgContent, String... registrationID) + public PushResult sendIosMessageWithAlias(String title, String msgContent, SMS sms, String... alias) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.ios()) + .setAudience(Audience.alias(alias)) + .setMessage(Message.newBuilder() + .setTitle(title) + .setMsgContent(msgContent) + .build()) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendIosMessageWithRegistrationID(String title, String msgContent, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setMessage(Message.newBuilder() + .setTitle(title) + .setMsgContent(msgContent) + .build()) + .build(); + return _pushClient.sendPush(payload); + } + + /** + * Send an iOS message with registration id. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The message title. + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param registrationID The registrationIds generated by JPush. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public PushResult sendIosMessageWithRegistrationID(String title, String msgContent, SMS sms, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.ios()) + .setAudience(Audience.registrationId(registrationID)) + .setMessage(Message.newBuilder() + .setTitle(title) + .setMsgContent(msgContent) + .build()) + .setSMS(sms) + .build(); + return _pushClient.sendPush(payload); + } + + public PushResult sendMessageWithRegistrationID(String title, String msgContent, String... registrationID) + throws APIConnectionException, APIRequestException { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.all()) .setAudience(Audience.registrationId(registrationID)) .setMessage(Message.newBuilder() .setTitle(title) @@ -340,9 +850,18 @@ public PushResult sendIosMessageWithRegistrationID(String title, String msgConte } /** - * Shortcut + * Send a message with registrationIds. + * If it doesn't received within the delay time,JPush will send a SMS to the corresponding users. + * + * @param title The message title. + * @param msgContent The message content. + * @param sms The SMS content and delay time. If null, sms doesn't work, no effect on Push feature. + * @param registrationID The registrationIds generated by JPush. + * @return push result. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public PushResult sendMessageWithRegistrationID(String title, String msgContent, String... registrationID) + public PushResult sendMessageWithRegistrationID(String title, String msgContent, SMS sms, String... registrationID) throws APIConnectionException, APIRequestException { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) @@ -351,74 +870,105 @@ public PushResult sendMessageWithRegistrationID(String title, String msgContent, .setTitle(title) .setMsgContent(msgContent) .build()) + .setSMS(sms) .build(); return _pushClient.sendPush(payload); } + /** + * Delete a push by msgId. + * + * @param msgId The message id + * @return delete result + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs + */ + public DefaultResult deletePush(String msgId) throws APIConnectionException, APIRequestException { + return _pushClient.deletePush(msgId); + } + - // ----------------------- Device - - public TagAliasResult getDeviceTagAlias(String registrationId) - throws APIConnectionException, APIRequestException { - return _deviceClient.getDeviceTagAlias(registrationId); + + public TagAliasResult getDeviceTagAlias(String registrationId) + throws APIConnectionException, APIRequestException { + return _deviceClient.getDeviceTagAlias(registrationId); } public DefaultResult updateDeviceTagAlias(String registrationId, boolean clearAlias, boolean clearTag) - throws APIConnectionException, APIRequestException { - return _deviceClient.updateDeviceTagAlias(registrationId, clearAlias, clearTag); + throws APIConnectionException, APIRequestException { + return _deviceClient.updateDeviceTagAlias(registrationId, clearAlias, clearTag); + } + + public DefaultResult updateDeviceTagAlias(String registrationId, String alias, + Set tagsToAdd, Set tagsToRemove) + throws APIConnectionException, APIRequestException { + return _deviceClient.updateDeviceTagAlias(registrationId, alias, tagsToAdd, tagsToRemove); + } + + public TagListResult getTagList() + throws APIConnectionException, APIRequestException { + return _deviceClient.getTagList(); } - - public DefaultResult updateDeviceTagAlias(String registrationId, String alias, - Set tagsToAdd, Set tagsToRemove) + + public BooleanResult isDeviceInTag(String theTag, String registrationID) throws APIConnectionException, APIRequestException { - return _deviceClient.updateDeviceTagAlias(registrationId, alias, tagsToAdd, tagsToRemove); + return _deviceClient.isDeviceInTag(theTag, registrationID); } - public TagListResult getTagList() - throws APIConnectionException, APIRequestException { - return _deviceClient.getTagList(); - } + public DefaultResult addRemoveDevicesFromTag(String theTag, + Set toAddUsers, Set toRemoveUsers) + throws APIConnectionException, APIRequestException { + return _deviceClient.addRemoveDevicesFromTag(theTag, toAddUsers, + toRemoveUsers); + } - public BooleanResult isDeviceInTag(String theTag, String registrationID) - throws APIConnectionException, APIRequestException { - return _deviceClient.isDeviceInTag(theTag, registrationID); - } + public DefaultResult deleteTag(String theTag, String platform) + throws APIConnectionException, APIRequestException { + return _deviceClient.deleteTag(theTag, platform); + } - public DefaultResult addRemoveDevicesFromTag(String theTag, - Set toAddUsers, Set toRemoveUsers) - throws APIConnectionException, APIRequestException { - return _deviceClient.addRemoveDevicesFromTag(theTag, toAddUsers, - toRemoveUsers); - } + public AliasDeviceListResult getAliasDeviceList(String alias, + String platform) throws APIConnectionException, APIRequestException { + return _deviceClient.getAliasDeviceList(alias, platform); + } - public DefaultResult deleteTag(String theTag, String platform) - throws APIConnectionException, APIRequestException { - return _deviceClient.deleteTag(theTag, platform); - } + public DefaultResult deleteAlias(String alias, String platform) + throws APIConnectionException, APIRequestException { + return _deviceClient.deleteAlias(alias, platform); + } - public AliasDeviceListResult getAliasDeviceList(String alias, - String platform) throws APIConnectionException, APIRequestException { - return _deviceClient.getAliasDeviceList(alias, platform); - } + public DefaultResult removeDevicesFromAlias(String alias, Set toRemoveDevice) + throws APIConnectionException, APIRequestException { + return _deviceClient.removeDevicesFromAlias(alias, toRemoveDevice); + } - public DefaultResult deleteAlias(String alias, String platform) - throws APIConnectionException, APIRequestException { - return _deviceClient.deleteAlias(alias, platform); - } + public Map getUserOnlineStatus(String... registrationIds) + throws APIConnectionException, APIRequestException { + return _deviceClient.getUserOnlineStatus(registrationIds); + } + + public DefaultResult bindMobile(String registrationId, String mobile) + throws APIConnectionException, APIRequestException { + return _deviceClient.bindMobile(registrationId, mobile); + } // ----------------------- Schedule /** * Create a single schedule. - * @param name The schedule name. - * @param time The push time, format is 'yyyy-MM-dd HH:mm:ss' - * @param push The push payload. + * + * @param name The schedule name. + * @param time The push time, format is 'yyyy-MM-dd HH:mm:ss' + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createSingleSchedule(String name, String time, PushPayload push) + public ScheduleResult createSingleSchedule(String name, String time, PushPayload push, String masterSecret, + String appKey) throws APIConnectionException, APIRequestException { TriggerPayload trigger = TriggerPayload.newBuilder() .setSingleTime(time) @@ -430,143 +980,185 @@ public ScheduleResult createSingleSchedule(String name, String time, PushPayload .setPush(push) .build(); - return _scheduleClient.createSchedule(payload); + return _scheduleClient.createSchedule(payload, masterSecret, appKey); } /** * Create a daily schedule push everyday. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss' - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss' + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createDailySchedule(String name, String start, String end, String time, PushPayload push) + public ScheduleResult createDailySchedule(String name, String start, String end, String time, PushPayload push, + String masterSecret, String appKey) throws APIConnectionException, APIRequestException { - return createPeriodicalSchedule(name, start, end, time, TimeUnit.DAY, 1, null, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.DAY, 1, null, push, + masterSecret, appKey); } /** * Create a daily schedule push with a custom frequency. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss' - * @param frequency The custom frequency. - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss' + * @param frequency The custom frequency. + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createDailySchedule(String name, String start, String end, String time, int frequency, PushPayload push) + public ScheduleResult createDailySchedule(String name, String start, String end, String time, int frequency, + PushPayload push, String masterSecret, String appKey) throws APIConnectionException, APIRequestException { - return createPeriodicalSchedule(name, start, end, time, TimeUnit.DAY, frequency, null, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.DAY, frequency, null, push, + masterSecret, appKey); } /** * Create a weekly schedule push every week at the appointed days. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss' - * @param days The appointed days. - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss' + * @param days The appointed days. + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createWeeklySchedule(String name, String start, String end, String time, Week[] days, PushPayload push) + public ScheduleResult createWeeklySchedule(String name, String start, String end, String time, Week[] days, + PushPayload push, String masterSecret, String appKey) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(null != days && days.length > 0, "The days must not be empty."); String[] points = new String[days.length]; - for(int i = 0 ; i < days.length; i++) { + for (int i = 0; i < days.length; i++) { points[i] = days[i].name(); } - return createPeriodicalSchedule(name, start, end, time, TimeUnit.WEEK, 1, points, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.WEEK, 1, points, push, + masterSecret, appKey); } /** * Create a weekly schedule push with a custom frequency at the appointed days. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss'. - * @param frequency The custom frequency. - * @param days The appointed days. - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss'. + * @param frequency The custom frequency. + * @param days The appointed days. + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createWeeklySchedule(String name, String start, String end, String time, int frequency, Week[] days, PushPayload push) + public ScheduleResult createWeeklySchedule(String name, String start, String end, String time, int frequency, + Week[] days, PushPayload push, String masterSecret, String appKey) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(null != days && days.length > 0, "The days must not be empty."); String[] points = new String[days.length]; - for(int i = 0 ; i < days.length; i++) { + for (int i = 0; i < days.length; i++) { points[i] = days[i].name(); } - return createPeriodicalSchedule(name, start, end, time, TimeUnit.WEEK, frequency, points, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.WEEK, frequency, points, push, masterSecret, appKey); } /** * Create a monthly schedule push every month at the appointed days. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss'. - * @param points The appointed days. - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss'. + * @param points The appointed days. + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createMonthlySchedule(String name, String start, String end, String time, String[] points, PushPayload push) + public ScheduleResult createMonthlySchedule(String name, String start, String end, String time, String[] points, + PushPayload push, String masterSecret, String appKey) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(null != points && points.length > 0, "The points must not be empty."); - return createPeriodicalSchedule(name, start, end, time, TimeUnit.MONTH, 1, points, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.MONTH, 1, points, push, masterSecret, appKey); } /** * Create a monthly schedule push with a custom frequency at the appointed days. - * @param name The schedule name. - * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. - * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. - * @param time The push time, format 'HH:mm:ss'. - * @param frequency The custom frequency. - * @param points The appointed days. - * @param push The push payload. + * + * @param name The schedule name. + * @param start The schedule comes into effect date, format 'yyyy-MM-dd HH:mm:ss'. + * @param end The schedule expiration date, format 'yyyy-MM-dd HH:mm:ss'. + * @param time The push time, format 'HH:mm:ss'. + * @param frequency The custom frequency. + * @param points The appointed days. + * @param push The push payload. + * @param masterSecret master secret + * @param appKey app key * @return The created scheduleResult instance. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ - public ScheduleResult createMonthlySchedule(String name, String start, String end, String time, int frequency, String[] points, PushPayload push) + public ScheduleResult createMonthlySchedule(String name, String start, String end, String time, int frequency, String[] points, + PushPayload push, String masterSecret, String appKey) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(null != points && points.length > 0, "The points must not be empty."); - return createPeriodicalSchedule(name, start, end, time, TimeUnit.MONTH, frequency, points, push); + return createPeriodicalSchedule(name, start, end, time, TimeUnit.MONTH, frequency, points, push, masterSecret, appKey); } /** * Get the schedule information by the schedule id. + * * @param scheduleId The schedule id. * @return The schedule information. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult getSchedule(String scheduleId) throws APIConnectionException, APIRequestException { - return _scheduleClient.getSchedule(scheduleId); + return _scheduleClient.getSchedule(scheduleId); + } + + /** + * Get the message id by the schedule id. + * + * @param scheduleId The schedule id. + * @return The message id list. + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. + */ + public ScheduleMsgIdsResult getScheduleMsgIds(String scheduleId) + throws APIConnectionException, APIRequestException { + return _scheduleClient.getScheduleMsgIds(scheduleId); } /** * Get the schedule list size and the first page. + * * @return The schedule list size and the first page. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleListResult getScheduleList() throws APIConnectionException, APIRequestException { @@ -575,10 +1167,11 @@ public ScheduleListResult getScheduleList() /** * Get the schedule list by the page. + * * @param page The page to search. * @return The schedule list of the appointed page. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleListResult getScheduleList(int page) throws APIConnectionException, APIRequestException { @@ -587,11 +1180,12 @@ public ScheduleListResult getScheduleList(int page) /** * Update the schedule name + * * @param scheduleId The schedule id. - * @param name The new name. + * @param name The new name. * @return The schedule information after updated. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult updateScheduleName(String scheduleId, String name) throws APIConnectionException, APIRequestException { @@ -604,10 +1198,11 @@ public ScheduleResult updateScheduleName(String scheduleId, String name) /** * Enable the schedule. + * * @param scheduleId The schedule id. * @return The schedule information after updated. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult enableSchedule(String scheduleId) throws APIConnectionException, APIRequestException { @@ -620,10 +1215,11 @@ public ScheduleResult enableSchedule(String scheduleId) /** * Disable the schedule. + * * @param scheduleId The schedule id. * @return The schedule information after updated. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult disableSchedule(String scheduleId) throws APIConnectionException, APIRequestException { @@ -635,11 +1231,12 @@ public ScheduleResult disableSchedule(String scheduleId) /** * Update the trigger of the schedule. + * * @param scheduleId The schedule id. - * @param trigger The new trigger. + * @param trigger The new trigger. * @return The schedule information after updated. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult updateScheduleTrigger(String scheduleId, TriggerPayload trigger) throws APIConnectionException, APIRequestException { @@ -652,11 +1249,12 @@ public ScheduleResult updateScheduleTrigger(String scheduleId, TriggerPayload tr /** * Update the push content of the schedule. + * * @param scheduleId The schedule id. - * @param push The new push payload. + * @param push The new push payload. * @return The schedule information after updated. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult updateSchedulePush(String scheduleId, PushPayload push) throws APIConnectionException, APIRequestException { @@ -669,11 +1267,12 @@ public ScheduleResult updateSchedulePush(String scheduleId, PushPayload push) /** * Update a schedule by the id. + * * @param scheduleId The schedule id to update. - * @param payload The new schedule payload. + * @param payload The new schedule payload. * @return The new schedule information. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public ScheduleResult updateSchedule(String scheduleId, SchedulePayload payload) throws APIConnectionException, APIRequestException { @@ -682,9 +1281,10 @@ public ScheduleResult updateSchedule(String scheduleId, SchedulePayload payload) /** * Delete a schedule by id. + * * @param scheduleId The schedule id. - * @throws APIConnectionException - * @throws APIRequestException + * @throws APIConnectionException if a remote or network exception occurs. + * @throws APIRequestException if a request exception occurs. */ public void deleteSchedule(String scheduleId) throws APIConnectionException, APIRequestException { @@ -692,11 +1292,12 @@ public void deleteSchedule(String scheduleId) } private ScheduleResult createPeriodicalSchedule(String name, String start, String end, String time, - TimeUnit timeUnit, int frequency, String[] point, PushPayload push) + TimeUnit timeUnit, int frequency, String[] point, PushPayload push, + String masterSecret, String appKey) throws APIConnectionException, APIRequestException { TriggerPayload trigger = TriggerPayload.newBuilder() .setPeriodTime(start, end, time) - .setTimeFrequency(timeUnit, frequency, point ) + .setTimeFrequency(timeUnit, frequency, point) .buildPeriodical(); SchedulePayload payload = SchedulePayload.newBuilder() .setName(name) @@ -705,8 +1306,17 @@ private ScheduleResult createPeriodicalSchedule(String name, String start, Strin .setPush(push) .build(); - return _scheduleClient.createSchedule(payload); + return _scheduleClient.createSchedule(payload, masterSecret, appKey); } + public PushResult sendLiveActivity(LiveActivity liveActivity) throws APIConnectionException, APIRequestException { + return _pushClient.sendLiveActivity(liveActivity); + } + + public void close() { + _pushClient.close(); + } + + } diff --git a/src/main/java/cn/jpush/api/JPushConfig.java b/src/main/java/cn/jpush/api/JPushConfig.java new file mode 100644 index 00000000..930e1e72 --- /dev/null +++ b/src/main/java/cn/jpush/api/JPushConfig.java @@ -0,0 +1,39 @@ +package cn.jpush.api; + +import cn.jiguang.common.ClientConfig; + +public class JPushConfig { + + private static ClientConfig clientConfig = ClientConfig.getInstance(); + + private static JPushConfig instance = new JPushConfig(); + + public static final String ADMIN_HOST_NAME = "api.admin.host.name"; + public static final String V1_APP_PATH = "jpush.v1.app.path"; + + private JPushConfig() { + clientConfig.put(ADMIN_HOST_NAME, "https://admin.jpush.cn"); + clientConfig.put(V1_APP_PATH, "/v1/app"); + } + + public static JPushConfig getInstance() { + return instance; + } + + public ClientConfig getClientConfig() { + return clientConfig; + } + + public JPushConfig setAdminHostName(String hostName) { + clientConfig.put(ADMIN_HOST_NAME, hostName); + return this; + } + + public void put(String key, Object value) { + clientConfig.put(key, value); + } + + public Object get(String key) { + return clientConfig.get(key); + } +} diff --git a/src/main/java/cn/jpush/api/admin/AdminClient.java b/src/main/java/cn/jpush/api/admin/AdminClient.java new file mode 100644 index 00000000..57bce1c2 --- /dev/null +++ b/src/main/java/cn/jpush/api/admin/AdminClient.java @@ -0,0 +1,134 @@ +package cn.jpush.api.admin; + +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.DefaultResult; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Preconditions; +import cn.jpush.api.JPushConfig; +import cn.jpush.api.file.FileClient; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Admin APIs + * https://docs.jiguang.cn/jpush/server/push/rest_api_admin_api_v1/ + */ +public class AdminClient { + + protected static final Logger LOG = LoggerFactory.getLogger(FileClient.class); + + + private IHttpClient mHttpClient; + private String mBasePath; + private String mV1AppPath; + private Gson mGson = new Gson(); + + /** + * Create a Push Client. + * + * @param appKey The KEY of one application on JPush. + * @param masterSecret API access secret of the appKey. + */ + public AdminClient(String appKey, String masterSecret) { + this(appKey, masterSecret, null, JPushConfig.getInstance()); + } + + public AdminClient(String appKey, String masterSecret, HttpProxy proxy) { + this(appKey, masterSecret, proxy, JPushConfig.getInstance()); + } + + + public AdminClient(String appKey, String masterSecret, HttpProxy proxy, JPushConfig conf) { + ServiceHelper.checkBasic(appKey, masterSecret); + mBasePath = (String) conf.get(JPushConfig.ADMIN_HOST_NAME); + mV1AppPath = (String) conf.get(JPushConfig.V1_APP_PATH); + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this.mHttpClient = new NativeHttpClient(authCode, proxy, conf.getClientConfig()); + } + + public void setHttpClient(IHttpClient client) { + this.mHttpClient = client; + } + + /** + * Create an app under developer account + * @param appName app name + * @param packageName android package name + * @param groupName developer app group name + * @return {@link CreateAppResult} + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public CreateAppResult createApp(String appName, String packageName, String groupName) + throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(null != appName, "app name should not be null"); + Preconditions.checkArgument(null != packageName, "package name should not be null"); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("app_name", appName); + jsonObject.addProperty("android_package", packageName); + if (null != groupName) { + jsonObject.addProperty("group_name", groupName); + } + ResponseWrapper responseWrapper = mHttpClient.sendPost(mBasePath + mV1AppPath, mGson.toJson(jsonObject)); + return CreateAppResult.fromResponse(responseWrapper, CreateAppResult.class); + } + + /** + * Delete app by app key + * @param appKey app key + * @return {@link AppResult} + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public AppResult deleteApp(String appKey) throws APIConnectionException, APIRequestException { + ResponseWrapper responseWrapper = mHttpClient.sendDelete(mBasePath + mV1AppPath + "/" + appKey + "/delete"); + return DefaultResult.fromResponse(responseWrapper, AppResult.class); + } + + /** + * Upload certificate + * @param appKey app key + * @param devCertificatePassword dev certificate password + * @param proCertificatePassword pro certificate password + * @param devCertificateFile dev certificate file + * @param proCertificateFile pro certificate file + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public void uploadCertificate(String appKey, String devCertificateFile, String devCertificatePassword, + String proCertificateFile, String proCertificatePassword) + throws APIConnectionException, APIRequestException { + + Preconditions.checkArgument(devCertificateFile != null || proCertificateFile != null, + "dev certificate file or pro certificate file should not be null"); + + NativeHttpClient client = (NativeHttpClient) mHttpClient; + String url = mBasePath + mV1AppPath + "/" + appKey + "/certificate"; + + Map fileMap = new HashMap(); + Map textMap = new HashMap(); + + if(devCertificateFile != null) { + textMap.put("devCertificatePassword", devCertificatePassword); + fileMap.put("devCertificateFile", devCertificateFile); + } + + if(proCertificateFile != null) { + textMap.put("proCertificatePassword", proCertificatePassword); + fileMap.put("proCertificateFile", proCertificateFile); + } + + String response = client.formUploadByPost(url, textMap, fileMap, null); + LOG.info("uploadFile:{}", response); + } +} diff --git a/src/main/java/cn/jpush/api/admin/AppResult.java b/src/main/java/cn/jpush/api/admin/AppResult.java new file mode 100644 index 00000000..8b22e585 --- /dev/null +++ b/src/main/java/cn/jpush/api/admin/AppResult.java @@ -0,0 +1,13 @@ +package cn.jpush.api.admin; + +import cn.jiguang.common.resp.BaseResult; +import com.google.gson.annotations.Expose; + +public class AppResult extends BaseResult { + + @Expose private String success; + + public String getSuccess() { + return success; + } +} diff --git a/src/main/java/cn/jpush/api/admin/CreateAppResult.java b/src/main/java/cn/jpush/api/admin/CreateAppResult.java new file mode 100644 index 00000000..64846452 --- /dev/null +++ b/src/main/java/cn/jpush/api/admin/CreateAppResult.java @@ -0,0 +1,22 @@ +package cn.jpush.api.admin; + +import cn.jiguang.common.resp.BaseResult; +import com.google.gson.annotations.Expose; + +public class CreateAppResult extends BaseResult { + @Expose private String app_key; + @Expose private boolean is_new_created; + @Expose private String android_package; + + public String getApp_key() { + return app_key; + } + + public boolean is_new_created() { + return is_new_created; + } + + public String getAndroid_package() { + return android_package; + } +} diff --git a/src/main/java/cn/jpush/api/common/ClientConfig.java b/src/main/java/cn/jpush/api/common/ClientConfig.java deleted file mode 100644 index 97eaf9de..00000000 --- a/src/main/java/cn/jpush/api/common/ClientConfig.java +++ /dev/null @@ -1,117 +0,0 @@ -package cn.jpush.api.common; - -import java.util.HashMap; -import java.util.Map; - -public class ClientConfig extends HashMap { - - private static ClientConfig instance = new ClientConfig(); - - public static final String DEVICE_HOST_NAME = "device.host.name"; - public static final Object DEVICE_HOST_NAME_SCHEMA = String.class; - - public static final String DEVICES_PATH = "devices.path"; - public static final Object DEVICES_PATH_SCHEMA = String.class; - - public static final String TAGS_PATH = "tags.path"; - public static final Object TAGS_PATH_SCHEMA = String.class; - - public static final String ALIASES_PATH = "aliases.path"; - public static final Object ALIASES_PATH_SCHEMA = String.class; - - public static final String PUSH_HOST_NAME = "push.host.name"; - public static final Object PUSH_HOST_NAME_SCHEMA = String.class; - - public static final String PUSH_PATH = "push.path"; - public static final Object PUSH_PATH_SCHEMA = String.class; - - public static final String PUSH_VALIDATE_PATH = "push.validate.path"; - public static final Object PUSH_VALIDATE_PATH_SCHMEA = String.class; - - public static final String REPORT_HOST_NAME = "report.host.name"; - public static final Object REPORT_HOST_NAME_SCHEMA = String.class; - - public static final String REPORT_RECEIVE_PATH = "report.receive.path"; - public static final Object REPORT_RECEIVE_PATH_SCHEMA = String.class; - - public static final String REPORT_USER_PATH = "report.user.path"; - public static final Object REPORT_USER_PATH_SCHEMA = String.class; - - public static final String REPORT_MESSAGE_PATH = "report.message.path"; - public static final Object REPORT_MESSAGE_PATH_SCHEMA = String.class; - - public static final String SCHEDULE_HOST_NAME = "schedule.host.name"; - public static final Object SCHEDULE_HOST_NAME_SCHEMA = String.class; - - public static final String SCHEDULE_PATH = "schedule.path"; - public static final Object SCHEDULE_PATH_SCHEMA = String.class; - - private ClientConfig() { - super(12); - this.put(DEVICE_HOST_NAME, "https://device.jpush.cn"); - this.put(DEVICES_PATH, "/v3/devices"); - this.put(TAGS_PATH, "/v3/tags"); - this.put(ALIASES_PATH, "/v3/aliases"); - - this.put(PUSH_HOST_NAME, "https://api.jpush.cn"); - this.put(PUSH_PATH, "/v3/push"); - this.put(PUSH_VALIDATE_PATH, "/v3/push/validate"); - - this.put(REPORT_HOST_NAME, "https://report.jpush.cn"); - this.put(REPORT_RECEIVE_PATH, "/v3/received"); - this.put(REPORT_USER_PATH, "/v3/users"); - this.put(REPORT_MESSAGE_PATH, "/v3/messages"); - - this.put(SCHEDULE_HOST_NAME, "https://api.jpush.cn"); - this.put(SCHEDULE_PATH, "/v3/schedules"); - } - - public static ClientConfig getInstance() { - return instance; - } - - public static void setDeviceHostName(Map conf, String hostName) { - conf.put(DEVICE_HOST_NAME, hostName); - } - - /** - * Setup custom device api host name, if using the JPush privacy cloud. - * @param hostName the custom api host name, default is JPush domain name - */ - public void setDeviceHostName(String hostName) { - setDeviceHostName(this, hostName); - } - - public static void setPushHostName(Map conf, String hostName) { - conf.put(PUSH_HOST_NAME, hostName); - } - - /** - * Setup custom push api host name, if using the JPush privacy cloud. - * @param hostName the custom api host name, default is JPush domain name - */ - public void setPushHostName(String hostName) { - setPushHostName(this, hostName); - } - - public static void setReportHostName(Map conf, String hostName) { - conf.put(REPORT_HOST_NAME, hostName); - } - - /** - * Setup custom report api host name, if using the JPush privacy cloud. - * @param hostName the custom api host name, default is JPush domain name - */ - public void setReportHostName(String hostName) { - setReportHostName(this, hostName); - } - - public static void setScheduleHostName(Map conf, String hostName) { - conf.put(SCHEDULE_HOST_NAME, hostName); - } - - public void setScheduleHostName(String hostName) { - setScheduleHostName(this, hostName); - } - -} diff --git a/src/main/java/cn/jpush/api/common/DeviceType.java b/src/main/java/cn/jpush/api/common/DeviceType.java deleted file mode 100644 index 1170fd14..00000000 --- a/src/main/java/cn/jpush/api/common/DeviceType.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.jpush.api.common; - -public enum DeviceType { - - Android("android"), - IOS("ios"), - WinPhone("winphone"); - - private final String value; - - private DeviceType(final String value) { - this.value = value; - } - - public String value() { - return this.value; - } - -} diff --git a/src/main/java/cn/jpush/api/common/ServiceHelper.java b/src/main/java/cn/jpush/api/common/ServiceHelper.java deleted file mode 100644 index ad905d14..00000000 --- a/src/main/java/cn/jpush/api/common/ServiceHelper.java +++ /dev/null @@ -1,94 +0,0 @@ -package cn.jpush.api.common; - -import java.text.SimpleDateFormat; -import java.util.Random; -import java.util.Set; -import java.util.regex.Pattern; - -import cn.jpush.api.utils.Base64; -import cn.jpush.api.utils.StringUtils; - -import com.google.gson.JsonArray; -import com.google.gson.JsonPrimitive; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ServiceHelper { - - private static final Logger LOG = LoggerFactory.getLogger(ServiceHelper.class); - private final static Pattern PUSH_PATTERNS = Pattern.compile("[^a-zA-Z0-9]"); - private final static String BASIC_PREFIX = "Basic"; - - private static final Random RANDOM = new Random(System.currentTimeMillis()); - private static final int MIN = 100000; - private static final int MAX = Integer.MAX_VALUE; - - private static final int MAX_BADGE_NUMBER = 99999; - - private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9][a-zA-Z_0-9.、。@,-]*"); - private static final Pattern DATE_PATTERN = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}"); - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); - - static { - DATE_FORMAT.setLenient(false); - } - - public static boolean isValidIntBadge(int intBadge) { - if (intBadge >= 0 && intBadge <= MAX_BADGE_NUMBER) { - return true; - } - return false; - } - - public static int generateSendno() { - return RANDOM.nextInt((MAX - MIN) + 1) + MIN; - } - - public static String getBasicAuthorization(String username, String password) { - String encodeKey = username + ":" + password; - return BASIC_PREFIX + " " + String.valueOf(Base64.encode(encodeKey.getBytes())); - } - - public static void checkBasic(String appKey, String masterSecret) { - if (StringUtils.isEmpty(appKey) - || StringUtils.isEmpty(masterSecret)) { - throw new IllegalArgumentException("appKey and masterSecret are both required."); - } - if (appKey.length() != 24 - || masterSecret.length() != 24 - || PUSH_PATTERNS.matcher(appKey).find() - || PUSH_PATTERNS.matcher(masterSecret).find()) { - throw new IllegalArgumentException("appKey and masterSecret format is incorrect. " - + "They should be 24 size, and be composed with alphabet and numbers. " - + "Please confirm that they are coming from JPush Web Portal."); - } - } - - public static JsonArray fromSet(Set sets) { - JsonArray array = new JsonArray(); - if (null != sets && sets.size() > 0) { - for (String item : sets) { - array.add(new JsonPrimitive(item)); - } - } - return array; - } - - public static boolean checkUsername(String username) { - return USERNAME_PATTERN.matcher(username).matches(); - } - - public static boolean isValidBirthday( String birthday) { - try { - if( ! DATE_PATTERN.matcher(birthday).matches() ) { - return false; - } - DATE_FORMAT.parse(birthday); - } catch (Exception e) { - LOG.error("incorrect date format. " + birthday, e); - return false; - } - return true; - } - -} diff --git a/src/main/java/cn/jpush/api/common/TimeUnit.java b/src/main/java/cn/jpush/api/common/TimeUnit.java deleted file mode 100644 index 7d6ca3b8..00000000 --- a/src/main/java/cn/jpush/api/common/TimeUnit.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.jpush.api.common; - -public enum TimeUnit { - - HOUR, - DAY, - MONTH, - WEEK - -} diff --git a/src/main/java/cn/jpush/api/common/Week.java b/src/main/java/cn/jpush/api/common/Week.java deleted file mode 100644 index df04313a..00000000 --- a/src/main/java/cn/jpush/api/common/Week.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.jpush.api.common; - -public enum Week { - MON, - TUE, - WED, - THU, - FRI, - SAT, - SUN -} diff --git a/src/main/java/cn/jpush/api/common/connection/HttpProxy.java b/src/main/java/cn/jpush/api/common/connection/HttpProxy.java deleted file mode 100644 index 376eec70..00000000 --- a/src/main/java/cn/jpush/api/common/connection/HttpProxy.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.jpush.api.common.connection; - -import java.net.InetSocketAddress; -import java.net.Proxy; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.utils.Preconditions; - -public class HttpProxy { - private static final Logger LOG = LoggerFactory.getLogger(HttpProxy.class); - - private String host; - private int port; - private String username; - private String password; - - private boolean authenticationNeeded = false; - - public HttpProxy(String host, int port) { - this.host = host; - this.port = port; - } - - public HttpProxy(String host, int port, String username, String password) { - this(host, port); - - Preconditions.checkArgument(! (null == username), "username should not be null"); - Preconditions.checkArgument(! (null == password), "password should not be null"); - - this.username = username; - this.password = password; - authenticationNeeded = true; - - LOG.info("Http Proxy - host:" + host + ", port:" + port - + ", username:" + username + ", password:" + password); - } - - - public Proxy getNetProxy() { - return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); - } - - public boolean isAuthenticationNeeded() { - return this.authenticationNeeded; - } - - public String getProxyAuthorization() { - return ServiceHelper.getBasicAuthorization(username, password); - } - - public String getUsername() { - return this.username; - } - - public String getPassword() { - return this.password; - } -} diff --git a/src/main/java/cn/jpush/api/common/connection/IHttpClient.java b/src/main/java/cn/jpush/api/common/connection/IHttpClient.java deleted file mode 100644 index 38f33629..00000000 --- a/src/main/java/cn/jpush/api/common/connection/IHttpClient.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.jpush.api.common.connection; - -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.ResponseWrapper; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -public interface IHttpClient { - - public static final String CHARSET = "UTF-8"; - public static final String CONTENT_TYPE_JSON = "application/json"; - public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"; - - public static final String RATE_LIMIT_QUOTA = "X-Rate-Limit-Limit"; - public static final String RATE_LIMIT_Remaining = "X-Rate-Limit-Remaining"; - public static final String RATE_LIMIT_Reset = "X-Rate-Limit-Reset"; - public static final String JPUSH_USER_AGENT = "JPush-API-Java-Client"; - - public static final int RESPONSE_OK = 200; - - public enum RequestMethod { - GET, - POST, - PUT, - DELETE - } - - public static final String IO_ERROR_MESSAGE = "Connection IO error. \n" - + "Can not connect to JPush Server. " - + "Please ensure your internet connection is ok. \n" - + "If the problem persists, please let us know at support@jpush.cn."; - - public static final String CONNECT_TIMED_OUT_MESSAGE = "connect timed out. \n" - + "Connect to JPush Server timed out, and already retried some times. \n" - + "Please ensure your internet connection is ok. \n" - + "If the problem persists, please let us know at support@jpush.cn."; - - public static final String READ_TIMED_OUT_MESSAGE = "Read timed out. \n" - + "Read response from JPush Server timed out. \n" - + "If this is a Push action, you may not want to retry. \n" - + "It may be due to slowly response from JPush server, or unstable connection. \n" - + "If the problem persists, please let us know at support@jpush.cn."; - - public static Gson _gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - - - //设置连接超时时间 - public static final int DEFAULT_CONNECTION_TIMEOUT = (5 * 1000); // milliseconds - - //设置读取超时时间 - public static final int DEFAULT_READ_TIMEOUT = (30 * 1000); // milliseconds - - public static final int DEFAULT_MAX_RETRY_TIMES = 3; - - public ResponseWrapper sendGet(String url) - throws APIConnectionException, APIRequestException; - - public ResponseWrapper sendDelete(String url) - throws APIConnectionException, APIRequestException; - - public ResponseWrapper sendPost(String url, String content) - throws APIConnectionException, APIRequestException; - - - public ResponseWrapper sendPut(String url, String content) - throws APIConnectionException, APIRequestException; -} diff --git a/src/main/java/cn/jpush/api/common/connection/NativeHttpClient.java b/src/main/java/cn/jpush/api/common/connection/NativeHttpClient.java deleted file mode 100644 index eb52944d..00000000 --- a/src/main/java/cn/jpush/api/common/connection/NativeHttpClient.java +++ /dev/null @@ -1,324 +0,0 @@ -package cn.jpush.api.common.connection; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.Authenticator; -import java.net.HttpURLConnection; -import java.net.PasswordAuthentication; -import java.net.SocketTimeoutException; -import java.net.URL; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.ResponseWrapper; - -/** - * The implementation has no connection pool mechanism, used origin java connection. - * - * 本实现没有连接池机制,基于 Java 原始的 HTTP 连接实现。 - * - * 遇到连接超时,会自动重连指定的次数(默认为 3);如果是读取超时,则不会自动重连。 - * - * 可选支持 HTTP 代理,同时支持 2 种方式:1) HTTP 头上加上 Proxy-Authorization 信息;2)全局配置 Authenticator.setDefault; - */ -public class NativeHttpClient implements IHttpClient { - private static final Logger LOG = LoggerFactory.getLogger(NativeHttpClient.class); - private static final String KEYWORDS_CONNECT_TIMED_OUT = "connect timed out"; - private static final String KEYWORDS_READ_TIMED_OUT = "Read timed out"; - - private int _maxRetryTimes = 0; - private String _authCode; - private HttpProxy _proxy; - - /** - * 默认的重连次数是 3 - */ - public NativeHttpClient(String authCode) { - this(authCode, DEFAULT_MAX_RETRY_TIMES, null); - } - - public NativeHttpClient(String authCode, int maxRetryTimes, HttpProxy proxy) { - this._maxRetryTimes = maxRetryTimes; - LOG.info("Created instance with _maxRetryTimes = " + _maxRetryTimes); - - this._authCode = authCode; - this._proxy = proxy; - - if ( null != _proxy && _proxy.isAuthenticationNeeded()) { - Authenticator.setDefault(new SimpleProxyAuthenticator( - _proxy.getUsername(), _proxy.getPassword())); - } - - initSSL(); - } - - public ResponseWrapper sendGet(String url) - throws APIConnectionException, APIRequestException { - return doRequest(url, null, RequestMethod.GET); - } - - public ResponseWrapper sendDelete(String url) - throws APIConnectionException, APIRequestException { - return doRequest(url, null, RequestMethod.DELETE); - } - - public ResponseWrapper sendPost(String url, String content) - throws APIConnectionException, APIRequestException { - return doRequest(url, content, RequestMethod.POST); - } - - public ResponseWrapper sendPut(String url, String content) - throws APIConnectionException, APIRequestException { - return doRequest(url, content, RequestMethod.PUT); - } - - public ResponseWrapper doRequest(String url, String content, - RequestMethod method) throws APIConnectionException, APIRequestException { - ResponseWrapper response = null; - for (int retryTimes = 0; ; retryTimes++) { - try { - response = _doRequest(url, content, method); - break; - } catch (SocketTimeoutException e) { - if (KEYWORDS_READ_TIMED_OUT.equals(e.getMessage())) { - // Read timed out. For push, maybe should not re-send. - throw new APIConnectionException(READ_TIMED_OUT_MESSAGE, e, true); - } else { // connect timed out - if (retryTimes >= _maxRetryTimes) { - throw new APIConnectionException(CONNECT_TIMED_OUT_MESSAGE, e, retryTimes); - } else { - LOG.debug("connect timed out - retry again - " + (retryTimes + 1)); - } - } - } - } - return response; - } - - private ResponseWrapper _doRequest(String url, String content, - RequestMethod method) throws APIConnectionException, APIRequestException, - SocketTimeoutException { - - LOG.debug("Send request - " + method.toString() + " "+ url); - if (null != content) { - LOG.debug("Request Content - " + content); - } - - HttpURLConnection conn = null; - OutputStream out = null; - StringBuffer sb = new StringBuffer(); - ResponseWrapper wrapper = new ResponseWrapper(); - - try { - URL aUrl = new URL(url); - - if (null != _proxy) { - conn = (HttpURLConnection) aUrl.openConnection(_proxy.getNetProxy()); - if (_proxy.isAuthenticationNeeded()) { - conn.setRequestProperty("Proxy-Authorization", _proxy.getProxyAuthorization()); - } - } else { - conn = (HttpURLConnection) aUrl.openConnection(); - } - - conn.setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT); - conn.setReadTimeout(DEFAULT_READ_TIMEOUT); - conn.setUseCaches(false); - conn.setRequestMethod(method.name()); - conn.setRequestProperty("User-Agent", JPUSH_USER_AGENT); - conn.setRequestProperty("Connection", "Keep-Alive"); - conn.setRequestProperty("Accept-Charset", CHARSET); - conn.setRequestProperty("Charset", CHARSET); - conn.setRequestProperty("Authorization", _authCode); - conn.setRequestProperty("Content-Type", CONTENT_TYPE_JSON); - - if (RequestMethod.GET == method) { - conn.setDoOutput(false); - } else if (RequestMethod.DELETE == method) { - conn.setDoOutput(false); - } else if (RequestMethod.POST == method || RequestMethod.PUT == method) { - conn.setDoOutput(true); - byte[] data = content.getBytes(CHARSET); - conn.setRequestProperty("Content-Length", String.valueOf(data.length)); - out = conn.getOutputStream(); - out.write(data); - out.flush(); - } - - int status = conn.getResponseCode(); - InputStream in = null; - if (status / 100 == 2) { - in = conn.getInputStream(); - } else { - in = conn.getErrorStream(); - } - - if (null != in) { - InputStreamReader reader = new InputStreamReader(in, CHARSET); - char[] buff = new char[1024]; - int len; - while ((len = reader.read(buff)) > 0) { - sb.append(buff, 0, len); - } - } - - String responseContent = sb.toString(); - wrapper.responseCode = status; - wrapper.responseContent = responseContent; - - String quota = conn.getHeaderField(RATE_LIMIT_QUOTA); - String remaining = conn.getHeaderField(RATE_LIMIT_Remaining); - String reset = conn.getHeaderField(RATE_LIMIT_Reset); - wrapper.setRateLimit(quota, remaining, reset); - - if (status >= 200 && status < 300) { - LOG.debug("Succeed to get response OK - responseCode:" + status); - LOG.debug("Response Content - " + responseContent); - - } else if (status >= 300 && status < 400) { - LOG.warn("Normal response but unexpected - responseCode:" + status + ", responseContent:" + responseContent); - - } else { - LOG.warn("Got error response - responseCode:" + status + ", responseContent:" + responseContent); - - switch (status) { - case 400: - LOG.error("Your request params is invalid. Please check them according to error message."); - wrapper.setErrorObject(); - break; - case 401: - LOG.error("Authentication failed! Please check authentication params according to docs."); - wrapper.setErrorObject(); - break; - case 403: - LOG.error("Request is forbidden! Maybe your appkey is listed in blacklist or your params is invalid."); - wrapper.setErrorObject(); - break; - case 404: - LOG.error("Request page is not found! Maybe your params is invalid."); - wrapper.setErrorObject(); - break; - case 410: - LOG.error("Request resource is no longer in service. Please according to notice on official website."); - wrapper.setErrorObject(); - case 429: - LOG.error("Too many requests! Please review your appkey's request quota."); - wrapper.setErrorObject(); - break; - case 500: - case 502: - case 503: - case 504: - LOG.error("Seems encountered server error. Maybe JPush is in maintenance? Please retry later."); - break; - default: - LOG.error("Unexpected response."); - } - - throw new APIRequestException(wrapper); - } - - } catch (SocketTimeoutException e) { - if (e.getMessage().contains(KEYWORDS_CONNECT_TIMED_OUT)) { - throw e; - } else if (e.getMessage().contains(KEYWORDS_READ_TIMED_OUT)) { - throw new SocketTimeoutException(KEYWORDS_READ_TIMED_OUT); - } - LOG.debug(IO_ERROR_MESSAGE, e); - throw new APIConnectionException(IO_ERROR_MESSAGE, e); - - } catch (IOException e) { - LOG.debug(IO_ERROR_MESSAGE, e); - throw new APIConnectionException(IO_ERROR_MESSAGE, e); - - } finally { - if (null != out) { - try { - out.close(); - } catch (IOException e) { - LOG.error("Failed to close stream.", e); - } - } - if (null != conn) { - conn.disconnect(); - } - } - - return wrapper; - } - - protected void initSSL() { - TrustManager[] tmCerts = new javax.net.ssl.TrustManager[1]; - tmCerts[0] = new SimpleTrustManager(); - try { - SSLContext sslContext = SSLContext.getInstance("SSL"); - sslContext.init(null, tmCerts, null); - HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); - - HostnameVerifier hostnameVerifier = new SimpleHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); - } catch (Exception e) { - LOG.error("Init SSL error", e); - } - } - - - private static class SimpleHostnameVerifier implements HostnameVerifier { - - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - - } - - private static class SimpleTrustManager implements TrustManager, X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - return; - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - return; - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - private static class SimpleProxyAuthenticator extends java.net.Authenticator { - private String username; - private String password; - - public SimpleProxyAuthenticator(String username, String password) { - this.username = username; - this.password = password; - } - - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication( - this.username, - this.password.toCharArray()); - } - } -} diff --git a/src/main/java/cn/jpush/api/common/resp/APIConnectionException.java b/src/main/java/cn/jpush/api/common/resp/APIConnectionException.java deleted file mode 100644 index ac000006..00000000 --- a/src/main/java/cn/jpush/api/common/resp/APIConnectionException.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.jpush.api.common.resp; - -/** - * Should retry for encountering this exception basically. - * Normally it is due to: - * 1. Connect timed out. - * 2. Read timed out. - * 3. Cannot parse domain. - * - * For Push action, if the exception is "Read timed out" you may not want to retry it. - */ -public class APIConnectionException extends Exception { - private static final long serialVersionUID = -2615370590441195647L; - private boolean readTimedout = false; - private int doneRetriedTimes = 0; - - public APIConnectionException(String message, Throwable e) { - super(message, e); - } - - public APIConnectionException(String message, Throwable e, int doneRetriedTimes) { - super(message, e); - this.doneRetriedTimes = doneRetriedTimes; - } - - public APIConnectionException(String message, Throwable e, boolean readTimedout) { - super(message, e); - this.readTimedout = readTimedout; - } - - public boolean isReadTimedout() { - return readTimedout; - } - - public int getDoneRetriedTimes() { - return this.doneRetriedTimes; - } -} - - diff --git a/src/main/java/cn/jpush/api/common/resp/APIRequestException.java b/src/main/java/cn/jpush/api/common/resp/APIRequestException.java deleted file mode 100644 index 341e436b..00000000 --- a/src/main/java/cn/jpush/api/common/resp/APIRequestException.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.jpush.api.common.resp; - -import cn.jpush.api.common.resp.ResponseWrapper.ErrorObject; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -public class APIRequestException extends Exception implements IRateLimiting { - private static final long serialVersionUID = -3921022835186996212L; - - protected static Gson _gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - - private final ResponseWrapper responseWrapper; - - public APIRequestException(ResponseWrapper responseWrapper) { - super(responseWrapper.responseContent); - this.responseWrapper = responseWrapper; - } - - public int getStatus() { - return this.responseWrapper.responseCode; - } - - public long getMsgId() { - ErrorObject eo = getErrorObject(); - if (null != eo) { - return eo.msg_id; - } - return 0; - } - - public int getErrorCode() { - ErrorObject eo = getErrorObject(); - if (null != eo && null != eo.error) { - return eo.error.code; - } - return -1; - } - - public String getErrorMessage() { - ErrorObject eo = getErrorObject(); - if (null != eo && null != eo.error) { - return eo.error.message; - } - return null; - } - - @Override - public String toString() { - return _gson.toJson(this); - } - - private ErrorObject getErrorObject() { - return this.responseWrapper.error; - } - - - @Override - public int getRateLimitQuota() { - return responseWrapper.rateLimitQuota; - } - - @Override - public int getRateLimitRemaining() { - return responseWrapper.rateLimitRemaining; - } - - @Override - public int getRateLimitReset() { - return responseWrapper.rateLimitReset; - } - -} - diff --git a/src/main/java/cn/jpush/api/common/resp/BaseResult.java b/src/main/java/cn/jpush/api/common/resp/BaseResult.java deleted file mode 100644 index b980fdd5..00000000 --- a/src/main/java/cn/jpush/api/common/resp/BaseResult.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.jpush.api.common.resp; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -public abstract class BaseResult implements IRateLimiting { - public static final int ERROR_CODE_NONE = -1; - public static final int ERROR_CODE_OK = 0; - public static final String ERROR_MESSAGE_NONE = "None error message."; - - protected static final int RESPONSE_OK = 200; - protected static Gson _gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); - - private ResponseWrapper responseWrapper; - - public void setResponseWrapper(ResponseWrapper responseWrapper) { - this.responseWrapper = responseWrapper; - } - - public String getOriginalContent() { - if (null != responseWrapper) { - return responseWrapper.responseContent; - } - return null; - } - - public boolean isResultOK() { - return RESPONSE_OK == responseWrapper.responseCode; - } - - public static T fromResponse( - ResponseWrapper responseWrapper, Class clazz) { - T result = null; - - if (responseWrapper.isServerResponse()) { - result = _gson.fromJson(responseWrapper.responseContent, clazz); - } else { - try { - result = clazz.newInstance(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - - result.setResponseWrapper(responseWrapper); - - return result; - } - - - @Override - public int getRateLimitQuota() { - if (null != responseWrapper) { - return responseWrapper.rateLimitQuota; - } - return 0; - } - - @Override - public int getRateLimitRemaining() { - if (null != responseWrapper) { - return responseWrapper.rateLimitRemaining; - } - return 0; - } - - @Override - public int getRateLimitReset() { - if (null != responseWrapper) { - return responseWrapper.rateLimitReset; - } - return 0; - } - - @Override - public String toString() { - return _gson.toJson(this); - } - - -} diff --git a/src/main/java/cn/jpush/api/common/resp/BooleanResult.java b/src/main/java/cn/jpush/api/common/resp/BooleanResult.java deleted file mode 100644 index 8487577c..00000000 --- a/src/main/java/cn/jpush/api/common/resp/BooleanResult.java +++ /dev/null @@ -1,9 +0,0 @@ -package cn.jpush.api.common.resp; - -import com.google.gson.annotations.Expose; - -public class BooleanResult extends DefaultResult { - - @Expose public boolean result; - -} diff --git a/src/main/java/cn/jpush/api/common/resp/DefaultResult.java b/src/main/java/cn/jpush/api/common/resp/DefaultResult.java deleted file mode 100644 index 951b9e73..00000000 --- a/src/main/java/cn/jpush/api/common/resp/DefaultResult.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.jpush.api.common.resp; - -public class DefaultResult extends BaseResult { - - public static DefaultResult fromResponse(ResponseWrapper responseWrapper) { - DefaultResult result = null; - - if (responseWrapper.isServerResponse()) { - result = new DefaultResult(); - } - - result.setResponseWrapper(responseWrapper); - - return result; - } - -} diff --git a/src/main/java/cn/jpush/api/common/resp/IRateLimiting.java b/src/main/java/cn/jpush/api/common/resp/IRateLimiting.java deleted file mode 100644 index 4d91dd82..00000000 --- a/src/main/java/cn/jpush/api/common/resp/IRateLimiting.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.jpush.api.common.resp; - -public interface IRateLimiting { - - public int getRateLimitQuota(); - - public int getRateLimitRemaining(); - - public int getRateLimitReset(); - -} - diff --git a/src/main/java/cn/jpush/api/common/resp/ResponseWrapper.java b/src/main/java/cn/jpush/api/common/resp/ResponseWrapper.java deleted file mode 100644 index 40fd1d9d..00000000 --- a/src/main/java/cn/jpush/api/common/resp/ResponseWrapper.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.jpush.api.common.resp; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ResponseWrapper { - private static final Logger LOG = LoggerFactory.getLogger(ResponseWrapper.class); - private static final int RESPONSE_CODE_NONE = -1; - - private static Gson _gson = new Gson(); - private static JsonParser jsonParser = new JsonParser(); - - public int responseCode = RESPONSE_CODE_NONE; - public String responseContent; - - public ErrorObject error; // error for non-200 response, used by new API - - public int rateLimitQuota; - public int rateLimitRemaining; - public int rateLimitReset; - - public void setRateLimit(String quota, String remaining, String reset) { - if (null == quota) return; - - try { - rateLimitQuota = Integer.parseInt(quota); - rateLimitRemaining = Integer.parseInt(remaining); - rateLimitReset = Integer.parseInt(reset); - - LOG.debug("JPush API Rate Limiting params - quota:" + quota + ", remaining:" + remaining + ", reset:" + reset); - } catch (NumberFormatException e) { - LOG.debug("Unexpected - parse rate limiting headers error."); - } - } - - public void setErrorObject() { - error = new ErrorObject(); - error.error = new ErrorEntity(); - try { - JsonElement element = jsonParser.parse(responseContent); - JsonObject errorObj = null; - if( element instanceof JsonArray) { - JsonArray array = (JsonArray) element; - for(int i = 0; i < array.size(); i++) { - if(array.get(i).getAsJsonObject().has("error")) { - errorObj = array.get(i).getAsJsonObject(); - break; - } - } - } else if(element instanceof JsonObject) { - errorObj = (JsonObject) element; - } else { - // nothing - } - if(null != errorObj) { - JsonObject errorMsg = errorObj; - if(errorObj.has("msg_id")) { - error.msg_id = errorObj.get("msg_id").getAsLong(); - } - if (errorObj.has("error")) { - errorMsg = (JsonObject) errorObj.get("error"); - } - if(errorMsg.has("code")) { - error.error.code = errorMsg.get("code").getAsInt(); - } - if(errorMsg.has("message")) { - error.error.message = errorMsg.get("message").getAsString(); - } - } - } catch(JsonSyntaxException e) { - LOG.error("Unexpected - responseContent:" + responseContent, e); - } catch (Exception e) { - LOG.error("Unexpected - responseContent:" + responseContent, e); - } - } - - public boolean isServerResponse() { - if (responseCode / 100 == 2) return true; - if (responseCode > 0 && null != error && error.error.code > 0) return true; - return false; - } - - @Override - public String toString() { - return _gson.toJson(this); - } - - public static class ErrorObject { - public long msg_id; - public ErrorEntity error; - } - - public static class ErrorEntity { - public int code; - public String message; - - @Override - public String toString() { - return _gson.toJson(this); - } - } - -} diff --git a/src/main/java/cn/jpush/api/device/AliasDeviceListResult.java b/src/main/java/cn/jpush/api/device/AliasDeviceListResult.java index be960e8b..259971b4 100644 --- a/src/main/java/cn/jpush/api/device/AliasDeviceListResult.java +++ b/src/main/java/cn/jpush/api/device/AliasDeviceListResult.java @@ -3,10 +3,10 @@ import java.util.ArrayList; import java.util.List; -import cn.jpush.api.common.resp.BaseResult; - import com.google.gson.annotations.Expose; +import cn.jiguang.common.resp.BaseResult; + public class AliasDeviceListResult extends BaseResult { @Expose public List registration_ids = new ArrayList(); diff --git a/src/main/java/cn/jpush/api/device/DeviceClient.java b/src/main/java/cn/jpush/api/device/DeviceClient.java index 0f4d1edf..c834a7a4 100644 --- a/src/main/java/cn/jpush/api/device/DeviceClient.java +++ b/src/main/java/cn/jpush/api/device/DeviceClient.java @@ -1,23 +1,27 @@ package cn.jpush.api.device; +import java.lang.reflect.Type; +import java.util.Map; import java.util.Set; -import cn.jpush.api.common.ClientConfig; -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.connection.IHttpClient; -import cn.jpush.api.common.connection.NativeHttpClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.BaseResult; -import cn.jpush.api.common.resp.BooleanResult; -import cn.jpush.api.common.resp.DefaultResult; -import cn.jpush.api.common.resp.ResponseWrapper; -import cn.jpush.api.utils.Preconditions; - +import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.google.gson.reflect.TypeToken; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.BooleanResult; +import cn.jiguang.common.resp.DefaultResult; +import cn.jiguang.common.resp.ResponseWrapper; public class DeviceClient { @@ -28,26 +32,54 @@ public class DeviceClient { private String aliasesPath; public DeviceClient(String masterSecret, String appKey) { - this(masterSecret, appKey, IHttpClient.DEFAULT_MAX_RETRY_TIMES); + this(masterSecret, appKey, null, ClientConfig.getInstance()); } - + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The max retry times. + * + */ + @Deprecated public DeviceClient(String masterSecret, String appKey, int maxRetryTimes) { this(masterSecret, appKey, maxRetryTimes, null); } - + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The max retry times. + * @param proxy The HTTP proxy. + * + */ + @Deprecated public DeviceClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { - this(masterSecret, appKey, maxRetryTimes, proxy, ClientConfig.getInstance()); + ClientConfig conf = ClientConfig.getInstance(); + conf.setMaxRetryTimes(maxRetryTimes); + ServiceHelper.checkBasic(appKey, masterSecret); + + hostName = (String) conf.get(ClientConfig.DEVICE_HOST_NAME); + devicesPath = (String) conf.get(ClientConfig.DEVICES_PATH); + tagsPath = (String) conf.get(ClientConfig.TAGS_PATH); + aliasesPath = (String) conf.get(ClientConfig.ALIASES_PATH); + + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + _httpClient = new NativeHttpClient(authCode, proxy, conf); + } /** + * Create a Device Client by client configuration. * * @param masterSecret API access secret of the appKey. * @param appKey The KEY of one application on JPush. - * @param maxRetryTimes Max retry times * @param proxy The proxy, if there is no proxy, should be null. * @param conf The client configuration. Can use ClientConfig.getInstance() as default. */ - public DeviceClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf) { + public DeviceClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { ServiceHelper.checkBasic(appKey, masterSecret); hostName = (String) conf.get(ClientConfig.DEVICE_HOST_NAME); @@ -56,7 +88,7 @@ public DeviceClient(String masterSecret, String appKey, int maxRetryTimes, HttpP aliasesPath = (String) conf.get(ClientConfig.ALIASES_PATH); String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); - _httpClient = new NativeHttpClient(authCode, maxRetryTimes, proxy); + _httpClient = new NativeHttpClient(authCode, proxy, conf); } // -------------- device @@ -116,6 +148,22 @@ public DefaultResult updateDeviceTagAlias(String registrationId, String alias, return DefaultResult.fromResponse(response); } + public DefaultResult bindMobile(String registrationId, String mobile) + throws APIConnectionException, APIRequestException { + if ( StringUtils.isEmpty(mobile) ) { + // delete bind while mobile is empty. + mobile = ""; + } else { +// Preconditions.checkArgument(StringUtils.isMobileNumber(mobile), "The mobile format is incorrect. " + mobile); + } + + String url = hostName + devicesPath + "/" + registrationId; + JsonObject top = new JsonObject(); + top.addProperty("mobile", mobile); + ResponseWrapper response = _httpClient.sendPost(url, top.toString()); + return DefaultResult.fromResponse(response); + } + // ------------- tags public TagListResult getTagList() throws APIConnectionException, APIRequestException { @@ -196,6 +244,50 @@ public DefaultResult deleteAlias(String alias, String platform) throws APIConnec return DefaultResult.fromResponse(response); } + + public DefaultResult removeDevicesFromAlias(String alias, Set toRemoveDevice) throws APIConnectionException, APIRequestException { + String url = hostName + aliasesPath + "/" + alias; + + JsonObject top = new JsonObject(); + JsonObject registrationIds = new JsonObject(); + + if (null != toRemoveDevice && toRemoveDevice.size() > 0) { + JsonArray array = new JsonArray(); + for (String device : toRemoveDevice) { + array.add(new JsonPrimitive(device)); + } + registrationIds.add("remove", array); + } + + top.add("registration_ids", registrationIds); + + ResponseWrapper response = _httpClient.sendPost(url, top.toString()); + + return DefaultResult.fromResponse(response); + } + + // -------------- devices status + + public Map getUserOnlineStatus(String... registrationIds) + throws APIConnectionException, APIRequestException + { + Preconditions.checkArgument((null != registrationIds ), + "The registration id list should not be null."); + Preconditions.checkArgument(registrationIds.length > 0 && registrationIds.length <= 1000, + "The length of registration id list should between 1 and 1000."); + + String url = hostName + devicesPath + "/status"; + JsonObject json = new JsonObject(); + JsonArray array = new JsonArray(); + for(int i = 0; i < registrationIds.length; i++) { + array.add(new JsonPrimitive(registrationIds[i])); + } + json.add("registration_ids", array); + Type type = new TypeToken>(){}.getType(); + ResponseWrapper response = _httpClient.sendPost(url, json.toString()); + Map map = new Gson().fromJson(response.responseContent, type); + return map; + } } diff --git a/src/main/java/cn/jpush/api/device/OnlineStatus.java b/src/main/java/cn/jpush/api/device/OnlineStatus.java new file mode 100644 index 00000000..7b2fcdba --- /dev/null +++ b/src/main/java/cn/jpush/api/device/OnlineStatus.java @@ -0,0 +1,35 @@ +package cn.jpush.api.device; + +import java.io.Serializable; + +public class OnlineStatus implements Serializable { + + private static final long serialVersionUID = -5436655826293828109L; + + private Boolean online; + private String last_online_time; + + public Boolean getOnline() { + return online; + } + + public void setOnline(Boolean online) { + this.online = online; + } + + public String getLast_online_time() { + return last_online_time; + } + + public void setLast_online_time(String last_online_time) { + this.last_online_time = last_online_time; + } + + @Override + public String toString() { + if(null == last_online_time) { + return "status: " + online; + } + return "status: " + online + " , last_online_time: " + last_online_time; + } +} diff --git a/src/main/java/cn/jpush/api/device/TagAliasResult.java b/src/main/java/cn/jpush/api/device/TagAliasResult.java index 569fff1e..18d92c19 100644 --- a/src/main/java/cn/jpush/api/device/TagAliasResult.java +++ b/src/main/java/cn/jpush/api/device/TagAliasResult.java @@ -2,12 +2,13 @@ import java.util.List; -import cn.jpush.api.common.resp.BaseResult; - import com.google.gson.annotations.Expose; +import cn.jiguang.common.resp.BaseResult; + public class TagAliasResult extends BaseResult { + private static final long serialVersionUID = -4765083329495728276L; @Expose public List tags; @Expose public String alias; diff --git a/src/main/java/cn/jpush/api/device/TagListResult.java b/src/main/java/cn/jpush/api/device/TagListResult.java index 426ee47d..fce2f6db 100644 --- a/src/main/java/cn/jpush/api/device/TagListResult.java +++ b/src/main/java/cn/jpush/api/device/TagListResult.java @@ -3,12 +3,13 @@ import java.util.ArrayList; import java.util.List; -import cn.jpush.api.common.resp.BaseResult; - import com.google.gson.annotations.Expose; +import cn.jiguang.common.resp.BaseResult; + public class TagListResult extends BaseResult { - + + private static final long serialVersionUID = -5395153728332839175L; @Expose public List tags = new ArrayList(); } diff --git a/src/main/java/cn/jpush/api/file/FileClient.java b/src/main/java/cn/jpush/api/file/FileClient.java new file mode 100644 index 00000000..da1ac10f --- /dev/null +++ b/src/main/java/cn/jpush/api/file/FileClient.java @@ -0,0 +1,98 @@ +package cn.jpush.api.file; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.file.model.FileModel; +import cn.jpush.api.file.model.FileModelPage; +import cn.jpush.api.file.model.FileType; +import cn.jpush.api.file.model.FileUploadResult; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author daixuan + * @version 2020/2/23 19:38 + */ +public class FileClient { + + protected static final Logger LOG = LoggerFactory.getLogger(FileClient.class); + + private IHttpClient _httpClient; + private String _baseUrl; + private String _filesPath; + private Gson _gson = new Gson(); + + public FileClient(String masterSecret, String appKey) { + this(masterSecret, appKey, null, ClientConfig.getInstance()); + } + + public FileClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { + _baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); + _filesPath = (String) conf.get(ClientConfig.V3_FILES_PATH); + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); + } + + public FileUploadResult uploadFile(FileType type, String filename, Integer ttl) + throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(type != null, "type should not be null"); + Preconditions.checkArgument(StringUtils.isNotEmpty(filename), "filename should not be null"); + Preconditions.checkArgument(ttl >= 1 && ttl <= 720,"TTL is not in the range of 1 to 720"); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String typeStr = type.value(); + String url = _baseUrl + _filesPath + "/" + typeStr; + Map fileMap = new HashMap(); + fileMap.put("filename", filename); + Map textMap = new HashMap(); + textMap.put("ttl",String.valueOf(ttl)); + String response = client.formUploadByPost(url, textMap, fileMap, null); + LOG.info("uploadFile:{}", response); + return _gson.fromJson(response, + new TypeToken() { + }.getType()); + } + + public FileUploadResult uploadFile(FileType type, String filename) throws APIConnectionException, APIRequestException { + return uploadFile(type,filename,720); + } + + public FileModelPage queryEffectFiles() throws APIConnectionException, APIRequestException { + String url = _baseUrl + _filesPath + "/"; + ResponseWrapper response = _httpClient.sendGet(url); + LOG.info("queryEffFiles:{}", response); + return _gson.fromJson(response.responseContent, + new TypeToken() { + }.getType()); + } + + public FileModel queryFile(String fileId) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(fileId), "fileId should not be null"); + String url = _baseUrl + _filesPath + "/" + fileId; + ResponseWrapper response = _httpClient.sendGet(url); + LOG.info("queryFile:{}", response); + return _gson.fromJson(response.responseContent, + new TypeToken() { + }.getType()); + } + + public ResponseWrapper deleteFile(String fileId) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(fileId), "fileId should not be null"); + String url = _baseUrl + _filesPath + "/" + fileId; + ResponseWrapper response = _httpClient.sendDelete(url); + LOG.info("deleteFile:{}", response); + return response; + } +} diff --git a/src/main/java/cn/jpush/api/file/model/FileModel.java b/src/main/java/cn/jpush/api/file/model/FileModel.java new file mode 100644 index 00000000..024a167f --- /dev/null +++ b/src/main/java/cn/jpush/api/file/model/FileModel.java @@ -0,0 +1,21 @@ +package cn.jpush.api.file.model; + +import com.google.gson.annotations.Expose; +import lombok.Data; + +import java.util.Date; + +/** + * @author daixuan + * @version 2020/2/23 20:18 + */ +@Data +public class FileModel { + @Expose + private String file_id; + @Expose + private String type; + @Expose + private Date create_time; + +} diff --git a/src/main/java/cn/jpush/api/file/model/FileModelPage.java b/src/main/java/cn/jpush/api/file/model/FileModelPage.java new file mode 100644 index 00000000..a8030adf --- /dev/null +++ b/src/main/java/cn/jpush/api/file/model/FileModelPage.java @@ -0,0 +1,21 @@ +package cn.jpush.api.file.model; + +import com.google.gson.annotations.Expose; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author daixuan + * @version 2020/2/23 20:18 + */ +@Data +public class FileModelPage { + + @Expose + private int total_count; + @Expose + private List files; + +} diff --git a/src/main/java/cn/jpush/api/file/model/FileType.java b/src/main/java/cn/jpush/api/file/model/FileType.java new file mode 100644 index 00000000..5a3a0142 --- /dev/null +++ b/src/main/java/cn/jpush/api/file/model/FileType.java @@ -0,0 +1,21 @@ +package cn.jpush.api.file.model; + +/** + * @author daixuan + * @version 2020/2/23 20:14 + */ +public enum FileType { + + ALIAS("alias"), + REGISTRATION_ID("registration_id"); + + private final String value; + + private FileType(final String value) { + this.value = value; + } + + public String value() { + return this.value; + } +} diff --git a/src/main/java/cn/jpush/api/file/model/FileUploadResult.java b/src/main/java/cn/jpush/api/file/model/FileUploadResult.java new file mode 100644 index 00000000..00713367 --- /dev/null +++ b/src/main/java/cn/jpush/api/file/model/FileUploadResult.java @@ -0,0 +1,16 @@ +package cn.jpush.api.file.model; + +import lombok.Data; + +@Data +public class FileUploadResult { + private String file_id; + private Error error; + + @Data + public static class Error { + private String message; + private int code; + + } +} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/image/ImageClient.java b/src/main/java/cn/jpush/api/image/ImageClient.java new file mode 100644 index 00000000..101f78c7 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/ImageClient.java @@ -0,0 +1,178 @@ +package cn.jpush.api.image; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.image.model.ImageFilePayload; +import cn.jpush.api.image.model.ImageSource; +import cn.jpush.api.image.model.ImageUploadResult; +import cn.jpush.api.image.model.ImageUrlPayload; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonSyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * Provide the ability to upload images to the Jiguang server. Only images in JPG, JPEG and PNG format are supported. + * + * @author fuyx + * @version 2020-12-14 + */ +public class ImageClient { + + protected static final Logger LOG = LoggerFactory.getLogger(ImageClient.class); + + private IHttpClient _httpClient; + private String _baseUrl; + private String _imagesPath; + private Gson _gson = new Gson(); + + public ImageClient(String masterSecret, String appKey) { + this(masterSecret, appKey, null, ClientConfig.getInstance()); + } + + public ImageClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { + _baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); + _imagesPath = (String) conf.get(ClientConfig.V3_IMAGES_PATH); + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); + } + + + /** + * Upload image by url. Require at least one non-null url. + * @param imageUrlPayload image url payload + * @return {@link ImageUploadResult} + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public ImageUploadResult uploadImage(ImageUrlPayload imageUrlPayload) + throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(imageUrlPayload.getImageType() != null, "Image type should not be null"); + checkImageUrlPayload(imageUrlPayload); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String url = _baseUrl + _imagesPath + "/" + ImageSource.URL.value(); + JsonElement jsonElement = imageUrlPayload.toJSON(); + String content = _gson.toJson(jsonElement); + ResponseWrapper responseWrapper = client.sendPost(url, content); + if (responseWrapper.responseCode != 200) { + LOG.error("upload image failed: {}", responseWrapper); + } + ImageUploadResult imageUploadResult = _gson.fromJson(responseWrapper.responseContent, ImageUploadResult.class); + + LOG.info("upload image result:{}", imageUploadResult); + return imageUploadResult; + } + + /** + * Upload image by file. Require at least 1 non-null fileName. Currently only support Xiaomi and OPPO + * @param imageFilePayload image file payload + * @return {@link ImageUploadResult} + */ + public ImageUploadResult uploadImage(ImageFilePayload imageFilePayload) { + Preconditions.checkArgument(imageFilePayload.getImageType() != null, "Image type should not be null"); + checkImageFilePayload(imageFilePayload); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String url = _baseUrl + _imagesPath + "/" + ImageSource.FILE.value(); + + Map textMap = new HashMap(); + textMap.put("image_type", String.valueOf(imageFilePayload.getImageType().value())); + + Map fileMap = imageFilePayload.toFileMap(); + LOG.debug("upload fileMap: {}", fileMap); + String response = client.formUploadByPost(url, textMap, fileMap, null); + LOG.debug("upload image result: {}", response); + ImageUploadResult imageUploadResult; + try { + imageUploadResult = _gson.fromJson(response, ImageUploadResult.class); + } catch (JsonSyntaxException e) { + LOG.error("could not parse response: {}", response); + throw new IllegalStateException("could not parse response", e); + } + LOG.info("upload image result:{}", imageUploadResult); + return imageUploadResult; + } + + /** + * Modify image by url. Require at least one non-null url. + * @param mediaId media id + * @param imageUrlPayload image url payload + * @return {@link ImageUploadResult} + * @throws APIConnectionException connection exception + * @throws APIRequestException request exception + */ + public ImageUploadResult modifyImage(String mediaId, ImageUrlPayload imageUrlPayload) + throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(mediaId), "mediaId should not be empty"); + checkImageUrlPayload(imageUrlPayload); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String url = _baseUrl + _imagesPath + "/" + ImageSource.URL.value() + "/" + mediaId; + JsonElement jsonElement = imageUrlPayload.toJSON(); + String content = _gson.toJson(jsonElement); + ResponseWrapper responseWrapper = client.sendPut(url, content); + if (responseWrapper.responseCode != 200) { + LOG.error("upload image failed: {}", responseWrapper); + } + ImageUploadResult imageUploadResult = _gson.fromJson(responseWrapper.responseContent, ImageUploadResult.class); + + LOG.info("upload image result:{}", imageUploadResult); + return imageUploadResult; + } + + + /** + * Modify image by file. Require at least 1 non-null fileName. Currently only support Xiaomi and OPPO + * @param mediaId media id + * @param imageFilePayload image file payload + * @return {@link ImageUploadResult} + */ + public ImageUploadResult modifyImage(String mediaId, ImageFilePayload imageFilePayload) { + Preconditions.checkArgument(StringUtils.isNotEmpty(mediaId), "mediaId should not be empty"); + checkImageFilePayload(imageFilePayload); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String url = _baseUrl + _imagesPath + "/" + ImageSource.FILE.value() + "/" + mediaId; + + Map fileMap = imageFilePayload.toFileMap(); + LOG.debug("upload image fileMap: {}", fileMap); + String response = client.formUploadByPut(url, null, fileMap, null); + LOG.debug("upload image result: {}", response); + ImageUploadResult imageUploadResult; + try { + imageUploadResult = _gson.fromJson(response, ImageUploadResult.class); + } catch (JsonSyntaxException e) { + LOG.error("could not parse response: {}", response); + throw new IllegalStateException("could not parse response", e); + } + LOG.info("upload image result:{}", imageUploadResult); + return imageUploadResult; + } + + private void checkImageUrlPayload(ImageUrlPayload imageUrlPayload) { + boolean anyUrlNotEmpty = StringUtils.isNotEmpty(imageUrlPayload.getImageUrl()) + || StringUtils.isNotEmpty(imageUrlPayload.getFcmImageUrl()) + || StringUtils.isNotEmpty(imageUrlPayload.getHuaweiImageUrl()) + || StringUtils.isNotEmpty(imageUrlPayload.getOppoImageUrl()) + || StringUtils.isNotEmpty(imageUrlPayload.getXiaomiImageUrl()) + || StringUtils.isNotEmpty(imageUrlPayload.getJiguangImageUrl()) ; + Preconditions.checkArgument(anyUrlNotEmpty, "Require at least 1 non-empty url"); + } + + private void checkImageFilePayload(ImageFilePayload imageFilePayload) { + boolean anyFileNotEmpty = StringUtils.isNotEmpty(imageFilePayload.getOppoFileName() ) + || StringUtils.isNotEmpty(imageFilePayload.getXiaomiFileName() ); + Preconditions.checkArgument(anyFileNotEmpty, "Require at least 1 non-empty fileName. Currently only support Xiaomi and OPPO"); + } + + +} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/image/model/ImageFilePayload.java b/src/main/java/cn/jpush/api/image/model/ImageFilePayload.java new file mode 100644 index 00000000..f8143484 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/model/ImageFilePayload.java @@ -0,0 +1,105 @@ +package cn.jpush.api.image.model; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class ImageFilePayload { + private static final String IMAGE_TYPE = "image_type"; + private static final String OPPO_IMAGE_FILE = "oppo_file"; + private static final String XIAOMI_IMAGE_FILE = "xiaomi_file"; + private static final String HUAWEI_IMAGE_FILE = "huawei_file"; + private static final String FCM_IMAGE_FILE = "fcm_file"; + private static final String JIGUANG_IMAGE_FILE = "jiguang_file"; + + private ImageType imageType; + private String oppoFileName; + private String xiaomiFileName; + private String huaweiFileName; + private String fcmFileName; + private String jiguangFileName; + + public Map toFileMap() { + HashMap fileMap = new HashMap(); + if (null != oppoFileName) { + fileMap.put(OPPO_IMAGE_FILE, oppoFileName); + } + if (null != xiaomiFileName) { + fileMap.put(XIAOMI_IMAGE_FILE, xiaomiFileName); + } + if (null != huaweiFileName) { + fileMap.put(HUAWEI_IMAGE_FILE, huaweiFileName); + } + if (null != fcmFileName) { + fileMap.put(FCM_IMAGE_FILE, fcmFileName); + } + if (null != jiguangFileName) { + fileMap.put(JIGUANG_IMAGE_FILE, jiguangFileName); + } + return fileMap; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private ImageType imageType; + private String oppoFileName; + private String xiaomiFileName; + private String huaweiFileName; + private String fcmFileName; + private String jiguangFileName; + + private Builder() { + } + + public static Builder builder() { + return new Builder(); + } + + public Builder setImageType(ImageType imageType) { + this.imageType = imageType; + return this; + } + + public Builder setOppoFileName(String oppoFileName) { + this.oppoFileName = oppoFileName; + return this; + } + + public Builder setXiaomiFileName(String xiaomiFileName) { + this.xiaomiFileName = xiaomiFileName; + return this; + } + + public Builder setHuaweiFileName(String huaweiFileName) { + this.huaweiFileName = huaweiFileName; + return this; + } + + public Builder setFcmFileName(String fcmFileName) { + this.fcmFileName = fcmFileName; + return this; + } + + public Builder setJiguangFileName(String jiguangFileName) { + this.jiguangFileName = jiguangFileName; + return this; + } + + public ImageFilePayload build() { + ImageFilePayload imageFilePayload = new ImageFilePayload(); + imageFilePayload.setImageType(imageType); + imageFilePayload.setOppoFileName(oppoFileName); + imageFilePayload.setXiaomiFileName(xiaomiFileName); + imageFilePayload.setHuaweiFileName(huaweiFileName); + imageFilePayload.setFcmFileName(fcmFileName); + imageFilePayload.setJiguangFileName(jiguangFileName); + return imageFilePayload; + } + } + +} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/image/model/ImageSource.java b/src/main/java/cn/jpush/api/image/model/ImageSource.java new file mode 100644 index 00000000..5bd847c1 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/model/ImageSource.java @@ -0,0 +1,27 @@ +package cn.jpush.api.image.model; + +/** + * @author fuyx + * @version 2020-12-14 + */ +public enum ImageSource { + + /** + * Network Resource + */ + URL("byurls"), + /** + * File Resource + */ + FILE("byfiles"); + + private final String value; + + ImageSource(final String value) { + this.value = value; + } + + public String value() { + return this.value; + } +} diff --git a/src/main/java/cn/jpush/api/image/model/ImageType.java b/src/main/java/cn/jpush/api/image/model/ImageType.java new file mode 100644 index 00000000..24b37425 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/model/ImageType.java @@ -0,0 +1,27 @@ +package cn.jpush.api.image.model; + +import com.google.gson.annotations.SerializedName; + +/** + * @author fuyx + * @version 2020-12-14 + */ +public enum ImageType { + + @SerializedName("1") + BIG_PICTURE(1), + @SerializedName("2") + LARGE_ICON(2), + @SerializedName("3") + SMALL_ICON(3); + + private final int value; + + ImageType(final int value) { + this.value = value; + } + + public int value() { + return this.value; + } +} diff --git a/src/main/java/cn/jpush/api/image/model/ImageUploadResult.java b/src/main/java/cn/jpush/api/image/model/ImageUploadResult.java new file mode 100644 index 00000000..2435eb22 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/model/ImageUploadResult.java @@ -0,0 +1,31 @@ +package cn.jpush.api.image.model; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +@Data +public class ImageUploadResult { + + @SerializedName("media_id") + private String mediaId; + @SerializedName("oppo_image_url") + private String oppoImageUrl; + @SerializedName("xiaomi_image_url") + private String xiaomiImageUrl; + @SerializedName("huawei_image_url") + private String huaweiImageUrl; + @SerializedName("fcm_image_url") + private String fcmImageUrl; + @SerializedName("jiguang_image_url") + private String jiguangImageUrl; + @SerializedName("error") + private Error error; + + @Data + public static class Error { + @SerializedName("message") + private String message; + @SerializedName("code") + private int code; + } +} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/image/model/ImageUrlPayload.java b/src/main/java/cn/jpush/api/image/model/ImageUrlPayload.java new file mode 100644 index 00000000..62cd0626 --- /dev/null +++ b/src/main/java/cn/jpush/api/image/model/ImageUrlPayload.java @@ -0,0 +1,119 @@ +package cn.jpush.api.image.model; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import lombok.Data; + +@Data +public class ImageUrlPayload { + private static final String IMAGE_TYPE = "image_type"; + private static final String IMAGE_URL = "image_url"; + private static final String OPPO_IMAGE_URL = "oppo_image_url"; + private static final String XIAOMI_IMAGE_URL = "xiaomi_image_url"; + private static final String HUAWEI_IMAGE_URL = "huawei_image_url"; + private static final String FCM_IMAGE_URL = "fcm_image_url"; + private static final String JIGUANG_IMAGE_URL = "jiguang_image_url"; + + private ImageType imageType; + private String imageUrl; + private String oppoImageUrl; + private String xiaomiImageUrl; + private String huaweiImageUrl; + private String fcmImageUrl; + private String jiguangImageUrl; + + public JsonElement toJSON() { + JsonObject json = new JsonObject(); + if (null != imageType) { + json.addProperty(IMAGE_TYPE, imageType.value()); + } + if (null != imageUrl) { + json.addProperty(IMAGE_URL, imageUrl); + } + if (null != oppoImageUrl) { + json.addProperty(OPPO_IMAGE_URL, oppoImageUrl); + } + if (null != xiaomiImageUrl) { + json.addProperty(XIAOMI_IMAGE_URL, xiaomiImageUrl); + } + if (null != huaweiImageUrl) { + json.addProperty(HUAWEI_IMAGE_URL, huaweiImageUrl); + } + if (null != fcmImageUrl) { + json.addProperty(FCM_IMAGE_URL, fcmImageUrl); + } + if (null != jiguangImageUrl) { + json.addProperty(JIGUANG_IMAGE_URL, jiguangImageUrl); + } + return json; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private ImageType imageType; + private String imageUrl; + private String oppoImageUrl; + private String xiaomiImageUrl; + private String huaweiImageUrl; + private String fcmImageUrl; + private String jiguangImageUrl; + + private Builder() { + } + + public static Builder builder() { + return new Builder(); + } + + public Builder setImageType(ImageType imageType) { + this.imageType = imageType; + return this; + } + + public Builder setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + return this; + } + + public Builder setOppoImageUrl(String oppoImageUrl) { + this.oppoImageUrl = oppoImageUrl; + return this; + } + + public Builder setXiaomiImageUrl(String xiaomiImageUrl) { + this.xiaomiImageUrl = xiaomiImageUrl; + return this; + } + + public Builder setHuaweiImageUrl(String huaweiImageUrl) { + this.huaweiImageUrl = huaweiImageUrl; + return this; + } + + public Builder setFcmImageUrl(String fcmImageUrl) { + this.fcmImageUrl = fcmImageUrl; + return this; + } + + public Builder setJiguangImageUrl(String jiguangImageUrl) { + this.jiguangImageUrl = jiguangImageUrl; + return this; + } + + public ImageUrlPayload build() { + ImageUrlPayload imageUrlPayload = new ImageUrlPayload(); + imageUrlPayload.setImageType(imageType); + imageUrlPayload.setImageUrl(imageUrl); + imageUrlPayload.setOppoImageUrl(oppoImageUrl); + imageUrlPayload.setXiaomiImageUrl(xiaomiImageUrl); + imageUrlPayload.setHuaweiImageUrl(huaweiImageUrl); + imageUrlPayload.setFcmImageUrl(fcmImageUrl); + imageUrlPayload.setJiguangImageUrl(jiguangImageUrl); + return imageUrlPayload; + } + } + +} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/push/CIDResult.java b/src/main/java/cn/jpush/api/push/CIDResult.java new file mode 100644 index 00000000..f5badd37 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/CIDResult.java @@ -0,0 +1,12 @@ +package cn.jpush.api.push; + +import cn.jiguang.common.resp.BaseResult; +import com.google.gson.annotations.Expose; + +import java.util.ArrayList; +import java.util.List; + +public class CIDResult extends BaseResult { + + @Expose public List cidlist = new ArrayList(); +} diff --git a/src/main/java/cn/jpush/api/push/GroupPushClient.java b/src/main/java/cn/jpush/api/push/GroupPushClient.java new file mode 100644 index 00000000..d1f0adc4 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/GroupPushClient.java @@ -0,0 +1,87 @@ +package cn.jpush.api.push; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Base64; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.sm2.SM2Util; +import cn.jpush.api.push.model.EncryptKeys; +import cn.jpush.api.push.model.EncryptPushPayload; +import cn.jpush.api.push.model.PushPayload; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +import java.util.Map; + +/** + * Created by caiyaoguan on 2017/7/4. + */ +public class GroupPushClient { + + private IHttpClient _httpClient; + private String _baseUrl; + private String _groupPushPath; + private String _encryptType; + private Gson _gson = new Gson(); + private JsonParser _jsonParser = new JsonParser(); + + + public GroupPushClient(String groupMasterSecret, String groupKey) { + this(groupMasterSecret, groupKey, null, ClientConfig.getInstance()); + } + + public GroupPushClient(String groupMasterSecret, String groupKey, HttpProxy proxy, ClientConfig conf) { + ServiceHelper.checkBasic(groupKey, groupMasterSecret); + this._baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); + this._groupPushPath = (String) conf.get(ClientConfig.GROUP_PUSH_PATH); + this._encryptType = (String) conf.get(ClientConfig.ENCRYPT_TYPE); + String authCode = ServiceHelper.getBasicAuthorization("group-" + groupKey, groupMasterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); + } + + public GroupPushResult sendGroupPush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(! (null == pushPayload), "pushPayload should not be null"); + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _groupPushPath, getEncryptData(pushPayload)); + // 2020-8-6 兼容分组推送新返回的group_msgid结构 + JsonObject responseJson = _jsonParser.parse(response.responseContent).getAsJsonObject(); + String groupMsgIdKey = "group_msgid"; + JsonElement _groupMsgId = responseJson.get(groupMsgIdKey); + String groupMsgId = null != _groupMsgId ? _groupMsgId.getAsString() : ""; + responseJson.remove(groupMsgIdKey); + Map result = _gson.fromJson(responseJson, new TypeToken>(){}.getType()); + return new GroupPushResult(groupMsgId, result); + } + + /** + * 获取加密的payload数据 + * @param pushPayload + * @return + */ + private String getEncryptData(PushPayload pushPayload) { + if (_encryptType.isEmpty()) { + return pushPayload.toString(); + } + if (EncryptKeys.ENCRYPT_SMS2_TYPE.equals(_encryptType)) { + EncryptPushPayload encryptPushPayload = new EncryptPushPayload(); + try { + encryptPushPayload.setPayload(String.valueOf(Base64.encode(SM2Util.encrypt(pushPayload.toString(), EncryptKeys.DEFAULT_SM2_ENCRYPT_KEY)))); + } catch (Exception e) { + throw new RuntimeException("encrypt word exception", e); + } + encryptPushPayload.setAudience(pushPayload.getAudience()); + return encryptPushPayload.toString(); + } + // 不支持的加密默认不加密 + return pushPayload.toString(); + } + +} diff --git a/src/main/java/cn/jpush/api/push/GroupPushResult.java b/src/main/java/cn/jpush/api/push/GroupPushResult.java new file mode 100644 index 00000000..3a49abe2 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/GroupPushResult.java @@ -0,0 +1,38 @@ +package cn.jpush.api.push; + +import java.util.Map; + +/** + * @author tp + * @since 2020/8/6 + */ +public class GroupPushResult { + + private Map appResultMap; + + private String groupMsgId; + + public GroupPushResult() { + } + + public GroupPushResult(String groupMsgId, Map appResultMap) { + this.groupMsgId = groupMsgId; + this.appResultMap = appResultMap; + } + + public Map getAppResultMap() { + return appResultMap; + } + + public void setAppResultMap(Map appResultMap) { + this.appResultMap = appResultMap; + } + + public String getGroupMsgId() { + return groupMsgId; + } + + public void setGroupMsgId(String groupMsgId) { + this.groupMsgId = groupMsgId; + } +} diff --git a/src/main/java/cn/jpush/api/push/PushClient.java b/src/main/java/cn/jpush/api/push/PushClient.java index f87a2252..493d0818 100644 --- a/src/main/java/cn/jpush/api/push/PushClient.java +++ b/src/main/java/cn/jpush/api/push/PushClient.java @@ -1,167 +1,391 @@ package cn.jpush.api.push; -import cn.jpush.api.common.ClientConfig; -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.connection.IHttpClient; -import cn.jpush.api.common.connection.NativeHttpClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.BaseResult; -import cn.jpush.api.common.resp.ResponseWrapper; -import cn.jpush.api.push.model.PushPayload; -import cn.jpush.api.utils.Preconditions; -import cn.jpush.api.utils.StringUtils; - -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.*; +import cn.jiguang.common.resp.*; +import cn.jiguang.common.utils.Base64; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jiguang.common.utils.sm2.SM2Util; +import cn.jpush.api.push.model.*; +import cn.jpush.api.push.model.audience.Audience; +import cn.jpush.api.push.model.live_activity.LiveActivity; +import com.google.gson.*; + +import java.util.List; /** * Entrance for sending Push. - * - * For the following parameters, you can set them by instance creation. + *

+ * For the following parameters, you can set them by instance creation. * This action will override setting in PushPayload Optional. * * apnsProduction If not present, the default is true. * * timeToLive If not present, the default is 86400(s) (one day). - * + *

* Can be used directly. */ public class PushClient { - private final NativeHttpClient _httpClient; + private IHttpClient _httpClient; private String _baseUrl; private String _pushPath; private String _pushValidatePath; + private String batchRegidPushPath; + private String batchAliasPushPath; + private String _filePushPath; private JsonParser _jsonParser = new JsonParser(); // If not present, true by default. - private boolean _apnsProduction = true; - + private int _apnsProduction; + // If not present, the default value is 86400(s) (one day) - private long _timeToLive = 60 * 60 * 24; - - private boolean _globalSettingEnabled = false; + private long _timeToLive; + + // encrypt type, the default value is empty + private String _encryptType; + + public PushClient() { + } /** * Create a Push Client. - * + * * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. + * @param appKey The KEY of one application on JPush. + */ + public PushClient(String masterSecret, String appKey) { + this(masterSecret, appKey, null, ClientConfig.getInstance()); + } + + public PushClient(String masterSecret, String appKey, ClientConfig clientConfig) { + this(masterSecret, appKey, null, clientConfig); + } + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The max retry times. + */ + @Deprecated + public PushClient(String masterSecret, String appKey, int maxRetryTimes) { + this(masterSecret, appKey, maxRetryTimes, null); + } + + /** + * Create a Push Client with max retry times. + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes max retry times + * @param proxy The max retry times. */ - public PushClient(String masterSecret, String appKey) { - this(masterSecret, appKey, IHttpClient.DEFAULT_MAX_RETRY_TIMES); - } - - public PushClient(String masterSecret, String appKey, int maxRetryTimes) { - this(masterSecret, appKey, maxRetryTimes, null); - } - - /** - * Create a Push Client with max retry times. - * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. - * @param maxRetryTimes max retry times - */ - public PushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { - this(masterSecret, appKey, maxRetryTimes, proxy, ClientConfig.getInstance()); - } - - public PushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf) { + @Deprecated + public PushClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { ServiceHelper.checkBasic(appKey, masterSecret); + ClientConfig conf = ClientConfig.getInstance(); + conf.setMaxRetryTimes(maxRetryTimes); + this._baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); this._pushPath = (String) conf.get(ClientConfig.PUSH_PATH); this._pushValidatePath = (String) conf.get(ClientConfig.PUSH_VALIDATE_PATH); + this._filePushPath = (String) conf.get(ClientConfig.FILE_PUSH_PATH); + + this._apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION); + this._timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE); String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); - this._httpClient = new NativeHttpClient(authCode, maxRetryTimes, proxy); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); + } + + public PushClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { + ServiceHelper.checkBasic(appKey, masterSecret); + + this._baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); + this._pushPath = (String) conf.get(ClientConfig.PUSH_PATH); + this._pushValidatePath = (String) conf.get(ClientConfig.PUSH_VALIDATE_PATH); + this._filePushPath = (String) conf.get(ClientConfig.FILE_PUSH_PATH); + + this.batchAliasPushPath = (String) conf.get(ClientConfig.BATCH_ALIAS_PUSH_PATH); + this.batchRegidPushPath = (String) conf.get(ClientConfig.BATCH_REGID_PUSH_PATH); + + this._apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION); + this._timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE); + this._encryptType = (String) conf.get(ClientConfig.ENCRYPT_TYPE); + + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); } - /** + /** * Create a Push Client with global settings. - * + *

* If you want different settings from default globally, this constructor is what you needed. - * - * @param masterSecret API access secret of the appKey. - * @param appKey The KEY of one application on JPush. + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig} instead of this constructor. + * + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. * @param apnsProduction Global APNs environment setting. It will override PushPayload Options. - * @param timeToLive Global time_to_live setting. It will override PushPayload Options. + * @param timeToLive Global time_to_live setting. It will override PushPayload Options. */ + @Deprecated public PushClient(String masterSecret, String appKey, boolean apnsProduction, long timeToLive) { this(masterSecret, appKey); - - this._apnsProduction = apnsProduction; + if (apnsProduction) { + _apnsProduction = 1; + } else { + _apnsProduction = 0; + } this._timeToLive = timeToLive; - this._globalSettingEnabled = true; } - + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setGlobalPushSetting} instead of this method. + * + * @param apnsProduction Global APNs environment setting. It will override PushPayload Options. + * @param timeToLive Global time_to_live setting. It will override PushPayload Options. + */ + @Deprecated public void setDefaults(boolean apnsProduction, long timeToLive) { - this._apnsProduction = apnsProduction; + if (apnsProduction) { + _apnsProduction = 1; + } else { + _apnsProduction = 0; + } this._timeToLive = timeToLive; - this._globalSettingEnabled = true; } - + public void setBaseUrl(String baseUrl) { this._baseUrl = baseUrl; } - + public PushResult sendPush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { - Preconditions.checkArgument(! (null == pushPayload), "pushPayload should not be null"); - - if (_globalSettingEnabled) { - pushPayload.resetOptionsTimeToLive(_timeToLive); - pushPayload.resetOptionsApnsProduction(_apnsProduction); - } - - ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, pushPayload.toString()); - + checkPushPayload(pushPayload); + + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, getEncryptData(pushPayload)); + return BaseResult.fromResponse(response, PushResult.class); } - + + public PushResult sendPushValidate(PushPayload pushPayload) throws APIConnectionException, APIRequestException { - Preconditions.checkArgument(! (null == pushPayload), "pushPayload should not be null"); - - if (_globalSettingEnabled) { - pushPayload.resetOptionsTimeToLive(_timeToLive); - pushPayload.resetOptionsApnsProduction(_apnsProduction); - } - - ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, pushPayload.toString()); - + checkPushPayload(pushPayload); + + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, getEncryptData(pushPayload)); + return BaseResult.fromResponse(response, PushResult.class); } - + public PushResult sendPush(String payloadString) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(StringUtils.isNotEmpty(payloadString), "pushPayload should not be empty"); - + try { _jsonParser.parse(payloadString); } catch (JsonParseException e) { Preconditions.checkArgument(false, "payloadString should be a valid JSON string."); } - - ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, payloadString); - + + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, getEncryptData(payloadString)); + return BaseResult.fromResponse(response, PushResult.class); } - + + public PushResult sendFilePush(PushPayload pushPayload) throws APIConnectionException, APIRequestException { + checkPushPayload(pushPayload); + + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _filePushPath, getEncryptData(pushPayload)); + + return BaseResult.fromResponse(response, PushResult.class); + } + public PushResult sendPushValidate(String payloadString) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(StringUtils.isNotEmpty(payloadString), "pushPayload should not be empty"); - + try { _jsonParser.parse(payloadString); } catch (JsonParseException e) { Preconditions.checkArgument(false, "payloadString should be a valid JSON string."); } - - ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, payloadString); - + + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushValidatePath, getEncryptData(payloadString)); + return BaseResult.fromResponse(response, PushResult.class); } + public BatchPushResult batchSendPushByRegId(List pushPayloadList) throws APIConnectionException, APIRequestException { + return batchSendPush(_baseUrl + batchRegidPushPath, pushPayloadList); + } + + public BatchPushResult batchSendPushByAlias(List pushPayloadList) throws APIConnectionException, APIRequestException { + return batchSendPush(_baseUrl + batchAliasPushPath, pushPayloadList); + } + + public BatchPushResult batchSendPush(String url, List pushPayloadList) throws APIConnectionException, APIRequestException { + + Preconditions.checkArgument((null != pushPayloadList), "param should not be null"); + Preconditions.checkArgument((!pushPayloadList.isEmpty()), "pushPayloadList should not be empty"); + + Gson gson = new Gson(); + + JsonObject contentJson = new JsonObject(); + + CIDResult cidResult = getCidList(pushPayloadList.size(), "push"); + int i = 0; + JsonObject pushPayLoadList = new JsonObject(); + // setting cid + for (PushPayload payload : pushPayloadList) { + String cid = payload.getCid(); + if (cid != null && !cid.trim().isEmpty()) { + payload.setCid(null); + } else { + cid = cidResult.cidlist.get(i++); + } + pushPayLoadList.add(cid, payload.toJSON()); + } + contentJson.add("pushlist", pushPayLoadList); + + ResponseWrapper response = _httpClient.sendPost(url, getEncryptData(gson.toJson(contentJson))); + + return BatchPushResult.fromResponse(response); + + } + + /** + * Get cid list, the data form of cid is appKey-uuid. + * + * @param count the count of cid list, from 1 to 1000. default is 1. + * @param type default is "push", option: "schedule" + * @return CIDResult, an array of cid + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public CIDResult getCidList(int count, String type) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(count >= 1 && count <= 1000, "count should not less than 1 or larger than 1000"); + Preconditions.checkArgument(type == null || type.equals("push") || type.equals("schedule"), "type should be \"push\" or \"schedule\""); + ResponseWrapper responseWrapper; + if (type != null) { + responseWrapper = _httpClient.sendGet(_baseUrl + _pushPath + "/cid?count=" + count + "&type=" + type); + } else { + responseWrapper = _httpClient.sendGet(_baseUrl + _pushPath + "/cid?count=" + count); + } + return BaseResult.fromResponse(responseWrapper, CIDResult.class); + } + + /** + * Delete a push by msgId. + * + * @param msgId The message id + * @return delete result + * @throws APIConnectionException connect exception + * @throws APIRequestException request exception + */ + public DefaultResult deletePush(String msgId) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(msgId), "msgId should not be empty"); + + ResponseWrapper responseWrapper = _httpClient.sendDelete(_baseUrl + _pushPath + "/" + msgId); + + return DefaultResult.fromResponse(responseWrapper); + } + + public void setHttpClient(IHttpClient client) { + this._httpClient = client; + } + + // 如果使用 NettyHttpClient,在发送请求后需要手动调用 close 方法 + public void close() { + if (_httpClient != null && _httpClient instanceof NettyHttpClient) { + ((NettyHttpClient) _httpClient).close(); + } else if (_httpClient != null && _httpClient instanceof ApacheHttpClient) { + ((ApacheHttpClient) _httpClient).close(); + } + } + + /** + * 获取加密的payload数据 + * + * @param payloadData + * @return + */ + private String getEncryptData(String payloadData) { + JsonElement payloadElement = _jsonParser.parse(payloadData); + JsonObject jsonObject = payloadElement.getAsJsonObject(); + Audience audience = Audience.fromJsonElement(jsonObject.get("audience")); + return getEncryptData(payloadData, audience); + } + + /** + * 获取加密的payload数据 + * + * @param pushPayload + * @return + */ + private String getEncryptData(PushPayload pushPayload) { + if (StringUtils.isEmpty(_encryptType)) { + return pushPayload.toString(); + } + if (EncryptKeys.ENCRYPT_SMS2_TYPE.equals(_encryptType)) { + EncryptPushPayload encryptPushPayload = new EncryptPushPayload(); + try { + encryptPushPayload.setPayload(String.valueOf(Base64.encode(SM2Util.encrypt(pushPayload.toString(), EncryptKeys.DEFAULT_SM2_ENCRYPT_KEY)))); + } catch (Exception e) { + throw new RuntimeException("encrypt word exception", e); + } + encryptPushPayload.setAudience(pushPayload.getAudience()); + return encryptPushPayload.toString(); + } + // 不支持的加密默认不加密 + return pushPayload.toString(); + } + + /** + * 获取加密的payload数据 + * + * @param pushPayload + * @return + */ + private String getEncryptData(String pushPayload, Audience audience) { + if (StringUtils.isEmpty(_encryptType)) { + return pushPayload; + } + if (EncryptKeys.ENCRYPT_SMS2_TYPE.equals(_encryptType)) { + EncryptPushPayload encryptPushPayload = new EncryptPushPayload(); + try { + encryptPushPayload.setPayload(String.valueOf(Base64.encode(SM2Util.encrypt(pushPayload, EncryptKeys.DEFAULT_SM2_ENCRYPT_KEY)))); + } catch (Exception e) { + throw new RuntimeException("encrypt word exception", e); + } + encryptPushPayload.setAudience(audience); + return encryptPushPayload.toString(); + } + // 不支持的加密默认不加密 + return pushPayload; + } + + private void checkPushPayload(PushPayload pushPayload) { + Preconditions.checkArgument(!(null == pushPayload), "pushPayload should not be null"); + + if (_apnsProduction > 0) { + pushPayload.resetOptionsApnsProduction(true); + } else if (_apnsProduction == 0) { + pushPayload.resetOptionsApnsProduction(false); + } + + if (_timeToLive >= 0) { + pushPayload.resetOptionsTimeToLive(_timeToLive); + } + } + + + public PushResult sendLiveActivity(LiveActivity liveActivity) throws APIConnectionException, APIRequestException { + ResponseWrapper response = _httpClient.sendPost(_baseUrl + _pushPath, liveActivity.toJSON().toString()); + return BaseResult.fromResponse(response, PushResult.class); + } } diff --git a/src/main/java/cn/jpush/api/push/PushResult.java b/src/main/java/cn/jpush/api/push/PushResult.java index 51576c3b..cb1bab61 100644 --- a/src/main/java/cn/jpush/api/push/PushResult.java +++ b/src/main/java/cn/jpush/api/push/PushResult.java @@ -1,13 +1,29 @@ package cn.jpush.api.push; -import cn.jpush.api.common.resp.BaseResult; - import com.google.gson.annotations.Expose; +import cn.jiguang.common.resp.BaseResult; + public class PushResult extends BaseResult { - + + private static final long serialVersionUID = 93783137655776743L; + @Expose public long msg_id; @Expose public int sendno; + @Expose public int statusCode; + @Expose public Error error; + public class Error { + @Expose String message; + @Expose int code; + + public String getMessage() { + return this.message; + } + + public int getCode() { + return this.code; + } + } } diff --git a/src/main/java/cn/jpush/api/push/model/BatchPushResult.java b/src/main/java/cn/jpush/api/push/model/BatchPushResult.java new file mode 100644 index 00000000..2690e135 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/BatchPushResult.java @@ -0,0 +1,49 @@ +package cn.jpush.api.push.model; + +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; +import com.google.gson.annotations.Expose; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.Map; + +public class BatchPushResult extends BaseResult { + + private static final Type RESULT_TYPE = new TypeToken>() {}.getType(); + + private Map batchPushResult; + + public class PushResult { + @Expose public long msg_id; + @Expose public Error error; + } + + public class Error { + @Expose String message; + @Expose int code; + + public String getMessage() { + return this.message; + } + + public int getCode() { + return this.code; + } + } + + public static BatchPushResult fromResponse(ResponseWrapper responseWrapper) { + + BatchPushResult result = new BatchPushResult(); + if (responseWrapper.isServerResponse()) { + result.batchPushResult = _gson.fromJson(responseWrapper.responseContent, RESULT_TYPE); + } + + result.setResponseWrapper(responseWrapper); + return result; + } + + public Map getBatchPushResult() { + return batchPushResult; + } +} diff --git a/src/main/java/cn/jpush/api/push/model/EncryptKeys.java b/src/main/java/cn/jpush/api/push/model/EncryptKeys.java new file mode 100644 index 00000000..735ff5da --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/EncryptKeys.java @@ -0,0 +1,8 @@ +package cn.jpush.api.push.model; + +public class EncryptKeys { + + public static String ENCRYPT_SMS2_TYPE = "SM2"; + public static String DEFAULT_SM2_ENCRYPT_KEY = "BPj6Mj/T444gxPaHc6CDCizMRp4pEl14WI2lvIbdEK2c+5XiSqmQt2TQc8hMMZqfxcDqUNQW95puAfQx1asv3rU="; + +} diff --git a/src/main/java/cn/jpush/api/push/model/EncryptPushPayload.java b/src/main/java/cn/jpush/api/push/model/EncryptPushPayload.java new file mode 100644 index 00000000..b1e8a1be --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/EncryptPushPayload.java @@ -0,0 +1,36 @@ +package cn.jpush.api.push.model; + +import cn.jpush.api.push.model.audience.Audience; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class EncryptPushPayload { + + private static Gson _gson = new GsonBuilder().disableHtmlEscaping().create(); + + private String payload; + + private Audience audience; + + public Audience getAudience() { + return audience; + } + + public void setAudience(Audience audience) { + this.audience = audience; + } + + public String getPayload() { + return payload; + } + + public void setPayload(String payload) { + this.payload = payload; + } + + @Override + public String toString() { + return _gson.toJson(this); + } + +} diff --git a/src/main/java/cn/jpush/api/push/model/InappMessage.java b/src/main/java/cn/jpush/api/push/model/InappMessage.java new file mode 100644 index 00000000..6f33dfac --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/InappMessage.java @@ -0,0 +1,53 @@ +package cn.jpush.api.push.model; + +import cn.jiguang.common.utils.Preconditions; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * inapp_message 此功能生效需Android push SDK≥V3.9.0、iOS push SDK≥V3.4.0,若低于此版本按照原流程执行。 + * + * 默认值为false + */ +public class InappMessage implements PushModel{ + + private boolean inappMessage; + + private InappMessage(boolean inappMessage) { + this.inappMessage = inappMessage; + } + + /** + * the entrance for building a inappMessage object + * @return inappMessage builder + */ + public static Builder newBuilder() { return new Builder(); } + + public boolean getInappMessage() { return inappMessage; } + + + @Override + public JsonElement toJSON() { + JsonObject json = new JsonObject(); + + json.addProperty("inapp_message", inappMessage); + + return json; + } + + + public static class Builder { + private boolean inappMessage; + + + public Builder setInappMessage(boolean inappMessage) { + this.inappMessage = inappMessage; + return this; + } + + public InappMessage build() { + return new InappMessage(inappMessage); + } + } +} diff --git a/src/main/java/cn/jpush/api/push/model/Message.java b/src/main/java/cn/jpush/api/push/model/Message.java index acf0e614..b87f5b6a 100644 --- a/src/main/java/cn/jpush/api/push/model/Message.java +++ b/src/main/java/cn/jpush/api/push/model/Message.java @@ -1,47 +1,65 @@ package cn.jpush.api.push.model; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; -import cn.jpush.api.utils.Preconditions; - import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -public class Message implements PushModel { - private static final String TITLE = "title"; +import cn.jiguang.common.utils.Preconditions; + +/** + * Android 1.6.2 及以下版本 接收 notification 与 message 并存(即本次 api 调用同时推送通知和消息)的离线推送, 只能收到通知部分,message 部分没有透传给 App。 + * + * Android 1.6.3 及以上 SDK 版本已做相应调整,能正常接收同时推送通知和消息的离线记录。 + * + * iOS 1.7.3 及以上的版本才能正确解析 v3 的 message,但是无法解析 v2 推送通知同时下发的应用内消息。 + */ +public class Message implements PushModel { private static final String MSG_CONTENT = "msg_content"; + private static final String TITLE = "title"; private static final String CONTENT_TYPE = "content_type"; + private static final String TEST_MESSAGE = "test_message"; private static final String EXTRAS = "extras"; - - private final String title; + private final String msgContent; + private final String title; private final String contentType; + private final Boolean testMessage; private final Map extras; private final Map numberExtras; private final Map booleanExtras; - - private Message(String title, String msgContent, String contentType, - Map extras, - Map numberExtras, - Map booleanExtras) { + private final Map jsonExtras; + private final Map customData; + + private Message(String title, String msgContent, String contentType, Boolean testMessage, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras, + Map customData) { this.title = title; this.msgContent = msgContent; this.contentType = contentType; + this.testMessage = testMessage; this.extras = extras; this.numberExtras = numberExtras; this.booleanExtras = booleanExtras; + this.jsonExtras = jsonExtras; + this.customData = customData; } - + public static Builder newBuilder() { return new Builder(); } - + public static Message content(String msgContent) { return new Builder().setMsgContent(msgContent).build(); } - + @Override public JsonElement toJSON() { JsonObject json = new JsonObject(); @@ -54,15 +72,22 @@ public JsonElement toJSON() { if (null != contentType) { json.add(CONTENT_TYPE, new JsonPrimitive(contentType)); } - + if (null != testMessage) { + json.add(TEST_MESSAGE, new JsonPrimitive(testMessage)); + } + JsonObject extrasObject = null; - if (null != extras || null != numberExtras || null != booleanExtras) { + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { extrasObject = new JsonObject(); } - + if (null != extras) { for (String key : extras.keySet()) { - extrasObject.add(key, new JsonPrimitive(extras.get(key))); + if (extras.get(key) != null) { + extrasObject.add(key, new JsonPrimitive(extras.get(key))); + } else { + extrasObject.add(key, JsonNull.INSTANCE); + } } } if (null != numberExtras) { @@ -75,48 +100,68 @@ public JsonElement toJSON() { extrasObject.add(key, new JsonPrimitive(booleanExtras.get(key))); } } + if (null != jsonExtras) { + for (String key : jsonExtras.keySet()) { + extrasObject.add(key, jsonExtras.get(key)); + } + } - if (null != extras || null != numberExtras || null != booleanExtras) { + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { json.add(EXTRAS, extrasObject); } - + + if (null != customData) { + for (Map.Entry entry : customData.entrySet()) { + json.add(entry.getKey(), entry.getValue()); + } + } + return json; } - + + public static class Builder { private String title; private String msgContent; private String contentType; + private Boolean testMessage; private Map extrasBuilder; private Map numberExtrasBuilder; private Map booleanExtrasBuilder; - + protected Map jsonExtrasBuilder; + private Map customData; + public Builder setTitle(String title) { this.title = title; return this; } - + public Builder setMsgContent(String msgContent) { this.msgContent = msgContent; return this; } - + public Builder setContentType(String contentType) { this.contentType = contentType; return this; } - + + public Builder setTestMessage(Boolean testMessage) { + this.testMessage = testMessage; + return this; + } + public Builder addExtra(String key, String value) { - Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + Preconditions.checkArgument(!(null == key || null == value), "Key/Value should not be null."); if (null == extrasBuilder) { extrasBuilder = new HashMap(); } extrasBuilder.put(key, value); return this; } - + public Builder addExtras(Map extras) { - Preconditions.checkArgument(! (null == extras), "extras should not be null."); + Preconditions.checkArgument(!(null == extras), "extras should not be null."); if (null == extrasBuilder) { extrasBuilder = new HashMap(); } @@ -125,30 +170,76 @@ public Builder addExtras(Map extras) { } return this; } - + public Builder addExtra(String key, Number value) { - Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + Preconditions.checkArgument(!(null == key || null == value), "Key/Value should not be null."); if (null == numberExtrasBuilder) { numberExtrasBuilder = new HashMap(); } numberExtrasBuilder.put(key, value); return this; } - + public Builder addExtra(String key, Boolean value) { - Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + Preconditions.checkArgument(!(null == key || null == value), "Key/Value should not be null."); if (null == booleanExtrasBuilder) { booleanExtrasBuilder = new HashMap(); } booleanExtrasBuilder.put(key, value); return this; } - + + public Builder addExtra(String key, JsonObject value) { + Preconditions.checkArgument(!(null == key || null == value), "Key/Value should not be null."); + if (null == jsonExtrasBuilder) { + jsonExtrasBuilder = new HashMap(); + } + jsonExtrasBuilder.put(key, value); + return this; + } + + public Builder addCustom(Map extras) { + if (customData == null) { + customData = new LinkedHashMap(); + } + for (Map.Entry entry : extras.entrySet()) { + customData.put(entry.getKey(), new JsonPrimitive(entry.getValue())); + } + return this; + } + + public Builder addCustom(String key, Number value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; + } + + public Builder addCustom(String key, String value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; + } + + public Builder addCustom(String key, Boolean value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; + } + public Message build() { - Preconditions.checkArgument(! (null == msgContent), + Preconditions.checkArgument(!(null == msgContent), "msgContent should be set"); - return new Message(title, msgContent, contentType, - extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder); + return new Message(title, msgContent, contentType, testMessage, + extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder, customData); } } } diff --git a/src/main/java/cn/jpush/api/push/model/Notification3rd.java b/src/main/java/cn/jpush/api/push/model/Notification3rd.java new file mode 100644 index 00000000..ef78e8ad --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/Notification3rd.java @@ -0,0 +1,283 @@ +package cn.jpush.api.push.model; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.utils.Preconditions; + +/** + * 使用说明 + * notification_3rd 只针对开通了厂商通道的用户生效; + * notification 和 notification_3rd 不能同时有内容,如果这两块同时有内容,则会返回错误提示; + * notification_3rd 的内容对 iOS 和 HMOS 平台无效,只针对 Android 平台生效; + * notification_3rd 是用作补发厂商通知的内容,只有当 message 部分有内容,才允许传递此字段,且要两者都不为空时,才会对离线的厂商设备转发厂商通道的通知。 + */ +public class Notification3rd implements PushModel{ + private static final String TITLE = "title"; + private static final String CONTENT = "content"; + private static final String CHANNEL_ID = "channel_id"; + private static final String URI_ACTIVITY = "uri_activity"; + private static final String URI_ACTION = "uri_action"; + private static final String BADGE_ADD_NUM = "badge_add_num"; + private static final String BADGE_SET_NUM = "badge_set_num"; + private static final String BADGE_CLASS = "badge_class"; + private static final String SOUND = "sound"; + private static final String EXTRAS = "extras"; + + + private final String title; + private final String content; + private final String channel_id; + private final String uri_activity; + private final String uri_action; + private final int badge_add_num; + private final int badge_set_num; + private final String badge_class; + private final String sound; + private final Map extras; + private final Map numberExtras; + private final Map booleanExtras; + private final Map jsonExtras; + + private Notification3rd(String title, String content, String channel_id, + String uri_activity, String uri_action, int badge_add_num,int badge_set_num, + String badge_class, String sound, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras) { + this.title = title; + this.content = content; + this.channel_id = channel_id; + this.uri_activity = uri_activity; + this.uri_action = uri_action; + this.badge_add_num = badge_add_num; + this.badge_set_num = badge_set_num; + this.badge_class = badge_class; + this.sound = sound; + this.extras = extras; + this.numberExtras = numberExtras; + this.booleanExtras = booleanExtras; + this.jsonExtras = jsonExtras; + } + + + /** + * The entrance for building a Notification3rd object. + * @return Notification3rd builder + */ + public static Builder newBuilder() { return new Builder(); } + + @Override + public JsonElement toJSON() { + JsonObject json = new JsonObject(); + + if (null != title) { + json.addProperty(TITLE, title); + } + + // 必填 + json.addProperty(CONTENT, content); + + if (null != channel_id) { + json.addProperty(CHANNEL_ID, channel_id); + } + + if (null != uri_activity) { + json.addProperty(URI_ACTIVITY, uri_activity); + } + + if (null != uri_action) { + json.addProperty(URI_ACTION, uri_action); + } + + if (0 != badge_add_num) { + json.addProperty(BADGE_ADD_NUM, badge_add_num); + } + + if (0 != badge_set_num) { + json.addProperty(BADGE_SET_NUM, badge_set_num); + } + + if (null != badge_class) { + json.addProperty(BADGE_CLASS, badge_class); + } + + if (null != sound) { + json.addProperty(SOUND, sound); + } + + /** + * for adding extras into json + */ + JsonObject extrasObject = null; + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { + extrasObject = new JsonObject(); + } + + if (null != extras) { + String value = null; + for (String key : extras.keySet()) { + value = extras.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != numberExtras) { + Number value = null; + for (String key : numberExtras.keySet()) { + value = numberExtras.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != booleanExtras) { + Boolean value = null; + for (String key : booleanExtras.keySet()) { + value = booleanExtras.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != jsonExtras) { + JsonObject value = null; + for (String key : jsonExtras.keySet()) { + value = jsonExtras.get(key); + if (null != value) { + extrasObject.add(key, value); + } + } + } + + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { + json.add(EXTRAS, extrasObject); + } + + return json; + } + + public static class Builder{ + private String title; + private String content; + private String channel_id; + private String uri_activity; + private String uri_action; + private int badge_add_num; + private int badge_set_num; + private String badge_class; + private String sound; + protected Map extrasBuilder; + protected Map numberExtrasBuilder; + protected Map booleanExtrasBuilder; + protected Map jsonExtrasBuilder; + + public Builder setTitle(String title) { + this.title = title; + return this; + } + + public Builder setContent(String content) { + this.content = content; + return this; + } + + public Builder setChannelId(String channel_id) { + this.channel_id = channel_id; + return this; + } + + public Builder setUriActivity(String uri_activity) { + this.uri_activity = uri_activity; + return this; + } + + public Builder setUriAction(String uri_action) { + this.uri_action = uri_action; + return this; + } + + public Builder setBadgeAddNum(int badge_add_num) { + this.badge_add_num = badge_add_num; + return this; + } + + public Builder setBadgeSetNum(int badge_set_num) { + this.badge_set_num = badge_set_num; + return this; + } + + public Builder setBadgeClass(String badge_class) { + this.badge_class = badge_class; + return this; + } + + public Builder setSound(String sound) { + this.sound = sound; + return this; + } + + // addExtra 一次加入一对 + public Builder addExtra(String key, String value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == extrasBuilder) { + extrasBuilder = new HashMap(); + } + extrasBuilder.put(key, value); + return this; + } + + // addExtras 可以一次加入多对 + public Builder addExtras(Map extras) { + Preconditions.checkArgument(! (null == extras), "extras should not be null."); + if (null == extrasBuilder) { + extrasBuilder = new HashMap(); + } + for (String key : extras.keySet()) { + extrasBuilder.put(key, extras.get(key)); + } + return this; + } + + public Builder addExtra(String key, Number value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == numberExtrasBuilder) { + numberExtrasBuilder = new HashMap(); + } + numberExtrasBuilder.put(key, value); + return this; + } + + public Builder addExtra(String key, Boolean value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == booleanExtrasBuilder) { + booleanExtrasBuilder = new HashMap(); + } + booleanExtrasBuilder.put(key, value); + return this; + } + + public Builder addExtra(String key, JsonObject value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == jsonExtrasBuilder) { + jsonExtrasBuilder = new HashMap(); + } + jsonExtrasBuilder.put(key, value); + return this; + } + + public Notification3rd build() { + Preconditions.checkArgument(content != null && content != "", "content should not be null or empty"); + + return new Notification3rd(title, content, channel_id, uri_activity, uri_action, badge_add_num, badge_set_num, + badge_class, sound, extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder); + } + } +} diff --git a/src/main/java/cn/jpush/api/push/model/Options.java b/src/main/java/cn/jpush/api/push/model/Options.java index 320f083d..dfcae593 100644 --- a/src/main/java/cn/jpush/api/push/model/Options.java +++ b/src/main/java/cn/jpush/api/push/model/Options.java @@ -1,64 +1,107 @@ package cn.jpush.api.push.model; -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.utils.Preconditions; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; +import com.google.gson.*; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.utils.Preconditions; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +/** + * 参考文档:https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push#options + * + *

Options

+ *
+ *
    + *
  • sendno: 推送序号
  • + *
  • time_to_live: 离线消息保留时长 (秒)
  • + *
  • override_msg_id: 要覆盖的消息 ID
  • + *
  • apns_production: APNs 是否生产环境
  • + *
  • apns_collapse_id: 更新 iOS 通知的标识符
  • + *
  • big_push_duration: 定速推送时长 (分钟)
  • + *
  • third_party_channel: 推送请求下发通道
  • + *
  • classification: 消息类型分类,极光不对指定的消息类型进行判断或校准,会以开发者自行指定的消息类型适配 Android 厂商通道。不填默认为 0
  • + *
+ */ public class Options implements PushModel { + private static final String SENDNO = "sendno"; private static final String OVERRIDE_MSG_ID = "override_msg_id"; private static final String TIME_TO_LIVE = "time_to_live"; private static final String APNS_PRODUCTION = "apns_production"; private static final String BIG_PUSH_DURATION = "big_push_duration"; - + private static final String APNS_COLLAPSE_ID = "apns_collapse_id"; + private static final String THIRD_PARTH_CHANNEl = "third_party_channel"; + private static final String CLASSIFICATION = "classification"; + private static final long NONE_TIME_TO_LIVE = -1; - + private final int sendno; private final long overrideMsgId; private long timeToLive; private boolean apnsProduction; - private int bigPushDuration; // minutes - - private Options(int sendno, long overrideMsgId, long timeToLive, boolean apnsProduction, - int bigPushDuration) { + // minutes + private int bigPushDuration; + private String apnsCollapseId; + private int classification; + /** + * 参考:https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push#third_party_channel-%E8%AF%B4%E6%98%8E + */ + private Map thirdPartyChannel; + private final Map customData; + + private Options(int sendno, + long overrideMsgId, + long timeToLive, + boolean apnsProduction, + int bigPushDuration, + String apnsCollapseId, + int classification, + Map thirdPartyChannel, + Map customData) { this.sendno = sendno; this.overrideMsgId = overrideMsgId; this.timeToLive = timeToLive; this.apnsProduction = apnsProduction; this.bigPushDuration = bigPushDuration; + this.apnsCollapseId = apnsCollapseId; + this.classification = classification; + this.thirdPartyChannel = thirdPartyChannel; + this.customData = customData; } - + public static Builder newBuilder() { return new Builder(); } - + public static Options sendno() { return newBuilder().setSendno(ServiceHelper.generateSendno()).build(); } - + public static Options sendno(int sendno) { return newBuilder().setSendno(sendno).build(); } - + public void setApnsProduction(boolean apnsProduction) { this.apnsProduction = apnsProduction; } - + public void setTimeToLive(long timeToLive) { this.timeToLive = timeToLive; } - + public void setBigPushDuration(int bigPushDuration) { - this.bigPushDuration = bigPushDuration; + this.bigPushDuration = bigPushDuration; } - + public int getSendno() { return this.sendno; } - + @Override public JsonElement toJSON() { JsonObject json = new JsonObject(); @@ -71,58 +114,178 @@ public JsonElement toJSON() { if (timeToLive >= 0) { json.add(TIME_TO_LIVE, new JsonPrimitive(timeToLive)); } - + json.add(APNS_PRODUCTION, new JsonPrimitive(apnsProduction)); - + if (bigPushDuration > 0) { - json.add(BIG_PUSH_DURATION, new JsonPrimitive(bigPushDuration)); + json.add(BIG_PUSH_DURATION, new JsonPrimitive(bigPushDuration)); + } + + if (apnsCollapseId != null) { + json.add(APNS_COLLAPSE_ID, new JsonPrimitive(apnsCollapseId)); + } + + json.add(CLASSIFICATION, new JsonPrimitive(classification)); + + if (null != thirdPartyChannel && thirdPartyChannel.size() > 0) { + JsonObject partyChannel = new JsonObject(); + for (Map.Entry entry : thirdPartyChannel.entrySet()) { + JsonObject channel = entry.getValue(); + partyChannel.add(entry.getKey(), channel); + } + json.add(THIRD_PARTH_CHANNEl, partyChannel); } - + + if (null != customData) { + for (Map.Entry entry : customData.entrySet()) { + json.add(entry.getKey(), entry.getValue()); + } + } + return json; } - + public static class Builder { + private int sendno = 0; private long overrideMsgId = 0; private long timeToLive = NONE_TIME_TO_LIVE; private boolean apnsProduction = false; private int bigPushDuration = 0; - + private String apnsCollapseId; + private int classification; + private Map thirdPartyChannel; + private Map customData; + public Builder setSendno(int sendno) { this.sendno = sendno; return this; } - + public Builder setOverrideMsgId(long overrideMsgId) { this.overrideMsgId = overrideMsgId; return this; } - + public Builder setTimeToLive(long timeToLive) { this.timeToLive = timeToLive; return this; } - + public Builder setApnsProduction(boolean apnsProduction) { this.apnsProduction = apnsProduction; return this; } - + + public Builder setApnsCollapseId(String id) { + this.apnsCollapseId = id; + return this; + } + public Builder setBigPushDuration(int bigPushDuration) { - this.bigPushDuration = bigPushDuration; - return this; + this.bigPushDuration = bigPushDuration; + return this; + } + + public Builder setClassification(int classification) { + this.classification = classification; + return this; + } + + @Deprecated + public Map> getThirdPartyChannel() { + if (null != thirdPartyChannel) { + Map> thirdPartyChannelRsp = new HashMap>(); + Set> entrySet = thirdPartyChannel.entrySet(); + for (Map.Entry entry : entrySet) { + JsonObject entryValue = entry.getValue(); + Set> valueEntrySet = entryValue.entrySet(); + Map valueMap = new HashMap(); + for (Map.Entry valueEntry : valueEntrySet) { + valueMap.put(valueEntry.getKey(), null == valueEntry.getValue() ? null : valueEntry.getValue().getAsString()); + } + thirdPartyChannelRsp.put(entry.getKey(), valueMap); + } + return thirdPartyChannelRsp; + } + return null; + } + + @Deprecated + public Builder setThirdPartyChannel(Map> thirdPartyChannel) { + this.thirdPartyChannel = new HashMap(); + if (null != thirdPartyChannel) { + Set>> entrySet = thirdPartyChannel.entrySet(); + for (Map.Entry> entry : entrySet) { + String key = entry.getKey(); + Map valueMap = entry.getValue(); + JsonObject valueObj = new JsonObject(); + if (null != valueMap) { + Set> valueEntrySet = valueMap.entrySet(); + for (Map.Entry valueEntry : valueEntrySet) { + valueObj.addProperty(valueEntry.getKey(), valueEntry.getValue()); + } + this.thirdPartyChannel.put(key, valueObj); + } + } + + } + return this; + } + + public Builder setThirdPartyChannelV2(Map thirdPartyChannel) { + this.thirdPartyChannel = thirdPartyChannel; + return this; + } + + public Builder addCustom(Map extras) { + if (customData == null) { + customData = new LinkedHashMap(); + } + for (Map.Entry entry : extras.entrySet()) { + customData.put(entry.getKey(), new JsonPrimitive(entry.getValue())); + } + return this; + } + + public Builder addCustom(String key, Number value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; + } + + public Builder addCustom(String key, String value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; } - + + public Builder addCustom(String key, Boolean value) { + Preconditions.checkArgument(!(null == key), "Key should not be null."); + if (customData == null) { + customData = new LinkedHashMap(); + } + customData.put(key, new JsonPrimitive(value)); + return this; + } + public Options build() { Preconditions.checkArgument(sendno >= 0, "sendno should be greater than 0."); Preconditions.checkArgument(overrideMsgId >= 0, "override_msg_id should be greater than 0."); Preconditions.checkArgument(timeToLive >= NONE_TIME_TO_LIVE, "time_to_live should be greater than 0."); Preconditions.checkArgument(bigPushDuration >= 0, "bigPushDuration should be greater than 0."); + if (sendno <= 0) { sendno = ServiceHelper.generateSendno(); } - - return new Options(sendno, overrideMsgId, timeToLive, apnsProduction, bigPushDuration); + + return new Options(sendno, overrideMsgId, timeToLive, apnsProduction, bigPushDuration, apnsCollapseId, classification, thirdPartyChannel, customData); } } diff --git a/src/main/java/cn/jpush/api/push/model/Platform.java b/src/main/java/cn/jpush/api/push/model/Platform.java index a3854cf5..eddeff42 100644 --- a/src/main/java/cn/jpush/api/push/model/Platform.java +++ b/src/main/java/cn/jpush/api/push/model/Platform.java @@ -3,13 +3,19 @@ import java.util.HashSet; import java.util.Set; -import cn.jpush.api.common.DeviceType; -import cn.jpush.api.utils.Preconditions; - +import cn.jiguang.common.DeviceType; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; +import cn.jiguang.common.utils.Preconditions; +/** + * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#platform + * + * JPush 当前支持 Android, iOS, QuickApp, HMOS 四个平台的推送。其关键字分别为:"android", "ios", "quickapp","hmos"。 + * 使用方法,只需要在PushPayload中调用setPlatform方法。如:setPlatform(Platform.android_ios()) + * 如需要全平台推送,只需要setPlatform(Platform.all()) + */ public class Platform implements PushModel { private static final String ALL = "all"; @@ -36,9 +42,13 @@ public static Platform android() { public static Platform ios() { return newBuilder().addDeviceType(DeviceType.IOS).build(); } + + public static Platform quickapp() { + return newBuilder().addDeviceType(DeviceType.QuickApp).build(); + } - public static Platform winphone() { - return newBuilder().addDeviceType(DeviceType.WinPhone).build(); + public static Platform hmos() { + return newBuilder().addDeviceType(DeviceType.HMOS).build(); } public static Platform android_ios() { @@ -48,17 +58,70 @@ public static Platform android_ios() { .build(); } - public static Platform android_winphone() { + public static Platform android_hmos() { return newBuilder() .addDeviceType(DeviceType.Android) - .addDeviceType(DeviceType.WinPhone) + .addDeviceType(DeviceType.HMOS) .build(); } - public static Platform ios_winphone() { + public static Platform ios_hmos() { + return newBuilder() + .addDeviceType(DeviceType.IOS) + .addDeviceType(DeviceType.HMOS) + .build(); + } + + public static Platform android_quickapp() { + return newBuilder() + .addDeviceType(DeviceType.Android) + .addDeviceType(DeviceType.QuickApp) + .build(); + } + + public static Platform ios_quickapp() { + return newBuilder() + .addDeviceType(DeviceType.IOS) + .addDeviceType(DeviceType.QuickApp) + .build(); + } + + public static Platform quickapp_hmos() { + return newBuilder() + .addDeviceType(DeviceType.QuickApp) + .addDeviceType(DeviceType.HMOS) + .build(); + } + + public static Platform android_ios_quickapp() { return newBuilder() + .addDeviceType(DeviceType.Android) .addDeviceType(DeviceType.IOS) - .addDeviceType(DeviceType.WinPhone) + .addDeviceType(DeviceType.QuickApp) + .build(); + } + + public static Platform android_ios_hmos() { + return newBuilder() + .addDeviceType(DeviceType.Android) + .addDeviceType(DeviceType.IOS) + .addDeviceType(DeviceType.HMOS) + .build(); + } + + public static Platform android_quickapp_hmos() { + return newBuilder() + .addDeviceType(DeviceType.Android) + .addDeviceType(DeviceType.QuickApp) + .addDeviceType(DeviceType.HMOS) + .build(); + } + + public static Platform ios_quickapp_hmos() { + return newBuilder() + .addDeviceType(DeviceType.IOS) + .addDeviceType(DeviceType.QuickApp) + .addDeviceType(DeviceType.HMOS) .build(); } @@ -78,8 +141,7 @@ public JsonElement toJSON() { } return json; } - - + public static class Builder { private boolean all; private Set deviceTypes; diff --git a/src/main/java/cn/jpush/api/push/model/PushModel.java b/src/main/java/cn/jpush/api/push/model/PushModel.java index a5275558..2be9f5d1 100644 --- a/src/main/java/cn/jpush/api/push/model/PushModel.java +++ b/src/main/java/cn/jpush/api/push/model/PushModel.java @@ -1,9 +1,11 @@ package cn.jpush.api.push.model; +import com.google.gson.Gson; import com.google.gson.JsonElement; public interface PushModel { + public static Gson gson = new Gson(); public JsonElement toJSON(); } diff --git a/src/main/java/cn/jpush/api/push/model/PushPayload.java b/src/main/java/cn/jpush/api/push/model/PushPayload.java index 1fcb2521..e3030924 100644 --- a/src/main/java/cn/jpush/api/push/model/PushPayload.java +++ b/src/main/java/cn/jpush/api/push/model/PushPayload.java @@ -1,16 +1,21 @@ package cn.jpush.api.push.model; +import cn.jiguang.common.utils.StringUtils; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.utils.Preconditions; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.notification.AndroidNotification; import cn.jpush.api.push.model.notification.IosNotification; import cn.jpush.api.push.model.notification.Notification; import cn.jpush.api.push.model.notification.PlatformNotification; -import cn.jpush.api.utils.Preconditions; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; +import java.util.LinkedHashMap; +import java.util.Map; /** * The object you should build for sending a push. @@ -22,35 +27,78 @@ * */ public class PushPayload implements PushModel { + private static final String PLATFORM = "platform"; private static final String AUDIENCE = "audience"; private static final String NOTIFICATION = "notification"; + private static final String INAPPMESSAGE = "inapp_message"; private static final String MESSAGE = "message"; private static final String OPTIONS = "options"; + private static final String SMS = "sms_message"; + private static final String NOTIFICATION3RD = "notification_3rd"; + private static final String CID = "cid"; + private static final String TARGET = "target"; + + /** + * Definition acording to JPush Docs + */ + private static final int MAX_GLOBAL_ENTITY_LENGTH = 4000; + + /** + * Definition acording to JPush Docs + */ + private static final int MAX_IOS_PAYLOAD_LENGTH = 2000; - private static final int MAX_GLOBAL_ENTITY_LENGTH = 1200; // Definition acording to JPush Docs - private static final int MAX_IOS_PAYLOAD_LENGTH = 220; // Definition acording to JPush Docs - - private static Gson _gson = new Gson(); + private static Gson _gson = new GsonBuilder().disableHtmlEscaping().create(); private final Platform platform; private final Audience audience; private final Notification notification; + private final InappMessage inappMessage; private final Message message; private Options options; - + private SMS sms; + private final Notification3rd notification3rd; + private String cid; + private String target; + protected Map custom; private PushPayload(Platform platform, Audience audience, - Notification notification, Message message, Options options) { + Notification notification, InappMessage inappMessage, Message message, Options options, + SMS sms, Notification3rd notification3rd, String cid, String target, Map custom) { this.platform = platform; this.audience = audience; this.notification = notification; + this.inappMessage = inappMessage; this.message = message; this.options = options; + this.sms = sms; + this.notification3rd = notification3rd; + this.cid = cid; + this.target = target; + this.custom = custom; } - + + public PushPayload setCid(String cid) { + this.cid = cid; + return this; + } + + public Platform getPlatform() { + return platform; + } + + public String getTarget() { + return target; + } + + public String getCid() { + return cid; + } + /** * The entrance for building a PushPayload object. + * @return PushPayload builder */ public static Builder newBuilder() { return new Builder(); @@ -58,6 +106,8 @@ public static Builder newBuilder() { /** * The shortcut of building a simple alert notification object to all platforms and all audiences + * @param alert The alert message. + * @return PushPayload */ public static PushPayload alertAll(String alert) { return new Builder() @@ -65,9 +115,20 @@ public static PushPayload alertAll(String alert) { .setAudience(Audience.all()) .setNotification(Notification.alert(alert)).build(); } + + public static PushPayload alertAll(String alert, SMS sms) { + return new Builder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setNotification(Notification.alert(alert)) + .setSMS(sms) + .build(); + } /** * The shortcut of building a simple message object to all platforms and all audiences + * @param msgContent The message content. + * @return PushPayload */ public static PushPayload messageAll(String msgContent) { return new Builder() @@ -75,6 +136,15 @@ public static PushPayload messageAll(String msgContent) { .setAudience(Audience.all()) .setMessage(Message.content(msgContent)).build(); } + + public static PushPayload messageAll(String msgContent, SMS sms) { + return new Builder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setMessage(Message.content(msgContent)) + .setSMS(sms) + .build(); + } public static PushPayload fromJSON(String payloadString) { return _gson.fromJson(payloadString, PushPayload.class); @@ -102,6 +172,14 @@ public int getSendno() { } return 0; } + + public Audience getAudience() { + return audience; + } + + public Options getOptions() { + return options; + } @Override public JsonElement toJSON() { @@ -115,16 +193,36 @@ public JsonElement toJSON() { if (null != notification) { json.add(NOTIFICATION, notification.toJSON()); } + if (null != inappMessage) { + json.add(INAPPMESSAGE, inappMessage.toJSON()); + } if (null != message) { json.add(MESSAGE, message.toJSON()); } if (null != options) { json.add(OPTIONS, options.toJSON()); } + if (null != sms) { + json.add(SMS, sms.toJSON()); + } + if (null != notification3rd) { + json.add(NOTIFICATION3RD, notification3rd.toJSON()); + } + if (null != cid) { + json.addProperty(CID, cid); + } + if (null != target) { + json.addProperty(TARGET, target); + } + if (null != custom) { + for (Map.Entry entry : custom.entrySet()) { + json.add(entry.getKey(), entry.getValue()); + } + } return json; } - + public boolean isGlobalExceedLength() { int messageLength = 0; JsonObject payload = (JsonObject) this.toJSON(); @@ -176,9 +274,24 @@ public static class Builder { private Platform platform = null; private Audience audience = null; private Notification notification = null; + private InappMessage inappMessage = null; private Message message = null; private Options options = null; - + private SMS sms = null; + private Notification3rd notification3rd = null; + private String cid; + private String target; + private Map custom; + + public Builder() { + this.custom = new LinkedHashMap(); + } + + public Builder setTarget(String target) { + this.target = target; + return this; + } + public Builder setPlatform(Platform platform) { this.platform = platform; return this; @@ -193,6 +306,11 @@ public Builder setNotification(Notification notification) { this.notification = notification; return this; } + + public Builder setInappMessage(InappMessage inappMessage) { + this.inappMessage = inappMessage; + return this; + } public Builder setMessage(Message message) { this.message = message; @@ -203,17 +321,47 @@ public Builder setOptions(Options options) { this.options = options; return this; } - + + public Builder setSMS(SMS sms) { + this.sms = sms; + return this; + } + + public Builder setNotification3rd(Notification3rd notification3rd) { + this.notification3rd = notification3rd; + return this; + } + + public Builder setCid(String cid) { + this.cid = cid; + return this; + } + + public Builder addCustom(String field, JsonObject jsonObject) { + this.custom.put(field, jsonObject); + return this; + } + public PushPayload build() { - Preconditions.checkArgument(! (null == audience || null == platform), "audience and platform both should be set."); - Preconditions.checkArgument(! (null == notification && null == message), "notification or message should be set at least one."); + + if (StringUtils.isTrimedEmpty(target)) { + Preconditions.checkArgument(!(null == audience || null == platform), + "audience and platform both should be set."); + } + if (!StringUtils.isTrimedEmpty(target)) { + Preconditions.checkArgument(!StringUtils.isTrimedEmpty(target) && null != platform, + "target and platform should be set."); + } + + Preconditions.checkArgument(! (null == notification && null == message), + "notification or message should be set at least one."); // if options is not set, a sendno will be generated for tracing easily if (null == options) { options = Options.sendno(); } - return new PushPayload(platform, audience, notification, message, options); + return new PushPayload(platform, audience, notification, inappMessage, message, options, sms, notification3rd, cid, target, custom); } } } diff --git a/src/main/java/cn/jpush/api/push/model/SMS.java b/src/main/java/cn/jpush/api/push/model/SMS.java new file mode 100644 index 00000000..b0a02ef4 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/SMS.java @@ -0,0 +1,220 @@ +package cn.jpush.api.push.model; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.utils.Preconditions; + +/** + * sms_message 用于设置短信推送内容以及短信发送的延迟时间。 + */ +public class SMS implements PushModel { + + private final String content; + private final int delay_time; + private final long temp_id; + // default is true + private boolean active_filter; + // this flag is used to indicate if the active_filter being set + private boolean is_set_active_filter = false; + private final Map extras; + private final Map numberExtras; + private final Map booleanExtras; + private final Map jsonExtras; + + private SMS(String content, int delay_time, long temp_id, boolean active_filter, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras) { + this.content = content; + this.delay_time = delay_time; + this.temp_id = temp_id; + this.active_filter = active_filter; + this.extras = extras; + this.numberExtras = numberExtras; + this.booleanExtras = booleanExtras; + this.jsonExtras = jsonExtras; + + } + + public static Builder newBuilder() { + return new Builder(); + } + + /** + * This will be removed in the future. Please use content(long tempId, int delayTime) this constructor. + * Create a SMS content with a delay time. + * JPush will send a SMS if the message doesn't received within the delay time. If the delay time is 0, the SMS will be sent immediately. + * Please note the delay time only works on Android. + * If you are pushing to iOS, the SMS will be sent immediately, whether or not the delay time is 0. + * + * @param content The SMS content. + * @param delayTime The seconds you want to delay, should be greater than or equal to 0. + * @return SMS payload. + */ + @Deprecated + public static SMS content(String content, int delayTime) { + return new Builder() + .setContent(content) + .setDelayTime(delayTime) + .build(); + } + + public static SMS content(long tempId, int delayTime) { + return new Builder() + .setTempID(tempId) + .setDelayTime(delayTime) + .build(); + } + + + @Override + public JsonElement toJSON() { + JsonObject json = new JsonObject(); + + json.addProperty("delay_time", delay_time); + + if (temp_id > 0) { + json.addProperty("temp_id", temp_id); + } + + if (null != content) { + json.addProperty("content", content); + } + + json.addProperty("active_filter", active_filter); + + + JsonObject extrasObject = null; + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { + extrasObject = new JsonObject(); + } + + if (null != extras) { + for (String key : extras.keySet()) { + if (extras.get(key) != null) { + extrasObject.add(key, new JsonPrimitive(extras.get(key))); + } else { + extrasObject.add(key, JsonNull.INSTANCE); + } + } + } + if (null != numberExtras) { + for (String key : numberExtras.keySet()) { + extrasObject.add(key, new JsonPrimitive(numberExtras.get(key))); + } + } + if (null != booleanExtras) { + for (String key : booleanExtras.keySet()) { + extrasObject.add(key, new JsonPrimitive(booleanExtras.get(key))); + } + } + if (null != jsonExtras) { + for (String key : jsonExtras.keySet()) { + extrasObject.add(key, jsonExtras.get(key)); + } + } + + if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { + json.add("temp_para", extrasObject); + } + return json; + } + + public static class Builder { + private String content; + private int delay_time; + private long temp_id; + private boolean active_filter; + private boolean is_set_active_filter; + private Map extrasBuilder; + private Map numberExtrasBuilder; + private Map booleanExtrasBuilder; + protected Map jsonExtrasBuilder; + + public Builder setContent(String content) { + this.content = content; + return this; + } + + public Builder setDelayTime(int delayTime) { + this.delay_time = delayTime; + return this; + } + + public Builder setTempID(long tempID) { + this.temp_id = tempID; + return this; + } + + public Builder setActiveFilter(boolean activeFilter) { + this.active_filter = activeFilter; + this.is_set_active_filter = true; + return this; + } + + public Builder addPara(String key, String value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == extrasBuilder) { + extrasBuilder = new HashMap(); + } + extrasBuilder.put(key, value); + return this; + } + + public Builder addParas(Map extras) { + Preconditions.checkArgument(! (null == extras), "extras should not be null."); + if (null == extrasBuilder) { + extrasBuilder = new HashMap(); + } + for (String key : extras.keySet()) { + extrasBuilder.put(key, extras.get(key)); + } + return this; + } + + public Builder addPara(String key, Number value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == numberExtrasBuilder) { + numberExtrasBuilder = new HashMap(); + } + numberExtrasBuilder.put(key, value); + return this; + } + + public Builder addPara(String key, Boolean value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == booleanExtrasBuilder) { + booleanExtrasBuilder = new HashMap(); + } + booleanExtrasBuilder.put(key, value); + return this; + } + + public Builder addPara(String key, JsonObject value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == jsonExtrasBuilder) { + jsonExtrasBuilder = new HashMap(); + } + jsonExtrasBuilder.put(key, value); + return this; + } + + public SMS build() { + Preconditions.checkArgument(delay_time >= 0, "The delay time must be greater than or equal to 0"); + + // if active filter not being set, will default set it to true. + if (is_set_active_filter == false) { active_filter = true; } + + return new SMS(content, delay_time, temp_id, active_filter, + extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder,jsonExtrasBuilder); + } + + } +} diff --git a/src/main/java/cn/jpush/api/push/model/audience/Audience.java b/src/main/java/cn/jpush/api/push/model/audience/Audience.java index 6f3a0fd6..3aad28c9 100644 --- a/src/main/java/cn/jpush/api/push/model/audience/Audience.java +++ b/src/main/java/cn/jpush/api/push/model/audience/Audience.java @@ -1,27 +1,29 @@ package cn.jpush.api.push.model.audience; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - +import cn.jiguang.common.utils.Preconditions; import cn.jpush.api.push.model.PushModel; -import cn.jpush.api.utils.Preconditions; - +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + public class Audience implements PushModel { private static final String ALL = "all"; private final boolean all; + private final boolean file; private final Set targets; - private Audience(boolean all, Set targets) { + private Audience(boolean all, boolean file, Set targets) { this.all = all; + this.file = file; this.targets = targets; } - + public static Builder newBuilder() { return new Builder(); } @@ -31,75 +33,80 @@ public static Audience all() { } public static Audience tag(String... tagValue) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValues(tagValue).build(); + AudienceTarget target = AudienceTarget.tag(tagValue); return newBuilder().addAudienceTarget(target).build(); } public static Audience tag(Collection tagValues) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValues(tagValues).build(); + AudienceTarget target = AudienceTarget.tag(tagValues); return newBuilder().addAudienceTarget(target).build(); } public static Audience tag_and(String... tagValue) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG_AND) - .addAudienceTargetValues(tagValue).build(); + AudienceTarget target = AudienceTarget.tag_and(tagValue); return newBuilder().addAudienceTarget(target).build(); } public static Audience tag_and(Collection tagValues) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG_AND) - .addAudienceTargetValues(tagValues).build(); + AudienceTarget target = AudienceTarget.tag_and(tagValues); + return newBuilder().addAudienceTarget(target).build(); + } + + public static Audience tag_not(String...tagValue) { + AudienceTarget target = AudienceTarget.tag_not(tagValue); + return newBuilder().addAudienceTarget(target).build(); + } + + public static Audience tag_not(Collection tagValues) { + AudienceTarget target = AudienceTarget.tag_not(tagValues); return newBuilder().addAudienceTarget(target).build(); } public static Audience alias(String... alias) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.ALIAS) - .addAudienceTargetValues(alias).build(); + AudienceTarget target = AudienceTarget.alias(alias); return newBuilder().addAudienceTarget(target).build(); } public static Audience alias(Collection aliases) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.ALIAS) - .addAudienceTargetValues(aliases).build(); + AudienceTarget target = AudienceTarget.alias(aliases); return newBuilder().addAudienceTarget(target).build(); } public static Audience segment(String... segment) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.SEGMENT) - .addAudienceTargetValues(segment).build(); + AudienceTarget target = AudienceTarget.segment(segment); return newBuilder().addAudienceTarget(target).build(); } public static Audience segment(Collection segments) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.SEGMENT) - .addAudienceTargetValues(segments).build(); + AudienceTarget target = AudienceTarget.segment(segments); return newBuilder().addAudienceTarget(target).build(); } public static Audience registrationId(String... registrationId) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.REGISTRATION_ID) - .addAudienceTargetValues(registrationId).build(); + AudienceTarget target = AudienceTarget.registrationId(registrationId); return newBuilder().addAudienceTarget(target).build(); } public static Audience registrationId(Collection registrationIds) { - AudienceTarget target = AudienceTarget.newBuilder() - .setAudienceType(AudienceType.REGISTRATION_ID) - .addAudienceTargetValues(registrationIds).build(); + AudienceTarget target = AudienceTarget.registrationId(registrationIds); return newBuilder().addAudienceTarget(target).build(); } - + + public static Audience abTest(String... abTestId) { + AudienceTarget target = AudienceTarget.abTest(abTestId); + return newBuilder().addAudienceTarget(target).build(); + } + + public static Audience abTest(Collection abTestIds) { + AudienceTarget target = AudienceTarget.abTest(abTestIds); + return newBuilder().addAudienceTarget(target).build(); + } + + public static Audience file(String fileId) { + AudienceTarget target = AudienceTarget.file(fileId); + return newBuilder().setFile(Boolean.TRUE).addAudienceTarget(target).build(); + } + public boolean isAll() { return this.all; @@ -109,9 +116,17 @@ public JsonElement toJSON() { if (all) { return new JsonPrimitive(ALL); } - + // if not all, there will be target be set. JsonObject json = new JsonObject(); + if (file) { + for (AudienceTarget target : targets) { + if (AudienceType.FILE == target.getAudienceType()) { + json.add(target.getAudienceTypeValue(), target.toFileJSON()); + } + } + return json; + } if (null != targets) { for (AudienceTarget target : targets) { json.add(target.getAudienceTypeValue(), target.toJSON()); @@ -119,16 +134,46 @@ public JsonElement toJSON() { } return json; } - + + public static Audience fromJsonElement(JsonElement jsonElement) { + if (jsonElement == null) { + return null; + } + boolean all = !jsonElement.isJsonObject(); + if (all) { + return new Audience(true, false,null); + } + boolean file = false; + JsonObject jsonObject = jsonElement.getAsJsonObject(); + Set audienceTargetSet = new HashSet(); + for (AudienceType type : AudienceType.values()) { + JsonArray jsonArray = jsonObject.getAsJsonArray(type.value()); + if (jsonArray == null) { + continue; + } + if (AudienceType.FILE == type) { + file = true; + } + audienceTargetSet.add(AudienceTarget.fromJsonElement(jsonArray, type)); + } + return new Audience(false, file, audienceTargetSet); + } + public static class Builder { private boolean all = false; + private boolean file = false; private Set audienceBuilder = null; - + public Builder setAll(boolean all) { this.all = all; return this; } - + + public Builder setFile(boolean file) { + this.file = file; + return this; + } + public Builder addAudienceTarget(AudienceTarget target) { if (null == audienceBuilder) { audienceBuilder = new HashSet(); @@ -136,14 +181,14 @@ public Builder addAudienceTarget(AudienceTarget target) { audienceBuilder.add(target); return this; } - + public Audience build() { Preconditions.checkArgument(! (all && null != audienceBuilder), "If audience is all, no any other audience may be set."); Preconditions.checkArgument(! (all == false && null == audienceBuilder), "No any audience target is set."); - return new Audience(all, audienceBuilder); + return new Audience(all, file, audienceBuilder); } } - + } diff --git a/src/main/java/cn/jpush/api/push/model/audience/AudienceTarget.java b/src/main/java/cn/jpush/api/push/model/audience/AudienceTarget.java index fd40a844..47b6f4e5 100644 --- a/src/main/java/cn/jpush/api/push/model/audience/AudienceTarget.java +++ b/src/main/java/cn/jpush/api/push/model/audience/AudienceTarget.java @@ -1,49 +1,57 @@ package cn.jpush.api.push.model.audience; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - +import cn.jiguang.common.utils.Preconditions; import cn.jpush.api.push.model.PushModel; -import cn.jpush.api.utils.Preconditions; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + public class AudienceTarget implements PushModel { private final AudienceType audienceType; private final Set values; - + private AudienceTarget(AudienceType audienceType, Set values) { this.audienceType = audienceType; this.values = values; } - + public static Builder newBuilder() { return new Builder(); } - + public static AudienceTarget tag(String... tag) { return newBuilder().setAudienceType(AudienceType.TAG).addAudienceTargetValues(tag).build(); } - + public static AudienceTarget tag(Collection tags) { return newBuilder().setAudienceType(AudienceType.TAG).addAudienceTargetValues(tags).build(); } - + public static AudienceTarget tag_and(String... tag) { return newBuilder().setAudienceType(AudienceType.TAG_AND).addAudienceTargetValues(tag).build(); } - + public static AudienceTarget tag_and(Collection tags) { return newBuilder().setAudienceType(AudienceType.TAG_AND).addAudienceTargetValues(tags).build(); } - + + public static AudienceTarget tag_not(String...tag) { + return newBuilder().setAudienceType(AudienceType.TAG_NOT).addAudienceTargetValues(tag).build(); + } + + public static AudienceTarget tag_not(Collection tags) { + return newBuilder().setAudienceType(AudienceType.TAG_NOT).addAudienceTargetValues(tags).build(); + } + public static AudienceTarget alias(String... alias) { return newBuilder().setAudienceType(AudienceType.ALIAS).addAudienceTargetValues(alias).build(); } - + public static AudienceTarget alias(Collection aliases) { return newBuilder().setAudienceType(AudienceType.ALIAS).addAudienceTargetValues(aliases).build(); } @@ -51,40 +59,80 @@ public static AudienceTarget alias(Collection aliases) { public static AudienceTarget registrationId(String... registrationId) { return newBuilder().setAudienceType(AudienceType.REGISTRATION_ID).addAudienceTargetValues(registrationId).build(); } - + public static AudienceTarget registrationId(Collection registrationIds) { return newBuilder().setAudienceType(AudienceType.REGISTRATION_ID).addAudienceTargetValues(registrationIds).build(); } - - + + public static AudienceTarget segment(String... segment) { + return newBuilder().setAudienceType(AudienceType.SEGMENT).addAudienceTargetValues(segment).build(); + } + + public static AudienceTarget segment(Collection segments) { + return newBuilder().setAudienceType(AudienceType.SEGMENT).addAudienceTargetValues(segments).build(); + } + + public static AudienceTarget abTest(String... abTestId) { + return newBuilder().setAudienceType(AudienceType.ABTEST).addAudienceTargetValues(abTestId).build(); + } + + public static AudienceTarget abTest(Collection abTestIds) { + return newBuilder().setAudienceType(AudienceType.ABTEST).addAudienceTargetValues(abTestIds).build(); + } + + public static AudienceTarget file(String fileId) { + return newBuilder().setAudienceType(AudienceType.FILE).addFileId(fileId).build(); + } + + public AudienceType getAudienceType() { return this.audienceType; } - + public String getAudienceTypeValue() { return this.audienceType.value(); } - + public JsonElement toJSON() { JsonArray array = new JsonArray(); - if (null != values) { - for (String value : values) { - array.add(new JsonPrimitive(value)); - } - } + if (null != values) { + for (String value : values) { + array.add(new JsonPrimitive(value)); + } + } return array; } - - + + public JsonElement toFileJSON() { + JsonObject jsonObject = new JsonObject(); + if (null != values) { + for (String value : values) { + jsonObject.add("file_id", new JsonPrimitive(value)); + } + } + return jsonObject; + } + + public static AudienceTarget fromJsonElement(JsonArray jsonArray, AudienceType type) { + Set stringSet = new HashSet(); + if (jsonArray != null) { + for (int i=0; i valueBuilder = null; - + public Builder setAudienceType(AudienceType audienceType) { this.audienceType = audienceType; return this; } - + public Builder addAudienceTargetValue(String value) { if (null == valueBuilder) { valueBuilder = new HashSet(); @@ -92,7 +140,7 @@ public Builder addAudienceTargetValue(String value) { valueBuilder.add(value); return this; } - + public Builder addAudienceTargetValues(Collection values) { if (null == valueBuilder) { valueBuilder = new HashSet(); @@ -102,7 +150,7 @@ public Builder addAudienceTargetValues(Collection values) { } return this; } - + public Builder addAudienceTargetValues(String... values) { if (null == valueBuilder) { valueBuilder = new HashSet(); @@ -112,11 +160,21 @@ public Builder addAudienceTargetValues(String... values) { } return this; } - + + public Builder addFileId(String fileId) { + if (null == valueBuilder) { + valueBuilder = new HashSet(); + } + valueBuilder.add(fileId); + return this; + } + public AudienceTarget build() { Preconditions.checkArgument(null != audienceType, "AudienceType should be set."); Preconditions.checkArgument(null != valueBuilder, "Target values should be set one at least."); return new AudienceTarget(audienceType, valueBuilder); } + + } } diff --git a/src/main/java/cn/jpush/api/push/model/audience/AudienceType.java b/src/main/java/cn/jpush/api/push/model/audience/AudienceType.java index 2ba55b5f..2d2da7f9 100644 --- a/src/main/java/cn/jpush/api/push/model/audience/AudienceType.java +++ b/src/main/java/cn/jpush/api/push/model/audience/AudienceType.java @@ -3,11 +3,17 @@ public enum AudienceType { TAG("tag"), TAG_AND("tag_and"), + TAG_NOT("tag_not"), ALIAS("alias"), SEGMENT("segment"), - REGISTRATION_ID("registration_id"); - + ABTEST("abtest"), + REGISTRATION_ID("registration_id"), + FILE("file"), + + ; + private final String value; + private AudienceType(final String value) { this.value = value; } @@ -15,5 +21,13 @@ public String value() { return this.value; } - + public static AudienceType getType(String value) { + for (AudienceType type: AudienceType.values()) { + if (type.value.equals(value)) { + return type; + } + } + return null; + } + } diff --git a/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivity.java b/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivity.java new file mode 100644 index 00000000..2a8fa091 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivity.java @@ -0,0 +1,180 @@ +package cn.jpush.api.push.model.live_activity; + +import cn.jpush.api.push.model.PushModel; +import com.google.gson.*; + +public class LiveActivity implements PushModel { + + private final Boolean apnsProduction; + + private final String liveActivityId; + + private final String iOSEvent; + private final JsonObject iOSContentState; + private final Long iOSDismissalDate; + private final JsonObject iOSAlert; + + public LiveActivity(Boolean apnsProduction, String liveActivityId, String iOSEvent, JsonObject iOSContentState, Long iOSDismissalDate, JsonObject iOSAlert) { + this.apnsProduction = apnsProduction; + this.liveActivityId = liveActivityId; + this.iOSEvent = iOSEvent; + this.iOSContentState = iOSContentState; + this.iOSDismissalDate = iOSDismissalDate; + this.iOSAlert = iOSAlert; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private Boolean apnsProduction; + private String liveActivityId; + private String iOSEvent; + private JsonObject iOSContentState; + private Long iOSDismissalDate; + private JsonObject iOSAlert; + + public Builder apnsProduction(Boolean apnsProduction) { + this.apnsProduction = apnsProduction; + return this; + } + + public Builder liveActivityId(String liveActivityId) { + this.liveActivityId = liveActivityId; + return this; + } + + public Builder iOSEvent(LiveActivityEvent iOSEvent) { + if (iOSEvent != null) { + this.iOSEvent = iOSEvent.getValue(); + } + return this; + } + + public Builder iOSContentState(String key, String value) { + if (this.iOSContentState == null) { + this.iOSContentState = new JsonObject(); + } + this.iOSContentState.addProperty(key, value); + return this; + } + + public Builder iOSContentState(String key, Number value) { + if (this.iOSContentState == null) { + this.iOSContentState = new JsonObject(); + } + this.iOSContentState.addProperty(key, value); + return this; + } + + public Builder iOSContentState(String key, Boolean value) { + if (this.iOSContentState == null) { + this.iOSContentState = new JsonObject(); + } + this.iOSContentState.addProperty(key, value); + return this; + } + + public Builder iOSDismissalDate(Long iOSDismissalDate) { + this.iOSDismissalDate = iOSDismissalDate; + return this; + } + + public Builder iOSAlertTitle(String iosAlertTitle) { + if (this.iOSAlert == null) { + this.iOSAlert = new JsonObject(); + } + this.iOSAlert.addProperty("title", iosAlertTitle); + return this; + } + + public Builder iOSAlertAlternateTitle(String iosAlertAlternateTitle) { + if (this.iOSAlert == null) { + this.iOSAlert = new JsonObject(); + } + this.iOSAlert.addProperty("alternate_title", iosAlertAlternateTitle); + return this; + } + + public Builder iOSAlertBody(String iosAlertBody) { + if (this.iOSAlert == null) { + this.iOSAlert = new JsonObject(); + } + this.iOSAlert.addProperty("body", iosAlertBody); + return this; + } + + public Builder iOSAlertAlternateBody(String iosAlertAlternateBody) { + if (this.iOSAlert == null) { + this.iOSAlert = new JsonObject(); + } + this.iOSAlert.addProperty("alternate_body", iosAlertAlternateBody); + return this; + } + + public Builder iOSAlertSound(String iosAlertSound) { + if (this.iOSAlert == null) { + this.iOSAlert = new JsonObject(); + } + this.iOSAlert.addProperty("sound", iosAlertSound); + return this; + } + + public LiveActivity build() { + return new LiveActivity(apnsProduction, liveActivityId, iOSEvent, iOSContentState, iOSDismissalDate, iOSAlert); + } + + } + + @Override + public JsonElement toJSON() { + JsonObject pushJsonObject = new JsonObject(); + + JsonArray platformJsonArray = new JsonArray(); + platformJsonArray.add(new JsonPrimitive("ios")); + + JsonObject audienceJsonObject = new JsonObject(); + if (liveActivityId != null) { + audienceJsonObject.addProperty("live_activity_id", liveActivityId); + } + + JsonObject liveActivityJsonObject = new JsonObject(); + JsonObject iOSJsonObject = new JsonObject(); + + if (iOSEvent != null) { + iOSJsonObject.addProperty("event", iOSEvent); + } + + if (iOSContentState != null) { + iOSJsonObject.add("content-state", iOSContentState); + } + + if (iOSDismissalDate != null) { + iOSJsonObject.addProperty("dismissal-date", iOSDismissalDate); + } + + if (iOSAlert != null) { + iOSJsonObject.add("alert", iOSAlert); + } + + if (!iOSJsonObject.entrySet().isEmpty()) { + liveActivityJsonObject.add("ios", iOSJsonObject); + } + + JsonObject optionsJsonObject = new JsonObject(); + if (apnsProduction != null) { + optionsJsonObject.addProperty("apns_production", apnsProduction); + } + if (iOSAlert != null) { + optionsJsonObject.addProperty("alternate_set", true); + } + + pushJsonObject.add("platform", platformJsonArray); + pushJsonObject.add("audience", audienceJsonObject); + pushJsonObject.add("live_activity", liveActivityJsonObject); + pushJsonObject.add("options", optionsJsonObject); + return pushJsonObject; + } + +} diff --git a/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivityEvent.java b/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivityEvent.java new file mode 100644 index 00000000..4f53e546 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/live_activity/LiveActivityEvent.java @@ -0,0 +1,24 @@ +package cn.jpush.api.push.model.live_activity; + +public enum LiveActivityEvent { + + UPDATE("update", "更新"), + END("end", "结束,dismissal-date为结束展示时间"); + + private String value; + private String describe; + + LiveActivityEvent(String value, String describe) { + this.value = value; + this.describe = describe; + } + + public String getValue() { + return this.value; + } + + public String getDescribe() { + return this.describe; + } + +} diff --git a/src/main/java/cn/jpush/api/push/model/notification/AndroidNotification.java b/src/main/java/cn/jpush/api/push/model/notification/AndroidNotification.java index b1d362b0..5cbac1e8 100644 --- a/src/main/java/cn/jpush/api/push/model/notification/AndroidNotification.java +++ b/src/main/java/cn/jpush/api/push/model/notification/AndroidNotification.java @@ -1,87 +1,448 @@ package cn.jpush.api.push.model.notification; -import java.util.Map; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import java.util.Map; + +/** + *

Android 通知类

+ *
+ * 具体使用方法请参考官方文档 + * 支持 Android Notification 的参数: + *
    + *
  • alert: 继承自父类 PlatformNotification 的 alert 属性;本类设置则覆盖。
  • + *
  • title: 支持 setTitle(string) 方法来设置;可替换展示App名称的地方。
  • + *
  • builder_id: 支持 setBuilderId(int) 方法来设置。android 8.0 开始建议采用NotificationChannel配置。
  • + *
  • channel_id: 支持 setChannelId(string) 方法来设置;不超过1000字节。
  • + *
  • priority: 支持 setPriority(int) 方法来设置。可改变通知栏展示优先级
  • + *
  • category: 支持 setCategory(string) 方法来设置。
  • + *
  • style: 支持 setStyle(int) 方法来设置;可改变通知栏样式类型。
  • + *
  • alert_type: 支持 setAlertType(int) 方法来设置;可改变通知方式。
  • + *
  • big_text: 支持 setBigText(string) 方法来设置;可改变大文本通知栏样式。
  • + *
  • inbox: 支持 setInbox(JSONObject) 方法来设置;可改变文本条目通知栏样式。
  • + *
  • big_pic_path: 支持 setBigPicPath(string) 方法来设置;可改变大图片通知栏样式。
  • + *
  • extras: 继承自父类 PlatformNotification 的 extras 属性;支持通过 addExtra(key, value) 来添加自定义字段,具体看代码。
  • + *
  • large_icon: 支持 setLargeIcon(string) 方法来设置;可设置通知栏大图标。
  • + *
  • small_icon_uri: 支持 setSmallIconUri(string) 方法来设置;可设置通知栏小图标。
  • + *
  • intent: 支持 setIntent(JSONObject) 方法来设置; 可指定跳转页面。
  • + *
  • uri_activity: 支持 setUriActivity(string) 方法来设置; 可指定跳转页面。
  • + *
  • uri_action: 支持 setUriAction(string) 方法来设置;可指定跳转页面。
  • + *
  • badge_add_num: 支持 setBadgeAddNum(int) 方法来设置;可指定角标数字增加
  • + *
  • badge_class: 支持 setBadgeClass(string) 方法来设置;配合badge_add_num使用,二者需要共存,缺一不可。
  • + *
  • sound: 支持 setSound(string) 方法来设置声音文件;填写文件名称即可,无需文件名后缀。
  • + *
  • show_begin_time: 支持 setShowBeginTime(string) 方法来设置;可定时展示开始时间。
  • + *
  • show_end_time: 支持 setShowEndTime(string) 方法来设置;可定时展示结束时间。
  • + *
  • display_foreground: 支持 setDisplayForeground(string) 方法来设置; 可设置app在前台,通知是否展示。
  • + **
+ *
+ */ public class AndroidNotification extends PlatformNotification { public static final String NOTIFICATION_ANDROID = "android"; - + private static final String TITLE = "title"; private static final String BUILDER_ID = "builder_id"; - + private static final String CHANNEL_ID = "channel_id"; + private static final String PRIORITY = "priority"; + private static final String CATEGORY = "category"; + private static final String STYLE = "style"; + private static final String ALERT_TYPE = "alert_type"; + private static final String BIG_TEXT = "big_text"; + private static final String INBOX = "inbox"; + private static final String BIG_PIC_PATH = "big_pic_path"; + private static final String LARGE_ICON = "large_icon"; + private static final String SMALL_ICON_URI = "small_icon_uri"; + private static final String INTENT = "intent"; + private static final String URI_ACTIVITY = "uri_activity"; + private static final String URI_ACTION = "uri_action"; + private static final String BADGE_ADD_NUM = "badge_add_num"; + private static final String BADGE_CLASS = "badge_class"; + private static final String SOUND = "sound"; + private static final String SHOW_BEGIN_TIME = "show_begin_time"; + private static final String SHOW_END_TIME = "show_end_time"; + private static final String DISPLAY_FOREGROUND = "display_foreground"; + private final String title; private final int builderId; - - private AndroidNotification(String alert, String title, int builderId, - Map extras, - Map numberExtras, - Map booleanExtras, - Map jsonExtras) { - super(alert, extras, numberExtras, booleanExtras, jsonExtras); - + private String channelId; + // range from [-2 ~ 2], default is 0 + private int priority; + private String category; + // range from [0 ~ 3], default is 0. bigText=1, Inbox=2, bigPicture=3. + private int style = 0; + // range from [-1 ~ 7], default is -1 + private int alert_type; + private String big_text; + private Object inbox; + private String big_pic_path; + private String large_icon; + private String small_icon_uri; + private JsonObject intent; + private String uri_activity; + private String uri_action; + // range from [1 ~ 99], suggest set to 1 + private int badge_add_num; + private String badge_class; + private String sound; + private String show_begin_time; + private String show_end_time; + private String display_foreground; + + private AndroidNotification(Object alert, + String title, + int builderId, + String channelId, + int priority, + String category, + int style, + int alertType, + String bigText, + Object inbox, + String bigPicPath, + String large_icon, + String small_icon_uri, + JsonObject intent, + String uri_activity, + String uri_action, + int badge_add_num, + String badge_class, + String sound, + String show_begin_time, + String show_end_time, + String display_foreground, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras, + Map customData) { + super(alert, extras, numberExtras, booleanExtras, jsonExtras, customData); + this.title = title; this.builderId = builderId; + this.channelId = channelId; + this.priority = priority; + this.category = category; + this.style = style; + this.alert_type = alertType; + this.big_text = bigText; + this.inbox = inbox; + this.big_pic_path = bigPicPath; + this.large_icon = large_icon; + this.small_icon_uri = small_icon_uri; + this.intent = intent; + this.uri_activity = uri_activity; + this.uri_action = uri_action; + this.badge_add_num = badge_add_num; + this.badge_class = badge_class; + this.sound = sound; + this.show_begin_time = show_begin_time; + this.show_end_time = show_end_time; + this.display_foreground = display_foreground; + } - + public static Builder newBuilder() { return new Builder(); } - + public static AndroidNotification alert(String alert) { return newBuilder().setAlert(alert).build(); } - - + @Override public String getPlatform() { return NOTIFICATION_ANDROID; } - + + protected Object getInbox() { + return this.inbox; + } + + protected void setInbox(Object inbox) { + this.inbox = inbox; + } + @Override public JsonElement toJSON() { JsonObject json = super.toJSON().getAsJsonObject(); - + + if (null != title) { + json.add(TITLE, new JsonPrimitive(title)); + } + if (builderId > 0) { json.add(BUILDER_ID, new JsonPrimitive(this.builderId)); } - if (null != title) { - json.add(TITLE, new JsonPrimitive(title)); + + if (null != channelId) { + json.add(CHANNEL_ID, new JsonPrimitive(channelId)); + } + + // 默认为 0 + if (0 != priority) { + json.add(PRIORITY, new JsonPrimitive(priority)); + } + + if (null != category) { + json.add(CATEGORY, new JsonPrimitive(category)); + } + + // 默认是 0 + if (0 != style) { + json.add(STYLE, new JsonPrimitive(this.style)); + } + + if (-1 != alert_type && alert_type <= 7) { + json.add(ALERT_TYPE, new JsonPrimitive(this.alert_type)); } - + + if (null != big_text) { + json.add(BIG_TEXT, new JsonPrimitive(this.big_text)); + } + + if (null != inbox) { + if (inbox instanceof JsonObject) { + json.add(INBOX, (JsonObject) inbox); + } + } + + if (null != big_pic_path) { + json.add(BIG_PIC_PATH, new JsonPrimitive(this.big_pic_path)); + } + + if (null != large_icon) { + json.add(LARGE_ICON, new JsonPrimitive(this.large_icon)); + } + + if (null != small_icon_uri) { + json.add(SMALL_ICON_URI, new JsonPrimitive(this.small_icon_uri)); + } + + if (null != intent) { + json.add(INTENT, intent); + } + + if (null != uri_activity) { + json.add(URI_ACTIVITY, new JsonPrimitive(this.uri_activity)); + } + + if (null != uri_action) { + json.add(URI_ACTION, new JsonPrimitive(this.uri_action)); + } + + // 如果不填写,表示不改变角标数字 + if (0 != badge_add_num) { + json.add(BADGE_ADD_NUM, new JsonPrimitive(this.badge_add_num)); + } + + if (null != badge_class) { + json.add(BADGE_CLASS, new JsonPrimitive(this.badge_class)); + } + + if (null != sound) { + json.add(SOUND, new JsonPrimitive(this.sound)); + } + + if (null != show_begin_time) { + json.add(SHOW_BEGIN_TIME, new JsonPrimitive(this.show_begin_time)); + } + + if (null != show_end_time) { + json.add(SHOW_END_TIME, new JsonPrimitive(this.show_end_time)); + } + + if (null != display_foreground) { + json.add(DISPLAY_FOREGROUND, new JsonPrimitive(this.display_foreground)); + } + + return json; } - - + public static class Builder extends PlatformNotification.Builder { private String title; private int builderId; - + private String channelId; + private int priority; + private String category; + private int style = 0; + private int alert_type = -1; + private String big_text; + private Object inbox; + private String big_pic_path; + private String large_icon; + private String small_icon_uri; + private JsonObject intent; + private String uri_activity; + private String uri_action; + private int badge_add_num; + private String badge_class; + private String sound; + private String show_begin_time; + private String show_end_time; + private String display_foreground; + + @Override protected Builder getThis() { - return this; + return this; } - + + @Override + public Builder setAlert(Object alert) { + this.alert = alert; + return this; + } + public Builder setTitle(String title) { this.title = title; return this; } - + public Builder setBuilderId(int builderId) { this.builderId = builderId; return this; } - - public Builder setAlert(String alert) { - this.alert = alert; + + public String getChannelId() { + return channelId; + } + + public Builder setChannelId(String channelId) { + this.channelId = channelId; + return this; + } + + public Builder setPriority(int priority) { + this.priority = priority; + return this; + } + + public Builder setCategory(String category) { + this.category = category; + return this; + } + + public Builder setStyle(int style) { + this.style = style; + return this; + } + + public Builder setAlertType(int alertType) { + this.alert_type = alertType; + return this; + } + + public Builder setBigText(String bigText) { + this.big_text = bigText; + return this; + } + + public Builder setInbox(Object inbox) { + if (null == inbox) { + LOG.warn("Null inbox. Throw away it."); + return this; + } + this.inbox = inbox; + return this; + } + + public Builder setBigPicPath(String bigPicPath) { + this.big_pic_path = bigPicPath; + return this; + } + + public Builder setLargeIcon(String largeIcon) { + this.large_icon = largeIcon; return this; } - - + + public Builder setSmallIconUri(String smallIconUri) { + this.small_icon_uri = smallIconUri; + return this; + } + + public Builder setIntent(JsonObject intent) { + if (null == intent) { + LOG.warn("Null intent. Throw away it."); + return this; + } + this.intent = intent; + return this; + } + + public Builder setUriActivity(String uriActivity) { + this.uri_activity = uriActivity; + return this; + } + + public Builder setUriAction(String uriAction) { + this.uri_action = uriAction; + return this; + } + + public Builder setBadgeAddNum(int badgeAddNum) { + this.badge_add_num = badgeAddNum; + return this; + } + + public Builder setBadgeClass(String badgeClass) { + this.badge_class = badgeClass; + return this; + } + + public Builder setSound(String sound) { + this.sound = sound; + return this; + } + + public Builder setShowBeginTime(String showBeginTime) { + this.show_begin_time = showBeginTime; + return this; + } + + public Builder setShowEndTime(String showEndTime) { + this.show_end_time = showEndTime; + return this; + } + + public Builder setDisplayForeground(String displayForeground) { + this.display_foreground = displayForeground; + return this; + } + + + @Override public AndroidNotification build() { - return new AndroidNotification(alert, title, builderId, - extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder); + return new AndroidNotification( + alert, + title, + builderId, + channelId, + priority, + category, + style, + alert_type, + big_text, + inbox, + big_pic_path, + large_icon, + small_icon_uri, + intent, + uri_activity, + uri_action, + badge_add_num, + badge_class, + sound, + show_begin_time, + show_end_time, + display_foreground, + extrasBuilder, + numberExtrasBuilder, + booleanExtrasBuilder, + jsonExtrasBuilder, + super.customData + ); } } } diff --git a/src/main/java/cn/jpush/api/push/model/notification/HmosNotification.java b/src/main/java/cn/jpush/api/push/model/notification/HmosNotification.java new file mode 100644 index 00000000..71e9135e --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/notification/HmosNotification.java @@ -0,0 +1,168 @@ +package cn.jpush.api.push.model.notification; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.util.Map; + +/** + *

HMOS Phone 通知类

+ *
+ * 具体使用方法请参考官方文档 https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#platform + * 支持 HMOS Notification 的参数: + *
    + *
  • alert: 继承自父类 PlatformNotification 的 alert 属性;本类设置则覆盖。
  • + *
  • title: 支持 setTitle(string) 方法来设置;可替换通知标题。
  • + *
  • _open_page: 支持 setOpenPage(String) 方法来设置;可设置点击打开的页面名称
  • + *
  • extras: 继承自父类 PlatformNotification 的 extras 属性;支持通过 addExtra(key, value) 来添加自定义字段,具体看代码。
  • + *
+ *
+ */ +public class HmosNotification extends PlatformNotification { + private static final String NOTIFICATION_HMOS = "hmos"; + + private static final String TITLE = "title"; + private static final String CATEGORY = "category"; + private static final String LARGE_ICON = "large_icon"; + private static final String INTENT = "intent"; + private static final String BADGE_ADD_NUM = "badge_add_num"; + private static final String TEST_MESSAGE = "test_message"; + private static final String RECEIPT_ID = "receipt_id"; + + private final String title; + private final String category; + private final String large_icon; + private final JsonObject intent; + private final Integer badge_add_num; + private final Boolean test_message; + private final String receipt_id; + + private HmosNotification(Object alert, + String title, + String category, + String large_icon, + JsonObject intent, + Integer badge_add_num, + Boolean test_message, + String receipt_id, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras, + Map customData) { + super(alert, extras, numberExtras, booleanExtras, jsonExtras, customData); + + this.title = title; + this.category = category; + this.large_icon = large_icon; + this.intent = intent; + this.badge_add_num = badge_add_num; + this.test_message = test_message; + this.receipt_id = receipt_id; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static HmosNotification alert(String alert) { + return newBuilder().setAlert(alert).build(); + } + + + @Override + public String getPlatform() { + return NOTIFICATION_HMOS; + } + + @Override + public JsonElement toJSON() { + JsonObject json = super.toJSON().getAsJsonObject(); + + if (null != title) { + json.add(TITLE, new JsonPrimitive(title)); + } + if (null != category) { + json.add(CATEGORY, new JsonPrimitive(category)); + } + if (null != large_icon) { + json.add(LARGE_ICON, new JsonPrimitive(large_icon)); + } + if (null != intent) { + json.add(INTENT, intent); + } + if (null != badge_add_num) { + json.add(BADGE_ADD_NUM, new JsonPrimitive(badge_add_num)); + } + if (null != test_message) { + json.add(TEST_MESSAGE, new JsonPrimitive(test_message)); + } + if (null != receipt_id) { + json.add(RECEIPT_ID, new JsonPrimitive(receipt_id)); + } + return json; + } + + + public static class Builder extends PlatformNotification.Builder { + private String title; + private String category; + private String large_icon; + private JsonObject intent; + private Integer badge_add_num; + private Boolean test_message; + private String receipt_id; + + @Override + protected Builder getThis() { + return this; + } + + @Override + public Builder setAlert(Object alert) { + this.alert = alert; + return this; + } + + public Builder setTitle(String title) { + this.title = title; + return this; + } + + public Builder setCategory(String category) { + this.category = category; + return this; + } + + public Builder setLarge_icon(String large_icon) { + this.large_icon = large_icon; + return this; + } + + public Builder setIntent(JsonObject intent) { + this.intent = intent; + return this; + } + + public Builder setBadge_add_num(Integer badge_add_num) { + this.badge_add_num = badge_add_num; + return this; + } + + public Builder setTest_message(Boolean test_message) { + this.test_message = test_message; + return this; + } + + public Builder setReceipt_id(String receipt_id) { + this.receipt_id = receipt_id; + return this; + } + + public HmosNotification build() { + return new HmosNotification(alert, title, category,large_icon,intent,badge_add_num,test_message,receipt_id, + extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder, super.customData); + } + } +} diff --git a/src/main/java/cn/jpush/api/push/model/notification/InterfaceAdapter.java b/src/main/java/cn/jpush/api/push/model/notification/InterfaceAdapter.java new file mode 100644 index 00000000..4208757b --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/notification/InterfaceAdapter.java @@ -0,0 +1,33 @@ +package cn.jpush.api.push.model.notification; + +import com.google.gson.*; + +import java.lang.reflect.Type; + +/** + * Created by Ken on 2016/10/25. + */ +public class InterfaceAdapter implements JsonSerializer, JsonDeserializer { + @Override + public T deserialize(JsonElement jsonElement, Type type, + JsonDeserializationContext jsonDeserializationContext) + throws JsonParseException { + JsonObject jsonObj = jsonElement.getAsJsonObject(); + String className = jsonObj.get("type").getAsString(); + try { + Class clz = Class.forName(className); + return jsonDeserializationContext.deserialize(jsonElement, clz); + } catch (ClassNotFoundException e) { + throw new JsonParseException(e); + } + } + + @Override + public JsonElement serialize(Object object, Type type, + JsonSerializationContext jsonSerializationContext) { + JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass()); + jsonEle.getAsJsonObject().addProperty("type", + object.getClass().getCanonicalName()); + return jsonEle; + } +} diff --git a/src/main/java/cn/jpush/api/push/model/notification/IosAlert.java b/src/main/java/cn/jpush/api/push/model/notification/IosAlert.java new file mode 100644 index 00000000..d8624f82 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/notification/IosAlert.java @@ -0,0 +1,140 @@ +package cn.jpush.api.push.model.notification; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.push.model.PushModel; + +public class IosAlert implements PushModel { + + private final String title; + private final String subtitle; + private final String body; + private final String title_loc_key; + private final String[] title_loc_args; + private final String action_loc_key; + private final String loc_key; + private final String[] loc_args; + private final String launch_image; + + private IosAlert(String title, String subtitle, String body, String title_loc_key, String[] title_loc_args, + String action_loc_key, String loc_key, String[] loc_args, String launch_image) { + this.title = title; + this.subtitle = subtitle; + this.body = body; + this.title_loc_key = title_loc_key; + this.title_loc_args = title_loc_args; + this.action_loc_key = action_loc_key; + this.loc_key = loc_key; + this.loc_args = loc_args; + this.launch_image = launch_image; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @Override + public JsonElement toJSON() { + JsonObject json = new JsonObject(); + + if( StringUtils.isNotEmpty(title) ) { + json.addProperty("title", title); + } + + if ( StringUtils.isNotEmpty(subtitle) ) { + json.addProperty("subtitle", subtitle); + } + + if( StringUtils.isNotEmpty(body) ) { + json.addProperty("body", body); + } + + if( StringUtils.isNotEmpty(title_loc_key) ) { + json.addProperty("title-loc-key", title_loc_key); + if( null != title_loc_args && title_loc_args.length > 0 ) { + JsonArray args = new JsonArray(); + for(int i = 0; i < title_loc_args.length; i++) { + args.add(new JsonPrimitive(title_loc_args[i])); + } + json.add("title-loc-args", args); + } + } + + if( StringUtils.isNotEmpty(action_loc_key) ) { + json.addProperty("action-loc-key", action_loc_key); + } + + if( StringUtils.isNotEmpty(loc_key) ) { + json.addProperty("loc-key", loc_key); + if( null != loc_args && loc_args.length > 0 ) { + JsonArray args = new JsonArray(); + for(int i = 0; i < loc_args.length; i++) { + args.add(new JsonPrimitive(loc_args[i])); + } + json.add("loc-args", args); + } + } + + if( StringUtils.isNotEmpty(launch_image) ) { + json.addProperty("launch-image", launch_image); + } + + return json; + } + + @Override + public String toString() { + return gson.toJson(toJSON()); + } + + public static class Builder { + private String title; + private String subtitle; + private String body; + private String title_loc_key; + private String[] title_loc_args; + private String action_loc_key; + private String loc_key; + private String[] loc_args; + private String launch_image; + + public Builder setTitleAndBody(String title, String subtitle, String body){ + this.title = title; + this.subtitle = subtitle; + this.body = body; + return this; + } + + public Builder setTitleLoc(String title_loc_key, String... title_loc_args) { + this.title_loc_key = title_loc_key; + this.title_loc_args = title_loc_args; + return this; + } + + public Builder setActionLocKey(String action_loc_key) { + this.action_loc_key = action_loc_key; + return this; + } + + public Builder setLoc(String loc_key, String... loc_args) { + this.loc_key = loc_key; + this.loc_args = loc_args; + return this; + } + + public Builder setLaunchImage(String launch_image) { + this.launch_image = launch_image; + return this; + } + + public IosAlert build() { + return new IosAlert(title, subtitle, body, title_loc_key, title_loc_args, action_loc_key, + loc_key, loc_args, launch_image); + } + } + +} diff --git a/src/main/java/cn/jpush/api/push/model/notification/IosNotification.java b/src/main/java/cn/jpush/api/push/model/notification/IosNotification.java index bcd6b191..c8c844af 100644 --- a/src/main/java/cn/jpush/api/push/model/notification/IosNotification.java +++ b/src/main/java/cn/jpush/api/push/model/notification/IosNotification.java @@ -2,27 +2,34 @@ import java.util.Map; -import cn.jpush.api.common.ServiceHelper; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import cn.jiguang.common.ServiceHelper; + /** - * APNs 通知类 - *

+ *

APNs 通知类

+ *
* 支持 APNs 默认的几个参数: + *
    *
  • alert: 继承自父类 PlatformNotification 的 alert 属性;本类设置则覆盖。
  • + *
  • sound: 支持 setSound(string) 方法来设置声音文件。或者 setSound(JSON object) 对应官方payload结构
  • *
  • badge: 支持 setBadge(int) 方法来设置;支持 incrBadge(int) 方法来增加。
  • - *
  • sound: 支持 setSound(string) 方法来设置声音文件。
  • *
  • content-available: 用来支持后台推送。如果该值赋值为 1,表示开启后台推送。
  • + *
  • mutable-content: 通知扩展
  • + *
  • category: IOS 8 才支持。设置 APNs payload 中的 "category" 字段值
  • + *
  • mutable-content: 通知扩展
  • *
  • extras: JSON object. 支持更多的自定义字段信息。
  • - *

    - *

    + *

  • thread-id: string. ios 的远程通知通过该属性来对通知进行分组,同一个 thread-id 的通知归为一组。
  • + *
  • interruption-level: string. ios 15 的通知级别,取值只能是 active,critical,passive,time-sensitive 中的一个,详情参考:UNNotificationInterruptionLevel。
  • + *
+ *
* 需要特别留意的是,JPush SDK 会对以下几个值有特别的默认设置考虑: - *
  • badge: 默认为 "+1"。如果需要取消 badge 值,需要显式地调用 disableBadge().
  • - *
  • sound: 默认为 "",即默认的声音提示。如果需要取消 sound 值,即不要声音,需要显式地调用 disableSound().
  • - *

    + *
      + *
    • badge: 默认为 "+1"。如果需要取消 badge 值,需要显式地调用 disableBadge()。
    • + *
    • sound: 默认为 "",即默认的声音提示。如果需要取消 sound 值,即不要声音,需要显式地调用 disableSound()。
    • + *
    */ public class IosNotification extends PlatformNotification { public static final String NOTIFICATION_IOS = "ios"; @@ -33,27 +40,34 @@ public class IosNotification extends PlatformNotification { private static final String BADGE = "badge"; private static final String SOUND = "sound"; private static final String CONTENT_AVAILABLE = "content-available"; + private static final String MUTABLE_CONTENT = "mutable-content"; private static final String CATEGORY = "category"; - + private static final String THREAD_ID = "thread-id"; + private static final String INTERRUPTION_LEVEL = "interruption-level"; + private static final String ALERT_VALID_BADGE = "Badge number should be 0~99999, " + "and can be prefixed with + to add, - to minus"; private final boolean soundDisabled; private final boolean badgeDisabled; - private final String sound; + private final Object sound; private final String badge; private final boolean contentAvailable; private final String category; - - private IosNotification(String alert, String sound, String badge, + private final boolean mutableContent; + private final String threadId; + private final String interruptionLevel; + + private IosNotification(Object alert, Object sound, String badge, boolean contentAvailable, boolean soundDisabled, boolean badgeDisabled, - String category, + String category, boolean mutableContent,String threadId,String interruptionLevel, Map extras, Map numberExtras, Map booleanExtras, - Map jsonExtras) { - super(alert, extras, numberExtras, booleanExtras, jsonExtras); + Map jsonExtras, + Map customData) { + super(alert, extras, numberExtras, booleanExtras, jsonExtras, customData); this.sound = sound; this.badge = badge; @@ -61,6 +75,9 @@ private IosNotification(String alert, String sound, String badge, this.soundDisabled = soundDisabled; this.badgeDisabled = badgeDisabled; this.category = category; + this.mutableContent = mutableContent; + this.threadId = threadId; + this.interruptionLevel = interruptionLevel; } public static Builder newBuilder() { @@ -90,35 +107,57 @@ public JsonElement toJSON() { } if (!soundDisabled) { if (null != sound) { - json.add(SOUND, new JsonPrimitive(sound)); + if(sound instanceof String){ + json.add(SOUND, new JsonPrimitive((String)sound)); + }else if (sound instanceof JsonObject) { + json.add(SOUND, (JsonObject) sound); + } + } else { json.add(SOUND, new JsonPrimitive(DEFAULT_SOUND)); } } if (contentAvailable) { - json.add(CONTENT_AVAILABLE, new JsonPrimitive(1)); + json.add(CONTENT_AVAILABLE, new JsonPrimitive(true)); } if (null != category) { json.add(CATEGORY, new JsonPrimitive(category)); } - + if (mutableContent) { + json.add(MUTABLE_CONTENT, new JsonPrimitive(true)); + } + if (null != threadId) { + json.add(THREAD_ID, new JsonPrimitive(threadId)); + } + if (null != interruptionLevel) { + json.add(INTERRUPTION_LEVEL, new JsonPrimitive(interruptionLevel)); + } + return json; } public static class Builder extends PlatformNotification.Builder { - private String sound; + private Object sound; private String badge; private boolean contentAvailable = false; private boolean soundDisabled = false; private boolean badgeDisabled = false; private String category; - + private boolean mutableContent; + private String threadId; + private String interruptionLevel; + + @Override protected Builder getThis() { return this; } - public Builder setSound(String sound) { + public Builder setSound(Object sound) { + if (null == sound) { + LOG.warn("Null sound. Throw away it."); + return this; + } this.sound = sound; return this; } @@ -153,6 +192,7 @@ public Builder setBadge(int badge) { /** * equals to: +1 + * @return IosNotification builder */ public Builder autoBadge() { return incrBadge(1); @@ -173,16 +213,32 @@ public Builder setCategory(String category) { return this; } - public Builder setAlert(String alert) { + @Override + public Builder setAlert(Object alert) { this.alert = alert; return this; } + + public Builder setMutableContent(boolean mutableContent) { + this.mutableContent = mutableContent; + return this; + } + public Builder setThreadId(String threadId) { + this.threadId = threadId; + return this; + } + + public Builder setInterruptionLevel(String interruptionLevel) { + this.interruptionLevel = interruptionLevel; + return this; + } + public IosNotification build() { return new IosNotification(alert, sound, badge, contentAvailable, - soundDisabled, badgeDisabled, category, - extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder); + soundDisabled, badgeDisabled, category, mutableContent, threadId, interruptionLevel, + extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder, super.customData); } } } diff --git a/src/main/java/cn/jpush/api/push/model/notification/Notification.java b/src/main/java/cn/jpush/api/push/model/notification/Notification.java index f8575bc9..2da780ca 100644 --- a/src/main/java/cn/jpush/api/push/model/notification/Notification.java +++ b/src/main/java/cn/jpush/api/push/model/notification/Notification.java @@ -1,28 +1,46 @@ package cn.jpush.api.push.model.notification; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import cn.jpush.api.push.model.PushModel; -import cn.jpush.api.utils.Preconditions; +import java.util.*; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -public class Notification implements PushModel { - private final String alert; +import cn.jiguang.common.utils.Preconditions; +import cn.jpush.api.push.model.PushModel; + +public class Notification implements PushModel { + private static final String AI_OPPORTUNITY = "ai_opportunity"; + private static final String VOIP = "voip"; + + // default is false + private boolean aiOpportunity; + private final Object alert; private final Set notifications; + private final Map voip; + private final Map numberVoip; + private final Map booleanVoip; + private final Map jsonVoip; - private Notification(String alert, Set notifications) { + private Notification(boolean aiOpportunity, Object alert, Set notifications, + Map voip, Map numberVoip, Map booleanVoip, + Map jsonVoip) { + this.aiOpportunity = aiOpportunity; this.alert = alert; this.notifications = notifications; + this.voip = voip; + this.numberVoip = numberVoip; + this.booleanVoip = booleanVoip; + this.jsonVoip = jsonVoip; } public static Builder newBuilder() { return new Builder(); } + + public static Notification aiOpportunity(boolean ai_opportunity) { + return newBuilder().setAiOpportunity(ai_opportunity).build(); + } /** * Quick set all platform alert. @@ -31,13 +49,10 @@ public static Builder newBuilder() { * @param alert Notification alert * @return first level notification object */ - public static Notification alert(String alert) { + public static Notification alert(Object alert) { return newBuilder().setAlert(alert).build(); } - - /** - * shortcut - */ + public static Notification android(String alert, String title, Map extras) { return newBuilder() .addPlatformNotification(AndroidNotification.newBuilder() @@ -47,11 +62,8 @@ public static Notification android(String alert, String title, Map extras) { + + public static Notification ios(Object alert, Map extras) { return newBuilder() .addPlatformNotification(IosNotification.newBuilder() .setAlert(alert) @@ -59,10 +71,7 @@ public static Notification ios(String alert, Map extras) { .build()) .build(); } - - /** - * shortcut - */ + public static Notification ios_auto_badge() { return newBuilder() .addPlatformNotification(IosNotification.newBuilder() @@ -71,10 +80,7 @@ public static Notification ios_auto_badge() { .build()) .build(); } - - /** - * shortcut - */ + public static Notification ios_set_badge(int badge) { return newBuilder() .addPlatformNotification(IosNotification.newBuilder() @@ -83,10 +89,7 @@ public static Notification ios_set_badge(int badge) { .build()) .build(); } - - /** - * shortcut - */ + public static Notification ios_incr_badge(int badge) { return newBuilder() .addPlatformNotification(IosNotification.newBuilder() @@ -95,23 +98,30 @@ public static Notification ios_incr_badge(int badge) { .build()) .build(); } - - /** - * shortcut - */ - public static Notification winphone(String alert, Map extras) { + + public static Notification hmos(String alert, String title, Map extras) { return newBuilder() - .addPlatformNotification(WinphoneNotification.newBuilder() + .addPlatformNotification(HmosNotification.newBuilder() .setAlert(alert) + .setTitle(title) .addExtras(extras) .build()) .build(); } - + public JsonElement toJSON() { JsonObject json = new JsonObject(); + + json.addProperty(AI_OPPORTUNITY, aiOpportunity); + if (null != alert) { - json.add(PlatformNotification.ALERT, new JsonPrimitive(alert)); + if(alert instanceof JsonObject) { + json.add(PlatformNotification.ALERT, (JsonObject) alert); + } else if (alert instanceof IosAlert) { + json.add(PlatformNotification.ALERT, ((IosAlert) alert).toJSON()); + } else { + json.add(PlatformNotification.ALERT, new JsonPrimitive(alert.toString())); + } } if (null != notifications) { for (PlatformNotification pn : notifications) { @@ -125,14 +135,74 @@ public JsonElement toJSON() { json.add(pn.getPlatform(), pn.toJSON()); } } + + + JsonObject extrasObject = null; + if (null != voip || null != numberVoip || null != booleanVoip || null != jsonVoip) { + extrasObject = new JsonObject(); + } + + if (null != voip) { + String value = null; + for (String key : voip.keySet()) { + value = voip.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != numberVoip) { + Number value = null; + for (String key : numberVoip.keySet()) { + value = numberVoip.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != booleanVoip) { + Boolean value = null; + for (String key : booleanVoip.keySet()) { + value = booleanVoip.get(key); + if (null != value) { + extrasObject.add(key, new JsonPrimitive(value)); + } + } + } + if (null != jsonVoip) { + JsonObject value = null; + for (String key : jsonVoip.keySet()) { + value = jsonVoip.get(key); + if (null != value) { + extrasObject.add(key, value); + } + } + } + + if (null != voip || null != numberVoip || null != booleanVoip || null != jsonVoip) { + json.add(VOIP, extrasObject); + } + return json; } - + public static class Builder { - private String alert; + private boolean aiOpportunity; + private Object alert; private Set builder; - - public Builder setAlert(String alert) { + protected Map voipBuilder; + protected Map numberVoipBuilder; + protected Map booleanVoipBuilder; + protected Map jsonVoipBuilder; + + + + public Builder setAiOpportunity(boolean aiOpportunity) { + this.aiOpportunity = aiOpportunity; + return this; + } + + public Builder setAlert(Object alert) { this.alert = alert; return this; } @@ -144,11 +214,59 @@ public Builder addPlatformNotification(PlatformNotification notification) { builder.add(notification); return this; } + + public Builder addVoip(String key, String value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == voipBuilder) { + voipBuilder = new HashMap(); + } + voipBuilder.put(key, value); + return this; + } + + public Builder addVoip(Map voip) { + Preconditions.checkArgument(! (null == voip), "extras should not be null."); + if (null == voipBuilder) { + voipBuilder = new HashMap(); + } + for (String key : voip.keySet()) { + voipBuilder.put(key, voip.get(key)); + } + return this; + } + + public Builder addVoip(String key, Number value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == numberVoipBuilder) { + numberVoipBuilder = new HashMap(); + } + numberVoipBuilder.put(key, value); + return this; + } + + public Builder addVoip(String key, Boolean value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == booleanVoipBuilder) { + booleanVoipBuilder = new HashMap(); + } + booleanVoipBuilder.put(key, value); + return this; + } + + public Builder addVoip(String key, JsonObject value) { + Preconditions.checkArgument(! (null == key || null == value), "Key/Value should not be null."); + if (null == jsonVoipBuilder) { + jsonVoipBuilder = new HashMap(); + } + jsonVoipBuilder.put(key, value); + return this; + } public Notification build() { - Preconditions.checkArgument(! (null == builder && null == alert), + Preconditions.checkArgument(! (null == builder && null == alert), "No notification payload is set."); - return new Notification(alert, builder); + return new Notification(aiOpportunity, alert, builder, voipBuilder, numberVoipBuilder, booleanVoipBuilder + , jsonVoipBuilder); } } } diff --git a/src/main/java/cn/jpush/api/push/model/notification/PlatformNotification.java b/src/main/java/cn/jpush/api/push/model/notification/PlatformNotification.java index da87ee74..ac2272dc 100644 --- a/src/main/java/cn/jpush/api/push/model/notification/PlatformNotification.java +++ b/src/main/java/cn/jpush/api/push/model/notification/PlatformNotification.java @@ -1,31 +1,33 @@ package cn.jpush.api.push.model.notification; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import cn.jpush.api.push.model.PushModel; -import cn.jpush.api.utils.Preconditions; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import cn.jiguang.common.utils.Preconditions; +import cn.jpush.api.push.model.PushModel; + public abstract class PlatformNotification implements PushModel { public static final String ALERT = "alert"; private static final String EXTRAS = "extras"; protected static final Logger LOG = LoggerFactory.getLogger(PlatformNotification.class); - private String alert; + private Object alert; private final Map extras; private final Map numberExtras; private final Map booleanExtras; private final Map jsonExtras; - - public PlatformNotification(String alert, Map extras, + private final Map customData; + + public PlatformNotification(Object alert, Map extras, Map numberExtras, Map booleanExtras, Map jsonExtras) { @@ -34,14 +36,34 @@ public PlatformNotification(String alert, Map extras, this.numberExtras = numberExtras; this.booleanExtras = booleanExtras; this.jsonExtras = jsonExtras; + customData = new LinkedHashMap(); } - + + public PlatformNotification(Object alert, Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras, + Map customData) { + this.alert = alert; + this.extras = extras; + this.numberExtras = numberExtras; + this.booleanExtras = booleanExtras; + this.jsonExtras = jsonExtras; + this.customData = customData; + } + @Override public JsonElement toJSON() { JsonObject json = new JsonObject(); if (null != alert) { - json.add(ALERT, new JsonPrimitive(this.alert)); + if ( alert instanceof JsonObject) { + json.add(ALERT, (JsonObject) alert); + } else if (alert instanceof IosAlert) { + json.add(ALERT, ((IosAlert) alert).toJSON()); + } else { + json.add(ALERT, new JsonPrimitive(alert.toString())); + } } JsonObject extrasObject = null; @@ -89,15 +111,21 @@ public JsonElement toJSON() { if (null != extras || null != numberExtras || null != booleanExtras || null != jsonExtras) { json.add(EXTRAS, extrasObject); } + + if (null != customData) { + for (Map.Entry entry : customData.entrySet()) { + json.add(entry.getKey(), entry.getValue()); + } + } return json; } - protected String getAlert() { + protected Object getAlert() { return this.alert; } - protected void setAlert(String alert) { + protected void setAlert(Object alert) { this.alert = alert; } @@ -106,19 +134,21 @@ protected void setAlert(String alert) { protected abstract static class Builder> { private B theBuilder; - protected String alert; + protected Object alert; protected Map extrasBuilder; protected Map numberExtrasBuilder; protected Map booleanExtrasBuilder; protected Map jsonExtrasBuilder; - + protected Map customData; + public Builder () { + customData = new LinkedHashMap(); theBuilder = getThis(); } - + protected abstract B getThis(); - public abstract B setAlert(String alert); + public abstract B setAlert(Object alert); public B addExtra(String key, String value) { Preconditions.checkArgument(! (null == key), "Key should not be null."); @@ -186,7 +216,32 @@ public B addExtra(String key, JsonObject value) { jsonExtrasBuilder.put(key, value); return theBuilder; } - + + public B addCustom(Map extras) { + for (Map.Entry entry : extras.entrySet()) { + customData.put(entry.getKey(), new JsonPrimitive(entry.getValue())); + } + return theBuilder; + } + + public B addCustom(String key, Number value) { + Preconditions.checkArgument(! (null == key), "Key should not be null."); + customData.put(key, new JsonPrimitive(value)); + return theBuilder; + } + + public B addCustom(String key, String value) { + Preconditions.checkArgument(! (null == key), "Key should not be null."); + customData.put(key, new JsonPrimitive(value)); + return theBuilder; + } + + public B addCustom(String key, Boolean value) { + Preconditions.checkArgument(! (null == key), "Key should not be null."); + customData.put(key, new JsonPrimitive(value)); + return theBuilder; + } + public abstract T build(); } diff --git a/src/main/java/cn/jpush/api/push/model/notification/QuickappNotification.java b/src/main/java/cn/jpush/api/push/model/notification/QuickappNotification.java new file mode 100644 index 00000000..110f46a3 --- /dev/null +++ b/src/main/java/cn/jpush/api/push/model/notification/QuickappNotification.java @@ -0,0 +1,102 @@ +package cn.jpush.api.push.model.notification; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.util.Map; + + +/** + *

    QuickApp 通知类

    + *
    + * 具体使用方法请参考官方文档 https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#platform + * 支持 QuickApp Notification 的参数: + *
      + *
    • alert: 继承自父类 PlatformNotification 的 alert 属性;本类设置则覆盖。
    • + *
    • title: 支持 setTitle(string) 方法来设置;可替换快应用推送通知的标题。
    • + *
    • page: 支持 setPage(String) 方法来设置;可设置快应用跳转页面
    • + *
    • extras: 继承自父类 PlatformNotification 的 extras 属性;支持通过 addExtra(key, value) 来添加自定义字段,具体看代码。
    • + *
    + *
    + */ +public class QuickappNotification extends PlatformNotification { + private static final String NOTIFICATION_QUICKAPP = "quickapp"; + + private static final String TITLE = "title"; + private static final String PAGE = "page"; + + private final String title; + private final String page; + + private QuickappNotification(Object alert, String title, String page, + Map extras, + Map numberExtras, + Map booleanExtras, + Map jsonExtras, + Map customData) { + super(alert, extras, numberExtras, booleanExtras, jsonExtras, customData); + + this.title = title; + this.page = page; + } + + public static Builder newBuilder() { + return new QuickappNotification.Builder(); + } + + public static QuickappNotification alert(String alert) { + return newBuilder().setAlert(alert).build(); + } + + @Override + public String getPlatform() { + return NOTIFICATION_QUICKAPP; + } + + @Override + public JsonElement toJSON() { + JsonObject json = super.toJSON().getAsJsonObject(); + + if (null != title) { + json.add(TITLE, new JsonPrimitive(title)); + } + if (null != page) { + json.add(PAGE, new JsonPrimitive(page)); + } + + return json; + } + + public static class Builder extends PlatformNotification.Builder { + private String title; + private String page; + + @Override + protected Builder getThis() { + return this; + } + + public Builder setTitle(String title) { + this.title = title; + return this; + } + + public Builder setPage(String page) { + this.page = page; + return this; + } + + @Override + public Builder setAlert(Object alert) { + this.alert = alert; + return this; + } + + + public QuickappNotification build() { + return new QuickappNotification(alert, title, page, + extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder, super.customData); + } + } +} diff --git a/src/main/java/cn/jpush/api/push/model/notification/WinphoneNotification.java b/src/main/java/cn/jpush/api/push/model/notification/WinphoneNotification.java deleted file mode 100644 index 388da698..00000000 --- a/src/main/java/cn/jpush/api/push/model/notification/WinphoneNotification.java +++ /dev/null @@ -1,87 +0,0 @@ -package cn.jpush.api.push.model.notification; - -import java.util.Map; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -public class WinphoneNotification extends PlatformNotification { - private static final String NOTIFICATION_WINPHONE = "winphone"; - - private static final String TITLE = "title"; - private static final String _OPEN_PAGE = "_open_page"; - - private final String title; - private final String openPage; - - private WinphoneNotification(String alert, String title, String openPage, - Map extras, - Map numberExtras, - Map booleanExtras, - Map jsonExtras) { - super(alert, extras, numberExtras, booleanExtras, jsonExtras); - - this.title = title; - this.openPage = openPage; - } - - public static Builder newBuilder() { - return new Builder(); - } - - public static WinphoneNotification alert(String alert) { - return newBuilder().setAlert(alert).build(); - } - - - @Override - public String getPlatform() { - return NOTIFICATION_WINPHONE; - } - - @Override - public JsonElement toJSON() { - JsonObject json = super.toJSON().getAsJsonObject(); - - if (null != title) { - json.add(TITLE, new JsonPrimitive(title)); - } - if (null != openPage) { - json.add(_OPEN_PAGE, new JsonPrimitive(openPage)); - } - - return json; - } - - - public static class Builder extends PlatformNotification.Builder { - private String title; - private String openPage; - - protected Builder getThis() { - return this; - } - - public Builder setTitle(String title) { - this.title = title; - return this; - } - - public Builder setOpenPage(String openPage) { - this.openPage = openPage; - return this; - } - - public Builder setAlert(String alert) { - this.alert = alert; - return this; - } - - - public WinphoneNotification build() { - return new WinphoneNotification(alert, title, openPage, - extrasBuilder, numberExtrasBuilder, booleanExtrasBuilder, jsonExtrasBuilder); - } - } -} diff --git a/src/main/java/cn/jpush/api/report/GroupMessageDetailResult.java b/src/main/java/cn/jpush/api/report/GroupMessageDetailResult.java new file mode 100644 index 00000000..1f380f71 --- /dev/null +++ b/src/main/java/cn/jpush/api/report/GroupMessageDetailResult.java @@ -0,0 +1,91 @@ +package cn.jpush.api.report; + +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +public class GroupMessageDetailResult extends BaseResult { + + // what is this? + private static final Type JSON_OBJECT_TYPE = new TypeToken>() {}.getType(); + private static final Type RECEIVED_TYPE = new TypeToken>() {}.getType(); + + @Expose + public List received_list = new ArrayList(); + + public static class Received { + @Expose + public String group_msgids; + @Expose + public JpushDetail jpush; + @Expose + public JsonObject android_pns; + @Expose + public IosDetail ios; + @Expose + public WinphoeDetail winphone; + } + + public static class JpushDetail { + @Expose + public long target; + @Expose + public int online_push; + @Expose + public int received; + @Expose + public int click; + @Expose + public int msg_click; + } + + public static class WinphoeDetail { + @Expose + public long mpns_target; + @Expose + public int mpns_sent; + @Expose + public int click; + } + + public static class IosDetail { + @Expose + public long apns_target; + @Expose + public int apns_sent; + @Expose + public int apns_received; + @Expose + public int apns_click; + @Expose + public int msg_target; + @Expose + public int msg_received; + } + + + static GroupMessageDetailResult fromResponse(ResponseWrapper responseWrapper) { + GroupMessageDetailResult result = new GroupMessageDetailResult(); + if (responseWrapper.isServerResponse()) { + List tempList = _gson.fromJson(responseWrapper.responseContent, JSON_OBJECT_TYPE); + for (JsonObject jsonObject : tempList) { + if (jsonObject.isJsonNull() || jsonObject.get("android_pns").isJsonNull()) { + continue; + } + Received received = _gson.fromJson(jsonObject, Received.class); + result.received_list.add(received); + } + } + + result.setResponseWrapper(responseWrapper); + return result; + } +} diff --git a/src/main/java/cn/jpush/api/report/GroupUsersResult.java b/src/main/java/cn/jpush/api/report/GroupUsersResult.java new file mode 100644 index 00000000..540be081 --- /dev/null +++ b/src/main/java/cn/jpush/api/report/GroupUsersResult.java @@ -0,0 +1,40 @@ +package cn.jpush.api.report; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.resp.BaseResult; + +public class GroupUsersResult extends BaseResult { + + @Expose public TimeUnit time_unit; + @Expose public String start; + @Expose public int duration; + @Expose public List items = new ArrayList(); + + + public static class User { + @Expose public String time; + @Expose public Android android; + @Expose public Ios ios; + } + + public static class Android { + @SerializedName("new") @Expose public long add; + @Expose public int online; + @Expose public int active; + } + + public static class Ios { + @SerializedName("new") @Expose public long add; + @Expose public int online; + @Expose public int active; + } + +} + + diff --git a/src/main/java/cn/jpush/api/report/MessageDetailResult.java b/src/main/java/cn/jpush/api/report/MessageDetailResult.java new file mode 100644 index 00000000..7fe5b6f5 --- /dev/null +++ b/src/main/java/cn/jpush/api/report/MessageDetailResult.java @@ -0,0 +1,86 @@ +package cn.jpush.api.report; + +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import com.google.gson.reflect.TypeToken; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +public class MessageDetailResult extends BaseResult { + + private static final Type RECEIVED_TYPE = new TypeToken>() {}.getType(); + private static final long serialVersionUID = 156439166846147394L; + + @Expose + public List received_list = new ArrayList(); + + + public static class Received { + @Expose + public long msg_id; + @Expose + public JpushDetail jpush; + @Expose + public JsonObject android_pns; + @Expose + public JsonObject details; + @Expose + public IosDetail ios; + @Expose + public WinphoeDetail winphone; + } + + public static class JpushDetail { + @Expose + public long target; + @Expose + public int online_push; + @Expose + public int received; + @Expose + public int click; + @Expose + public int msg_click; + } + + public static class WinphoeDetail { + @Expose + public long mpns_target; + @Expose + public int mpns_sent; + @Expose + public int click; + } + + public static class IosDetail { + @Expose + public long apns_target; + @Expose + public int apns_sent; + @Expose + public int apns_received; + @Expose + public int apns_click; + @Expose + public int msg_target; + @Expose + public int msg_received; + } + + + static MessageDetailResult fromResponse(ResponseWrapper responseWrapper) { + MessageDetailResult result = new MessageDetailResult(); + if (responseWrapper.isServerResponse()) { + result.received_list = _gson.fromJson(responseWrapper.responseContent, RECEIVED_TYPE); + } + + result.setResponseWrapper(responseWrapper); + return result; + } + +} diff --git a/src/main/java/cn/jpush/api/report/MessageStatus.java b/src/main/java/cn/jpush/api/report/MessageStatus.java new file mode 100644 index 00000000..de3f902d --- /dev/null +++ b/src/main/java/cn/jpush/api/report/MessageStatus.java @@ -0,0 +1,28 @@ +package cn.jpush.api.report; + +import java.io.Serializable; + +public class MessageStatus implements Serializable { + + /** + * 0 送达 + * 1 未送达 + * 2 用户不属于该 app + * 3 用户属于该 app,但不属于该 msgid + * 4 系统异常 + */ + private int status; + + public void setStatus(int status) { + this.status = status; + } + + public int getStatus() { + return status; + } + + @Override + public String toString() { + return "status : " + status; + } +} diff --git a/src/main/java/cn/jpush/api/report/MessagesResult.java b/src/main/java/cn/jpush/api/report/MessagesResult.java index fc8b945e..e21a910e 100644 --- a/src/main/java/cn/jpush/api/report/MessagesResult.java +++ b/src/main/java/cn/jpush/api/report/MessagesResult.java @@ -4,48 +4,75 @@ import java.util.ArrayList; import java.util.List; -import cn.jpush.api.common.resp.BaseResult; -import cn.jpush.api.common.resp.ResponseWrapper; - import com.google.gson.annotations.Expose; import com.google.gson.reflect.TypeToken; +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; + public class MessagesResult extends BaseResult { - private static final Type MESSAGE_TYPE = new TypeToken>(){}.getType(); - - @Expose public List messages = new ArrayList(); - - public static class Message { - @Expose public long msg_id; - @Expose public Android android; - @Expose public Ios ios; - } - + private static final Type MESSAGE_TYPE = new TypeToken>() {}.getType(); + private static final long serialVersionUID = -1582895355000647292L; + + @Expose + public List messages = new ArrayList(); + + public static class Message { + @Expose + public String msg_id; + @Expose + public Android android; + @Expose + public Ios ios; + @Expose + public Winphone winphone; + } + public static class Android { - @Expose public int received; - @Expose public int target; - @Expose public int online_push; - @Expose public int click; - @Expose public int msg_click; + @Expose + public int received; + @Expose + public int target; + @Expose + public int online_push; + @Expose + public int click; + @Expose + public int msg_click; } - + public static class Ios { - @Expose public int apns_sent; - @Expose public int apns_target; - @Expose public int click; - @Expose public int target; - @Expose public int received; - @Expose public int msg_click; + @Expose + public int apns_sent; + @Expose + public int apns_target; + @Expose + public int apns_received; + @Expose + public int click; + @Expose + public int target; + @Expose + public int received; } - - static MessagesResult fromResponse(ResponseWrapper responseWrapper) { + + public static class Winphone { + @Expose + public int mpns_target; + @Expose + public int mpns_sent; + @Expose + public int click; + } + + static MessagesResult fromResponse(ResponseWrapper responseWrapper) { MessagesResult result = new MessagesResult(); if (responseWrapper.isServerResponse()) { result.messages = _gson.fromJson(responseWrapper.responseContent, MESSAGE_TYPE); } - + result.setResponseWrapper(responseWrapper); return result; - } - + } + } diff --git a/src/main/java/cn/jpush/api/report/ReceivedsResult.java b/src/main/java/cn/jpush/api/report/ReceivedsResult.java index 0be45dd6..49daad5a 100644 --- a/src/main/java/cn/jpush/api/report/ReceivedsResult.java +++ b/src/main/java/cn/jpush/api/report/ReceivedsResult.java @@ -4,32 +4,53 @@ import java.util.ArrayList; import java.util.List; -import cn.jpush.api.common.resp.BaseResult; -import cn.jpush.api.common.resp.ResponseWrapper; - import com.google.gson.annotations.Expose; import com.google.gson.reflect.TypeToken; +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; + public class ReceivedsResult extends BaseResult { - private static final Type RECEIVED_TYPE = new TypeToken>(){}.getType(); - - @Expose public List received_list = new ArrayList(); - - - public static class Received { - @Expose public long msg_id; - @Expose public int android_received; - @Expose public int ios_apns_sent; - } - - static ReceivedsResult fromResponse(ResponseWrapper responseWrapper) { + private static final Type RECEIVED_TYPE = new TypeToken>() {}.getType(); + private static final long serialVersionUID = 1761456104618847304L; + + @Expose + public List received_list = new ArrayList(); + + + public static class Received { + @Expose + public long msg_id; + @Expose + public int android_pns_sent; + @Expose + public int android_pns_received; + @Expose + public int quickapp_jpush_received; + @Expose + public int quickapp_pns_sent; + @Expose + public int android_received; + @Expose + public int ios_apns_sent; + @Expose + public int ios_apns_received; + @Expose + public int ios_msg_received; + @Expose + public int wp_mpns_sent; + @Expose + public int jpush_received; + } + + static ReceivedsResult fromResponse(ResponseWrapper responseWrapper) { ReceivedsResult result = new ReceivedsResult(); if (responseWrapper.isServerResponse()) { result.received_list = _gson.fromJson(responseWrapper.responseContent, RECEIVED_TYPE); } - + result.setResponseWrapper(responseWrapper); return result; - } - + } + } diff --git a/src/main/java/cn/jpush/api/report/ReportClient.java b/src/main/java/cn/jpush/api/report/ReportClient.java index 5c09b31e..9a7ee6e8 100644 --- a/src/main/java/cn/jpush/api/report/ReportClient.java +++ b/src/main/java/cn/jpush/api/report/ReportClient.java @@ -1,20 +1,25 @@ package cn.jpush.api.report; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.BaseResult; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.report.model.CheckMessagePayload; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; import java.net.URLEncoder; +import java.util.Map; import java.util.regex.Pattern; -import cn.jpush.api.common.ClientConfig; -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.connection.IHttpClient; -import cn.jpush.api.common.connection.NativeHttpClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.BaseResult; -import cn.jpush.api.common.resp.ResponseWrapper; -import cn.jpush.api.utils.StringUtils; - public class ReportClient { private final NativeHttpClient _httpClient; @@ -22,29 +27,75 @@ public class ReportClient { private String _receivePath; private String _userPath; private String _messagePath; + private String _statusPath; + + private String messageDetailPath; + private String receiveDetailPath; + private String groupMessageDetailPath; + private String groupUserPath; public ReportClient(String masterSecret, String appKey) { - this(masterSecret, appKey, IHttpClient.DEFAULT_MAX_RETRY_TIMES, null); + this(masterSecret, appKey, null, ClientConfig.getInstance()); } - + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes max retry times. + * + */ + @Deprecated public ReportClient(String masterSecret, String appKey, int maxRetryTimes) { this(masterSecret, appKey, maxRetryTimes, null); } - + + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes max retry times + * @param proxy The max retry times. + * + */ + @Deprecated public ReportClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { - this(masterSecret, appKey, maxRetryTimes, proxy, ClientConfig.getInstance()); + ServiceHelper.checkBasic(appKey, masterSecret); + + ClientConfig conf = ClientConfig.getInstance(); + conf.setMaxRetryTimes(maxRetryTimes); + + _hostName = (String) conf.get(ClientConfig.REPORT_HOST_NAME); + _receivePath = (String) conf.get(ClientConfig.REPORT_RECEIVE_PATH); + _userPath = (String) conf.get(ClientConfig.REPORT_USER_PATH); + _messagePath = (String) conf.get(ClientConfig.REPORT_MESSAGE_PATH); + _statusPath = (String) conf.get(ClientConfig.REPORT_STATUS_PATH); + + messageDetailPath = (String) conf.get(ClientConfig.REPORT_MESSAGE_DETAIL_PATH); + receiveDetailPath = (String) conf.get(ClientConfig.REPORT_RECEIVE_DETAIL_PATH); + groupMessageDetailPath = (String) conf.get(ClientConfig.REPORT_GROUP_MESSAGE_DETAIL_PATH); + groupUserPath = (String) conf.get(ClientConfig.REPORT_GROUP_USER_PATH); + + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + _httpClient = new NativeHttpClient(authCode, proxy, conf); } - public ReportClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf) { + public ReportClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { ServiceHelper.checkBasic(appKey, masterSecret); _hostName = (String) conf.get(ClientConfig.REPORT_HOST_NAME); _receivePath = (String) conf.get(ClientConfig.REPORT_RECEIVE_PATH); _userPath = (String) conf.get(ClientConfig.REPORT_USER_PATH); _messagePath = (String) conf.get(ClientConfig.REPORT_MESSAGE_PATH); + _statusPath = (String) conf.get(ClientConfig.REPORT_STATUS_PATH); + + messageDetailPath = (String) conf.get(ClientConfig.REPORT_MESSAGE_DETAIL_PATH); + receiveDetailPath = (String) conf.get(ClientConfig.REPORT_RECEIVE_DETAIL_PATH); + groupMessageDetailPath = (String) conf.get(ClientConfig.REPORT_GROUP_MESSAGE_DETAIL_PATH); + groupUserPath = (String) conf.get(ClientConfig.REPORT_GROUP_USER_PATH); String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); - _httpClient = new NativeHttpClient(authCode, maxRetryTimes, proxy); + _httpClient = new NativeHttpClient(authCode, proxy, conf); } @@ -62,6 +113,16 @@ public ReceivedsResult getReceiveds(String msgIds) return ReceivedsResult.fromResponse(response); } + + public ReceivedsResult getReceivedsDetail(String msgIds) + throws APIConnectionException, APIRequestException { + checkMsgids(msgIds); + + String url = _hostName + receiveDetailPath + "?msg_ids=" + msgIds; + ResponseWrapper response = _httpClient.sendGet(url); + + return ReceivedsResult.fromResponse(response); + } public MessagesResult getMessages(String msgIds) throws APIConnectionException, APIRequestException { @@ -72,6 +133,34 @@ public MessagesResult getMessages(String msgIds) return MessagesResult.fromResponse(response); } + + public MessageDetailResult getMessagesDetail(String msgIds) + throws APIConnectionException, APIRequestException { + checkMsgids(msgIds); + + String url = _hostName + messageDetailPath + "?msg_ids=" + msgIds; + ResponseWrapper response = _httpClient.sendGet(url); + + return MessageDetailResult.fromResponse(response); + } + + + public GroupMessageDetailResult getGroupMessagesDetail(String groupMsgIds) + throws APIConnectionException, APIRequestException { + String url = _hostName + groupMessageDetailPath + "?group_msgids=" + groupMsgIds; + ResponseWrapper response = _httpClient.sendGet(url); + + return GroupMessageDetailResult.fromResponse(response); + } + + + public Map getMessagesStatus(CheckMessagePayload payload) + throws APIConnectionException, APIRequestException { + String url = _hostName + (_statusPath.endsWith("/message")?_statusPath:(_statusPath+"/message")); + ResponseWrapper result = _httpClient.sendPost(url, payload.toString()); + Type type = new TypeToken>(){}.getType(); + return new Gson().fromJson(result.responseContent, type); + } public UsersResult getUsers(TimeUnit timeUnit, String start, int duration) throws APIConnectionException, APIRequestException { @@ -88,7 +177,23 @@ public UsersResult getUsers(TimeUnit timeUnit, String start, int duration) return BaseResult.fromResponse(response, UsersResult.class); } - + + public GroupUsersResult getGroupUsers(TimeUnit timeUnit, String start, int duration) + throws APIConnectionException, APIRequestException { + String startEncoded = null; + try { + startEncoded = URLEncoder.encode(start, "utf-8"); + } catch (Exception e) { + } + + String url = _hostName + groupUserPath + + "?time_unit=" + timeUnit.toString() + + "&start=" + startEncoded + "&duration=" + duration; + ResponseWrapper response = _httpClient.sendGet(url); + + return BaseResult.fromResponse(response, GroupUsersResult.class); + } + private final static Pattern MSGID_PATTERNS = Pattern.compile("[^0-9, ]"); diff --git a/src/main/java/cn/jpush/api/report/UsersResult.java b/src/main/java/cn/jpush/api/report/UsersResult.java index 6ddb8284..67974319 100644 --- a/src/main/java/cn/jpush/api/report/UsersResult.java +++ b/src/main/java/cn/jpush/api/report/UsersResult.java @@ -3,14 +3,15 @@ import java.util.ArrayList; import java.util.List; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.common.resp.BaseResult; - import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.resp.BaseResult; + public class UsersResult extends BaseResult { + private static final long serialVersionUID = -963296929272770550L; @Expose public TimeUnit time_unit; @Expose public String start; @Expose public int duration; diff --git a/src/main/java/cn/jpush/api/report/model/CheckMessagePayload.java b/src/main/java/cn/jpush/api/report/model/CheckMessagePayload.java new file mode 100644 index 00000000..95ba6dd6 --- /dev/null +++ b/src/main/java/cn/jpush/api/report/model/CheckMessagePayload.java @@ -0,0 +1,115 @@ +package cn.jpush.api.report.model; + +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.TimeUtils; +import cn.jpush.api.schedule.model.IModel; +import com.google.gson.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CheckMessagePayload implements IModel{ + + public final static String MSG_ID = "msg_id"; + public final static String REGISTRATION_IDS = "registration_ids"; + public final static String DATE = "date"; + + private long msgId = -1L; + private List registrationIds; + private String date; + private Gson gson = new Gson(); + public CheckMessagePayload(long msgId, List rids, String date) { + this.msgId = msgId; + this.registrationIds = rids; + this.date = date; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private long msgId; + private List registrationIds = new ArrayList(); + private String date; + + public Builder setMsgId(long msgId) { + this.msgId = msgId; + return this; + } + + public Builder setRegistrationIds(String[] rids) { + Preconditions.checkArgument(rids != null && rids.length > 0, "Registration ids is empty"); + Collections.addAll(registrationIds, rids); + return this; + } + + public Builder setRegistrationsIds(List rids) { + Preconditions.checkArgument(rids != null && rids.size() > 0, "Registration ids is empty"); + registrationIds = rids; + return this; + } + + public Builder addRegistrationIds(String... rids) { + if (null == rids) { + return this; + } + Collections.addAll(registrationIds, rids); + return this; + } + + public Builder addRegistrationIds(List rids) { + registrationIds.addAll(rids); + return this; + } + + public Builder setDate(String date) { + Preconditions.checkArgument(isDayFormat(date), "Date format is invalid"); + this.date = date; + return this; + } + + public CheckMessagePayload build() { + return new CheckMessagePayload(msgId, registrationIds, date); + } + } + + @Override + public JsonElement toJSON() { + JsonObject jsonObject = new JsonObject(); + if (msgId != -1L) { + jsonObject.addProperty(MSG_ID, msgId); + } + if (null != registrationIds) { + JsonArray jsonArray = new JsonArray(); + for (String rid : registrationIds) { + jsonArray.add(new JsonPrimitive(rid)); + } + jsonObject.add(REGISTRATION_IDS, jsonArray); + } + if (null != date) { + jsonObject.addProperty(DATE, date); + } + return jsonObject; + } + + @Override + public String toString() { + return gson.toJson(toJSON()); + } + + private static boolean isDayFormat(String date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + try { + simpleDateFormat.parse(date); + return true; + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/src/main/java/cn/jpush/api/schedule/ScheduleClient.java b/src/main/java/cn/jpush/api/schedule/ScheduleClient.java index 3219e748..d5efa7fc 100644 --- a/src/main/java/cn/jpush/api/schedule/ScheduleClient.java +++ b/src/main/java/cn/jpush/api/schedule/ScheduleClient.java @@ -1,16 +1,17 @@ package cn.jpush.api.schedule; -import cn.jpush.api.common.ClientConfig; -import cn.jpush.api.common.ServiceHelper; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.connection.IHttpClient; -import cn.jpush.api.common.connection.NativeHttpClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.ResponseWrapper; +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.push.CIDResult; +import cn.jpush.api.push.PushClient; import cn.jpush.api.schedule.model.SchedulePayload; -import cn.jpush.api.utils.Preconditions; -import cn.jpush.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,39 +23,96 @@ public class ScheduleClient { private String hostName; private String schedulePath; + private PushClient pushClient; + + // If not present, true by default. + private int apnsProduction; + + // If not present, the default value is 86400(s) (one day) + private long timeToLive; + public ScheduleClient(String masterSecret, String appkey) { - this(masterSecret, appkey, IHttpClient.DEFAULT_MAX_RETRY_TIMES, null, ClientConfig.getInstance()); + this(masterSecret, appkey, null, ClientConfig.getInstance()); } + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The mas retry times. + * + */ + @Deprecated public ScheduleClient(String masterSecret, String appKey, int maxRetryTimes) { - this(masterSecret, appKey, maxRetryTimes, null, ClientConfig.getInstance()); + this(masterSecret, appKey, maxRetryTimes, null); } + /** + * This will be removed in the future. Please use ClientConfig{jiguang-common cn.jiguang.common.ClientConfig#setMaxRetryTimes} instead of this constructor. + * @param masterSecret API access secret of the appKey. + * @param appKey The KEY of one application on JPush. + * @param maxRetryTimes The mas retry times. + * @param proxy The proxy, if there is no proxy, should be null. + */ + @Deprecated public ScheduleClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy) { - this(masterSecret, appKey, maxRetryTimes, proxy, ClientConfig.getInstance()); + ServiceHelper.checkBasic(appKey, masterSecret); + + ClientConfig conf = ClientConfig.getInstance(); + conf.setMaxRetryTimes(maxRetryTimes); + + hostName = (String) conf.get(ClientConfig.SCHEDULE_HOST_NAME); + schedulePath = (String) conf.get(ClientConfig.SCHEDULE_PATH); + apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION); + timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE); + + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); } /** * Create a Schedule Client with custom configuration. * @param masterSecret API access secret of the appKey. * @param appKey The KEY of one application on JPush. - * @param maxRetryTimes Max retry times * @param proxy The proxy, if there is no proxy, should be null. * @param conf The client configuration. Can use ClientConfig.getInstance() as default. */ - public ScheduleClient(String masterSecret, String appKey, int maxRetryTimes, HttpProxy proxy, ClientConfig conf) { + public ScheduleClient(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { ServiceHelper.checkBasic(appKey, masterSecret); hostName = (String) conf.get(ClientConfig.SCHEDULE_HOST_NAME); schedulePath = (String) conf.get(ClientConfig.SCHEDULE_PATH); + apnsProduction = (Integer) conf.get(ClientConfig.APNS_PRODUCTION); + timeToLive = (Long) conf.get(ClientConfig.TIME_TO_LIVE); + //createSchedule接口需要用到这个类 + pushClient = new PushClient(masterSecret, appKey, proxy, conf); String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); - this._httpClient = new NativeHttpClient(authCode, maxRetryTimes, proxy); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); } - public ScheduleResult createSchedule(SchedulePayload payload) throws APIConnectionException, APIRequestException { + public ScheduleResult createSchedule(SchedulePayload payload, String masterSecret, + String appKey) throws APIConnectionException, APIRequestException { Preconditions.checkArgument(null != payload, "payload should not be null"); + if (apnsProduction > 0) { + payload.resetPushApnsProduction(true); + } else if(apnsProduction == 0) { + payload.resetPushApnsProduction(false); + } + + if (timeToLive >= 0) { + payload.resetPushTimeToLive(timeToLive); + } + + // 调用getCidList方法来获取cid并赋值到payload中 + String cid = payload.getCid(); + if (cid == null) { + CIDResult cidResult = pushClient.getCidList(1 , "schedule"); + payload.setCid(cidResult.cidlist.get(0)); + } + + ResponseWrapper response = _httpClient.sendPost(hostName + schedulePath, payload.toString()); return ScheduleResult.fromResponse(response, ScheduleResult.class); } @@ -74,12 +132,30 @@ public ScheduleResult getSchedule(String scheduleId) throws APIConnectionExcepti ResponseWrapper response = _httpClient.sendGet(hostName + schedulePath + "/" + scheduleId); return ScheduleResult.fromResponse(response, ScheduleResult.class); } + + public ScheduleMsgIdsResult getScheduleMsgIds(String scheduleId) throws APIConnectionException, APIRequestException{ + + Preconditions.checkArgument(StringUtils.isNotEmpty(scheduleId), "scheduleId should not be empty"); + + ResponseWrapper response = _httpClient.sendGet(hostName + schedulePath + "/" + scheduleId + "/msg_ids"); + return ScheduleResult.fromResponse(response, ScheduleMsgIdsResult.class); + } public ScheduleResult updateSchedule(String scheduleId, SchedulePayload payload) throws APIConnectionException, APIRequestException{ Preconditions.checkArgument(StringUtils.isNotEmpty(scheduleId), "scheduleId should not be empty"); Preconditions.checkArgument(null != payload, "payload should not be null"); + if (apnsProduction > 0) { + payload.resetPushApnsProduction(true); + } else if(apnsProduction == 0) { + payload.resetPushApnsProduction(false); + } + + if (timeToLive >= 0) { + payload.resetPushTimeToLive(timeToLive); + } + ResponseWrapper response = _httpClient.sendPut(hostName + schedulePath + "/" + scheduleId, payload.toString()); return ScheduleResult.fromResponse(response, ScheduleResult.class); diff --git a/src/main/java/cn/jpush/api/schedule/ScheduleListResult.java b/src/main/java/cn/jpush/api/schedule/ScheduleListResult.java index eeda28db..73ffa39c 100644 --- a/src/main/java/cn/jpush/api/schedule/ScheduleListResult.java +++ b/src/main/java/cn/jpush/api/schedule/ScheduleListResult.java @@ -1,13 +1,15 @@ package cn.jpush.api.schedule; -import cn.jpush.api.common.resp.BaseResult; +import java.util.List; + import com.google.gson.annotations.Expose; -import java.util.List; +import cn.jiguang.common.resp.BaseResult; public class ScheduleListResult extends BaseResult{ + private static final long serialVersionUID = 86248096939746151L; @Expose int total_count; @Expose int total_pages; @Expose int page; diff --git a/src/main/java/cn/jpush/api/schedule/ScheduleMsgIdsResult.java b/src/main/java/cn/jpush/api/schedule/ScheduleMsgIdsResult.java new file mode 100644 index 00000000..4f1a1385 --- /dev/null +++ b/src/main/java/cn/jpush/api/schedule/ScheduleMsgIdsResult.java @@ -0,0 +1,37 @@ +package cn.jpush.api.schedule; + + + +import java.util.List; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; + +import cn.jiguang.common.resp.BaseResult; + +public class ScheduleMsgIdsResult extends BaseResult{ + + private static final long serialVersionUID = 995450157929893257L; + + @Expose int count; + + @Expose List msgids; + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public List getMsgids() { + return msgids; + } + + public void setMsgids(List msgids) { + this.msgids = msgids; + } + + +} diff --git a/src/main/java/cn/jpush/api/schedule/ScheduleResult.java b/src/main/java/cn/jpush/api/schedule/ScheduleResult.java index 50619aa4..a0d9b916 100644 --- a/src/main/java/cn/jpush/api/schedule/ScheduleResult.java +++ b/src/main/java/cn/jpush/api/schedule/ScheduleResult.java @@ -1,11 +1,13 @@ package cn.jpush.api.schedule; -import cn.jpush.api.common.resp.BaseResult; import com.google.gson.JsonObject; import com.google.gson.annotations.Expose; +import cn.jiguang.common.resp.BaseResult; + public class ScheduleResult extends BaseResult{ + private static final long serialVersionUID = 995450157929190757L; @Expose String schedule_id; @Expose String name; @Expose Boolean enabled; diff --git a/src/main/java/cn/jpush/api/schedule/model/SchedulePayload.java b/src/main/java/cn/jpush/api/schedule/model/SchedulePayload.java index 2fe0302f..c8b5ec12 100644 --- a/src/main/java/cn/jpush/api/schedule/model/SchedulePayload.java +++ b/src/main/java/cn/jpush/api/schedule/model/SchedulePayload.java @@ -1,27 +1,50 @@ package cn.jpush.api.schedule.model; -import cn.jpush.api.push.model.PushPayload; -import cn.jpush.api.utils.StringUtils; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.push.model.PushPayload; + public class SchedulePayload implements IModel { + private static final String CID = "cid"; + private static final String NAME = "name"; + private static final String ENABLED = "enabled"; + private static final String TRIGGER = "trigger"; + private static final String PUSH = "push"; + private static Gson gson = new Gson(); + private String cid; private String name; private Boolean enabled; private TriggerPayload trigger; private PushPayload push; - private SchedulePayload(String name, Boolean enabled, TriggerPayload trigger, PushPayload push) { + private SchedulePayload(String cid, String name, Boolean enabled, TriggerPayload trigger, PushPayload push) { + this.cid = cid; this.name = name; this.enabled = enabled; this.trigger = trigger; this.push = push; } + public SchedulePayload setCid(String cid) { + this.cid = cid; + return this; + } + + public String getCid() { + return cid; + } + + /** + * + * The entrance for building a SchedulePayload object. + * @return SchedulePayload builder + */ public static Builder newBuilder() { return new Builder(); } @@ -29,17 +52,20 @@ public static Builder newBuilder() { @Override public JsonElement toJSON() { JsonObject json = new JsonObject(); + if ( null != cid ) { + json.addProperty(CID, cid); + } if ( StringUtils.isNotEmpty(name) ) { - json.addProperty("name", name); + json.addProperty(NAME, name); } if ( null != enabled ) { - json.addProperty("enabled", enabled); + json.addProperty(ENABLED, enabled); } if ( null != trigger ) { - json.add("trigger", trigger.toJSON()); + json.add(TRIGGER, trigger.toJSON()); } if ( null != push ) { - json.add("push", push.toJSON()); + json.add(PUSH, push.toJSON()); } return json; } @@ -49,12 +75,30 @@ public String toString() { return gson.toJson(toJSON()); } + public void resetPushApnsProduction(boolean apnsProduction) { + if(null != push) { + push.resetOptionsApnsProduction(apnsProduction); + } + } + + public void resetPushTimeToLive(long timeToLive) { + if(null != push) { + push.resetOptionsTimeToLive(timeToLive); + } + } + public static class Builder{ + private String cid; private String name; private Boolean enabled; private TriggerPayload trigger; private PushPayload push; + public Builder setCid(String cid) { + this.cid = cid; + return this; + } + public Builder setName(String name) { this.name = name; return this; @@ -77,7 +121,7 @@ public Builder setPush(PushPayload push) { public SchedulePayload build() { - return new SchedulePayload(name, enabled, trigger, push); + return new SchedulePayload(cid, name, enabled, trigger, push); } } } diff --git a/src/main/java/cn/jpush/api/schedule/model/TriggerPayload.java b/src/main/java/cn/jpush/api/schedule/model/TriggerPayload.java index ad3bd2e3..d3ddb35a 100644 --- a/src/main/java/cn/jpush/api/schedule/model/TriggerPayload.java +++ b/src/main/java/cn/jpush/api/schedule/model/TriggerPayload.java @@ -1,10 +1,15 @@ package cn.jpush.api.schedule.model; -import cn.jpush.api.common.TimeUnit; -import cn.jpush.api.utils.Preconditions; -import cn.jpush.api.utils.StringUtils; -import cn.jpush.api.utils.TimeUtils; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.TimeUnit; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jiguang.common.utils.TimeUtils; public class TriggerPayload implements IModel { diff --git a/src/main/java/cn/jpush/api/utils/Base64.java b/src/main/java/cn/jpush/api/utils/Base64.java deleted file mode 100644 index f6b4e150..00000000 --- a/src/main/java/cn/jpush/api/utils/Base64.java +++ /dev/null @@ -1,120 +0,0 @@ -package cn.jpush.api.utils; - -import java.io.CharArrayWriter; -import java.io.IOException; - -public class Base64 { - static final char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - .toCharArray(); - - public static char[] encode(byte[] content) { - CharArrayWriter cw = new CharArrayWriter(4 * content.length / 3); - - int idx = 0; - - int x = 0; - - for (int i = 0; i < content.length; ++i) { - if (idx == 0) - x = (content[i] & 0xFF) << 16; - else if (idx == 1) - x |= (content[i] & 0xFF) << 8; - else { - x |= content[i] & 0xFF; - } - - if (++idx == 3) { - cw.write(alphabet[(x >> 18)]); - cw.write(alphabet[(x >> 12 & 0x3F)]); - cw.write(alphabet[(x >> 6 & 0x3F)]); - cw.write(alphabet[(x & 0x3F)]); - - idx = 0; - } - } - - if (idx == 1) { - cw.write(alphabet[(x >> 18)]); - cw.write(alphabet[(x >> 12 & 0x3F)]); - cw.write(61); - cw.write(61); - } - - if (idx == 2) { - cw.write(alphabet[(x >> 18)]); - cw.write(alphabet[(x >> 12 & 0x3F)]); - cw.write(alphabet[(x >> 6 & 0x3F)]); - cw.write(61); - } - - return cw.toCharArray(); - } - - public static byte[] decode(char[] message) throws IOException { - byte[] buff = new byte[4]; - byte[] dest = new byte[message.length]; - - int bpos = 0; - int destpos = 0; - - for (int i = 0; i < message.length; ++i) { - int c = message[i]; - - if ((c != 10) && (c != 13) && (c != 32)) { - if (c == 9) - continue; - - if ((c >= 65) && (c <= 90)) { - buff[(bpos++)] = (byte) (c - 65); - } else if ((c >= 97) && (c <= 122)) { - buff[(bpos++)] = (byte) (c - 97 + 26); - } else if ((c >= 48) && (c <= 57)) { - buff[(bpos++)] = (byte) (c - 48 + 52); - } else if (c == 43) { - buff[(bpos++)] = 62; - } else if (c == 47) { - buff[(bpos++)] = 63; - } else if (c == 61) { - buff[(bpos++)] = 64; - } else { - throw new IOException("Illegal char in base64 code."); - } - - if (bpos == 4) { - bpos = 0; - - if (buff[0] == 64) - break; - - if (buff[1] == 64) - throw new IOException("Unexpected '=' in base64 code."); - - int v; - if (buff[2] == 64) { - v = (buff[0] & 0x3F) << 6 | buff[1] & 0x3F; - dest[(destpos++)] = (byte) (v >> 4); - break; - } - if (buff[3] == 64) { - v = (buff[0] & 0x3F) << 12 | (buff[1] & 0x3F) << 6 - | buff[2] & 0x3F; - dest[(destpos++)] = (byte) (v >> 10); - dest[(destpos++)] = (byte) (v >> 2); - break; - } - - v = (buff[0] & 0x3F) << 18 | (buff[1] & 0x3F) << 12 - | (buff[2] & 0x3F) << 6 | buff[3] & 0x3F; - dest[(destpos++)] = (byte) (v >> 16); - dest[(destpos++)] = (byte) (v >> 8); - dest[(destpos++)] = (byte) v; - } - } - } - - byte[] res = new byte[destpos]; - System.arraycopy(dest, 0, res, 0, destpos); - - return res; - } -} \ No newline at end of file diff --git a/src/main/java/cn/jpush/api/utils/Nullable.java b/src/main/java/cn/jpush/api/utils/Nullable.java deleted file mode 100644 index 98d9d1ec..00000000 --- a/src/main/java/cn/jpush/api/utils/Nullable.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.jpush.api.utils; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Copied from javax.annotation.Nullable - */ -@Documented -//@TypeQualifierNickname -//@Nonnull(when = When.UNKNOWN) -@Retention(RetentionPolicy.RUNTIME) -public @interface Nullable { - -} diff --git a/src/main/java/cn/jpush/api/utils/Preconditions.java b/src/main/java/cn/jpush/api/utils/Preconditions.java deleted file mode 100644 index e32e8292..00000000 --- a/src/main/java/cn/jpush/api/utils/Preconditions.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (C) 2007 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package cn.jpush.api.utils; - -/** - * Copied from Google Guava. - * - * Static convenience methods that help a method or constructor check whether it was invoked - * correctly (whether its preconditions have been met). These methods generally accept a - * {@code boolean} expression which is expected to be {@code true} (or in the case of {@code - * checkNotNull}, an object reference which is expected to be non-null). When {@code false} (or - * {@code null}) is passed instead, the {@code Preconditions} method throws an unchecked exception, - * which helps the calling method communicate to its caller that that caller has made - * a mistake. Example:
       {@code
    - *
    - *   /**
    - *    * Returns the positive square root of the given value.
    - *    *
    - *    * @throws IllegalArgumentException if the value is negative
    - *    *}{@code /
    - *   public static double sqrt(double value) {
    - *     Preconditions.checkArgument(value >= 0.0, "negative value: %s", value);
    - *     // calculate the square root
    - *   }
    - *
    - *   void exampleBadCaller() {
    - *     double d = sqrt(-1.0);
    - *   }}
    - * - * In this example, {@code checkArgument} throws an {@code IllegalArgumentException} to indicate - * that {@code exampleBadCaller} made an error in its call to {@code sqrt}. - * - *

    Warning about performance

    - * - *

    The goal of this class is to improve readability of code, but in some circumstances this may - * come at a significant performance cost. Remember that parameter values for message construction - * must all be computed eagerly, and autoboxing and varargs array creation may happen as well, even - * when the precondition check then succeeds (as it should almost always do in production). In some - * circumstances these wasted CPU cycles and allocations can add up to a real problem. - * Performance-sensitive precondition checks can always be converted to the customary form: - *

       {@code
    - *
    - *   if (value < 0.0) {
    - *     throw new IllegalArgumentException("negative value: " + value);
    - *   }}
    - * - *

    Other types of preconditions

    - * - *

    Not every type of precondition failure is supported by these methods. Continue to throw - * standard JDK exceptions such as {@link java.util.NoSuchElementException} or {@link - * UnsupportedOperationException} in the situations they are intended for. - * - *

    Non-preconditions

    - * - *

    It is of course possible to use the methods of this class to check for invalid conditions - * which are not the caller's fault. Doing so is not recommended because it is - * misleading to future readers of the code and of stack traces. See - * Conditional - * failures explained in the Guava User Guide for more advice. - * - *

    {@code java.util.Objects.requireNonNull()}

    - * - *

    Projects which use {@code com.google.common} should generally avoid the use of {@link - * java.util.Objects#requireNonNull(Object)}. Instead, use whichever of {@link - * #checkNotNull(Object)} or {@link Verify#verifyNotNull(Object)} is appropriate to the situation. - * (The same goes for the message-accepting overloads.) - * - *

    Only {@code %s} is supported

    - * - *

    In {@code Preconditions} error message template strings, only the {@code "%s"} specifier is - * supported, not the full range of {@link java.util.Formatter} specifiers. However, note that if - * the number of arguments does not match the number of occurrences of {@code "%s"} in the format - * string, {@code Preconditions} will still behave as expected, and will still include all argument - * values in the error message; the message will simply not be formatted exactly as intended. - * - *

    More information

    - * - *

    See the Guava User Guide on - * using {@code - * Preconditions}. - * - * @author Kevin Bourrillion - * @since 2.0 (imported from Google Collections Library) - */ -public final class Preconditions { - private Preconditions() {} - - /** - * Ensures the truth of an expression involving one or more parameters to the calling method. - * - * @param expression a boolean expression - * @throws IllegalArgumentException if {@code expression} is false - */ - public static void checkArgument(boolean expression) { - if (!expression) { - throw new IllegalArgumentException(); - } - } - - /** - * Ensures the truth of an expression involving one or more parameters to the calling method. - * - * @param expression a boolean expression - * @param errorMessage the exception message to use if the check fails; will be converted to a - * string using {@link String#valueOf(Object)} - * @throws IllegalArgumentException if {@code expression} is false - */ - public static void checkArgument(boolean expression, @Nullable Object errorMessage) { - if (!expression) { - throw new IllegalArgumentException(String.valueOf(errorMessage)); - } - } - - /** - * Ensures the truth of an expression involving one or more parameters to the calling method. - * - * @param expression a boolean expression - * @param errorMessageTemplate a template for the exception message should the check fail. The - * message is formed by replacing each {@code %s} placeholder in the template with an - * argument. These are matched by position - the first {@code %s} gets {@code - * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message - * in square braces. Unmatched placeholders will be left as-is. - * @param errorMessageArgs the arguments to be substituted into the message template. Arguments - * are converted to strings using {@link String#valueOf(Object)}. - * @throws IllegalArgumentException if {@code expression} is false - * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or - * {@code errorMessageArgs} is null (don't let this happen) - */ - public static void checkArgument(boolean expression, - @Nullable String errorMessageTemplate, - @Nullable Object... errorMessageArgs) { - if (!expression) { - throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs)); - } - } - - /** - * Ensures the truth of an expression involving the state of the calling instance, but not - * involving any parameters to the calling method. - * - * @param expression a boolean expression - * @throws IllegalStateException if {@code expression} is false - */ - public static void checkState(boolean expression) { - if (!expression) { - throw new IllegalStateException(); - } - } - - /** - * Ensures the truth of an expression involving the state of the calling instance, but not - * involving any parameters to the calling method. - * - * @param expression a boolean expression - * @param errorMessage the exception message to use if the check fails; will be converted to a - * string using {@link String#valueOf(Object)} - * @throws IllegalStateException if {@code expression} is false - */ - public static void checkState(boolean expression, @Nullable Object errorMessage) { - if (!expression) { - throw new IllegalStateException(String.valueOf(errorMessage)); - } - } - - /** - * Ensures the truth of an expression involving the state of the calling instance, but not - * involving any parameters to the calling method. - * - * @param expression a boolean expression - * @param errorMessageTemplate a template for the exception message should the check fail. The - * message is formed by replacing each {@code %s} placeholder in the template with an - * argument. These are matched by position - the first {@code %s} gets {@code - * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message - * in square braces. Unmatched placeholders will be left as-is. - * @param errorMessageArgs the arguments to be substituted into the message template. Arguments - * are converted to strings using {@link String#valueOf(Object)}. - * @throws IllegalStateException if {@code expression} is false - * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or - * {@code errorMessageArgs} is null (don't let this happen) - */ - public static void checkState(boolean expression, - @Nullable String errorMessageTemplate, - @Nullable Object... errorMessageArgs) { - if (!expression) { - throw new IllegalStateException(format(errorMessageTemplate, errorMessageArgs)); - } - } - - /** - * Ensures that an object reference passed as a parameter to the calling method is not null. - * - * @param reference an object reference - * @return the non-null reference that was validated - * @throws NullPointerException if {@code reference} is null - */ - public static T checkNotNull(T reference) { - if (reference == null) { - throw new NullPointerException(); - } - return reference; - } - - /** - * Ensures that an object reference passed as a parameter to the calling method is not null. - * - * @param reference an object reference - * @param errorMessage the exception message to use if the check fails; will be converted to a - * string using {@link String#valueOf(Object)} - * @return the non-null reference that was validated - * @throws NullPointerException if {@code reference} is null - */ - public static T checkNotNull(T reference, @Nullable Object errorMessage) { - if (reference == null) { - throw new NullPointerException(String.valueOf(errorMessage)); - } - return reference; - } - - /** - * Ensures that an object reference passed as a parameter to the calling method is not null. - * - * @param reference an object reference - * @param errorMessageTemplate a template for the exception message should the check fail. The - * message is formed by replacing each {@code %s} placeholder in the template with an - * argument. These are matched by position - the first {@code %s} gets {@code - * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message - * in square braces. Unmatched placeholders will be left as-is. - * @param errorMessageArgs the arguments to be substituted into the message template. Arguments - * are converted to strings using {@link String#valueOf(Object)}. - * @return the non-null reference that was validated - * @throws NullPointerException if {@code reference} is null - */ - public static T checkNotNull(T reference, - @Nullable String errorMessageTemplate, - @Nullable Object... errorMessageArgs) { - if (reference == null) { - // If either of these parameters is null, the right thing happens anyway - throw new NullPointerException(format(errorMessageTemplate, errorMessageArgs)); - } - return reference; - } - - /* - * All recent hotspots (as of 2009) *really* like to have the natural code - * - * if (guardExpression) { - * throw new BadException(messageExpression); - * } - * - * refactored so that messageExpression is moved to a separate String-returning method. - * - * if (guardExpression) { - * throw new BadException(badMsg(...)); - * } - * - * The alternative natural refactorings into void or Exception-returning methods are much slower. - * This is a big deal - we're talking factors of 2-8 in microbenchmarks, not just 10-20%. (This - * is a hotspot optimizer bug, which should be fixed, but that's a separate, big project). - * - * The coding pattern above is heavily used in java.util, e.g. in ArrayList. There is a - * RangeCheckMicroBenchmark in the JDK that was used to test this. - * - * But the methods in this class want to throw different exceptions, depending on the args, so it - * appears that this pattern is not directly applicable. But we can use the ridiculous, devious - * trick of throwing an exception in the middle of the construction of another exception. Hotspot - * is fine with that. - */ - - /** - * Ensures that {@code index} specifies a valid element in an array, list or string of size - * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive. - * - * @param index a user-supplied index identifying an element of an array, list or string - * @param size the size of that array, list or string - * @return the value of {@code index} - * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size} - * @throws IllegalArgumentException if {@code size} is negative - */ - public static int checkElementIndex(int index, int size) { - return checkElementIndex(index, size, "index"); - } - - /** - * Ensures that {@code index} specifies a valid element in an array, list or string of size - * {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive. - * - * @param index a user-supplied index identifying an element of an array, list or string - * @param size the size of that array, list or string - * @param desc the text to use to describe this index in an error message - * @return the value of {@code index} - * @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size} - * @throws IllegalArgumentException if {@code size} is negative - */ - public static int checkElementIndex( - int index, int size, @Nullable String desc) { - // Carefully optimized for execution by hotspot (explanatory comment above) - if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); - } - return index; - } - - private static String badElementIndex(int index, int size, String desc) { - if (index < 0) { - return format("%s (%s) must not be negative", desc, index); - } else if (size < 0) { - throw new IllegalArgumentException("negative size: " + size); - } else { // index >= size - return format("%s (%s) must be less than size (%s)", desc, index, size); - } - } - - /** - * Ensures that {@code index} specifies a valid position in an array, list or string of - * size {@code size}. A position index may range from zero to {@code size}, inclusive. - * - * @param index a user-supplied index identifying a position in an array, list or string - * @param size the size of that array, list or string - * @return the value of {@code index} - * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size} - * @throws IllegalArgumentException if {@code size} is negative - */ - public static int checkPositionIndex(int index, int size) { - return checkPositionIndex(index, size, "index"); - } - - /** - * Ensures that {@code index} specifies a valid position in an array, list or string of - * size {@code size}. A position index may range from zero to {@code size}, inclusive. - * - * @param index a user-supplied index identifying a position in an array, list or string - * @param size the size of that array, list or string - * @param desc the text to use to describe this index in an error message - * @return the value of {@code index} - * @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size} - * @throws IllegalArgumentException if {@code size} is negative - */ - public static int checkPositionIndex(int index, int size, @Nullable String desc) { - // Carefully optimized for execution by hotspot (explanatory comment above) - if (index < 0 || index > size) { - throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); - } - return index; - } - - private static String badPositionIndex(int index, int size, String desc) { - if (index < 0) { - return format("%s (%s) must not be negative", desc, index); - } else if (size < 0) { - throw new IllegalArgumentException("negative size: " + size); - } else { // index > size - return format("%s (%s) must not be greater than size (%s)", desc, index, size); - } - } - - /** - * Ensures that {@code start} and {@code end} specify a valid positions in an array, list - * or string of size {@code size}, and are in order. A position index may range from zero to - * {@code size}, inclusive. - * - * @param start a user-supplied index identifying a starting position in an array, list or string - * @param end a user-supplied index identifying a ending position in an array, list or string - * @param size the size of that array, list or string - * @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size}, - * or if {@code end} is less than {@code start} - * @throws IllegalArgumentException if {@code size} is negative - */ - public static void checkPositionIndexes(int start, int end, int size) { - // Carefully optimized for execution by hotspot (explanatory comment above) - if (start < 0 || end < start || end > size) { - throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); - } - } - - private static String badPositionIndexes(int start, int end, int size) { - if (start < 0 || start > size) { - return badPositionIndex(start, size, "start index"); - } - if (end < 0 || end > size) { - return badPositionIndex(end, size, "end index"); - } - // end < start - return format("end index (%s) must not be less than start index (%s)", end, start); - } - - /** - * Substitutes each {@code %s} in {@code template} with an argument. These are matched by - * position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than - * placeholders, the unmatched arguments will be appended to the end of the formatted message in - * square braces. - * - * @param template a non-null string containing 0 or more {@code %s} placeholders. - * @param args the arguments to be substituted into the message template. Arguments are converted - * to strings using {@link String#valueOf(Object)}. Arguments can be null. - */ - // Note that this is somewhat-improperly used from Verify.java as well. - static String format(String template, @Nullable Object... args) { - template = String.valueOf(template); // null -> "null" - - // start substituting the arguments into the '%s' placeholders - StringBuilder builder = new StringBuilder(template.length() + 16 * args.length); - int templateStart = 0; - int i = 0; - while (i < args.length) { - int placeholderStart = template.indexOf("%s", templateStart); - if (placeholderStart == -1) { - break; - } - builder.append(template.substring(templateStart, placeholderStart)); - builder.append(args[i++]); - templateStart = placeholderStart + 2; - } - builder.append(template.substring(templateStart)); - - // if we run out of placeholders, append the extra args in square braces - if (i < args.length) { - builder.append(" ["); - builder.append(args[i++]); - while (i < args.length) { - builder.append(", "); - builder.append(args[i++]); - } - builder.append(']'); - } - - return builder.toString(); - } -} diff --git a/src/main/java/cn/jpush/api/utils/StringUtils.java b/src/main/java/cn/jpush/api/utils/StringUtils.java deleted file mode 100644 index 104831c2..00000000 --- a/src/main/java/cn/jpush/api/utils/StringUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -package cn.jpush.api.utils; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.MessageDigest; - - -public class StringUtils { - private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5", - "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; - - private static String byteArrayToHexString(byte[] b) { - StringBuffer resultSb = new StringBuffer(); - for (int i = 0; i < b.length; i++) { - resultSb.append(byteToHexString(b[i])); - } - return resultSb.toString(); - } - - private static String byteToHexString(byte b) { - int n = b; - if (n < 0) - n = 256 + n; - int d1 = n / 16; - int d2 = n % 16; - return hexDigits[d1] + hexDigits[d2]; - } - - public static String toMD5(String origin) { - String resultString = null; - try { - resultString = new String(origin); - MessageDigest md = MessageDigest.getInstance("MD5"); - resultString = byteArrayToHexString(md.digest(resultString.getBytes())); - } catch (Exception ex) { - ex.printStackTrace(); - } - return resultString; - } - - public static String encodeParam(String param) { - String encodeParam = null; - try { - encodeParam = URLEncoder.encode(param, "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - return encodeParam; - } - - public static String arrayToString(String[] values) { - if (null == values) return ""; - - StringBuffer buffer = new StringBuffer(values.length); - for (int i = 0; i < values.length; i++) { - buffer.append(values[i]).append(","); - } - if (buffer.length() > 0) { - return buffer.toString().substring(0, buffer.length() - 1); - } - return ""; - } - - public static boolean isEmpty(String s) { - return s == null || s.length() == 0; - } - - public static boolean isTrimedEmpty(String s) { - return s == null || s.trim().length() == 0; - } - - public static boolean isNotEmpty(String s) { - return s != null && s.length() > 0; - } - - public static boolean isLineBroken(String s) { - if ( null == s ) { - return false; - } - if (s.contains("\n")) { - return true; - } - if (s.contains("\r\n")) { - return true; - } - return false; - } - -} diff --git a/src/main/java/cn/jpush/api/utils/TimeUtils.java b/src/main/java/cn/jpush/api/utils/TimeUtils.java deleted file mode 100644 index 5d53c6a5..00000000 --- a/src/main/java/cn/jpush/api/utils/TimeUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.jpush.api.utils; - - -import java.text.ParseException; -import java.text.SimpleDateFormat; - -public class TimeUtils { - - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - private static final SimpleDateFormat TIME_ONLY_FORMAT = new SimpleDateFormat("HH:mm:ss"); - - static { - DATE_FORMAT.setLenient(false); - TIME_ONLY_FORMAT.setLenient(false); - } - - public static boolean isDateFormat(String time) { - try { - DATE_FORMAT.parse(time); - } catch (ParseException e) { - return false; - } - return true; - } - - public static boolean isTimeFormat(String time) { - try{ - TIME_ONLY_FORMAT.parse(time); - } catch (ParseException e) { - return false; - } - return true; - } - -} diff --git a/src/main/resources/javadoc-overview.html b/src/main/resources/javadoc-overview.html index 7b36a45e..09fd5e36 100644 --- a/src/main/resources/javadoc-overview.html +++ b/src/main/resources/javadoc-overview.html @@ -5,6 +5,6 @@ JPush API Java 客户端。 - 主要分为 4 个功能部分:推送、报表、Tag/Alias管理、定时任务管理 + 主要分为 4 个功能部分:推送、报表、Device管理、定时任务管理 diff --git a/src/test/java/cn/jpush/api/BaseTest.java b/src/test/java/cn/jpush/api/BaseTest.java index 48ca5acb..030f65c1 100644 --- a/src/test/java/cn/jpush/api/BaseTest.java +++ b/src/test/java/cn/jpush/api/BaseTest.java @@ -4,14 +4,17 @@ public abstract class BaseTest { - protected static final String APP_KEY ="dd1066407b044738b6479275"; - protected static final String MASTER_SECRET = "6b135be0037a5c1e693c3dfa"; + protected static final String APP_KEY = "eb67142502ec9f5556875b9a"; + protected static final String MASTER_SECRET = "186aa57bc697c94f8698bbbf"; + protected static final String GROUP_MASTER_SECRET = "b11314807507e2bcfdeebe2e"; + protected static final String GROUP_PUSH_KEY = "2c88a01e073a0fe4fc7b167c"; public static final String ALERT = "JPush Test - alert"; public static final String MSG_CONTENT = "JPush Test - msgContent"; public static final String REGISTRATION_ID1 = "0900e8d85ef"; public static final String REGISTRATION_ID2 = "0a04ad7d8b4"; + public static final String REGISTRATION_ID3 = "18071adc030dcba91c0"; protected JPushClient jpushClient = null; diff --git a/src/test/java/cn/jpush/api/device/DeviceNormalRemoteTest.java b/src/test/java/cn/jpush/api/device/DeviceNormalRemoteTest.java index 1b7f26a6..701aa501 100644 --- a/src/test/java/cn/jpush/api/device/DeviceNormalRemoteTest.java +++ b/src/test/java/cn/jpush/api/device/DeviceNormalRemoteTest.java @@ -5,22 +5,23 @@ import static org.junit.Assert.assertTrue; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.BooleanResult; +import cn.jiguang.common.resp.DefaultResult; import cn.jpush.api.BaseTest; import cn.jpush.api.JUnitOrderedRunner; import cn.jpush.api.TestOrder; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.BooleanResult; -import cn.jpush.api.common.resp.DefaultResult; @RunWith(JUnitOrderedRunner.class) public class DeviceNormalRemoteTest extends BaseTest { - + // ------------------ device @Test @@ -30,16 +31,16 @@ public void testUpdateDeviceTagAlias_add_remove_tags() throws APIConnectionExcep tagsToAdd.add("tag1"); tagsToAdd.add("tag2"); Set tagsToRemove = new HashSet(); - tagsToRemove.add("tag3"); - tagsToRemove.add("tag4"); - DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID1, "alias1", tagsToAdd, tagsToRemove); + tagsToRemove.add("tag1"); + tagsToRemove.add("tag2"); + DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID3, "alias1", tagsToAdd, tagsToRemove); assertTrue(result.isResultOK()); } - + @Test @TestOrder(order = 110) public void testGetDeviceTagAlias_1() throws Exception { - TagAliasResult result = jpushClient.getDeviceTagAlias(REGISTRATION_ID1); + TagAliasResult result = jpushClient.getDeviceTagAlias(REGISTRATION_ID3); assertTrue(result.isResultOK()); assertEquals("alias not equals", "alias1", result.alias); @@ -73,8 +74,8 @@ public void testGetDeviceTagAlias_cleard() throws Exception { assertEquals("tags cleared", 0, result.tags.size()); } - - + + // ------------------ tags @Test @@ -91,10 +92,8 @@ public void testAddRemoveDevicesFromTag() throws APIConnectionException, APIRequ @Test @TestOrder(order = 210) public void testIsDeviceInTag() throws APIConnectionException, APIRequestException { - BooleanResult result = jpushClient.isDeviceInTag("tag3", REGISTRATION_ID1); + BooleanResult result = jpushClient.isDeviceInTag("tag2", REGISTRATION_ID3); assertTrue("", result.result); - result = jpushClient.isDeviceInTag("tag3", REGISTRATION_ID2); - assertFalse("", result.result); } @Test @@ -169,4 +168,42 @@ public void testDeleteAlias_2() throws APIConnectionException, APIRequestExcepti DefaultResult result = jpushClient.deleteAlias("alias2", null); assertTrue(result.isResultOK()); } + + @Test + @TestOrder(order = 340) + public void testTetUserOnlineStatus() throws APIConnectionException, APIRequestException{ + Map result = jpushClient.getUserOnlineStatus(REGISTRATION_ID1, REGISTRATION_ID2); + assertTrue(result.get(REGISTRATION_ID1) != null); + } + + @Test + @TestOrder(order = 360) + public void testBindMobile() throws APIConnectionException, APIRequestException { + DefaultResult result = jpushClient.bindMobile(REGISTRATION_ID1, "13000000000"); + assertTrue(result.isResultOK()); + } + + @Test + @TestOrder(order = 361) + public void testBindMobile_null() throws APIConnectionException, APIRequestException { + DefaultResult result = jpushClient.bindMobile(REGISTRATION_ID1, null); + assertTrue(result.isResultOK()); + } + + @Test + @TestOrder(order = 362) + public void testBindMobile_empty() throws APIConnectionException, APIRequestException { + DefaultResult result = jpushClient.bindMobile(REGISTRATION_ID1, ""); + assertTrue(result.isResultOK()); + } + + @Test + @TestOrder(order = 330) + public void testRemoveDevicesFromAlias() throws APIConnectionException, APIRequestException { + Set toRemoveDevice = new HashSet(); + toRemoveDevice.add(REGISTRATION_ID1); + DefaultResult result = jpushClient.removeDevicesFromAlias("alias1", toRemoveDevice); + assertTrue(result.isResultOK()); + } + } diff --git a/src/test/java/cn/jpush/api/files/FileClient2.java b/src/test/java/cn/jpush/api/files/FileClient2.java new file mode 100644 index 00000000..b005aa1b --- /dev/null +++ b/src/test/java/cn/jpush/api/files/FileClient2.java @@ -0,0 +1,92 @@ +package cn.jpush.api.files; + +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jiguang.common.utils.Preconditions; +import cn.jiguang.common.utils.StringUtils; +import cn.jpush.api.file.model.FileModel; +import cn.jpush.api.file.model.FileModelPage; +import cn.jpush.api.file.model.FileType; +import cn.jpush.api.file.model.FileUploadResult; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author daixuan + * @version 2020/2/23 19:38 + */ +public class FileClient2 { + + protected static final Logger LOG = LoggerFactory.getLogger(FileClient2.class); + + private IHttpClient _httpClient; + private String _baseUrl; + private String _filesPath; + private Gson _gson = new Gson(); + + public FileClient2(String masterSecret, String appKey) { + this(masterSecret, appKey, null, ClientConfig.getInstance()); + } + + public FileClient2(String masterSecret, String appKey, HttpProxy proxy, ClientConfig conf) { + _baseUrl = (String) conf.get(ClientConfig.PUSH_HOST_NAME); + _filesPath = (String) conf.get(ClientConfig.V3_FILES_PATH); + String authCode = ServiceHelper.getBasicAuthorization(appKey, masterSecret); + this._httpClient = new NativeHttpClient(authCode, proxy, conf); + } + + public String uploadFile(FileType type, String filename, Integer ttl) + throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(type != null, "type should not be null"); + Preconditions.checkArgument(StringUtils.isNotEmpty(filename), "filename should not be null"); + Preconditions.checkArgument(ttl >= 1 && ttl <= 720,"TTL is not in the range of 1 to 720"); + NativeHttpClient client = (NativeHttpClient) _httpClient; + String typeStr = type.value(); + String url = _baseUrl + _filesPath + "/" + typeStr; + Map fileMap = new HashMap(); + fileMap.put("filename", filename); + Map textMap = new HashMap(); + textMap.put("ttl",String.valueOf(ttl)); + String response = client.formUploadByPost(url, textMap, fileMap, null); + LOG.info("uploadFile:{}", response); + return response; + } + + public String uploadFile(FileType type, String filename) throws APIConnectionException, APIRequestException { + return uploadFile(type,filename,720); + } + + public String queryEffectFiles() throws APIConnectionException, APIRequestException { + String url = _baseUrl + _filesPath + "/"; + ResponseWrapper response = _httpClient.sendGet(url); + LOG.info("queryEffFiles:{}", response); + return response.responseContent; + } + + public String queryFile(String fileId) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(fileId), "fileId should not be null"); + String url = _baseUrl + _filesPath + "/" + fileId; + ResponseWrapper response = _httpClient.sendGet(url); + LOG.info("queryFile:{}", response); + return response.responseContent; + } + + public ResponseWrapper deleteFile(String fileId) throws APIConnectionException, APIRequestException { + Preconditions.checkArgument(StringUtils.isNotEmpty(fileId), "fileId should not be null"); + String url = _baseUrl + _filesPath + "/" + fileId; + ResponseWrapper response = _httpClient.sendDelete(url); + LOG.info("deleteFile:{}", response); + return response; + } +} diff --git a/src/test/java/cn/jpush/api/files/FileClientTest.java b/src/test/java/cn/jpush/api/files/FileClientTest.java new file mode 100644 index 00000000..8151b628 --- /dev/null +++ b/src/test/java/cn/jpush/api/files/FileClientTest.java @@ -0,0 +1,100 @@ +package cn.jpush.api.files; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.BaseTest; +import cn.jpush.api.file.FileClient; +import cn.jpush.api.file.model.FileModel; +import cn.jpush.api.file.model.FileModelPage; +import cn.jpush.api.file.model.FileType; +import cn.jpush.api.file.model.FileUploadResult; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author daixuan + * @version 2020/2/24 14:01 + */ +public class FileClientTest extends BaseTest { + + protected static final Logger LOG = LoggerFactory.getLogger(FileClientTest.class); + + String fileId = "d4ee2375846bc30fa51334f5-69653861-1408-4d0a-abef-117808632b23"; + + @Test + public void testUploadFile() { + FileClient fileClient = new FileClient(MASTER_SECRET, APP_KEY); + try { + FileUploadResult result = fileClient.uploadFile(FileType.ALIAS, "README.md"); + LOG.info("uploadFile:{}", result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + + @Test + public void testQueryEffFiles() { + FileClient fileClient = new FileClient(MASTER_SECRET, APP_KEY); + try { + FileModelPage result = fileClient.queryEffectFiles(); + LOG.info("queryEffFiles:{}", result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + + @Test + public void testQueryFile() { + FileClient fileClient = new FileClient(MASTER_SECRET, APP_KEY); + try { + FileModel fileModel = fileClient.queryFile(fileId); + LOG.info("fileModel:{}", fileModel); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + + @Test + public void testDeleteFile() { + FileClient fileClient = new FileClient(MASTER_SECRET, APP_KEY); + + + try { + fileClient.deleteFile(fileId); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + } + } + + + + +} diff --git a/src/test/java/cn/jpush/api/image/ImageClientTest.java b/src/test/java/cn/jpush/api/image/ImageClientTest.java new file mode 100644 index 00000000..8999ce5d --- /dev/null +++ b/src/test/java/cn/jpush/api/image/ImageClientTest.java @@ -0,0 +1,195 @@ +package cn.jpush.api.image; + +import cn.jiguang.common.connection.NativeHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jpush.api.BaseTest; +import cn.jpush.api.image.model.ImageFilePayload; +import cn.jpush.api.image.model.ImageType; +import cn.jpush.api.image.model.ImageUploadResult; +import cn.jpush.api.image.model.ImageUrlPayload; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.internal.util.reflection.FieldSetter; + +import java.util.HashMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +public class ImageClientTest extends BaseTest { + + @Test + public void testUploadImageByUrl() throws NoSuchFieldException, APIConnectionException, APIRequestException { + ResponseWrapper mockResponseWrapper = new ResponseWrapper(); + mockResponseWrapper.responseCode = 200; + mockResponseWrapper.responseContent = "{\n" + + " \"media_id\": \"jgmedia-2-14b23451-0001-41ce-89d9-987b465122da\", \n" + + " \"oppo_image_url\": \"3653918_5f92b5739ae676f5745bcbf4\", \n" + + " \"xiaomi_image_url\": \"http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png\" \n" + + "}"; + + NativeHttpClient mockIHttpClient = mock(NativeHttpClient.class); + when(mockIHttpClient.sendPost(anyString(), anyString())).thenReturn(mockResponseWrapper); + + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + new FieldSetter(client, client.getClass().getDeclaredField("_httpClient")).set(mockIHttpClient); + ImageClient spyClient = Mockito.spy(client); + ImageUrlPayload payload = ImageUrlPayload.newBuilder() + .setImageUrl("xxx") + .setImageType(ImageType.BIG_PICTURE) + .setFcmImageUrl("xxx") + .setHuaweiImageUrl("xxx") + .build(); + ImageUploadResult imageUploadResult = spyClient.uploadImage(payload); + verify(mockIHttpClient).sendPost("https://api.jpush.cn/v3/images/byurls", "{\"image_type\":1,\"image_url\":\"xxx\",\"huawei_image_url\":\"xxx\",\"fcm_image_url\":\"xxx\"}"); + + assertThat(imageUploadResult.getMediaId(), equalTo("jgmedia-2-14b23451-0001-41ce-89d9-987b465122da")); + assertThat(imageUploadResult.getOppoImageUrl(), equalTo("3653918_5f92b5739ae676f5745bcbf4")); + assertThat(imageUploadResult.getXiaomiImageUrl(), equalTo("http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png")); + assertThat(imageUploadResult.getHuaweiImageUrl(), nullValue()); + } + + @Test + public void testUploadImageByFile() throws NoSuchFieldException { + String content = "{\n" + + " \"media_id\": \"jgmedia-2-14b23451-0001-41ce-89d9-987b465122da\", \n" + + " \"oppo_image_url\": \"3653918_5f92b5739ae676f5745bcbf4\", \n" + + " \"xiaomi_image_url\": \"http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png\" \n" + + "}"; + + NativeHttpClient mockIHttpClient = mock(NativeHttpClient.class); + when(mockIHttpClient.formUploadByPost(anyString(), anyMap(), anyMap(), anyString())).thenReturn(content); + + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + new FieldSetter(client, client.getClass().getDeclaredField("_httpClient")).set(mockIHttpClient); + ImageClient spyClient = Mockito.spy(client); + ImageFilePayload payload = ImageFilePayload.newBuilder() + .setImageType(ImageType.LARGE_ICON) + .setOppoFileName("oppoXX.jpg") + .setXiaomiFileName("dir/xiaomiXX.jpg") + .build(); + ImageUploadResult imageUploadResult = spyClient.uploadImage(payload); + HashMap textMap = new HashMap(); + textMap.put("image_type", "2"); + HashMap fileMap = new HashMap(); + fileMap.put("oppo_file", "oppoXX.jpg"); + fileMap.put("xiaomi_file", "dir/xiaomiXX.jpg"); + verify(mockIHttpClient).formUploadByPost("https://api.jpush.cn/v3/images/byfiles", textMap, fileMap, null); + + assertThat(imageUploadResult.getMediaId(), equalTo("jgmedia-2-14b23451-0001-41ce-89d9-987b465122da")); + assertThat(imageUploadResult.getOppoImageUrl(), equalTo("3653918_5f92b5739ae676f5745bcbf4")); + assertThat(imageUploadResult.getXiaomiImageUrl(), equalTo("http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png")); + assertThat(imageUploadResult.getHuaweiImageUrl(), nullValue()); + } + + @Test + public void testModifyImageByUrl() throws NoSuchFieldException, APIConnectionException, APIRequestException { + ResponseWrapper mockResponseWrapper = new ResponseWrapper(); + mockResponseWrapper.responseCode = 200; + mockResponseWrapper.responseContent = "{\n" + + " \"media_id\": \"jgmedia-2-14b23451-0001-41ce-89d9-987b465122da\", \n" + + " \"oppo_image_url\": \"3653918_5f92b5739ae676f5745bcbf4\", \n" + + " \"xiaomi_image_url\": \"http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png\" \n" + + "}"; + String mediaId = "jgmedia-2-14b23451-0001-41ce-89d9-987b465122da"; + NativeHttpClient mockIHttpClient = mock(NativeHttpClient.class); + when(mockIHttpClient.sendPut(anyString(), anyString())).thenReturn(mockResponseWrapper); + + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + new FieldSetter(client, client.getClass().getDeclaredField("_httpClient")).set(mockIHttpClient); + ImageClient spyClient = Mockito.spy(client); + ImageUrlPayload payload = ImageUrlPayload.newBuilder() + .setImageUrl("xxx.jpg") + .setFcmImageUrl("xxx.png") + .setHuaweiImageUrl("xxx.jpeg") + .build(); + ImageUploadResult imageUploadResult = spyClient.modifyImage(mediaId, payload); + verify(mockIHttpClient).sendPut("https://api.jpush.cn/v3/images/byurls/" + mediaId, "{\"image_url\":\"xxx.jpg\",\"huawei_image_url\":\"xxx.jpeg\",\"fcm_image_url\":\"xxx.png\"}"); + + assertThat(imageUploadResult.getMediaId(), equalTo("jgmedia-2-14b23451-0001-41ce-89d9-987b465122da")); + assertThat(imageUploadResult.getOppoImageUrl(), equalTo("3653918_5f92b5739ae676f5745bcbf4")); + assertThat(imageUploadResult.getXiaomiImageUrl(), equalTo("http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png")); + assertThat(imageUploadResult.getHuaweiImageUrl(), nullValue()); + } + + @Test + public void testModifyImageByFile() throws NoSuchFieldException { + String content = "{\n" + + " \"media_id\": \"jgmedia-2-14b23451-0001-41ce-89d9-987b465122da\", \n" + + " \"oppo_image_url\": \"3653918_5f92b5739ae676f5745bcbf4\", \n" + + " \"xiaomi_image_url\": \"http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png\" \n" + + "}"; + String mediaId = "jgmedia-2-14b23451-0001-41ce-89d9-987b465122da"; + + NativeHttpClient mockIHttpClient = mock(NativeHttpClient.class); + when(mockIHttpClient.formUploadByPut(anyString(), anyMap(), anyMap(), anyString())).thenReturn(content); + + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + new FieldSetter(client, client.getClass().getDeclaredField("_httpClient")).set(mockIHttpClient); + ImageClient spyClient = Mockito.spy(client); + ImageFilePayload payload = ImageFilePayload.newBuilder() + .setOppoFileName("oppoXX.jpg") + .setXiaomiFileName("dir/xiaomiXX.jpg") + .build(); + ImageUploadResult imageUploadResult = spyClient.modifyImage(mediaId, payload); + HashMap fileMap = new HashMap(); + fileMap.put("oppo_file", "oppoXX.jpg"); + fileMap.put("xiaomi_file", "dir/xiaomiXX.jpg"); + verify(mockIHttpClient).formUploadByPut("https://api.jpush.cn/v3/images/byfiles/" + mediaId, null, fileMap, null); + + assertThat(imageUploadResult.getMediaId(), equalTo("jgmedia-2-14b23451-0001-41ce-89d9-987b465122da")); + assertThat(imageUploadResult.getOppoImageUrl(), equalTo("3653918_5f92b5739ae676f5745bcbf4")); + assertThat(imageUploadResult.getXiaomiImageUrl(), equalTo("http://f6.market.xiaomi.com/download/MiPass/01fff50f50ba193f94074ec/d1671936d468383f.png")); + assertThat(imageUploadResult.getHuaweiImageUrl(), nullValue()); + } + + @Test + public void testUploadImageByUrl2() throws APIConnectionException, APIRequestException { + + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageUrlPayload payload = ImageUrlPayload.newBuilder() + .setImageType(ImageType.LARGE_ICON) + .setImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009232P5.jpg") + .setOppoImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009232P5.jpg") + .setHuaweiImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009232P5.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + assertThat(imageUploadResult, notNullValue()); + String mediaId = imageUploadResult.getMediaId(); + assertThat(mediaId, notNullValue()); + ImageUrlPayload payload2 = ImageUrlPayload.newBuilder() + .setImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009225435.jpg") + .setFcmImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009225435.jpg") + .setHuaweiImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009225435.jpg") + .build(); + ImageUploadResult imageUploadResult2 = client.modifyImage(mediaId, payload2); + assertThat(imageUploadResult2, notNullValue()); + assertThat(imageUploadResult2.getHuaweiImageUrl(), notNullValue()); + } + + @Test + public void testUploadImageByFile2() { + ImageClient client = new ImageClient(MASTER_SECRET, APP_KEY); + ImageFilePayload payload = ImageFilePayload.newBuilder() + .setImageType(ImageType.BIG_PICTURE) + .setOppoFileName("/Users/yongxing/Downloads/Xnip2020-12-11_14-24-28.jpg") + .setXiaomiFileName("/Users/yongxing/Downloads/Xnip2020-12-11_14-24-28.jpg") + .build(); + ImageUploadResult imageUploadResult = client.uploadImage(payload); + assertThat(imageUploadResult, notNullValue()); + assertThat(imageUploadResult.getError(), nullValue()); + String mediaId = imageUploadResult.getMediaId(); + assertThat(mediaId, notNullValue()); + ImageFilePayload payload2 = ImageFilePayload.newBuilder() + .setOppoFileName("/Users/yongxing/Downloads/IMG_2778.jpeg") + .setXiaomiFileName("/Users/yongxing/Downloads/IMG_2778.jpeg") + .build(); + imageUploadResult = client.modifyImage(mediaId, payload2); + assertThat(imageUploadResult, notNullValue()); + assertThat(imageUploadResult.getOppoImageUrl(), notNullValue()); + } +} \ No newline at end of file diff --git a/src/test/java/cn/jpush/api/push/GroupPushClientTest.java b/src/test/java/cn/jpush/api/push/GroupPushClientTest.java new file mode 100644 index 00000000..574871b1 --- /dev/null +++ b/src/test/java/cn/jpush/api/push/GroupPushClientTest.java @@ -0,0 +1,67 @@ +package cn.jpush.api.push; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.BaseTest; +import cn.jpush.api.push.model.Platform; +import cn.jpush.api.push.model.PushPayload; +import cn.jpush.api.push.model.audience.Audience; +import cn.jpush.api.push.model.notification.AndroidNotification; +import cn.jpush.api.push.model.notification.IosNotification; +import cn.jpush.api.push.model.notification.Notification; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class GroupPushClientTest extends BaseTest { + + protected static final Logger LOG = LoggerFactory.getLogger(GroupPushClientTest.class); + + @Test + public void testSendGroupPush() { + GroupPushClient groupPushClient = new GroupPushClient(GROUP_MASTER_SECRET, GROUP_PUSH_KEY); + final PushPayload payload = buildPushObject_android(); + try { + GroupPushResult groupPushresult = groupPushClient.sendGroupPush(payload); + Map result = groupPushresult.getAppResultMap(); + for (Map.Entry entry : result.entrySet()) { + PushResult pushResult = entry.getValue(); + PushResult.Error error = pushResult.error; + if (error != null) { + LOG.info("AppKey: " + entry.getKey() + " error code : " + error.getCode() + " error message: " + error.getMessage()); + } else { + LOG.info("AppKey: " + entry.getKey() + " sendno: " + pushResult.sendno + " msg_id:" + pushResult.msg_id); + } + + } + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); + } + } + + public static PushPayload buildPushObject_android() { + return PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.registrationId(REGISTRATION_ID3)) + .setNotification(Notification.newBuilder() + .setAlert("alert content") + .addPlatformNotification(AndroidNotification.newBuilder() + .setTitle("Android Title").build()) + .addPlatformNotification(IosNotification.newBuilder() + .incrBadge(1) + .addExtra("extra_key", "extra_value").build()) + .build()) + .build(); + } +} diff --git a/src/test/java/cn/jpush/api/push/PushClientTest.java b/src/test/java/cn/jpush/api/push/PushClientTest.java index 81c25f3c..0453a462 100644 --- a/src/test/java/cn/jpush/api/push/PushClientTest.java +++ b/src/test/java/cn/jpush/api/push/PushClientTest.java @@ -3,20 +3,95 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import cn.jiguang.common.ClientConfig; +import cn.jiguang.common.ServiceHelper; +import cn.jiguang.common.connection.NettyHttpClient; +import cn.jiguang.common.resp.DefaultResult; +import cn.jiguang.common.resp.ResponseWrapper; +import cn.jpush.api.JPushClient; +import cn.jpush.api.push.model.Options; +import cn.jpush.api.push.model.Platform; +import cn.jpush.api.push.model.audience.Audience; +import cn.jpush.api.push.model.notification.*; +import com.google.gson.JsonObject; +import io.netty.handler.codec.http.HttpMethod; +import lombok.SneakyThrows; import org.junit.Test; +import cn.jiguang.common.connection.HttpProxy; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.BaseTest; -import cn.jpush.api.common.connection.HttpProxy; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; import cn.jpush.api.push.model.PushPayload; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; public class PushClientTest extends BaseTest { + protected static final Logger LOG = LoggerFactory.getLogger(PushClientTest.class); + + @Test + public void testSendPush() { + ClientConfig clientConfig = ClientConfig.getInstance(); + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig); + PushPayload payload = buildPushObject_all_alias_alert(); + try { + PushResult result = jpushClient.sendPush(payload); + int status = result.getResponseCode(); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + LOG.error("Sendno: " + payload.getSendno()); + + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); + LOG.error("Sendno: " + payload.getSendno()); + } + } + + @Test + public void testSendPushWithCallback() { + ClientConfig clientConfig = ClientConfig.getInstance(); + String host = (String) clientConfig.get(ClientConfig.PUSH_HOST_NAME); + final NettyHttpClient client = new NettyHttpClient(ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET), + null, clientConfig); + try { + URI uri = new URI(host + clientConfig.get(ClientConfig.PUSH_PATH)); + PushPayload payload = buildPushObject_all_alias_alert(); + client.sendRequest(HttpMethod.POST, payload.toString(), uri, new NettyHttpClient.BaseCallback() { + @Override + public void onSucceed(ResponseWrapper responseWrapper) { + LOG.info("Got result: " + responseWrapper.responseContent); + } + }); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + + public static PushPayload buildPushObject_all_alias_alert() { + return PushPayload.newBuilder() + .setPlatform(Platform.all()) + .setAudience(Audience.registrationId(REGISTRATION_ID3)) + .setNotification(Notification.alert(ALERT)) + .setOptions(Options.newBuilder().setApnsProduction(false).setTimeToLive(86000).build()) + .build(); + } + @Test(expected = IllegalArgumentException.class) public void test_invalid_json() { PushClient pushClient = new PushClient(MASTER_SECRET, APP_KEY); - + try { pushClient.sendPush("{aaa:'a}"); } catch (APIConnectionException e) { @@ -25,11 +100,11 @@ public void test_invalid_json() { e.printStackTrace(); } } - + @Test(expected = IllegalArgumentException.class) public void test_empty_string() { PushClient pushClient = new PushClient(MASTER_SECRET, APP_KEY); - + try { pushClient.sendPush(""); } catch (APIConnectionException e) { @@ -42,22 +117,147 @@ public void test_empty_string() { @Test(expected = IllegalArgumentException.class) public void test_empty_password() { new HttpProxy("127.0.0.1", 8080, "", null); - } + } @Test public void test_validate() { - PushClient pushClient = new PushClient(MASTER_SECRET, APP_KEY); - - try { - PushResult result = pushClient.sendPushValidate(PushPayload.alertAll("alert")); - assertTrue("", result.isResultOK()); - } catch (APIRequestException e) { - fail("Should not fail"); - } catch (APIConnectionException e) { - e.printStackTrace(); - } - } - - + PushClient pushClient = new PushClient(MASTER_SECRET, APP_KEY); + + try { + PushResult result = pushClient.sendPushValidate(PushPayload.alertAll("alert")); + assertTrue("", result.isResultOK()); + } catch (APIRequestException e) { + fail("Should not fail"); + } catch (APIConnectionException e) { + e.printStackTrace(); + } + } + + @Test + public void testGetCidList() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + try { + CIDResult result = jPushClient.getCidList(3, "push"); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + @Test + public void testSendPushWithCid() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + PushPayload pushPayload = buildPushObject_android_cid(); + try { + PushResult result = jPushClient.sendPush(pushPayload); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + @Test + public void testSendFilePush() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + PushPayload filePushPayload = buildFilePushPayload(); + try { + + PushResult result = jPushClient.sendFilePush(filePushPayload); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + @Test + public void testDeletePush() { + JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY); + try { + String msgId = "58546877793854733"; + DefaultResult result = jPushClient.deletePush(msgId); + LOG.info("Got result - " + result); + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } + + private static PushPayload buildFilePushPayload() { + return PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.file("file-id-test")) + .setNotification(Notification.alert(ALERT)) + .build(); + } + + private static PushPayload buildPushObject_android_cid() { + return PushPayload.newBuilder() + .setPlatform(Platform.android()) + .setAudience(Audience.registrationId("18071adc030dcba91c0")) + .setNotification(Notification.alert(ALERT)) + .setCid("d4ee2375846bc30fa51334f5-21f305e0-4a52-42f3-a3dd-d2e49bdf0499") + .build(); + } + + @Test + public void testAlertType(){ + Notification notification = Notification.newBuilder() + .addPlatformNotification(AndroidNotification.newBuilder() + .setAlert("android内容") + .setTitle("android标题") + .setAlertType(-1) + .addCustom("uri_activity","uri_activity") + .addCustom("uri_action","uri_action") + .addExtra("a","a") + .build() + ).build(); + System.out.println(notification.toJSON()); + } + + @Test + @SneakyThrows + public void testHmos(){ + JsonObject intentJson = new JsonObject(); + intentJson.addProperty("url","scheme://hmos?key1=val1&key2=val2"); + Notification notification = Notification.newBuilder() + .addPlatformNotification(HmosNotification.newBuilder() + .setAlert("hmos内容") + .setTitle("hmos标题") + .setCategory("IM") + .setLarge_icon("https://www.jiguang.cn/largeIcon.jpg") + .setIntent(intentJson) + .setBadge_add_num(1) + .setTest_message(false) + .setReceipt_id("receipt_id_2024") + .addExtra("a","a") + .build() + ).build(); + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); + PushPayload payload = PushPayload.newBuilder() + .setAudience(Audience.all()) + .setPlatform(Platform.hmos()) + .setNotification(notification) + .build(); + jpushClient.sendPush(payload); + } } diff --git a/src/test/java/cn/jpush/api/push/mock/BaseMockTest.java b/src/test/java/cn/jpush/api/push/mock/BaseMockTest.java index c224d301..2ff188e8 100644 --- a/src/test/java/cn/jpush/api/push/mock/BaseMockTest.java +++ b/src/test/java/cn/jpush/api/push/mock/BaseMockTest.java @@ -1,6 +1,7 @@ package cn.jpush.api.push.mock; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.net.URL; @@ -11,10 +12,6 @@ import org.junit.Before; import org.junit.BeforeClass; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.push.PushClient; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -24,12 +21,16 @@ import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.push.PushClient; + public class BaseMockTest implements IMockTest { static { SUPPORT_PLATFORM.add("android"); SUPPORT_PLATFORM.add("ios"); - SUPPORT_PLATFORM.add("winphone"); + SUPPORT_PLATFORM.add("hmos"); SUPPORT_AUDIENCE.add("tag"); SUPPORT_AUDIENCE.add("tag_and"); diff --git a/src/test/java/cn/jpush/api/push/mock/ConnectionExceptionTest.java b/src/test/java/cn/jpush/api/push/mock/ConnectionExceptionTest.java index ce10a4c5..e4717c2f 100644 --- a/src/test/java/cn/jpush/api/push/mock/ConnectionExceptionTest.java +++ b/src/test/java/cn/jpush/api/push/mock/ConnectionExceptionTest.java @@ -1,6 +1,9 @@ package cn.jpush.api.push.mock; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.net.URL; @@ -8,21 +11,21 @@ import org.junit.After; import org.junit.Test; -import cn.jpush.api.common.connection.IHttpClient; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.push.PushClient; -import cn.jpush.api.push.model.PushPayload; - import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.SocketPolicy; +import cn.jiguang.common.connection.IHttpClient; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.push.PushClient; +import cn.jpush.api.push.model.PushPayload; + /** - * Record: MockResponse->throttleBody will delay response body, but sometimes has no effect. - * MockResponse->setBodyDelayTimeMs has no effect for delay test. + * Record: MockResponse.throttleBody will delay response body, but sometimes has no effect. + * MockResponse.setBodyDelayTimeMs has no effect for delay test. * */ public class ConnectionExceptionTest implements IMockTest { diff --git a/src/test/java/cn/jpush/api/push/mock/ResponseErrorTest.java b/src/test/java/cn/jpush/api/push/mock/ResponseErrorTest.java index 537cef39..e4641414 100644 --- a/src/test/java/cn/jpush/api/push/mock/ResponseErrorTest.java +++ b/src/test/java/cn/jpush/api/push/mock/ResponseErrorTest.java @@ -112,13 +112,13 @@ public void invalidParams_notification_ios() { } @Test - public void invalidParams_notification_winphone() { + public void invalidParams_notification_hmos() { JsonObject payload = new JsonObject(); payload.add("platform", Platform.all().toJSON()); payload.add("audience", Audience.all().toJSON()); JsonObject notification = new JsonObject(); - notification.add("winphone", new JsonPrimitive(ALERT)); + notification.add("hmos", new JsonPrimitive(ALERT)); payload.add("notification", notification); System.out.println("json string: " + payload.toString()); @@ -219,15 +219,15 @@ public void lackOfParams_notification_ios_empty() { } @Test - public void lackOfParams_notification_winphone_empty() { + public void lackOfParams_notification_hmos_empty() { JsonObject payload = new JsonObject(); payload.add("platform", Platform.all().toJSON()); payload.add("audience", Audience.all().toJSON()); JsonObject notification = new JsonObject(); - JsonObject winphone = new JsonObject(); + JsonObject hmos = new JsonObject(); - notification.add("winphone", winphone); + notification.add("hmos", hmos); payload.add("notification", notification); System.out.println("json string: " + payload.toString()); @@ -275,16 +275,16 @@ public void lackOfParams_notification_ios_noalert() { } @Test - public void lackOfParams_notification_winphone_noalert() { + public void lackOfParams_notification_hmos_noalert() { JsonObject payload = new JsonObject(); payload.add("platform", Platform.all().toJSON()); payload.add("audience", Audience.all().toJSON()); JsonObject notification = new JsonObject(); - JsonObject winphone = new JsonObject(); - winphone.add("title", new JsonPrimitive("title")); + JsonObject hmos = new JsonObject(); + hmos.add("title", new JsonPrimitive("title")); - notification.add("winphone", winphone); + notification.add("hmos", hmos); payload.add("notification", notification); System.out.println("json string: " + payload.toString()); diff --git a/src/test/java/cn/jpush/api/push/model/LiveActivityTest.java b/src/test/java/cn/jpush/api/push/model/LiveActivityTest.java new file mode 100644 index 00000000..b8d1a797 --- /dev/null +++ b/src/test/java/cn/jpush/api/push/model/LiveActivityTest.java @@ -0,0 +1,68 @@ +package cn.jpush.api.push.model; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.FastTests; +import cn.jpush.api.JPushClient; +import cn.jpush.api.push.PushResult; +import cn.jpush.api.push.model.live_activity.LiveActivity; +import cn.jpush.api.push.model.live_activity.LiveActivityEvent; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(FastTests.class) +public class LiveActivityTest { + + @Test + public void update() { + LiveActivity liveActivity = new LiveActivity.Builder() + .liveActivityId("LiveActivity-1") + .apnsProduction(false) + .iOSEvent(LiveActivityEvent.UPDATE) + .iOSContentState("eventStr", "更新") + .iOSContentState("eventTime", System.currentTimeMillis()) + .iOSContentState("eventBool", true) + // 需要联系商务开通 alternate_set 才能使用 + // .iOSAlertTitle("alertTitle") + // .iOSAlertAlternateTitle("alertAlternateTitle") + // .iOSAlertBody("alertBody") + // .iOSAlertAlternateBody("alertAlternateBody") + // .iOSAlertSound("alertSound") + .build(); + System.out.println("send liveActivity param:" + liveActivity.toJSON()); + + try { + JPushClient pushClient = new JPushClient("8d8623440ff329ff38597da3", "2785bc46145eaa91a00c0728"); + PushResult pushResult = pushClient.sendLiveActivity(liveActivity); + System.out.println("send liveActivity result:" + pushResult); + } catch (APIConnectionException e) { + throw new RuntimeException(e); + } catch (APIRequestException e) { + throw new RuntimeException(e); + } + } + + @Test + public void end() { + LiveActivity liveActivity = new LiveActivity.Builder() + .liveActivityId("LiveActivity-1") + .apnsProduction(false) + .iOSEvent(LiveActivityEvent.END) + .iOSContentState("eventStr", "结束") + .iOSContentState("eventTime", System.currentTimeMillis()) + .iOSDismissalDate((System.currentTimeMillis() / 1000) + 60) + .build(); + System.out.println("send liveActivity param:" + liveActivity.toJSON()); + + try { + JPushClient pushClient = new JPushClient("8d8623440ff329ff38597da3", "2785bc46145eaa91a00c0728"); + PushResult pushResult = pushClient.sendLiveActivity(liveActivity); + System.out.println("send liveActivity result:" + pushResult); + } catch (APIConnectionException e) { + throw new RuntimeException(e); + } catch (APIRequestException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/test/java/cn/jpush/api/push/model/OptionsTest.java b/src/test/java/cn/jpush/api/push/model/OptionsTest.java index ca1018c5..e36dd9d1 100644 --- a/src/test/java/cn/jpush/api/push/model/OptionsTest.java +++ b/src/test/java/cn/jpush/api/push/model/OptionsTest.java @@ -6,13 +6,16 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import cn.jpush.api.FastTests; -import cn.jpush.api.common.ServiceHelper; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import cn.jiguang.common.ServiceHelper; +import cn.jpush.api.FastTests; + +import java.util.HashMap; +import java.util.Map; + @Category(FastTests.class) public class OptionsTest { @@ -128,5 +131,61 @@ public void testBigPushDuration() { assertThat(options.toJSON(), is((JsonElement) json)); } + + @Test + public void testThirdPartyChannel() { + int sendno = ServiceHelper.generateSendno(); + + Map> thirdMap = new HashMap>(); + Map huaweiMap = new HashMap(); + huaweiMap.put("distribution", "jpush"); + thirdMap.put("huawei", huaweiMap); + + Options options = Options.newBuilder() + .setSendno(sendno) + .setThirdPartyChannel(thirdMap) + .build(); + System.out.println("json string: " + options.toJSON()); + + JsonObject json = new JsonObject(); + JsonObject thirdPartyChannel = new JsonObject(); + JsonObject huawei = new JsonObject(); + huawei.addProperty("distribution", "jpush"); + thirdPartyChannel.add("huawei", huawei); + json.add("sendno", new JsonPrimitive(sendno)); + json.add("apns_production", new JsonPrimitive(false)); + json.add("third_party_channel", thirdPartyChannel); + + assertThat(options.toJSON(), is((JsonElement) json)); + } + + @Test + public void testThirdPartyChannelV2() { + int sendno = ServiceHelper.generateSendno(); + + Map thirdMap = new HashMap(); + JsonObject vivoJsonObj = new JsonObject(); + vivoJsonObj.addProperty("distribution", "ospush"); + vivoJsonObj.addProperty("classification", 1); + thirdMap.put("vivo", vivoJsonObj); + + Options options = Options.newBuilder() + .setSendno(sendno) + .setThirdPartyChannelV2(thirdMap) + .build(); + System.out.println("json string: " + options.toJSON()); + + JsonObject json = new JsonObject(); + JsonObject thirdPartyChannel = new JsonObject(); + JsonObject vivo = new JsonObject(); + vivo.addProperty("distribution", "ospush"); + vivo.addProperty("classification", 1); + thirdPartyChannel.add("vivo", vivo); + json.add("sendno", new JsonPrimitive(sendno)); + json.add("apns_production", new JsonPrimitive(false)); + json.add("third_party_channel", thirdPartyChannel); + + assertThat(options.toJSON(), is((JsonElement) json)); + } } diff --git a/src/test/java/cn/jpush/api/push/model/PlatformTesst.java b/src/test/java/cn/jpush/api/push/model/PlatformTesst.java index 7fde0020..b481934e 100644 --- a/src/test/java/cn/jpush/api/push/model/PlatformTesst.java +++ b/src/test/java/cn/jpush/api/push/model/PlatformTesst.java @@ -3,17 +3,17 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import cn.jiguang.common.DeviceType; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; -import cn.jpush.api.FastTests; -import cn.jpush.api.common.DeviceType; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; +import cn.jpush.api.FastTests; + @Category(FastTests.class) public class PlatformTesst { diff --git a/src/test/java/cn/jpush/api/push/model/PushPayloadTest.java b/src/test/java/cn/jpush/api/push/model/PushPayloadTest.java index ad5ef205..9c93bf26 100644 --- a/src/test/java/cn/jpush/api/push/model/PushPayloadTest.java +++ b/src/test/java/cn/jpush/api/push/model/PushPayloadTest.java @@ -4,15 +4,15 @@ import org.junit.Test; import org.junit.experimental.categories.Category; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.ServiceHelper; import cn.jpush.api.FastTests; -import cn.jpush.api.common.ServiceHelper; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.notification.IosNotification; import cn.jpush.api.push.model.notification.Notification; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - @Category(FastTests.class) public class PushPayloadTest { @@ -66,6 +66,7 @@ public void testNotification() { json.add("platform", new JsonPrimitive("all")); JsonObject noti = new JsonObject(); + noti.addProperty("ai_opportunity", false); noti.add("alert", new JsonPrimitive("alert")); json.add("notification", noti); @@ -110,10 +111,22 @@ public void testGlobalExceed() { .setMessage(Message.content(LONG_TEXT_2)) .build(); System.out.println("Size: " + LONG_TEXT_2.getBytes().length); - Assert.assertTrue("Should exceed - " + LONG_TEXT_2.getBytes().length, + Assert.assertFalse("Shouldn't exceed - " + LONG_TEXT_2.getBytes().length, payload.isGlobalExceedLength()); } + @Test + public void testGlobalExeed2() { + PushPayload payload = PushPayload.newBuilder() + .setPlatform(Platform.all()) + .setAudience(Audience.all()) + .setMessage(Message.content(LONG_TEXT_3)) + .build(); + System.out.println("Size: " + LONG_TEXT_3.getBytes().length); + Assert.assertTrue("Should exeed - " + LONG_TEXT_3.getBytes().length, + payload.isGlobalExceedLength()); + } + @Test public void testIosExceed() { PushPayload payload = PushPayload.newBuilder() @@ -122,7 +135,7 @@ public void testIosExceed() { .setNotification(Notification.alert(LONG_TEXT_1)) .build(); System.out.println("Size: " + LONG_TEXT_1.getBytes().length); - Assert.assertTrue("Should exceed - " + LONG_TEXT_1.getBytes().length, + Assert.assertFalse("Shouldn't exceed - " + LONG_TEXT_1.getBytes().length, payload.isIosExceedLength()); } @@ -132,10 +145,10 @@ public void testIosExceed2() { .setPlatform(Platform.all()) .setAudience(Audience.all()) .setNotification(Notification.newBuilder().addPlatformNotification( - IosNotification.alert(LONG_TEXT_1)).build()) + IosNotification.alert(LONG_TEXT_3)).build()) .build(); - System.out.println("Size: " + LONG_TEXT_1.getBytes().length); - Assert.assertTrue("Should exceed - " + LONG_TEXT_1.getBytes().length, + System.out.println("Size: " + LONG_TEXT_3.getBytes().length); + Assert.assertTrue("Should exceed - " + LONG_TEXT_3.getBytes().length, payload.isIosExceedLength()); } @@ -159,6 +172,57 @@ public void testIosExceed2() { + "本 Wiki 是极光推送 (JPush) 产品的开发者文档网站。" + "极光推送所有技术文档都在本 Wiki 里,没有别的提供渠道。同时,我们也在不断地补充、完善文档。" + "这些文档包括这样几种类型:常见问题、入门指南、API定义、教程等。"; + private static final String LONG_TEXT_3 = "" + + "这是 Push API 最近的版本。" + + "相比于 API v2 版本,v3 版本的改进为:" + + "完全基于 https,不再提供 http 访问;" + + "使用 HTTP Basic Authentication 的方式做访问授权。这样整个 API 请求可以使用常见的 HTTP 工具来完成,比如:curl,浏览器插件等;" + + "推送内容完全使用 JSON 的格式;" + + "支持的功能有所改进:支持多 tag 的与或操作;可单独发送通知或者自定义消息,也可同时推送通知与自定义消息;windows phone 目前只有通知。" + + "向某单个设备或者某设备列表推送一条通知、或者消息。" + + "推送的内容只能是 JSON 表示的一个推送对象。" + + "调用地址:POST https://api.jpush.cn/v3/push" + + "别名与标签使用教程 为什么需要别名与标签" + + "推送消息时,要指定推送的对象:全部,某一个人,或者某一群人。" + + "全部很好办,针对某应用“群发”就好了。Portal与API都支持向指定的 appKey 群发消息。" + + "要指定向某一个特定的人,或者某一群特定的人,则相对复杂。" + + "因为对于 JPush 来说,某一个人就是一个注册ID,这个注册ID与开发者App没有任何关系,或者说对开发者App是没有意义的。" + + "如果要对开发者App有意义的某个特定的用户推送消息,则需要:把 JPush 注册用户与开发者App 用户绑定起来。" + + "这个绑定有两个基本思路:" + + "把绑定关系保存到 JPush 服务器端" + + "把绑定关系保存到开发者应用服务器中" + + "前者,就是这里要说到的:别名与标签的功能。这个机制简单易用,适用于大多数开发者。" + + "后者,则是 JPush 提供的另外一套 RegistrationID 机制。这套机制开发者需要有应用服务器来维护绑定关系,不适用于普通开发者。" + + "Android SDK r1.6.0 版本开始支持。" + + "别名与标签的机制,其工作方式是:" + + "客户端开发者App调用 setAliasAndTags API 来设置关系" + + "JPush SDK 把该关系设置保存到 JPush Server 上" + + "在服务器端推送消息时,指定向之前设置过的别名或者标签推送" + + "SDK 支持的 setAliasAndTags 请参考相应的文档:别名与标签 API" + + "使用过程中有几个点做特别说明:" + + "App 调用 SDK setAliasAndTags API 时,r1.5.0 版本提供了 Callback 来返回设置状态。如果返回 6002 (超时)则建议重试" + + "老版本没有提供 Callback 无设置状态返回,从而没有机制确定一定成功。建议升级到新版本" + + "Portal 上推送或者 API 调用向别名或者标签推送时,可能会报错:不存在推送目标用户。" + + "该报错表明,JPush Server 上还没有针对你所推送的别名或者标签的用户绑定关系,所以没有推送目标。" + + "这时请开发者检查确认,开发者App是否正确地调用了 setAliasAndTags API,以及调用时是否网络不好,JPush SDK 暂时未能保存成功。" + + "使用别名 用于给某特定用户推送消息。别名,可以近似地被认为,是用户帐号里的昵称。" + + "使用标签 用于给某一群人推送消息。" + + "标签类似于博客里为文章打上 tag ,即为某资源分类。" + + "动态标签 JPush 提供的设置标签的 API 是在客户端的。" + + "开发者如何做到在自己的服务器端动态去设置分组呢? 比如一个企业OA系统,经常需要去变更部门人员分组。以下是大概的思路:" + + "设计一种自定义消息格式(业务协议),App解析后可以调用 JPush SDK setAliasAndTags API 来重新设置标签(分组)" + + "例:{\"action\":\"resetTags\", \"newTags\":[\"dep_level_1\":\"A公司\", \"dep_level_2\":\"技术部\", \"dep_level_3\"" + + ":\"Android开发组\", \"address\":\"深圳\", \"lang\":\"zh\"]}" + + "要动态设置分组时,推送这条自定义消息给指定的用户" + + "使用别名的机制,推送到指定的用户。" + + "客户端App 调用 JPush SDK API 来设置新的标签" + + "通过极光推送服务,主动、及时地向您的用户发起交互,向其推送聊天消息、日程提醒、活动预告、进度提示、动态更新等。" + + "精准的目标用户和有价值的推送内容可以提升用户忠诚度,提高留存率与收入。" + + "客户端 SDK 采用自定义的协议保持长连接,电量、流量消耗都很少。 " + + "服务端先进技术架构,高并发可扩展性的云服务,经受过几亿用户的考验," + + "完全省去应用开发者自己维护长连接的设备和人力的成本投入。" + + "简单的SDK集成方式,使开发商可以快速部署,更专注主营业务。灵活的推送入接入," + + "同时支持网站上直接推送,也提供 消息推送和送达统计的 API调用。 "; } diff --git a/src/test/java/cn/jpush/api/push/model/notification/AndroidNotificationTest.java b/src/test/java/cn/jpush/api/push/model/notification/AndroidNotificationTest.java index bc8963ec..c3748e4c 100644 --- a/src/test/java/cn/jpush/api/push/model/notification/AndroidNotificationTest.java +++ b/src/test/java/cn/jpush/api/push/model/notification/AndroidNotificationTest.java @@ -9,6 +9,9 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import java.util.HashMap; +import java.util.Map; + @Category(FastTests.class) public class AndroidNotificationTest { @@ -60,6 +63,23 @@ public void testExtra_nullvalue() { json.add("extras", extra); Assert.assertEquals("", json, an.toJSON()); } + + @Test + public void testCustomParam() { + + Map customParams = new HashMap(); + customParams.put("custom_field1", "field1"); + customParams.put("custom_field2", "field2"); + customParams.put("custom_field3", "field3"); + + AndroidNotification an = AndroidNotification.newBuilder() + .addCustom("custom_field_num", 1) + .addCustom("custom_field_string", "string") + .addCustom("custom_field_boolean", true) + .addCustom(customParams) + .build(); + Assert.assertEquals("{\"custom_field_num\":1,\"custom_field_string\":\"string\",\"custom_field_boolean\":true,\"custom_field1\":\"field1\",\"custom_field3\":\"field3\",\"custom_field2\":\"field2\"}", an.toJSON().toString()); + } } diff --git a/src/test/java/cn/jpush/api/push/model/notification/WinphoneNotificationTest.java b/src/test/java/cn/jpush/api/push/model/notification/HmosNotificationTest.java similarity index 61% rename from src/test/java/cn/jpush/api/push/model/notification/WinphoneNotificationTest.java rename to src/test/java/cn/jpush/api/push/model/notification/HmosNotificationTest.java index 9cadb938..bbee925a 100644 --- a/src/test/java/cn/jpush/api/push/model/notification/WinphoneNotificationTest.java +++ b/src/test/java/cn/jpush/api/push/model/notification/HmosNotificationTest.java @@ -10,33 +10,33 @@ import com.google.gson.JsonPrimitive; @Category(FastTests.class) -public class WinphoneNotificationTest { +public class HmosNotificationTest { @Test public void testEmpty() { - WinphoneNotification winphone = WinphoneNotification.newBuilder().build(); - Assert.assertEquals("", new JsonObject(), winphone.toJSON()); + HmosNotification hmos = HmosNotification.newBuilder().build(); + Assert.assertEquals("", new JsonObject(), hmos.toJSON()); } @Test public void testQuickAlert() { - WinphoneNotification winphone = WinphoneNotification.alert("aaa"); + HmosNotification hmos = HmosNotification.alert("aaa"); JsonObject json = new JsonObject(); json.add("alert", new JsonPrimitive("aaa")); - Assert.assertEquals("", json, winphone.toJSON()); + Assert.assertEquals("", json, hmos.toJSON()); } @Test public void testTitle() { - WinphoneNotification winphone = WinphoneNotification.newBuilder().setTitle("title").build(); + HmosNotification hmos = HmosNotification.newBuilder().setTitle("title").build(); JsonObject json = new JsonObject(); json.add("title", new JsonPrimitive("title")); - Assert.assertEquals("", json, winphone.toJSON()); + Assert.assertEquals("", json, hmos.toJSON()); } @Test public void testExtra() { - WinphoneNotification winphone = WinphoneNotification.newBuilder() + HmosNotification hmos = HmosNotification.newBuilder() .addExtra("key2", 222) .addExtra("key", "value").build(); JsonObject json = new JsonObject(); @@ -44,7 +44,7 @@ public void testExtra() { extra.add("key", new JsonPrimitive("value")); extra.add("key2", new JsonPrimitive(222)); json.add("extras", extra); - Assert.assertEquals("", json, winphone.toJSON()); + Assert.assertEquals("", json, hmos.toJSON()); } diff --git a/src/test/java/cn/jpush/api/push/model/notification/IosNotificationTest.java b/src/test/java/cn/jpush/api/push/model/notification/IosNotificationTest.java index 45f76fef..d8b87cdf 100644 --- a/src/test/java/cn/jpush/api/push/model/notification/IosNotificationTest.java +++ b/src/test/java/cn/jpush/api/push/model/notification/IosNotificationTest.java @@ -1,18 +1,19 @@ package cn.jpush.api.push.model.notification; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - +import cn.jpush.api.FastTests; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; -import cn.jpush.api.FastTests; +import java.util.HashMap; +import java.util.Map; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; @Category(FastTests.class) public class IosNotificationTest { @@ -152,6 +153,7 @@ public void testCategory() { assertThat(ios.toJSON(), is((JsonElement) json)); } + } diff --git a/src/test/java/cn/jpush/api/push/model/notification/NotificationTest.java b/src/test/java/cn/jpush/api/push/model/notification/NotificationTest.java index ec5c0464..c2bdbfe1 100644 --- a/src/test/java/cn/jpush/api/push/model/notification/NotificationTest.java +++ b/src/test/java/cn/jpush/api/push/model/notification/NotificationTest.java @@ -43,6 +43,7 @@ public void testAlert_android() { JsonObject json = new JsonObject(); JsonObject android = new JsonObject(); android.add("alert", new JsonPrimitive("alert")); + json.addProperty("ai_opportunity", false); json.add("android", android); Assert.assertEquals("", json, notification.toJSON()); } @@ -57,19 +58,21 @@ public void testAlert_ios() { ios.add("alert", new JsonPrimitive("alert")); ios.add("sound", new JsonPrimitive("")); ios.add("badge", new JsonPrimitive("+1")); + json.addProperty("ai_opportunity", false); json.add("ios", ios); Assert.assertEquals("", json, notification.toJSON()); } @Test - public void testAlert_winphone() { + public void testAlert_hmos() { Notification notification = Notification.newBuilder() - .addPlatformNotification(WinphoneNotification.alert("alert")) + .addPlatformNotification(HmosNotification.alert("alert")) .build(); JsonObject json = new JsonObject(); - JsonObject winphone = new JsonObject(); - winphone.add("alert", new JsonPrimitive("alert")); - json.add("winphone", winphone); + JsonObject hmos = new JsonObject(); + hmos.add("alert", new JsonPrimitive("alert")); + json.addProperty("ai_opportunity", false); + json.add("hmos", hmos); Assert.assertEquals("", json, notification.toJSON()); } @@ -77,6 +80,7 @@ public void testAlert_winphone() { public void testAlert_all() { Notification notification = Notification.alert("alert"); JsonObject json = new JsonObject(); + json.addProperty("ai_opportunity", false); json.add("alert", new JsonPrimitive("alert")); Assert.assertEquals("", json, notification.toJSON()); @@ -104,7 +108,7 @@ public void testExtras_jsonValue() { JsonObject extra = new JsonObject(); extra.add("key", extraValue); android.add("extras", extra); - + json.addProperty("ai_opportunity", false); json.add("android", android); Assert.assertEquals("", json, notification.toJSON()); @@ -120,6 +124,7 @@ public void testShortcut_android() { JsonObject android = new JsonObject(); android.add("alert", new JsonPrimitive("alert")); android.add("title", new JsonPrimitive("title")); + json.addProperty("ai_opportunity", false); json.add("android", android); Assert.assertEquals("", json, notification.toJSON()); diff --git a/src/test/java/cn/jpush/api/push/remote/AlertOverrideTest.java b/src/test/java/cn/jpush/api/push/remote/AlertOverrideTest.java index bf94eb78..dcc24ace 100644 --- a/src/test/java/cn/jpush/api/push/remote/AlertOverrideTest.java +++ b/src/test/java/cn/jpush/api/push/remote/AlertOverrideTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertTrue; +import cn.jiguang.common.resp.APIRequestException; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -13,7 +14,7 @@ import cn.jpush.api.push.model.notification.AndroidNotification; import cn.jpush.api.push.model.notification.IosNotification; import cn.jpush.api.push.model.notification.Notification; -import cn.jpush.api.push.model.notification.WinphoneNotification; +import cn.jpush.api.push.model.notification.HmosNotification; @Category(SlowTests.class) public class AlertOverrideTest extends BaseRemotePushTest { @@ -27,7 +28,7 @@ public void sendAlert_all() throws Exception { .setAlert("alert") .addPlatformNotification(AndroidNotification.alert("android alert")) .addPlatformNotification(IosNotification.alert("ios alert")) - .addPlatformNotification(WinphoneNotification.alert("winphone alert")) + .addPlatformNotification(HmosNotification.alert("hmos alert")) .build()) .build(); PushResult result = _client.sendPush(payload); @@ -58,22 +59,28 @@ public void sendAlert_ios() throws Exception { .addPlatformNotification(IosNotification.alert("ios alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } @Test - public void sendAlert_wp() throws Exception { + public void sendAlert_hmos() throws Exception { PushPayload payload = PushPayload.newBuilder() - .setPlatform(Platform.winphone()) + .setPlatform(Platform.hmos()) .setAudience(Audience.all()) .setNotification(Notification.newBuilder() .setAlert("alert") - .addPlatformNotification(WinphoneNotification.alert("winphone alert")) + .addPlatformNotification(HmosNotification.alert("hmos alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } diff --git a/src/test/java/cn/jpush/api/push/remote/AudienceTest.java b/src/test/java/cn/jpush/api/push/remote/AudienceTest.java index a8a9142b..3fce8f30 100644 --- a/src/test/java/cn/jpush/api/push/remote/AudienceTest.java +++ b/src/test/java/cn/jpush/api/push/remote/AudienceTest.java @@ -12,11 +12,11 @@ import org.junit.Test; import org.junit.experimental.categories.Category; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.DefaultResult; import cn.jpush.api.JPushClient; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.DefaultResult; import cn.jpush.api.push.PushResult; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; @@ -28,12 +28,12 @@ /** * Device1: 0900e8d85ef * Device2: - * + * * tag1: Device1 * tag2: Device2 * tag_all: Device1, Device2 * tag_no: no Device - * + * * alias1: Device1 * alias2: Device2 * alias_no: no Device @@ -48,27 +48,27 @@ public class AudienceTest extends BaseRemotePushTest { public static final String ALIAS1 = "audience_alias1"; public static final String ALIAS2 = "audience_alias2"; public static final String ALIAS_NO = "audience_alias_no"; - + @BeforeClass public static void setAudiences() throws Exception { - Set tags1 = new HashSet(); - tags1.add(TAG1); - tags1.add(TAG_ALL); - - Set tags2 = new HashSet(); - tags1.add(TAG2); - tags1.add(TAG_ALL); - - JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); - DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID1, ALIAS1, tags1, null); - assertThat(result.isResultOK(), is(true)); - - result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID2, ALIAS2, tags2, null); - assertThat(result.isResultOK(), is(true)); + Set tags1 = new HashSet(); + tags1.add(TAG1); + tags1.add(TAG_ALL); + + Set tags2 = new HashSet(); + tags1.add(TAG2); + tags1.add(TAG_ALL); + + JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); + DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID3, ALIAS1, tags1, null); + assertThat(result.isResultOK(), is(true)); + + result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID3, ALIAS2, tags2, null); + assertThat(result.isResultOK(), is(true)); } - + // one -------- - + @Test public void sendByTag() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -79,7 +79,7 @@ public void sendByTag() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagAnd() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -90,7 +90,7 @@ public void sendByTagAnd() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByAlias() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -98,23 +98,25 @@ public void sendByAlias() throws Exception { .setAudience(Audience.alias(ALIAS1)) .setNotification(Notification.alert(ALERT)) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } - + @Test public void sendByRegistrationID() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) - .setAudience(Audience.registrationId(REGISTRATION_ID1)) + .setAudience(Audience.registrationId(REGISTRATION_ID3)) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); } - + // one more ------------------------- - + @Test public void sendByTagMore() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -125,7 +127,7 @@ public void sendByTagMore() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagAndMore() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -136,7 +138,7 @@ public void sendByTagAndMore() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagAndMore_fail() { PushPayload payload = PushPayload.newBuilder() @@ -144,7 +146,7 @@ public void sendByTagAndMore_fail() { .setAudience(Audience.tag_and(TAG1, TAG2)) .setNotification(Notification.alert(ALERT)) .build(); - + try { _client.sendPush(payload); } catch (APIConnectionException e) { @@ -153,7 +155,7 @@ public void sendByTagAndMore_fail() { assertEquals(NO_TARGET, e.getErrorCode()); } } - + @Test public void sendByAliasMore() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -164,7 +166,7 @@ public void sendByAliasMore() throws Exception { PushResult result = _client.sendPush(payload); assertTrue("Should be OK", result.isResultOK()); } - + @Test public void sendByRegistrationIDMore() throws Exception { @@ -173,80 +175,83 @@ public void sendByRegistrationIDMore() throws Exception { .setAudience(Audience.registrationId(REGISTRATION_ID1, REGISTRATION_ID2)) .setNotification(Notification.alert(ALERT)) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } - - + + // composite ok ------------------------- - + @Test public void sendByTagAlias() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.newBuilder() .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.ALIAS) - .addAudienceTargetValue(ALIAS1).build()) - .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValue(TAG_ALL).build()) - .build()) + .setAudienceType(AudienceType.ALIAS) + .addAudienceTargetValue(ALIAS1).build()) + .addAudienceTarget(AudienceTarget.newBuilder() + .setAudienceType(AudienceType.TAG) + .addAudienceTargetValue(TAG_ALL).build()) + .build()) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagRegistrationID() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.newBuilder() .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.REGISTRATION_ID) - .addAudienceTargetValue(REGISTRATION_ID1).build()) - .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValue(TAG_ALL).build()) - .build()) + .setAudienceType(AudienceType.REGISTRATION_ID) + .addAudienceTargetValue(REGISTRATION_ID1).build()) + .addAudienceTarget(AudienceTarget.newBuilder() + .setAudienceType(AudienceType.TAG) + .addAudienceTargetValue(TAG_ALL).build()) + .build()) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagRegistrationID_0() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.newBuilder() .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.REGISTRATION_ID) - .addAudienceTargetValue(REGISTRATION_ID1).build()) - .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValue(TAG_NO).build()) - .build()) + .setAudienceType(AudienceType.REGISTRATION_ID) + .addAudienceTargetValue(REGISTRATION_ID1).build()) + .addAudienceTarget(AudienceTarget.newBuilder() + .setAudienceType(AudienceType.TAG) + .addAudienceTargetValue(TAG_NO).build()) + .build()) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendByTagAlias_0() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.newBuilder() .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.ALIAS) - .addAudienceTargetValue(ALIAS1).build()) - .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValue(TAG2).build()) - .build()) + .setAudienceType(AudienceType.ALIAS) + .addAudienceTargetValue(ALIAS1).build()) + .addAudienceTarget(AudienceTarget.newBuilder() + .setAudienceType(AudienceType.TAG) + .addAudienceTargetValue(TAG2).build()) + .build()) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); @@ -259,18 +264,18 @@ public void sendByTagAlias_0_2() throws Exception { .setPlatform(Platform.all()) .setAudience(Audience.newBuilder() .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.ALIAS) - .addAudienceTargetValue(ALIAS_NO).build()) - .addAudienceTarget(AudienceTarget.newBuilder() - .setAudienceType(AudienceType.TAG) - .addAudienceTargetValue(TAG_ALL).build()) - .build()) + .setAudienceType(AudienceType.ALIAS) + .addAudienceTargetValue(ALIAS_NO).build()) + .addAudienceTarget(AudienceTarget.newBuilder() + .setAudienceType(AudienceType.TAG) + .addAudienceTargetValue(TAG_ALL).build()) + .build()) .setNotification(Notification.alert(ALERT)) .build(); PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + } diff --git a/src/test/java/cn/jpush/api/push/remote/BasicFunctionsTest.java b/src/test/java/cn/jpush/api/push/remote/BasicFunctionsTest.java index 713d40a6..bc541daa 100644 --- a/src/test/java/cn/jpush/api/push/remote/BasicFunctionsTest.java +++ b/src/test/java/cn/jpush/api/push/remote/BasicFunctionsTest.java @@ -1,12 +1,13 @@ package cn.jpush.api.push.remote; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; +import cn.jiguang.common.resp.APIRequestException; import org.junit.Test; import org.junit.experimental.categories.Category; +import cn.jiguang.common.DeviceType; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.DeviceType; import cn.jpush.api.push.PushResult; import cn.jpush.api.push.model.Message; import cn.jpush.api.push.model.Platform; @@ -15,7 +16,7 @@ import cn.jpush.api.push.model.notification.AndroidNotification; import cn.jpush.api.push.model.notification.IosNotification; import cn.jpush.api.push.model.notification.Notification; -import cn.jpush.api.push.model.notification.WinphoneNotification; +import cn.jpush.api.push.model.notification.HmosNotification; @Category(SlowTests.class) public class BasicFunctionsTest extends BaseRemotePushTest { @@ -62,8 +63,11 @@ public void sendSimpleNotification_Pios_Nios() throws Exception { .addPlatformNotification(IosNotification.alert("Pios Nios alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } @Test @@ -75,34 +79,43 @@ public void sendSimpleNotification_Pall_Nios() throws Exception { .addPlatformNotification(IosNotification.alert("Pall Nios alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } @Test - public void sendSimpleNotification_Pwp_Nwp() throws Exception { + public void sendSimpleNotification_Phmos_Nhmos() throws Exception { PushPayload payload = PushPayload.newBuilder() - .setPlatform(Platform.winphone()) + .setPlatform(Platform.hmos()) .setAudience(Audience.all()) .setNotification(Notification.newBuilder() - .addPlatformNotification(WinphoneNotification.alert("Pwp Nwp alert")) + .addPlatformNotification(HmosNotification.alert("Phmos Nhmos alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } @Test - public void sendSimpleNotification_Pall_Nwp() throws Exception { + public void sendSimpleNotification_Pall_Nhmos() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.all()) .setNotification(Notification.newBuilder() - .addPlatformNotification(WinphoneNotification.alert("Pall Nwp alert")) + .addPlatformNotification(HmosNotification.alert("Pall Nhmos alert")) .build()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } @@ -111,11 +124,11 @@ public void sendSimpleNotification_Pall_Nall() throws Exception { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.newBuilder() .addDeviceType(DeviceType.IOS) - .addDeviceType(DeviceType.WinPhone) + .addDeviceType(DeviceType.HMOS) .addDeviceType(DeviceType.Android).build()) .setAudience(Audience.all()) .setNotification(Notification.newBuilder() - .addPlatformNotification(WinphoneNotification.alert("Pall Nall wp alert")) + .addPlatformNotification(HmosNotification.alert("Pall Nall hmos alert")) .addPlatformNotification(IosNotification.alert("Pall Nall ios alert")) .addPlatformNotification(AndroidNotification.alert("Pall Nall android alert")) .build()) @@ -149,21 +162,12 @@ public void sendSimpleMessage_Pios() throws Exception { .setAudience(Audience.all()) .setMessage(Message.content("Pios msg")) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); - } - - //@Test - public void sendSimpleMessage_Pwinphone() throws Exception { - PushPayload payload = PushPayload.newBuilder() - .setPlatform(Platform.winphone()) - .setAudience(Audience.all()) - .setMessage(Message.content("Pwp msg")) - .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } - @Test public void sendSimpleMessageAndNotification_Pall() throws Exception { diff --git a/src/test/java/cn/jpush/api/push/remote/ExceptionTest.java b/src/test/java/cn/jpush/api/push/remote/ExceptionTest.java index c38e0df9..e92ac55a 100644 --- a/src/test/java/cn/jpush/api/push/remote/ExceptionTest.java +++ b/src/test/java/cn/jpush/api/push/remote/ExceptionTest.java @@ -1,21 +1,21 @@ package cn.jpush.api.push.remote; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import org.junit.Test; import org.junit.experimental.categories.Category; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.JPushClient; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.notification.Notification; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - @Category(SlowTests.class) public class ExceptionTest extends BaseRemotePushTest { @@ -30,7 +30,7 @@ public void appKeyNotExist() { } catch (APIConnectionException e) { e.printStackTrace(); } catch (APIRequestException e) { - assertEquals(APPKEY_NOT_EXIST, e.getErrorCode()); + assertEquals(AUTHENTICATION_FAIL, e.getErrorCode()); } } @@ -160,28 +160,7 @@ public void invalidParams_notification_ios() { assertEquals(INVALID_PARAMS, e.getErrorCode()); } } - - @Test - public void invalidParams_notification_winphone() { - JsonObject payload = new JsonObject(); - payload.add("platform", Platform.all().toJSON()); - payload.add("audience", Audience.all().toJSON()); - - JsonObject notification = new JsonObject(); - notification.add("winphone", new JsonPrimitive(ALERT)); - payload.add("notification", notification); - - System.out.println("json string: " + payload.toString()); - - try { - _client.sendPush(payload.toString()); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIRequestException e) { - assertEquals(INVALID_PARAMS, e.getErrorCode()); - } - } - + @Test public void invalidParams_notification_android_builderidNotNumber() { JsonObject payload = new JsonObject(); @@ -254,15 +233,15 @@ public void invalidParams_notification_ios_empty() { } @Test - public void invalidParams_notification_winphone_empty() { + public void invalidParams_notification_hmos_empty() { JsonObject payload = new JsonObject(); payload.add("platform", Platform.all().toJSON()); payload.add("audience", Audience.all().toJSON()); JsonObject notification = new JsonObject(); - JsonObject winphone = new JsonObject(); + JsonObject hmos = new JsonObject(); - notification.add("winphone", winphone); + notification.add("hmos", hmos); payload.add("notification", notification); System.out.println("json string: " + payload.toString()); @@ -272,7 +251,7 @@ public void invalidParams_notification_winphone_empty() { } catch (APIConnectionException e) { e.printStackTrace(); } catch (APIRequestException e) { - assertEquals(INVALID_PARAMS, e.getErrorCode()); + assertEquals(LACK_OF_PARAMS, e.getErrorCode()); } } @@ -326,16 +305,16 @@ public void invalidParams_notification_ios_noalert() { } @Test - public void invalidParams_notification_winphone_noalert() { + public void invalidParams_notification_hmos_noalert() { JsonObject payload = new JsonObject(); payload.add("platform", Platform.all().toJSON()); payload.add("audience", Audience.all().toJSON()); JsonObject notification = new JsonObject(); - JsonObject winphone = new JsonObject(); - winphone.add("title", new JsonPrimitive("title")); + JsonObject hmos = new JsonObject(); + hmos.add("title", new JsonPrimitive("title")); - notification.add("winphone", winphone); + notification.add("hmos", hmos); payload.add("notification", notification); System.out.println("json string: " + payload.toString()); diff --git a/src/test/java/cn/jpush/api/push/remote/NotificationTest.java b/src/test/java/cn/jpush/api/push/remote/NotificationTest.java index c18faa20..6b73954c 100644 --- a/src/test/java/cn/jpush/api/push/remote/NotificationTest.java +++ b/src/test/java/cn/jpush/api/push/remote/NotificationTest.java @@ -1,32 +1,37 @@ package cn.jpush.api.push.remote; -import static org.junit.Assert.*; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - +import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.SlowTests; +import cn.jpush.api.image.ImageClient; +import cn.jpush.api.image.model.ImageType; +import cn.jpush.api.image.model.ImageUploadResult; +import cn.jpush.api.image.model.ImageUrlPayload; import cn.jpush.api.push.PushResult; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.notification.AndroidNotification; +import cn.jpush.api.push.model.notification.IosAlert; import cn.jpush.api.push.model.notification.Notification; - import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static org.junit.Assert.assertTrue; @Category(SlowTests.class) public class NotificationTest extends BaseRemotePushTest { - + @Test public void sendNotification_alert_json() throws Exception { JsonObject json = new JsonObject(); json.addProperty("key1", "value1"); json.addProperty("key2", true); - + String alert = json.toString(); System.out.println(alert); - + PushPayload payload = PushPayload.newBuilder() .setAudience(Audience.all()) .setPlatform(Platform.all()) @@ -38,9 +43,9 @@ public void sendNotification_alert_json() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + // --------------- Android - + @Test public void sendNotification_android_title() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -54,7 +59,7 @@ public void sendNotification_android_title() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendNotification_android_buildId() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -69,7 +74,7 @@ public void sendNotification_android_buildId() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - + @Test public void sendNotification_android_extras() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -85,10 +90,43 @@ public void sendNotification_android_extras() throws Exception { PushResult result = _client.sendPush(payload); assertTrue(result.isResultOK()); } - - + + @Test + public void sendNotification_android_media_id() throws Exception { + ImageClient imageClient = new ImageClient(MASTER_SECRET, APP_KEY); + ImageUploadResult imageUploadResult = imageClient.uploadImage(ImageUrlPayload.newBuilder() + .setImageType(ImageType.SMALL_ICON) + .setImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009225435.jpg") + .setXiaomiImageUrl("http://img.aiimg.com/uploads/allimg/151009/280082-151009225435.jpg") + .build()); + String mediaId = imageUploadResult.getMediaId(); + JsonObject json = new JsonObject(); + json.addProperty("key1", "value1"); + json.addProperty("key2", true); + + String alert = json.toString(); + System.out.println(alert); + + PushPayload payload = PushPayload.newBuilder() + .setAudience(Audience.all()) + .setPlatform(Platform.all()) + .setNotification(Notification.newBuilder() + .addPlatformNotification(AndroidNotification.newBuilder() + .setAlert(alert) + .setSmallIconUri(mediaId) + .setLargeIcon(mediaId) + .setBigPicPath(mediaId) + .setInbox(mediaId) + .setBigText(mediaId) + .setTitle("title") + .build()).build()) + .build(); + PushResult result = _client.sendPush(payload); + assertTrue(result.isResultOK()); + } + // ------------------ ios - + @Test public void sendNotification_ios_badge() throws Exception { PushPayload payload = PushPayload.newBuilder() @@ -96,12 +134,48 @@ public void sendNotification_ios_badge() throws Exception { .setPlatform(Platform.ios()) .setNotification(Notification.ios_auto_badge()) .build(); - PushResult result = _client.sendPush(payload); - assertTrue(result.isResultOK()); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } + } + + @Test + public void sendNotification_ios_alert_jsonStr() throws Exception { + JsonObject alert = new JsonObject(); + alert.add("title", new JsonPrimitive("Game Request")); + alert.add("body", new JsonPrimitive("Bob wants to play poker")); + alert.add("action-loc-key", new JsonPrimitive("PLAY")); + PushPayload payload = PushPayload.newBuilder() + .setAudience(Audience.all()) + .setPlatform(Platform.ios()) + .setNotification(Notification.alert(alert.toString())) + .build(); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } + } + + @Test + public void sendNotification_ios_alert_jsonObj() throws Exception { + IosAlert alert = IosAlert.newBuilder() + .setTitleAndBody("ios title", "test subtitle", "test ios title") + .build(); + + PushPayload payload = PushPayload.newBuilder() + .setAudience(Audience.all()) + .setPlatform(Platform.ios()) + .setNotification(Notification.alert(alert)) + .build(); + try { + PushResult result = _client.sendPush(payload); + } catch (APIRequestException e) { + e.printStackTrace(); + } } - - - - + } diff --git a/src/test/java/cn/jpush/api/push/remote/SpecialCharacterTest.java b/src/test/java/cn/jpush/api/push/remote/SpecialCharacterTest.java index 7bf90225..40067676 100644 --- a/src/test/java/cn/jpush/api/push/remote/SpecialCharacterTest.java +++ b/src/test/java/cn/jpush/api/push/remote/SpecialCharacterTest.java @@ -8,11 +8,11 @@ import org.junit.Test; import org.junit.experimental.categories.Category; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jiguang.common.resp.DefaultResult; import cn.jpush.api.JPushClient; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; -import cn.jpush.api.common.resp.DefaultResult; import cn.jpush.api.push.model.Message; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; @@ -66,7 +66,7 @@ public int sendNotification(String alert) { @BeforeClass public static void prepareAudience() throws Exception { JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY); - DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID1, "special_c", null, null); + DefaultResult result = jpushClient.updateDeviceTagAlias(REGISTRATION_ID3, "special_c", null, null); assertThat(result.isResultOK(), is(true)); } diff --git a/src/test/java/cn/jpush/api/report/MessageDetailsResultTest.java b/src/test/java/cn/jpush/api/report/MessageDetailsResultTest.java new file mode 100644 index 00000000..995b233b --- /dev/null +++ b/src/test/java/cn/jpush/api/report/MessageDetailsResultTest.java @@ -0,0 +1,17 @@ +package cn.jpush.api.report; + +import cn.jpush.api.BaseTest; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class MessageDetailsResultTest extends BaseTest { + + @Test + public void getMessageDetailsResultTest() throws Exception{ + MessageDetailResult result = jpushClient.getMessagesDetail("38280845540235675"); + assertTrue(result.isResultOK()); + System.out.println(result.received_list.get(0).details); + assertTrue(result.received_list.size() > 0); + } +} diff --git a/src/test/java/cn/jpush/api/report/ReportFunctionTests.java b/src/test/java/cn/jpush/api/report/ReportFunctionTests.java index f663cfef..dacf1a8e 100644 --- a/src/test/java/cn/jpush/api/report/ReportFunctionTests.java +++ b/src/test/java/cn/jpush/api/report/ReportFunctionTests.java @@ -2,16 +2,26 @@ import static org.junit.Assert.assertTrue; +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; +import cn.jpush.api.push.model.Message; +import cn.jpush.api.report.model.CheckMessagePayload; import org.junit.Test; import org.junit.experimental.categories.Category; +import cn.jiguang.common.TimeUnit; import cn.jpush.api.BaseTest; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; @Category(SlowTests.class) public class ReportFunctionTests extends BaseTest { - + + private static final Logger LOG = LoggerFactory.getLogger(ReportFunctionTests.class); + @Test public void getReceivedsFixed() throws Exception { ReceivedsResult result = jpushClient.getReportReceiveds("1613113584,1229760629,1174658841,1174658641"); @@ -21,7 +31,7 @@ public void getReceivedsFixed() throws Exception { @Test public void getReceivedsFixed2() throws Exception { - ReceivedsResult result = jpushClient.getReportReceiveds("1613113584, ,1229760629, "); + ReceivedsResult result = jpushClient.getReportReceiveds("1613113584, 1229760629"); assertTrue(result.isResultOK()); assertTrue(result.received_list.size() > 0); } @@ -56,7 +66,27 @@ public void getUserTest3() throws Exception { assertTrue(result.items.size() > 0); } - + @Test + public void testGetMessageStatus() { + CheckMessagePayload payload = CheckMessagePayload.newBuilder() + .setMsgId(3993287034L) + .addRegistrationIds(REGISTRATION_ID1, REGISTRATION_ID2, REGISTRATION_ID3) + .setDate("2017-08-08") + .build(); + try { + Map map = jpushClient.getMessageStatus(payload); + for (Map.Entry entry : map.entrySet()) { + LOG.info("registrationId: " + entry.getKey() + " status: " + entry.getValue().getStatus()); + } + } catch (APIConnectionException e) { + LOG.error("Connection error. Should retry later. ", e); + } catch (APIRequestException e) { + LOG.error("Error response from JPush server. Should review and fix it. ", e); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + } + } } diff --git a/src/test/java/cn/jpush/api/schedule/ScheduleClientTest.java b/src/test/java/cn/jpush/api/schedule/ScheduleClientTest.java index 34e91579..d9747321 100644 --- a/src/test/java/cn/jpush/api/schedule/ScheduleClientTest.java +++ b/src/test/java/cn/jpush/api/schedule/ScheduleClientTest.java @@ -1,15 +1,18 @@ package cn.jpush.api.schedule; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import cn.jiguang.common.resp.APIConnectionException; +import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.BaseTest; import cn.jpush.api.SlowTests; -import cn.jpush.api.common.resp.APIConnectionException; -import cn.jpush.api.common.resp.APIRequestException; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.schedule.model.SchedulePayload; import cn.jpush.api.schedule.model.TriggerPayload; -import org.junit.Assert; -import org.junit.Test; -import org.junit.experimental.categories.Category; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * ScheduleClient Tester. @@ -21,6 +24,8 @@ @Category(SlowTests.class) public class ScheduleClientTest extends BaseTest { + protected static final Logger LOG = LoggerFactory.getLogger(ScheduleClientTest.class); + public static final int NOT_EXIST = 8104; public static final int AUTH_FAILED = 8101; public static final int INVALID_PARAM = 8100; @@ -56,9 +61,11 @@ public void testGetScheduleList() { */ @Test public void testScheduleMethods() { + String masterSecret = MASTER_SECRET; + String appKey = APP_KEY; String name = "test_schedule"; TriggerPayload trigger = TriggerPayload.newBuilder() - .setSingleTime("2105-07-30 12:00:00") + .setSingleTime("2022-07-30 12:00:00") .buildSingle(); PushPayload push = PushPayload.alertAll("test schedule"); @@ -76,7 +83,7 @@ public void testScheduleMethods() { ScheduleResult result = null; boolean success = false; try { - result = client.createSchedule(payload); + result = client.createSchedule(payload, masterSecret, appKey); Assert.assertNotNull("test createSchedule failed.", result); ScheduleResult getResult = client.getSchedule(result.schedule_id); @@ -92,7 +99,11 @@ public void testScheduleMethods() { } catch (APIConnectionException e) { e.printStackTrace(); } catch (APIRequestException e) { - Assert.assertTrue(e.getErrorMessage(), false); + e.printStackTrace(); + LOG.info("HTTP Status: " + e.getStatus()); + LOG.info("Error Code: " + e.getErrorCode()); + LOG.info("Error Message: " + e.getErrorMessage()); + LOG.info("Msg ID: " + e.getMsgId()); } finally { if(!success && null != result) { try { diff --git a/src/test/java/cn/jpush/api/schedule/model/TriggerPayloadTest.java b/src/test/java/cn/jpush/api/schedule/model/TriggerPayloadTest.java index 49a75225..4772a32f 100644 --- a/src/test/java/cn/jpush/api/schedule/model/TriggerPayloadTest.java +++ b/src/test/java/cn/jpush/api/schedule/model/TriggerPayloadTest.java @@ -1,14 +1,16 @@ package cn.jpush.api.schedule.model; -import cn.jpush.api.FastTests; -import cn.jpush.api.common.TimeUnit; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import cn.jiguang.common.TimeUnit; +import cn.jpush.api.FastTests; + /** * TriggerPayload Tester. *