Procházet zdrojové kódy

Merge remote-tracking branch 'origin/master'

by su před 3 roky
rodič
revize
cd624b6526
22 změnil soubory, kde provedl 1268 přidání a 0 odebrání
  1. 65 0
      4dkankan-common-utils/src/main/java/com/fdkankan/common/util/SpringUtil.java
  2. 64 0
      4dkankan-utils-app-push/pom.xml
  3. 199 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/AndroidNotification.java
  4. 6 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/App.java
  5. 95 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/IOSNotification.java
  6. 103 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushClient.java
  7. 331 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushMessageConfig.java
  8. 45 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushMsgUtil.java
  9. 86 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/UmengNotification.java
  10. 11 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidBroadcast.java
  11. 22 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidCustomizedcast.java
  12. 15 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidFilecast.java
  13. 16 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidGroupcast.java
  14. 16 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidUnicast.java
  15. 12 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSBroadcast.java
  16. 23 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSCustomizedcast.java
  17. 15 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSFilecast.java
  18. 16 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSGroupcast.java
  19. 15 0
      4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSUnicast.java
  20. 40 0
      4dkankan-utils-dingtalk/pom.xml
  21. 71 0
      4dkankan-utils-dingtalk/src/main/java/com/fdkankan/dingtalk/DingTalkSendUtils.java
  22. 2 0
      pom.xml

+ 65 - 0
4dkankan-common-utils/src/main/java/com/fdkankan/common/util/SpringUtil.java

