diff --git a/pom.xml b/pom.xml
index e9a0c78..f788872 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.clevertap.apns
apns-http2
- 1.0.3
+ 1.0.4
apns-http2
A library for communicating with the Apple Push Gateway in HTTP/2.
diff --git a/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java b/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java
index ceaaf93..2ed9a3a 100644
--- a/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java
+++ b/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java
@@ -50,6 +50,10 @@
public class ApnsClientBuilder {
private InputStream certificate;
private boolean production;
+ /**
+ * gateway field should be filled for development purposes only, and contain the address of local APNS mock instance.
+ */
+ private String customGateway;
private String password;
private int connectionPort = 443;
@@ -138,18 +142,25 @@ public ApnsClientBuilder withKeyID(String keyID) {
return this;
}
+ public ApnsClientBuilder withCustomGateway(String customGateway) {
+ this.customGateway = customGateway;
+ this.production = false;
+ return this;
+ }
+
public ApnsClientBuilder withProductionGateway() {
+ this.customGateway = null;
this.production = true;
return this;
}
public ApnsClientBuilder withProductionGateway(boolean production) {
if (production) return withProductionGateway();
-
return withDevelopmentGateway();
}
public ApnsClientBuilder withDevelopmentGateway() {
+ this.customGateway = null;
this.production = false;
return this;
}
@@ -183,15 +194,31 @@ public ApnsClient build() throws CertificateException,
if (certificate != null) {
if (asynchronous) {
- return new AsyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort);
+ if (customGateway != null){
+ return new AsyncOkHttpApnsClient(certificate, password, customGateway, defaultTopic, builder, connectionPort);
+ } else {
+ return new AsyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort);
+ }
} else {
- return new SyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort);
+ if (customGateway != null){
+ return new SyncOkHttpApnsClient(certificate, password, customGateway, defaultTopic, builder, connectionPort);
+ } else {
+ return new SyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort);
+ }
}
} else if (keyID != null && teamID != null && apnsAuthKey != null) {
if (asynchronous) {
- return new AsyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort);
+ if (customGateway != null) {
+ return new AsyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, customGateway, defaultTopic, builder, connectionPort);
+ } else {
+ return new AsyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort);
+ }
} else {
- return new SyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort);
+ if (customGateway != null) {
+ return new SyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, customGateway, defaultTopic, builder, connectionPort);
+ } else {
+ return new SyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort);
+ }
}
} else {
throw new IllegalArgumentException("Either the token credentials (team ID, key ID, and the private key) " +
diff --git a/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java b/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java
index 4e79ee1..bdbddce 100644
--- a/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java
+++ b/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java
@@ -60,6 +60,13 @@ public AsyncOkHttpApnsClient(InputStream certificate, String password, boolean p
super(certificate, password, production, defaultTopic, connectionPool);
}
+ public AsyncOkHttpApnsClient(InputStream certificate, String password, String gateway,
+ String defaultTopic, OkHttpClient.Builder builder, int connectionPort)
+ throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
+ IOException, UnrecoverableKeyException, KeyManagementException {
+ super(certificate, password, gateway, defaultTopic, builder, connectionPort);
+ }
+
public AsyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID,
boolean production, String defaultTopic, OkHttpClient.Builder builder) {
this(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, 443);
@@ -70,6 +77,11 @@ public AsyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID,
super(apnsAuthKey, teamID, keyID, production, defaultTopic, builder);
}
+ public AsyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, String gateway,
+ String defaultTopic, OkHttpClient.Builder builder, int connectionPort) {
+ super(apnsAuthKey, teamID, keyID, gateway, defaultTopic, builder, connectionPort);
+ }
+
public AsyncOkHttpApnsClient(InputStream certificate, String password, boolean production,
String defaultTopic, OkHttpClient.Builder builder)
throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
diff --git a/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java b/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java
index 3ba261c..cc80f53 100644
--- a/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java
+++ b/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java
@@ -89,6 +89,23 @@ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boo
*/
public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boolean production,
String defaultTopic, OkHttpClient.Builder clientBuilder, int connectionPort) {
+ this (apnsAuthKey, teamID, keyID, production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX,
+ defaultTopic,clientBuilder, connectionPort);
+ }
+
+ /**
+ * Creates a new client which uses token authentication API.
+ *
+ * @param apnsAuthKey The private key - exclude -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
+ * @param teamID The team ID
+ * @param keyID The key ID (retrieved from the file name)
+ * @param gateway Endpoint address
+ * @param defaultTopic A default topic (can be changed per message)
+ * @param clientBuilder An OkHttp client builder, possibly pre-initialized, to build the actual client
+ * @param connectionPort The port to establish a connection with APNs. Either 443 or 2197
+ */
+ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, String gateway,
+ String defaultTopic, OkHttpClient.Builder clientBuilder, int connectionPort) {
this.apnsAuthKey = apnsAuthKey;
this.teamID = teamID;
this.keyID = keyID;
@@ -96,7 +113,7 @@ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boo
this.defaultTopic = defaultTopic;
- gateway = (production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX) + ":" + connectionPort;
+ this.gateway = gateway + ":" + connectionPort;
}
/**
@@ -161,7 +178,6 @@ public SyncOkHttpApnsClient(InputStream certificate, String password, boolean pr
String defaultTopic, OkHttpClient.Builder builder, int connectionPort)
throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
IOException, UnrecoverableKeyException, KeyManagementException {
-
teamID = keyID = apnsAuthKey = null;
password = password == null ? "" : password;
@@ -190,6 +206,57 @@ public SyncOkHttpApnsClient(InputStream certificate, String password, boolean pr
gateway = (production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX) + ":" + connectionPort;
}
+ /**
+ * Creates a new client for custom endpoint and automatically loads the key store
+ * with the push certificate read from the input stream.
+ * Certificate will not be validated
+ *
+ * @param certificate The client certificate to be used
+ * @param password The password (if required, else null)
+ * @param gateway Address of custom gateway.
+ * @param defaultTopic A default topic (can be changed per message)
+ * @param builder An OkHttp client builder, possibly pre-initialized, to build the actual client
+ * @param connectionPort The port to establish a connection with APNs. Either 443 or 2197
+ * @throws UnrecoverableKeyException If the key cannot be recovered
+ * @throws KeyManagementException if the key failed to be loaded
+ * @throws CertificateException if any of the certificates in the keystore could not be loaded
+ * @throws NoSuchAlgorithmException if the algorithm used to check the integrity of the keystore cannot be found
+ * @throws IOException if there is an I/O or format problem with the keystore data,
+ * if a password is required but not given, or if the given password was incorrect
+ * @throws KeyStoreException if no Provider supports a KeyStoreSpi implementation for the specified type
+ */
+
+ public SyncOkHttpApnsClient(InputStream certificate, String password, String gateway,
+ String defaultTopic, OkHttpClient.Builder builder, int connectionPort)
+ throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
+ IOException, UnrecoverableKeyException, KeyManagementException {
+
+ teamID = keyID = apnsAuthKey = null;
+
+ password = password == null ? "" : password;
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(certificate, password.toCharArray());
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(ks, password.toCharArray());
+ KeyManager[] keyManagers = kmf.getKeyManagers();
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ sslContext.init(keyManagers, tmf.getTrustManagers(), null);
+
+ final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ builder.sslSocketFactory(sslSocketFactory);
+
+ client = builder.build();
+
+ this.defaultTopic = defaultTopic;
+ this.gateway = gateway + ":" + connectionPort;
+
+ }
+
/**
* Creates a new client and automatically loads the key store
* with the push certificate read from the input stream.