我正在尝试使用HTTP / 2在生产时向我的设备发送苹果通知。
我将 -Xbootclasspath / p:/home/mohamed/Desktop/alpn-boot-8.1.9.v20160720.jar 作为默认虚拟机参数传递给我蚀。
以下是我现在使用的代码:
public static void pushoNotification() {
try {
// create a low-level Jetty HTTP/2 client
HTTP2Client lowLevelClient = new HTTP2Client();
lowLevelClient.start();
// APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
KeyStore ks = KeyStore.getInstance("PKCS12");
// Ensure that the password is the same as the one used later in setKeyStorePassword()
ks.load(PushNotifications.class.getClassLoader().getResourceAsStream("Prod2.p12"), "a12B34".toCharArray());
SslContextFactory ssl = new SslContextFactory(true);
ssl.setKeyStore(ks);
ssl.setKeyStorePassword("a12B34");
// create a high-level Jetty client
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
client.start();
// request-response exchange
ContentResponse response = client.POST("https://api.push.apple.com").path("/3/device/19297dba97212ac6fd16b9cd50f2d86629aed0e49576b2b52ed05086087da802")
.content(new StringContentProvider("{ \"aps\" : { \"alert\" : \"Hello\" } }")).send();
response.toString();
client.stop();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
我的依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
<version>9.4.0.M1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>8.1.9.v20160720</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.4.1</version>
</dependency>
但是当我从 main 方法运行此方法时,它会抛出 java.nio.channels.ClosedChannelException
此外,我在eclipse控制台中得到了这个 INFO org.eclipse.jetty.http2.HTTP2Session - 通知监听器时失败org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2$SessionListenerPromise@87eaf9c
有什么想法吗?
由于
答案 0 :(得分:0)
我现在是在大约3年零6个月后粘贴我的答案,目的只是为了帮助任何一个人遇到相同的错误,实际上我不记得我如何解决此问题,但是下面是我现在正在使用的有效代码...
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myproject.path.model.APNSObject;
public void sendIOSNotification(APNSObject apnsObject, List<String> deviceIds, String notificationType) {
HTTP2Client lowLevelClient = null;
HttpClient client = null;
String hostname = null;
InputStream inputStream = null;
try {
lowLevelClient = new HTTP2Client(); // create a low-level Jetty HTTP/2 client
lowLevelClient.start();
// APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
inputStream = getClass().getClassLoader().getResourceAsStream(APPLE_CERTIFICATE_PATH);
// Ensure that the password is the same as the one used later in setKeyStorePassword()
ks.load(inputStream, APPLE_CERTIFICATE_PASSWORD.toCharArray());
inputStream.close();
SslContextFactory ssl = new SslContextFactory(true);
ssl.setKeyStore(ks);
ssl.setKeyStorePassword(APPLE_CERTIFICATE_PASSWORD);
FuturePromise<Session> sessionPromise = new FuturePromise<>();
if (notificationType != null && notificationType.trim().equalsIgnoreCase("Development"))
hostname = APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME;
else
hostname = APPLE_NOTIFICATION_PRODUCTION_HOSTNAME;
lowLevelClient.connect(ssl, new InetSocketAddress(hostname, Integer.parseInt(APPLE_NOTIFICATION_PORT)), new ServerSessionListener.Adapter(), sessionPromise);
// create a high-level Jetty client
client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
client.start();
// logger.info("Start Sending Notification.");
for (String token : deviceIds) {
ObjectMapper mapper = new ObjectMapper();
String fcmJsonObject = mapper.setSerializationInclusion(Include.NON_NULL).setSerializationInclusion(Include.NON_EMPTY).writeValueAsString(apnsObject);
Request request = client.POST("https://" + hostname).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
.content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
request = request.header("apns-topic", APPLE_APNS_TOPIC);
ContentResponse response = request.send();
// For development mode if it's not passed in parameters
if (response.getStatus() == 400 && !hostname.equals(APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME)) {
request = client.POST("https://" + APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
.content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
request = request.header("apns-topic", APPLE_APNS_TOPIC);
response = request.send();
logger.info("Sending notification to '" + token + "' in debugging mode...");
}
if (response.getStatus() == 200)
logger.info("Date: " + new Date() + " Notification sent successfully to '" + token + "' With Response Status: " + response.getStatus());
else
logger.warning("Sending Notification to token '" + token + "' Failed :( >> Response Status: " + response.getStatus() + "\nReason: " + response.getReason());
}
logger.info("End Sending Notification.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (lowLevelClient != null && !lowLevelClient.isStopped())
lowLevelClient.stop();
if (client != null && !client.isStopped())
client.stop();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
APNSObject.java类
import java.io.Serializable;
public class APNSObject implements Serializable {
// {\"aps\":{\"alert\":{" + messageTitle + "\"body\":\"" + alert + "\"}, \"sound\":\"default\"}" + payload + "}
private static final long serialVersionUID = 1L;
private Aps aps;
private TripBruEntity payload;// Our custom JSON Object
public APNSObject() {
}
public APNSObject(String title, String body, TripBruEntity payload) {
this(title, body, null, payload);
}
public APNSObject(String title, String body, String sound, TripBruEntity payload) {
aps = new Aps(title, body, sound);
this.payload = payload;
}
public Aps getAps() {
return aps;
}
public void setAps(Aps aps) {
this.aps = aps;
}
public TripBruEntity getPayload() {
return payload;
}
public void setPayload(TripBruEntity payload) {
this.payload = payload;
}
static class Aps {
private Alert alert;
private String sound;
public Aps() {
}
public Aps(String title, String body, String sound) {
this.alert = new Alert(title, body);
this.sound = sound == null || sound.isEmpty() ? "default" : sound;
}
public Alert getAlert() {
return alert;
}
public void setAlert(Alert alert) {
this.alert = alert;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
static class Alert {
private String title;
private String body;
public Alert() {
}
public Alert(String title, String body) {
this.title = title;
this.body = body;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
}
}
这是我的配置文件:
APPLE_CERTIFICATE_PATH=/my/apply/certificate/path/so/plz/change/it/Certificates.p12
APPLE_CERTIFICATE_PASSWORD=myPassword(plz change it)
KEYSTORE_TYPE=PKCS12
APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME=api.development.push.apple.com
APPLE_NOTIFICATION_PRODUCTION_HOSTNAME=api.push.apple.com
APPLE_NOTIFICATION_PORT=2197
APPLE_APNS_TOPIC=MyAPNS_Topic(plz change it)
最后,这是我在项目中使用的jars