@@ -0,0 +1,65 @@
+package com.fdkankan.common.util;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 实现ApplicationContextAware接口,并加入Component注解,让spring扫描到该bean
+ * 该类用于在普通Java类中注入bean,普通Java类中用@Autowired是无法注入bean的
+ */
+@Component
+public class SpringUtil implements ApplicationContextAware {
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        if(SpringUtil.applicationContext == null) {
+            SpringUtil.applicationContext = applicationContext;
+        }
+    }
+
+    /**
+     * 获取applicationContext
+     */
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+    /**
+     *通过name获取 Bean.
+     * @param name
+     * @return
+     */
+    public static Object getBean(String name){
+        return getApplicationContext().getBean(name);
+    }
+
+    /**
+     * 通过class获取Bean.
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(Class<T> clazz){
+        return getApplicationContext().getBean(clazz);
+    }
+
+    /**
+     * 通过name,以及Clazz返回指定的Bean
+     * @param name
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(String name,Class<T> clazz){
+        return getApplicationContext().getBean(name, clazz);
+    }
+
+    public <T> Map<String, T> getBeansOfType(Class<T> clazz) {
+        return applicationContext.getBeansOfType(clazz);
+    }
+}

+ 64 - 0
4dkankan-utils-app-push/pom.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>4dkankan-utils</artifactId>
+        <groupId>com.fdkankan</groupId>
+        <version>2.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>4dkankan-utils-app-push</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
+            <version>1.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk</artifactId>
+            <version>1.11.327</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+            <version>1.5.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.firebase</groupId>
+            <artifactId>firebase-admin</artifactId>
+            <version>6.8.1</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 199 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/AndroidNotification.java

@@ -0,0 +1,199 @@
+package com.fdkankan.push;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public abstract class AndroidNotification extends UmengNotification {
+	// Keys can be set in the payload level
+	protected static final HashSet<String> PAYLOAD_KEYS = new HashSet<String>(Arrays.asList(new String[]{
+			"display_type"}));
+	
+	// Keys can be set in the body level
+	protected static final HashSet<String> BODY_KEYS = new HashSet<String>(Arrays.asList(new String[]{
+			"ticker", "title", "text", "builder_id", "icon", "largeIcon", "img", "play_vibrate", "play_lights", "play_sound",
+			"sound", "after_open", "url", "activity", "custom"}));
+
+	public enum DisplayType{
+		NOTIFICATION{public String getValue(){return "notification";}},///通知:消息送达到用户设备后,由友盟SDK接管处理并在通知栏上显示通知内容。
+		MESSAGE{public String getValue(){return "message";}};///消息:消息送达到用户设备后,消息内容透传给应用自身进行解析处理。
+		public abstract String getValue();
+	}
+	public enum AfterOpenAction{
+        go_app,//打开应用
+        go_url,//跳转到URL
+        go_activity,//打开特定的activity
+        go_custom//用户自定义内容。
+	}
+	// Set key/value in the rootJson, for the keys can be set please see ROOT_KEYS, PAYLOAD_KEYS, 
+	// BODY_KEYS and POLICY_KEYS.
+	@Override
+	public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
+		if (ROOT_KEYS.contains(key)) {
+			// This key should be in the root level
+			rootJson.put(key, value);
+		} else if (PAYLOAD_KEYS.contains(key)) {
+			// This key should be in the payload level
+			JSONObject payloadJson = null;
+			if (rootJson.containsKey("payload")) {
+				payloadJson = rootJson.getJSONObject("payload");
+			} else {
+				payloadJson = new JSONObject();
+				rootJson.put("payload", payloadJson);
+			}
+			payloadJson.put(key, value);
+		} else if (BODY_KEYS.contains(key)) {
+			// This key should be in the body level
+			JSONObject bodyJson = null;
+			JSONObject payloadJson = null;
+			// 'body' is under 'payload', so build a payload if it doesn't exist
+			if (rootJson.containsKey("payload")) {
+				payloadJson = rootJson.getJSONObject("payload");
+			} else {
+				payloadJson = new JSONObject();
+				rootJson.put("payload", payloadJson);
+			}
+			// Get body JSONObject, generate one if not existed
+			if (payloadJson.containsKey("body")) {
+				bodyJson = payloadJson.getJSONObject("body");
+			} else {
+				bodyJson = new JSONObject();
+				payloadJson.put("body", bodyJson);
+			}
+			bodyJson.put(key, value);
+		} else if (POLICY_KEYS.contains(key)) {
+			// This key should be in the body level
+			JSONObject policyJson = null;
+			if (rootJson.containsKey("policy")) {
+				policyJson = rootJson.getJSONObject("policy");
+			} else {
+				policyJson = new JSONObject();
+				rootJson.put("policy", policyJson);
+			}
+			policyJson.put(key, value);
+		} else {
+			if (key == "payload" || key == "body" || key == "policy" || key == "extra") {
+				throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
+			} else {
+				throw new Exception("Unknown key: " + key);
+			}
+		}
+		return true;
+	}
+	
+	// Set extra key/value for Android notification
+	public boolean setExtraField(String key, String value) throws Exception {
+		JSONObject payloadJson = null;
+		JSONObject extraJson = null;
+		if (rootJson.containsKey("payload")) {
+			payloadJson = rootJson.getJSONObject("payload");
+		} else {
+			payloadJson = new JSONObject();
+			rootJson.put("payload", payloadJson);
+		}
+		
+		if (payloadJson.containsKey("extra")) {
+			extraJson = payloadJson.getJSONObject("extra");
+		} else {
+			extraJson = new JSONObject();
+			payloadJson.put("extra", extraJson);
+		}
+		extraJson.put(key, value);
+		return true;
+	}
+	
+	//
+	public void setDisplayType(DisplayType d) throws Exception {
+		setPredefinedKeyValue("display_type", d.getValue());
+	}
+	///通知栏提示文字
+	public void setTicker(String ticker) throws Exception {
+		setPredefinedKeyValue("ticker", ticker);
+	}
+	///通知标题
+	public void setTitle(String title) throws Exception {
+		setPredefinedKeyValue("title", title);
+	}
+	///通知文字描述
+	public void setText(String text) throws Exception {
+		setPredefinedKeyValue("text", text);
+	}
+	///用于标识该通知采用的样式。使用该参数时, 必须在SDK里面实现自定义通知栏样式。
+	public void setBuilderId(Integer builder_id) throws Exception {
+		setPredefinedKeyValue("builder_id", builder_id);
+	}
+	///状态栏图标ID, R.drawable.[smallIcon],如果没有, 默认使用应用图标。
+	public void setIcon(String icon) throws Exception {
+		setPredefinedKeyValue("icon", icon);
+	}
+	///通知栏拉开后左侧图标ID
+	public void setLargeIcon(String largeIcon) throws Exception {
+		setPredefinedKeyValue("largeIcon", largeIcon);
+	}
+	///通知栏大图标的URL链接。该字段的优先级大于largeIcon。该字段要求以http或者https开头。
+	public void setImg(String img) throws Exception {
+		setPredefinedKeyValue("img", img);
+	}
+	///收到通知是否震动,默认为"true"
+	public void setPlayVibrate(Boolean play_vibrate) throws Exception {
+		setPredefinedKeyValue("play_vibrate", play_vibrate.toString());
+	}
+	///收到通知是否闪灯,默认为"true"
+	public void setPlayLights(Boolean play_lights) throws Exception {
+		setPredefinedKeyValue("play_lights", play_lights.toString());
+	}
+	///收到通知是否发出声音,默认为"true"
+	public void setPlaySound(Boolean play_sound) throws Exception {
+		setPredefinedKeyValue("play_sound", play_sound.toString());
+	}
+	///通知声音,R.raw.[sound]. 如果该字段为空,采用SDK默认的声音
+	public void setSound(String sound) throws Exception {
+		setPredefinedKeyValue("sound", sound);
+	}
+	///收到通知后播放指定的声音文件
+	public void setPlaySound(String sound) throws Exception {
+		setPlaySound(true);
+		setSound(sound);
+	}
+	
+	///点击"通知"的后续行为,默认为打开app。
+	public void goAppAfterOpen() throws Exception {
+		setAfterOpenAction(AfterOpenAction.go_app);
+	}
+	public void goUrlAfterOpen(String url) throws Exception {
+		setAfterOpenAction(AfterOpenAction.go_url);
+		setUrl(url);
+	}
+	public void goActivityAfterOpen(String activity) throws Exception {
+		setAfterOpenAction(AfterOpenAction.go_activity);
+		setActivity(activity);
+	}
+	public void goCustomAfterOpen(String custom) throws Exception {
+		setAfterOpenAction(AfterOpenAction.go_custom);
+		setCustomField(custom);
+	}
+	public void goCustomAfterOpen(JSONObject custom) throws Exception {
+		setAfterOpenAction(AfterOpenAction.go_custom);
+		setCustomField(custom);
+	}
+	
+	///点击"通知"的后续行为,默认为打开app。原始接口
+	public void setAfterOpenAction(AfterOpenAction action) throws Exception {
+		setPredefinedKeyValue("after_open", action.toString());
+	}
+	public void setUrl(String url) throws Exception {
+		setPredefinedKeyValue("url", url);
+	}
+	public void setActivity(String activity) throws Exception {
+		setPredefinedKeyValue("activity", activity);
+	}
+	///can be a string of json
+	public void setCustomField(String custom) throws Exception {
+		setPredefinedKeyValue("custom", custom);
+	}
+	public void setCustomField(JSONObject custom) throws Exception {
+		setPredefinedKeyValue("custom", custom);
+	}
+	
+}

+ 6 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/App.java

@@ -0,0 +1,6 @@
+package com.fdkankan.modeling.push;
+
+
+public class App {
+
+}

+ 95 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/IOSNotification.java

@@ -0,0 +1,95 @@
+package com.fdkankan.push;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public abstract class IOSNotification extends UmengNotification {
+
+	// Keys can be set in the aps level
+	protected static final HashSet<String> APS_KEYS = new HashSet<String>(Arrays.asList(new String[]{
+			"alert", "badge", "sound", "content-available", "url", "mutable-content"
+	}));
+	
+	@Override
+	public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
+		if (ROOT_KEYS.contains(key)) {
+			// This key should be in the root level
+			rootJson.put(key, value);
+		} else if (APS_KEYS.contains(key)) {
+			// This key should be in the aps level
+			JSONObject apsJson = null;
+			JSONObject payloadJson = null;
+			if (rootJson.containsKey("payload")) {
+				payloadJson = rootJson.getJSONObject("payload");
+			} else {
+				payloadJson = new JSONObject();
+				rootJson.put("payload", payloadJson);
+			}
+			if (payloadJson.containsKey("aps")) {
+				apsJson = payloadJson.getJSONObject("aps");
+			} else {
+				apsJson = new JSONObject();
+				payloadJson.put("aps", apsJson);
+			}
+			apsJson.put(key, value);
+		} else if (POLICY_KEYS.contains(key)) {
+			// This key should be in the body level
+			JSONObject policyJson = null;
+			if (rootJson.containsKey("policy")) {
+				policyJson = rootJson.getJSONObject("policy");
+			} else {
+				policyJson = new JSONObject();
+				rootJson.put("policy", policyJson);
+			}
+			policyJson.put(key, value);
+		} else {
+			if (key == "payload" || key == "aps" || key == "policy") {
+				throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
+			} else {
+				throw new Exception("Unknownd key: " + key);
+			}
+		}
+		
+		return true;
+	}
+	// Set customized key/value for IOS notification
+	public boolean setCustomizedField(String key, String value) throws Exception {
+		//rootJson.put(key, value);
+		JSONObject payloadJson = null;
+		if (rootJson.containsKey("payload")) {
+			payloadJson = rootJson.getJSONObject("payload");
+		} else {
+			payloadJson = new JSONObject();
+			rootJson.put("payload", payloadJson);
+		}
+		payloadJson.put(key, value);
+		return true;
+	}
+
+	public void setAlert(String token) throws Exception {
+    	setPredefinedKeyValue("alert", token);
+    }
+
+    public void setAlert(String title ,String subtitle , String body, String url) throws Exception{
+		JSONObject object = new JSONObject();
+		object.put("title" , title);
+		object.put("subtitle" , subtitle);
+		object.put("body" , body);
+		setPredefinedKeyValue("alert",object );
+		setPredefinedKeyValue("url", url);
+		setPredefinedKeyValue("mutable-content", 1);
+	}
+	public void setBadge(Integer badge) throws Exception {
+    	setPredefinedKeyValue("badge", badge);
+    }
+	
+	public void setSound(String sound) throws Exception {
+    	setPredefinedKeyValue("sound", sound);
+    }
+	
+	public void setContentAvailable(Integer contentAvailable) throws Exception {
+    	setPredefinedKeyValue("content-available", contentAvailable);
+    }
+}

+ 103 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushClient.java

@@ -0,0 +1,103 @@
+package com.fdkankan.push;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+@Slf4j
+public class PushClient {
+	
+	// The user agent
+	protected final String USER_AGENT = "Mozilla/5.0";
+
+	// This object is used for sending the post request to Umeng
+	protected HttpClient client = new DefaultHttpClient();
+	
+	// The host
+	protected static final String host = "http://msg.umeng.com";
+	
+	// The upload path
+	protected static final String uploadPath = "/upload";
+	
+	// The post path
+	protected static final String postPath = "/api/send";
+
+	public boolean send(UmengNotification msg) throws Exception {
+		String timestamp = Integer.toString((int)(System.currentTimeMillis() / 1000));
+		msg.setPredefinedKeyValue("timestamp", timestamp);
+        String url = host + postPath;
+        String postBody = msg.getPostBody();
+        String sign = DigestUtils.md5Hex(("POST" + url + postBody + msg.getAppMasterSecret()).getBytes("utf8"));
+        url = url + "?sign=" + sign;
+        HttpPost post = new HttpPost(url);
+        post.setHeader("User-Agent", USER_AGENT);
+        StringEntity se = new StringEntity(postBody, "UTF-8");
+        post.setEntity(se);
+        // Send the post request and get the response
+        HttpResponse response = client.execute(post);
+        int status = response.getStatusLine().getStatusCode();
+        log.info("Response Code : " + status);
+        BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+        StringBuffer result = new StringBuffer();
+        String line = "";
+        while ((line = rd.readLine()) != null) {
+            result.append(line);
+        }
+        log.info(result.toString());
+        if (status == 200) {
+            log.info("Notification sent successfully.");
+        } else {
+            log.info("Failed to send the notification!");
+        }
+        return true;
+    }
+
+	// Upload file with device_tokens to Umeng
+	public String uploadContents(String appkey,String appMasterSecret,String contents) throws Exception {
+		// Construct the json string
+		JSONObject uploadJson = new JSONObject();
+		uploadJson.put("appkey", appkey);
+		String timestamp = Integer.toString((int)(System.currentTimeMillis() / 1000));
+		uploadJson.put("timestamp", timestamp);
+		uploadJson.put("content", contents);
+		// Construct the request
+		String url = host + uploadPath;
+		String postBody = uploadJson.toString();
+		String sign = DigestUtils.md5Hex(("POST" + url + postBody + appMasterSecret).getBytes("utf8"));
+		url = url + "?sign=" + sign;
+		HttpPost post = new HttpPost(url);
+		post.setHeader("User-Agent", USER_AGENT);
+		StringEntity se = new StringEntity(postBody, "UTF-8");
+		post.setEntity(se);
+		// Send the post request and get the response
+		HttpResponse response = client.execute(post);
+		log.info("Response Code : " + response.getStatusLine().getStatusCode());
+		BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+		StringBuffer result = new StringBuffer();
+		String line = "";
+		while ((line = rd.readLine()) != null) {
+			result.append(line);
+		}
+		log.info(result.toString());
+		// Decode response string and get file_id from it
+		JSONObject respJson = JSONObject.parseObject(result.toString());
+		String ret = respJson.getString("ret");
+		if (!ret.equals("SUCCESS")) {
+			throw new Exception("Failed to upload file");
+		}
+		JSONObject data = respJson.getJSONObject("data");
+		String fileId = data.getString("file_id");
+		// Set file_id into rootJson using setPredefinedKeyValue
+		
+		return fileId;
+	}
+
+}

+ 331 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushMessageConfig.java

@@ -0,0 +1,331 @@
+package com.fdkankan.push;
+
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.push.android.*;
+import com.fdkankan.push.ios.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Date;
+
+@Slf4j
+public class PushMessageConfig {
+	private String appkey = null;
+	private String appMasterSecret = null;
+	private String timestamp = null;
+	private PushClient client = new PushClient();
+
+	public static final String ANDROID_KEY = "5ee71c03dbc2ec076dd488cb";
+	public static final String ANDROID_SECRET = "gzw4r8frbhq6eigxrvgjkdrm7wgtu83g";
+	public static final String IOS_KEY = "5ee71ca9978eea081640f22a";
+	public static final String IOS_SECRET = "tpuhyojch16pcha2qmpidlbnzkielv9w";
+
+	//转台双目使用
+	public static final String ANDROID_KEY_Z = "60efd777a6f90557b7b97c25";
+	public static final String ANDROID_SECRET_Z = "ll85ov3qzeuas0ig7cw0v5bgzq1bdl07";
+	public static final String IOS_KEY_Z = "60efd7c9a6f90557b7b97d10";
+	public static final String IOS_SECRET_Z = "li62b5f3d9kn8idvy6qva3c5gyidmqwl";
+
+	public PushMessageConfig(String key, String secret) {
+		try {
+			appkey = key;
+			appMasterSecret = secret;
+		} catch (Exception e) {
+			e.printStackTrace();
+			System.exit(1);
+		}
+	}
+	
+	public void sendAndroidBroadcast() throws Exception {
+		AndroidBroadcast broadcast = new AndroidBroadcast(appkey,appMasterSecret);
+		broadcast.setTicker( "Android broadcast ticker");
+		broadcast.setTitle(  "中文的title");
+		broadcast.setText(   "Android broadcast text");
+		broadcast.goAppAfterOpen();
+		broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		// TODO Set 'production_mode' to 'false' if it's a test device. 
+		// For how to register a test device, please see the developer doc.
+		broadcast.setProductionMode();
+		// Set customized fields
+		broadcast.setExtraField("test", "helloworld");
+		//厂商通道相关参数
+		broadcast.setChannelActivity("your channel activity");
+		broadcast.setChannelProperties("abc");
+		client.send(broadcast);
+	}
+	
+	public void sendAndroidUnicast(String token, String ticker, String title, String text, String url) throws Exception {
+		AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
+		// TODO Set your device token
+		unicast.setDeviceToken(token);
+		unicast.setTicker(ticker);
+		unicast.setTitle(title);
+		unicast.setText(text);
+		unicast.goUrlAfterOpen(url);
+		unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		// TODO Set 'production_mode' to 'false' if it's a test device. 
+		// For how to register a test device, please see the developer doc.
+		unicast.setProductionMode();
+		// Set customized fields
+		unicast.setExtraField("test", "helloworld");
+		unicast.setChannelActivity("com.fdage.eight.module.EightPushMsgHandlerActivity");
+//		unicast.setChannelProperties("abc");
+
+		client.send(unicast);
+	}
+
+	//转台相机
+	public void sendAndroidUnicast2(String token, String ticker, String title, String text, String url) throws Exception {
+		AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
+		// TODO Set your device token
+		unicast.setDeviceToken(token);
+		unicast.setTicker(ticker);
+		unicast.setTitle(title);
+		unicast.setText(text);
+		unicast.goUrlAfterOpen(url);
+		unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		// TODO Set 'production_mode' to 'false' if it's a test device.
+		// For how to register a test device, please see the developer doc.
+		unicast.setProductionMode();
+		// Set customized fields
+		unicast.setExtraField("test", "helloworld");
+		unicast.setChannelActivity("io.github.zileyuan.umeng_analytics_push.OfflineNotifyClickActivity");
+//		unicast.setChannelProperties("abc");
+
+		client.send(unicast);
+	}
+	
+	public void sendAndroidGroupcast() throws Exception {
+		AndroidGroupcast groupcast = new AndroidGroupcast(appkey,appMasterSecret);
+		/*  TODO
+		 *  Construct the filter condition:
+		 *  "where": 
+		 *	{
+    	 *		"and": 
+    	 *		[
+      	 *			{"tag":"test"},
+      	 *			{"tag":"Test"}
+    	 *		]
+		 *	}
+		 */
+		JSONObject filterJson = new JSONObject();
+		JSONObject whereJson = new JSONObject();
+		JSONArray tagArray = new JSONArray();
+		JSONObject testTag = new JSONObject();
+		JSONObject TestTag = new JSONObject();
+		testTag.put("tag", "test");
+		TestTag.put("tag", "Test");
+		tagArray.add(testTag);
+		tagArray.add(TestTag);
+		whereJson.put("and", tagArray);
+		filterJson.put("where", whereJson);
+
+		groupcast.setFilter(filterJson);
+		groupcast.setTicker( "Android groupcast ticker");
+		groupcast.setTitle(  "中文的title");
+		groupcast.setText(   "Android groupcast text");
+		groupcast.goAppAfterOpen();
+		groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		groupcast.setChannelActivity("your channel activity");
+		// TODO Set 'production_mode' to 'false' if it's a test device. 
+		// For how to register a test device, please see the developer doc.
+		groupcast.setProductionMode();
+		//厂商通道相关参数
+		groupcast.setChannelActivity("your channel activity");
+		groupcast.setChannelProperties("abc");
+		client.send(groupcast);
+	}
+	
+	public void sendAndroidCustomizedcast() throws Exception {
+		AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
+		// TODO Set your alias here, and use comma to split them if there are multiple alias.
+		// And if you have many alias, you can also upload a file containing these alias, then 
+		// use file_id to send customized notification.
+		customizedcast.setAlias("alias", "alias_type");
+		customizedcast.setTicker( "Android customizedcast ticker");
+		customizedcast.setTitle(  "中文的title");
+		customizedcast.setText(   "Android customizedcast text");
+		customizedcast.goAppAfterOpen();
+		customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		// TODO Set 'production_mode' to 'false' if it's a test device. 
+		// For how to register a test device, please see the developer doc.
+		customizedcast.setProductionMode();
+		//厂商通道相关参数
+		customizedcast.setChannelActivity("your channel activity");
+		customizedcast.setChannelProperties("abc");
+		client.send(customizedcast);
+	}
+	
+	public void sendAndroidCustomizedcastFile() throws Exception {
+		AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
+		// TODO Set your alias here, and use comma to split them if there are multiple alias.
+		// And if you have many alias, you can also upload a file containing these alias, then 
+		// use file_id to send customized notification.
+		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb"+"\n"+"alias");
+		customizedcast.setFileId(fileId, "alias_type");
+		customizedcast.setTicker( "Android customizedcast ticker");
+		customizedcast.setTitle(  "中文的title");
+		customizedcast.setText(   "Android customizedcast text");
+		customizedcast.goAppAfterOpen();
+		customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		// TODO Set 'production_mode' to 'false' if it's a test device. 
+		// For how to register a test device, please see the developer doc.
+		customizedcast.setProductionMode();
+		//厂商通道相关参数
+		customizedcast.setChannelActivity("your channel activity");
+		customizedcast.setChannelProperties("abc");
+		client.send(customizedcast);
+	}
+	
+	public void sendAndroidFilecast() throws Exception {
+		AndroidFilecast filecast = new AndroidFilecast(appkey,appMasterSecret);
+		// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens 
+		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
+		filecast.setFileId( fileId);
+		filecast.setTicker( "Android filecast ticker");
+		filecast.setTitle(  "中文的title");
+		filecast.setText(   "Android filecast text");
+		filecast.goAppAfterOpen();
+		filecast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
+		//厂商通道相关参数
+		filecast.setChannelActivity("your channel activity");
+		filecast.setChannelProperties("abc");
+		client.send(filecast);
+	}
+	
+	public void sendIOSBroadcast() throws Exception {
+		IOSBroadcast broadcast = new IOSBroadcast(appkey,appMasterSecret);
+        //alert值设置为字符串
+		//broadcast.setAlert("IOS 广播测试");
+		//alert的值设置为字典
+//		broadcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+		broadcast.setBadge( 0);
+		broadcast.setSound( "default");
+		// TODO set 'production_mode' to 'true' if your app is under production mode
+		broadcast.setTestMode();
+		// Set customized fields
+		broadcast.setCustomizedField("test", "helloworld");
+		client.send(broadcast);
+	}
+	
+	public void sendIOSUnicast(String token, String title ,String subtitle , String body, String url) throws Exception {
+		IOSUnicast unicast = new IOSUnicast(appkey,appMasterSecret);
+		// TODO Set your device token
+		unicast.setDeviceToken(token);
+		//alert值设置为字符串
+		//unicast.setAlert("IOS 单播测试");
+		//alert的值设置为字典
+		unicast.setAlert(title, subtitle, body, url);
+//		unicast.setBadge( 0);
+		unicast.setSound( "default");
+		// TODO set 'production_mode' to 'true' if your app is under production mode
+		unicast.setProductionMode();
+//		unicast.setTestMode();
+		unicast.setDescription(title);
+		unicast.setExpireTime(DateUtil.formatTime(DateUtil.offsetDay(new Date(), 1)));
+		// Set customized fields
+//		unicast.setCustomizedField("url", url);
+		client.send(unicast);
+	}
+
+	
+	public void sendIOSGroupcast() throws Exception {
+		IOSGroupcast groupcast = new IOSGroupcast(appkey,appMasterSecret);
+		/*  TODO
+		 *  Construct the filter condition:
+		 *  "where": 
+		 *	{
+    	 *		"and": 
+    	 *		[
+      	 *			{"tag":"iostest"}
+    	 *		]
+		 *	}
+		 */
+		JSONObject filterJson = new JSONObject();
+		JSONObject whereJson = new JSONObject();
+		JSONArray tagArray = new JSONArray();
+		JSONObject testTag = new JSONObject();
+		testTag.put("tag", "iostest");
+		tagArray.add(testTag);
+		whereJson.put("and", tagArray);
+		filterJson.put("where", whereJson);
+		log.info(filterJson.toString());
+		
+		// Set filter condition into rootJson
+		groupcast.setFilter(filterJson);
+		//groupcast.setAlert("IOS 组播测试");
+		//alert的值设置为字典
+//		groupcast.setAlert("今日天气" , "subtitle" , "今日可能下雨🌂");
+		groupcast.setBadge( 0);
+		groupcast.setSound( "default");
+		// TODO set 'production_mode' to 'true' if your app is under production mode
+		groupcast.setTestMode();
+		client.send(groupcast);
+	}
+	
+	public void sendIOSCustomizedcast() throws Exception {
+		IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey,appMasterSecret);
+		// TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias.
+		// And if you have many alias, you can also upload a file containing these alias, then 
+		// use file_id to send customized notification.
+		customizedcast.setAlias("alias", "alias_type");
+		//customizedcast.setAlert("IOS 个性化测试");
+		//alert的值设置为字典
+//		customizedcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+		customizedcast.setBadge( 0);
+		customizedcast.setSound( "default");
+		// TODO set 'production_mode' to 'true' if your app is under production mode
+		customizedcast.setTestMode();
+		client.send(customizedcast);
+	}
+	
+	public void sendIOSFilecast() throws Exception {
+		IOSFilecast filecast = new IOSFilecast(appkey,appMasterSecret);
+		// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens 
+		String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
+		filecast.setFileId( fileId);
+		//filecast.setAlert("IOS 文件播测试");
+		//alert的值设置为字典
+//		filecast.setAlert("今日天气" , "" , "今日可能下雨🌂");
+		filecast.setBadge( 0);
+		filecast.setSound( "default");
+		// TODO set 'production_mode' to 'true' if your app is under production mode
+		filecast.setTestMode();
+		client.send(filecast);
+	}
+	
+	public static void main(String[] args) {
+		// TODO set your appkey and master secret here
+		//安卓
+//		Demo demo = new Demo(ANDROID_KEY, ANDROID_SECRET);
+		//ios
+		PushMessageConfig pushMessageConfig = new PushMessageConfig(IOS_KEY, IOS_SECRET);
+		try {
+//			demo.sendAndroidUnicast("AneqkEZahjbW3cF7gu8juNYqz54ZFfK7kjMpTOiQL9dl",
+//					"测试项目计算完成", "四维看看Pro", "您上传的测试项目计算完成,点击查看",
+//					"https://test.4dkankan.com/smobile.html?m=t-e9uHHdn");
+			pushMessageConfig.sendIOSUnicast("ec61a2aa52673c96c12024e07ce267e391ca560e0c60f15ee09e65c8843ef7f4",
+					"四维看看Pro", "测试项目计算完成", "您上传的测试项目计算完成,点击查看",
+					"https://test.4dkankan.com/smobile.html?m=t-e9uHHdn");
+			/* TODO these methods are all available, just fill in some fields and do the test
+			 * demo.sendAndroidCustomizedcastFile();
+			 * demo.sendAndroidBroadcast();
+			 * demo.sendAndroidGroupcast();
+			 * demo.sendAndroidCustomizedcast();
+			 * demo.sendAndroidFilecast();
+			 * 
+			 * demo.sendIOSBroadcast();
+			 * demo.sendIOSUnicast();
+			 * demo.sendIOSGroupcast();
+			 * demo.sendIOSCustomizedcast();
+			 * demo.sendIOSFilecast();
+			 */
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+	}
+	
+
+}

