支持鸿蒙推送
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package cn.wildfirechat.push;
|
||||
|
||||
import cn.wildfirechat.push.android.AndroidPushService;
|
||||
import cn.wildfirechat.push.hm.HMPushService;
|
||||
import cn.wildfirechat.push.ios.IOSPushService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -16,13 +17,21 @@ public class PushController {
|
||||
@Autowired
|
||||
private IOSPushService mIOSPushService;
|
||||
|
||||
@PostMapping(value = "/android/push", produces = "application/json;charset=UTF-8" )
|
||||
@Autowired
|
||||
private HMPushService hmPushService;
|
||||
|
||||
@PostMapping(value = "/android/push", produces = "application/json;charset=UTF-8")
|
||||
public Object androidPush(@RequestBody PushMessage pushMessage) {
|
||||
return mAndroidPushService.push(pushMessage);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/ios/push", produces = "application/json;charset=UTF-8" )
|
||||
@PostMapping(value = "/ios/push", produces = "application/json;charset=UTF-8")
|
||||
public Object iOSPush(@RequestBody PushMessage pushMessage) {
|
||||
return mIOSPushService.push(pushMessage);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/hm/push", produces = "application/json;charset=UTF-8")
|
||||
public Object hmPush(@RequestBody PushMessage pushMessage) {
|
||||
return hmPushService.push(pushMessage);
|
||||
}
|
||||
}
|
||||
|
||||
47
src/main/java/cn/wildfirechat/push/hm/HMConfig.java
Normal file
47
src/main/java/cn/wildfirechat/push/hm/HMConfig.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package cn.wildfirechat.push.hm;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "hm")
|
||||
@PropertySource(value = "file:config/hm.properties")
|
||||
public class HMConfig {
|
||||
private String privateKey;
|
||||
private String iss;
|
||||
private String kid;
|
||||
private String projectId;
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getIss() {
|
||||
return iss;
|
||||
}
|
||||
|
||||
public void setIss(String iss) {
|
||||
this.iss = iss;
|
||||
}
|
||||
|
||||
public String getKid() {
|
||||
return kid;
|
||||
}
|
||||
|
||||
public void setKid(String kid) {
|
||||
this.kid = kid;
|
||||
}
|
||||
|
||||
public String getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(String projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
}
|
||||
7
src/main/java/cn/wildfirechat/push/hm/HMPushService.java
Normal file
7
src/main/java/cn/wildfirechat/push/hm/HMPushService.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push.hm;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
|
||||
public interface HMPushService {
|
||||
Object push(PushMessage pushMessage);
|
||||
}
|
||||
154
src/main/java/cn/wildfirechat/push/hm/HMPushServiceImpl.java
Normal file
154
src/main/java/cn/wildfirechat/push/hm/HMPushServiceImpl.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package cn.wildfirechat.push.hm;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import cn.wildfirechat.push.PushMessageType;
|
||||
import cn.wildfirechat.push.Utility;
|
||||
import cn.wildfirechat.push.hm.payload.AlertPayload;
|
||||
import cn.wildfirechat.push.hm.payload.VoipPayload;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTCreator;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class HMPushServiceImpl implements HMPushService {
|
||||
private static final String AUD = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
|
||||
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HMPushServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
HMConfig config;
|
||||
|
||||
private String pushUrl;
|
||||
|
||||
@PostConstruct
|
||||
void setupPushUrl() {
|
||||
this.pushUrl = String.format("https://push-api.cloud.huawei.com/v3/%s/messages:send", config.getProjectId());
|
||||
}
|
||||
|
||||
private String createJwt() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
RSAPrivateKey prk = (RSAPrivateKey) getPrivateKey(config.getPrivateKey());
|
||||
Algorithm algorithm = Algorithm.RSA256(null, prk);
|
||||
long iat = System.currentTimeMillis() / 1000;
|
||||
long exp = iat + 3600;
|
||||
JWTCreator.Builder builder =
|
||||
JWT.create()
|
||||
.withIssuer(config.getIss())
|
||||
.withKeyId(config.getKid())
|
||||
.withAudience(AUD)
|
||||
.withClaim("iat", iat)
|
||||
.withClaim("exp", exp);
|
||||
String jwt = builder.sign(algorithm);
|
||||
return jwt;
|
||||
}
|
||||
|
||||
private PrivateKey getPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodeBase64(key));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
private byte[] decodeBase64(String key) {
|
||||
return Base64.decodeBase64(key.getBytes(DEFAULT_CHARSET));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object push(PushMessage pushMessage) {
|
||||
try {
|
||||
String jwt = null;
|
||||
jwt = createJwt();
|
||||
|
||||
if (pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_RECALLED || pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_DELETED) {
|
||||
//Todo not implement
|
||||
//撤回或者删除消息,需要更新远程通知,暂未实现
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_INVITE || pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_INVITE) {
|
||||
// TODO
|
||||
String data = "TODO";
|
||||
VoipPayload voipPayload = VoipPayload.buildAlertPayload(pushMessage.getDeviceToken(), data);
|
||||
httpPost(this.pushUrl, jwt, 10, voipPayload.toString(), 10000, 10000);
|
||||
} else {
|
||||
String[] titleAndContent = Utility.getPushTitleAndContent(pushMessage);
|
||||
AlertPayload alertPayload = AlertPayload.buildAlertPayload(pushMessage.getDeviceToken(), titleAndContent[0], titleAndContent[1]);
|
||||
String response = httpPost(this.pushUrl, jwt, 0, alertPayload.toString(), 10000, 10000);
|
||||
LOG.info("Push to {} response {}", pushMessage.getDeviceToken(), response);
|
||||
}
|
||||
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String httpPost(String httpUrl, String jwt, int pushType, String data, int connectTimeout, int readTimeout) throws IOException {
|
||||
OutputStream outPut = null;
|
||||
HttpURLConnection urlConnection = null;
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(httpUrl);
|
||||
urlConnection = (HttpURLConnection) url.openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/json");
|
||||
urlConnection.setRequestProperty("Authorization", "Bearer " + jwt);
|
||||
urlConnection.setRequestProperty("push-type", pushType + "");
|
||||
urlConnection.setConnectTimeout(connectTimeout);
|
||||
urlConnection.setReadTimeout(readTimeout);
|
||||
urlConnection.connect();
|
||||
|
||||
// POST data
|
||||
outPut = urlConnection.getOutputStream();
|
||||
outPut.write(data.getBytes("UTF-8"));
|
||||
outPut.flush();
|
||||
|
||||
// read response
|
||||
if (urlConnection.getResponseCode() < 400) {
|
||||
in = urlConnection.getInputStream();
|
||||
} else {
|
||||
in = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
List<String> lines = IOUtils.readLines(in, urlConnection.getContentEncoding());
|
||||
StringBuffer strBuf = new StringBuffer();
|
||||
for (String line : lines) {
|
||||
strBuf.append(line);
|
||||
}
|
||||
// LOG.info(strBuf.toString());
|
||||
return strBuf.toString();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(outPut);
|
||||
IOUtils.closeQuietly(in);
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package cn.wildfirechat.push.hm.payload;
|
||||
|
||||
import cn.wildfirechat.push.hm.payload.internal.ClickAction;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Notification;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Payload;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Target;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class AlertPayload {
|
||||
Payload payload;
|
||||
Target target;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
public static AlertPayload buildAlertPayload(String token, String title, String body) {
|
||||
Notification notification = new Notification();
|
||||
notification.title = title;
|
||||
notification.body = body;
|
||||
|
||||
ClickAction clickAction = new ClickAction();
|
||||
notification.clickAction = clickAction;
|
||||
|
||||
Target target = new Target();
|
||||
target.token = new ArrayList<>();
|
||||
target.token.add(token);
|
||||
|
||||
AlertPayload alertPayload = new AlertPayload();
|
||||
alertPayload.payload = new Payload();
|
||||
alertPayload.payload.notification = notification;
|
||||
alertPayload.target = target;
|
||||
|
||||
return alertPayload;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.wildfirechat.push.hm.payload;
|
||||
|
||||
import cn.wildfirechat.push.hm.payload.internal.ClickAction;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Notification;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Payload;
|
||||
import cn.wildfirechat.push.hm.payload.internal.Target;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class VoipPayload {
|
||||
Payload payload;
|
||||
Target target;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
public static VoipPayload buildAlertPayload(String token, String extraData) {
|
||||
Target target = new Target();
|
||||
target.token = new ArrayList<>();
|
||||
target.token.add(token);
|
||||
|
||||
VoipPayload voipPayload = new VoipPayload();
|
||||
voipPayload.payload = new Payload();
|
||||
voipPayload.payload.extraData = extraData;
|
||||
voipPayload.target = target;
|
||||
|
||||
return voipPayload;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.wildfirechat.push.hm.payload.internal;
|
||||
|
||||
public class ClickAction {
|
||||
/**
|
||||
* 0:打开应用首页
|
||||
* <p>
|
||||
* 1:打开应用自定义页面
|
||||
*/
|
||||
public int actionType;
|
||||
|
||||
public String action;
|
||||
public String uri;
|
||||
public String data;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cn.wildfirechat.push.hm.payload.internal;
|
||||
|
||||
public class Notification {
|
||||
public String category = "IM";
|
||||
public String title;
|
||||
public String body;
|
||||
public ClickAction clickAction;
|
||||
public int style;
|
||||
public String image;
|
||||
public Integer notifyId;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package cn.wildfirechat.push.hm.payload.internal;
|
||||
|
||||
public class Payload {
|
||||
public Notification notification;
|
||||
public String extraData;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push.hm.payload.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Target {
|
||||
public ArrayList<String> token;
|
||||
}
|
||||
Reference in New Issue
Block a user