+ 45 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/PushMsgUtil.java

@@ -0,0 +1,45 @@
+package com.fdkankan.push;
+
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.FirebaseOptions;
+import com.google.firebase.messaging.FirebaseMessaging;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.FileInputStream;
+
+/**
+ * Created by Hb_zzZ on 2020/7/27.
+ */
+@Slf4j
+public class PushMsgUtil {
+
+    /**
+     * 海外谷歌推送
+     */
+    public static void googlePushMsg(String refreshTokenJsonFileUrl, String token, String title, String text, String url){
+        try{
+            FileInputStream refreshToken = new FileInputStream(refreshTokenJsonFileUrl);
+
+            FirebaseOptions options = new FirebaseOptions.Builder()
+                    .setCredentials(GoogleCredentials.fromStream(refreshToken))
+                    .setDatabaseUrl("https://dkankan-pro.firebaseio.com")
+                    .build();
+
+            FirebaseApp.initializeApp(options);
+
+            com.google.firebase.messaging.Message message = com.google.firebase.messaging.Message.builder()
+                    .putData("titile", title)
+                    .putData("text", text)
+                    .putData("url", url)
+                    .setNotification(new com.google.firebase.messaging.Notification(title, text))
+                    .setToken(token)
+                    .build();
+            String response = FirebaseMessaging.getInstance().send(message);
+            log.info("Successfully sent message: " + response);
+        }catch (Exception e ){
+            e.printStackTrace();
+        }
+
+    }
+}

+ 86 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/UmengNotification.java

@@ -0,0 +1,86 @@
+package com.fdkankan.push;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+public abstract class UmengNotification {
+	// This JSONObject is used for constructing the whole request string.
+	protected final JSONObject rootJson = new JSONObject();
+	
+	
+	// The app master secret
+	protected String appMasterSecret;
+	
+	// Keys can be set in the root level
+	protected static final HashSet<String> ROOT_KEYS = new HashSet<String>(Arrays.asList(new String[]{
+			"appkey", "timestamp", "type", "device_tokens", "alias", "alias_type", "file_id", 
+			"filter", "production_mode", "feedback", "description", "thirdparty_id" , "mipush" , "mi_activity" , "channel_properties"}));
+	
+	// Keys can be set in the policy level
+	protected static final HashSet<String> POLICY_KEYS = new HashSet<String>(Arrays.asList(new String[]{
+			"start_time", "expire_time", "max_send_num"
+	}));
+	
+	// Set predefined keys in the rootJson, for extra keys(Android) or customized keys(IOS) please 
+	// refer to corresponding methods in the subclass.
+	public abstract boolean setPredefinedKeyValue(String key, Object value) throws Exception;
+	public void setAppMasterSecret(String secret) {
+		appMasterSecret = secret;
+	}
+	
+	public String getPostBody(){
+		return rootJson.toString();
+	}
+	
+	protected final String getAppMasterSecret(){
+		return appMasterSecret;
+	}
+	
+	protected void setProductionMode(Boolean prod) throws Exception {
+    	setPredefinedKeyValue("production_mode", prod.toString());
+    }
+
+	///正式模式
+    public void setProductionMode() throws Exception {
+    	setProductionMode(true);
+    }
+
+    ///测试模式
+    public void setTestMode() throws Exception {
+    	setProductionMode(false);
+    }
+
+    ///发送消息描述,建议填写。
+    public void setDescription(String description) throws Exception {
+    	setPredefinedKeyValue("description", description);
+    }
+
+    ///定时发送时间,若不填写表示立即发送。格式: "YYYY-MM-DD hh:mm:ss"。
+    public void setStartTime(String startTime) throws Exception {
+    	setPredefinedKeyValue("start_time", startTime);
+    }
+    ///消息过期时间,格式: "YYYY-MM-DD hh:mm:ss"。
+    public void setExpireTime(String expireTime) throws Exception {
+    	setPredefinedKeyValue("expire_time", expireTime);
+    }
+    ///发送限速,每秒发送的最大条数。
+    public void setMaxSendNum(Integer num) throws Exception {
+    	setPredefinedKeyValue("max_send_num", num);
+    }
+
+    //厂商弹窗activity
+	public void setChannelActivity(String activity) throws Exception{
+       setPredefinedKeyValue("mipush", "true");
+       setPredefinedKeyValue("mi_activity",activity );
+	}
+
+	//厂商属性配置
+	public void setChannelProperties(String xiaoMiChannelId) throws Exception{
+		JSONObject object = new JSONObject();
+		object.put("xiaomi_channel_id" , xiaoMiChannelId);
+		setPredefinedKeyValue("channel_properties", object);
+	}
+
+}

+ 11 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidBroadcast.java

@@ -0,0 +1,11 @@
+package com.fdkankan.push.android;
+
+import com.fdkankan.push.AndroidNotification;
+
+public class AndroidBroadcast extends AndroidNotification {
+	public AndroidBroadcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "broadcast");	
+	}
+}

+ 22 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidCustomizedcast.java

@@ -0,0 +1,22 @@
+package com.fdkankan.push.android;
+
+import com.fdkankan.push.AndroidNotification;
+
+public class AndroidCustomizedcast extends AndroidNotification {
+	public AndroidCustomizedcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "customizedcast");	
+	}
+	
+	public void setAlias(String alias,String aliasType) throws Exception {
+    	setPredefinedKeyValue("alias", alias);
+    	setPredefinedKeyValue("alias_type", aliasType);
+    }
+			
+	public void setFileId(String fileId,String aliasType) throws Exception {
+    	setPredefinedKeyValue("file_id", fileId);
+    	setPredefinedKeyValue("alias_type", aliasType);
+    }
+
+}

+ 15 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidFilecast.java

@@ -0,0 +1,15 @@
+package com.fdkankan.push.android;
+
+import com.fdkankan.push.AndroidNotification;
+
+public class AndroidFilecast extends AndroidNotification {
+	public AndroidFilecast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "filecast");	
+	}
+	
+	public void setFileId(String fileId) throws Exception {
+    	setPredefinedKeyValue("file_id", fileId);
+    }
+}

+ 16 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidGroupcast.java

@@ -0,0 +1,16 @@
+package com.fdkankan.push.android;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.push.AndroidNotification;
+
+public class AndroidGroupcast extends AndroidNotification {
+	public AndroidGroupcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "groupcast");	
+	}
+	
+	public void setFilter(JSONObject filter) throws Exception {
+    	setPredefinedKeyValue("filter", filter);
+    }
+}

+ 16 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/android/AndroidUnicast.java

@@ -0,0 +1,16 @@
+package com.fdkankan.push.android;
+
+import com.fdkankan.push.AndroidNotification;
+
+public class AndroidUnicast extends AndroidNotification {
+	public AndroidUnicast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "unicast");	
+	}
+	
+	public void setDeviceToken(String token) throws Exception {
+    	setPredefinedKeyValue("device_tokens", token);
+    }
+
+}

+ 12 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSBroadcast.java

@@ -0,0 +1,12 @@
+package com.fdkankan.push.ios;
+
+import com.fdkankan.push.IOSNotification;
+
+public class IOSBroadcast extends IOSNotification {
+	public IOSBroadcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "broadcast");	
+		
+	}
+}

+ 23 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSCustomizedcast.java

@@ -0,0 +1,23 @@
+package com.fdkankan.push.ios;
+
+
+import com.fdkankan.push.IOSNotification;
+
+public class IOSCustomizedcast extends IOSNotification {
+	public IOSCustomizedcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "customizedcast");	
+	}
+	
+	public void setAlias(String alias,String aliasType) throws Exception {
+    	setPredefinedKeyValue("alias", alias);
+    	setPredefinedKeyValue("alias_type", aliasType);
+    }
+		
+	public void setFileId(String fileId, String aliasType) throws Exception {
+		setPredefinedKeyValue("file_id", fileId);
+		setPredefinedKeyValue("alias_type", aliasType);
+	}
+
+}

+ 15 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSFilecast.java

@@ -0,0 +1,15 @@
+package com.fdkankan.push.ios;
+
+import com.fdkankan.push.IOSNotification;
+
+public class IOSFilecast extends IOSNotification {
+	public IOSFilecast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "filecast");	
+	}
+	
+	public void setFileId(String fileId) throws Exception {
+    	setPredefinedKeyValue("file_id", fileId);
+    }
+}

+ 16 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSGroupcast.java

@@ -0,0 +1,16 @@
+package com.fdkankan.push.ios;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.push.IOSNotification;
+
+public class IOSGroupcast extends IOSNotification {
+	public IOSGroupcast(String appkey,String appMasterSecret) throws Exception {
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "groupcast");	
+	}
+	
+	public void setFilter(JSONObject filter) throws Exception {
+    	setPredefinedKeyValue("filter", filter);
+    }
+}

+ 15 - 0
4dkankan-utils-app-push/src/main/java/com/fdkankan/push/ios/IOSUnicast.java

@@ -0,0 +1,15 @@
+package com.fdkankan.push.ios;
+
+import com.fdkankan.push.IOSNotification;
+
+public class IOSUnicast extends IOSNotification {
+	public IOSUnicast(String appkey,String appMasterSecret) throws Exception{
+			setAppMasterSecret(appMasterSecret);
+			setPredefinedKeyValue("appkey", appkey);
+			this.setPredefinedKeyValue("type", "unicast");	
+	}
+	
+	public void setDeviceToken(String token) throws Exception {
+    	setPredefinedKeyValue("device_tokens", token);
+    }
+}

+ 40 - 0
4dkankan-utils-dingtalk/pom.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>4dkankan-utils</artifactId>
+        <groupId>com.fdkankan</groupId>
+        <version>2.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>4dkankan-utils-dingtalk</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-common-utils</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+        </dependency>
+        <!-- 钉钉sdk -->
+        <dependency>
+            <groupId>com.dingtalk.open</groupId>
+            <artifactId>taobao-sdk-java-auto</artifactId>
+            <version>1479188381469-20211020</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 71 - 0
4dkankan-utils-dingtalk/src/main/java/com/fdkankan/dingtalk/DingTalkSendUtils.java

@@ -0,0 +1,71 @@
+package com.fdkankan.dingtalk;
+
+import com.dingtalk.api.DefaultDingTalkClient;
+import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.OapiRobotSendRequest;
+import com.dingtalk.api.response.OapiRobotSendResponse;
+import com.fdkankan.common.util.Base64Converter;
+import com.taobao.api.ApiException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+@Component
+public class DingTalkSendUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(DingTalkSendUtils.class);
+
+    private static String token;
+
+    private static String secret="SECca5af660ed882a67d8bda469095bf8454831528bd25bc7b1a3ff5f686109b9e5";
+
+    @Value("${dingtalk.token:e712c41d917b303e21c1550ad9966b33dad874043f2f73fb347dce67a0a201bc}")
+    public void setToken(String token) {
+        DingTalkSendUtils.token = token;
+    }
+
+    @Value("${dingtalk.secret:SECca5af660ed882a67d8bda469095bf8454831528bd25bc7b1a3ff5f686109b9e5}")
+    public void setSign(String secret) {
+        DingTalkSendUtils.secret = secret;
+    }
+
+
+    public void sendActioncardMsgToDingRobot(String content,String title) throws ApiException, UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
+        Long timestamp = System.currentTimeMillis();
+        String sign = getSign(timestamp);
+        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?" +
+                "access_token="+token +
+                "&timestamp=".concat(String.valueOf(timestamp)).concat("&sign=").concat(sign));
+        OapiRobotSendRequest request = new OapiRobotSendRequest();
+        request.setMsgtype("actionCard");
+        OapiRobotSendRequest.Actioncard actioncard = new OapiRobotSendRequest.Actioncard();
+        actioncard.setTitle(title);
+        actioncard.setText(content);
+        request.setActionCard(actioncard);
+        OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
+        at.setAtMobiles(new ArrayList<>(0));
+        // isAtAll类型如果不为Boolean,请升级至最新SDK
+        at.setIsAtAll(true);
+        request.setAt(at);
+        OapiRobotSendResponse re = client.execute(request);
+        System.out.println(re.getBody());
+    }
+
+    public static String getSign(Long timestamp) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
+        String stringToSign = timestamp + "\n" + secret;
+        Mac mac = Mac.getInstance("HmacSHA256");
+        mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
+        byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+        System.out.println(new String(signData));
+        return URLEncoder.encode(Base64Converter.encode(signData));
+    }
+}

+ 2 - 0
pom.xml

@@ -10,6 +10,8 @@
         <module>4dkankan-utils-redis</module>
         <module>4dkankan-utils-fyun</module>
         <module>4dkankan-utils-sms</module>
+        <module>4dkankan-utils-app-push</module>
+        <module>4dkankan-utils-dingtalk</module>
     </modules>
 
     <groupId>com.fdkankan</groupId>