第一步 初始化firebaseAdminSDK
引入依赖
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>6.8.1</version>
</dependency>
初始化
@Component
@Slf4j
@Order(1)
public class FireBaseConfig implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
init();
}
private void init() throws IOException {
//协议开放 克服握手错误
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
log.info("协议开放成功:",System.getProperty("https.protocols"));
//firebase初始化
ClassPathResource classPathResource = new ClassPathResource("{firebase下发的json}");
InputStream inputStream = classPathResource.getInputStream();
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(inputStream))
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")//
.build();
FirebaseApp.initializeApp(options);
log.info("firebase初始化成功!!!");
}
}
firebaseUtils
package com.hengde.lit.producers.business.common.util;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.Bucket;
import com.google.common.collect.Lists;
import com.google.firebase.auth.*;
import com.google.firebase.cloud.StorageClient;
import com.google.firebase.messaging.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
* @Author fanqiang
* @Date 2019/7/10 11:56
**/
@Slf4j
public class FirebaseUtils {
private static FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
/**
* 系统标识符
*/
public static final String COLLAPSEKEY_SYSTEM = "collApseKey_system";
/**
* 系统主题
*/
public static final String TOPIC_SYSTEM = "topic_system";
/*********************************************************************
* 用户基本操作
********************************************************************/
/**
* 功能描述:
* <根据uid查找firebase用户>
*
* @Param: [uid]
* @return: com.google.firebase.auth.UserRecord
* @Author: FanQiang
* @Date: 2019/7/10
*/
public static UserRecord getUserByUid(Long uid) throws FirebaseAuthException {
return firebaseAuth.getUser(uid.toString());
}
/**
* 功能描述:
* <根据email查找firebase用户>
*
* @Param: [email]
* @return: com.google.firebase.auth.UserRecord
* @Author: FanQiang
* @Date: 2019/7/10
*/
public static UserRecord getUserByEmail(String email) throws FirebaseAuthException {
return firebaseAuth.getUserByEmail(email);
}
/**
* 功能描述:
* <查询firebase全部用户>
*
* @Param: []
* @return: java.util.List<com.google.firebase.auth.UserRecord>
* @Author: FanQiang
* @Date: 2019/7/10
*/
public static List<UserRecord> findAllUser() throws FirebaseAuthException {
List<UserRecord> userRecords = new ArrayList<>();
ListUsersPage page = firebaseAuth.listUsers(null);
while (page != null) {
for (ExportedUserRecord user : page.getValues()) {
userRecords.add(user);
}
page = page.getNextPage();
}
return userRecords;
}
/**
* 功能描述:
* <创建firebase用户>
*
* @Param: [uid, userName, email, avatar]
* @return: com.google.firebase.auth.UserRecord
* @Author: FanQiang
* @Date: 2019/7/10
*/
public static UserRecord createUser(Long uid, String userName, String email, String avatar) throws FirebaseAuthException {
UserRecord.CreateRequest createRequest = new UserRecord.CreateRequest()
.setDisplayName(userName).setUid(uid.toString()).setEmail(email)
.setPhotoUrl(avatar).setEmailVerified(false).setDisabled(false);
return firebaseAuth.createUser(createRequest);
}
public static UserRecord updateUser(Long uid, String userName, String email, String avatar) throws FirebaseAuthException {
UserRecord.UpdateRequest request = new UserRecord.UpdateRequest(uid.toString());
if (!StringUtils.isEmpty(userName)) {
request.setDisplayName(userName);
}
if (!StringUtils.isEmpty(avatar)) {
request.setPhotoUrl(avatar);
}
if (!StringUtils.isEmpty(email)) {
request.setEmail(email);
}
request.setDisabled(false)
.setEmailVerified(false);
return firebaseAuth.updateUser(request);
}
/**
* 功能描述:
* <删除firebase用户>
*
* @Param: [uid]
* @return: void
* @Author: FanQiang
* @Date: 2019/7/10
*/
public static void deleteUser(Long uid) throws FirebaseAuthException {
firebaseAuth.deleteUser(uid.toString());
}
/**
* 通用消息推送 单条消息 向单个用户推送
*
* @param title
* @param body
* @param registrationToken 用户设备令牌
* @param collapseKey 消息标识符
* @param datas 额外参数 k-v
*/
public static String sendMsgToToken(String title, String body, String registrationToken, String collapseKey,Map<String,String> datas) {
Message message = getBuilder(title, body, collapseKey,datas)
.setToken(registrationToken)
.build();
return send(message);
}
/**
* 通用消息推送 向多个用户推送
*
* @param title
* @param body
* @param registrationTokens 用户设备令牌
* @param collapseKey 消息标识符
* @param datas 额外参数 k-v
*/
public static void sendMsgToTokens(String title, String body, List<String> registrationTokens, String collapseKey,Map<String,String> datas) throws FirebaseMessagingException {
MulticastMessage message = getMulticastBuilder(title,body,collapseKey,datas)
.addAllTokens(registrationTokens)
.build();
BatchResponse response = FirebaseMessaging.getInstance().sendMulticast(message);
if (response.getFailureCount() > 0) {
List<SendResponse> responses = response.getResponses();
List<String> failedTokens = new ArrayList<>();
for (int i = 0; i < responses.size(); i++) {
if (!responses.get(i).isSuccessful()) {
// The order of responses corresponds to the order of the registration tokens.
failedTokens.add(registrationTokens.get(i));
}
}
log.info("List of tokens that caused failures: " + failedTokens);
}
}
/**
* 通用消息推送 主题消息 订阅该主题的用户全部可以接收到
*
* @param collapseKey 一组消息的标识符,这组消息可以折叠,以便当恢复传送时只发送最后一条消息。在任意给定时间最多允许 4 个不同的折叠键。
* @param topic 要将消息发送至的主题名称。该主题名称不能包含 /topics/ 前缀。
* @param title
* @param body
* @param datas 额外参数 k-v
*/
/*----------------------------------关于anps的headers配置说明---------------------------------------*/
/* authorization
授权APN发送指定主题的推送通知的提供者令牌。令牌采用Base64URL编码的JWT格式,指定为bearer <provider token>。
使用提供程序证书建立连接时,将忽略此请求标头。
apns-id
标识通知的规范UUID。如果发送通知时出错,则APN使用此值来标识通知您的服务器。
规范形式是32个小写十六进制数字,显示在由8-4-4-4-12形式的连字符分隔的五个组中。示例UUID如下:
123e4567-e89b-12d3-a456-42665544000
如果省略此标头,则APN会创建一个新的UUID并在响应中返回。
apns-expiration
以星期(UTC)表示的UNIX纪元日期。此标头标识通知不再有效的日期,可以将其丢弃。
如果此值非零,则APN会存储通知并尝试至少传递一次,如果第一次无法传递通知,则会根据需要重复尝试。如果值为0,则APN将通知视为立即过期,并且不存储通知或尝试重新发送通知。
apns-priority
通知的优先级。指定以下值之一:
10 - 立即发送推送消息。具有此优先级的通知必须在目标设备上触发警报,声音或徽章。将此优先级用于仅包含content-available密钥的推送通知是错误的。
5 - 在考虑设备功率考虑因素的时间发送推送消息。具有此优先级的通知可能会分组并以突发方式传递。它们受到限制,在某些情况下不会被交付。
如果省略此标头,则APNs服务器将优先级设置为10。
apns-topic
远程通知的主题,通常是应用程序的软件包ID。您在开发人员帐户中创建的证书必须包含此主题的功能。
如果您的证书包含多个主题,则必须为此标题指定值。
如果省略此请求标头,并且您的APNs证书未指定多个主题,则APNs服务器将证书的主题用作默认主题。
如果使用提供者令牌而不是证书,则必须为此请求标头指定值。您应该为开发人员帐户中指定的团队配置您提供的主题。
apns-collapse-id
具有相同折叠标识符的多个通知作为单个通知显示给用户。该密钥的值不得超过64个字节。有关更多信息,请参阅服务质量,存储转发和合并通知。*/
public static void sendMsg(String collapseKey, String topic, String title, String body,Map<String,String> datas) {
Message message = getBuilder(title, body, collapseKey,datas)
.setTopic(topic)
.build();
send(message);
}
/**
* 安卓消息推送 主题订阅模式
*
* @param collapseKey 一组消息的标识符,这组消息可以折叠,以便当恢复传送时只发送最后一条消息。在任意给定时间最多允许 4 个不同的折叠键。
* @param topic 要将消息发送至的主题名称。该主题名称不能包含 /topics/ 前缀。
* @param title
* @param body
*/
public static void sendMsgByAndroid(String collapseKey, String topic, String title, String body) {
Message message = Message.builder()
.setAndroidConfig(AndroidConfig.builder()
.setTtl(3600 * 1000)//消息的生存时间
.setCollapseKey(collapseKey)
.setPriority(AndroidConfig.Priority.HIGH)//消息优先级。必须是 normal 和 high 中的一个。
.setNotification(AndroidNotification.builder()
.setTitle(title)
.setBody(body)
.build())
.build())
.setTopic(topic)
.build();
send(message);
}
private static String send(Message message) {
String response = null;
try {
response = FirebaseMessaging.getInstance().sendAsync(message).get();
System.out.println("run successful: " + response);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return response;
}
/**
* IOS推送 主题订阅模式
*
* @param collapseKey 一组消息的标识符,这组消息可以折叠,以便当恢复传送时只发送最后一条消息。在任意给定时间最多允许 4 个不同的折叠键。
* @param topic 要将消息发送至的主题名称。该主题名称不能包含 /topics/ 前缀。
* @param title
* @param body
*/
public static void sendMsgByIOS(String collapseKey, String topic, String title, String body) {
Message message = Message.builder()
.setApnsConfig(ApnsConfig.builder()
.putHeader("apns-priority", "10")
.putHeader("apns-collapse-id", collapseKey)
.setAps(Aps.builder()
.setAlert(ApsAlert.builder()
.setTitle(title)
.setBody(body)
.build())
.setBadge(42)
.build())
.build())
.setTopic(topic)
.build();
send(message);
}
/**
* 功能描述:
* <创建主题订阅>
*
* @Param: [registrationTokens, topic]
* @return: com.google.firebase.messaging.TopicManagementResponse
* @Author: FanQiang
* @Date: 2019/8/5
*/
public static void subscribeToTopic(List<String> registrationTokens, String topic) throws
FirebaseMessagingException {
List<List<String>> lists = splitList(registrationTokens, 1000);
for (List<String> tokens : lists) {
TopicManagementResponse response = FirebaseMessaging.getInstance().subscribeToTopic(tokens, topic);
log.info(response.getSuccessCount() + " tokens were subscribed successfully");
}
}
/**
* 功能描述:
* <退订主题订阅>
*
* @Param: [registrationTokens, topic]
* @return: com.google.firebase.messaging.TopicManagementResponse
* @Author: FanQiang
* @Date: 2019/8/5
*/
public static void unsubscribeFromTopic(List<String> registrationTokens, String topic) throws
FirebaseMessagingException {
List<List<String>> lists = splitList(registrationTokens, 1000);
for (List<String> tokens : lists) {
TopicManagementResponse response = FirebaseMessaging.getInstance().unsubscribeFromTopic(
tokens, topic);
// See the TopicManagementResponse reference documentation
// for the contents of response.
log.info(response.getSuccessCount() + " tokens were unsubscribed successfully");
}
}
private static List<List<String>> splitList(List<String> list, int groupSize) {
int length = list.size();
// 计算可以分成多少组
int num = (length + groupSize - 1) / groupSize; // TODO
List<List<String>> newList = new ArrayList<>(num);
for (int i = 0; i < num; i++) {
// 开始位置
int fromIndex = i * groupSize;
// 结束位置
int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
newList.add(list.subList(fromIndex, toIndex));
}
return newList;
}
private static Message.Builder getBuilder(String title, String body, String collapseKey, Map<String,String> map) {
return Message.builder()
.setNotification(new Notification(
title,
body))
.setAndroidConfig(AndroidConfig.builder()
.setTtl(3600 * 1000)
.setCollapseKey(collapseKey)
.setPriority(AndroidConfig.Priority.HIGH)
.setNotification(AndroidNotification.builder()
.setTitle(title)
.setBody(body)
.build())
.build())
.setApnsConfig(ApnsConfig.builder()
.putHeader("apns-priority", "10")
.putHeader("apns-collapse-id", collapseKey)
.setAps(Aps.builder()
.setBadge(42)
.build())
.build()).putAllData(map);
}
private static MulticastMessage.Builder getMulticastBuilder(String title, String body, String collapseKey,Map<String,String> map) {
return MulticastMessage.builder()
.setNotification(new Notification(
title,
body))
.setAndroidConfig(AndroidConfig.builder()
.setTtl(3600 * 1000)
.setCollapseKey(collapseKey)
.setPriority(AndroidConfig.Priority.HIGH)
.setNotification(AndroidNotification.builder()
.setTitle(title)
.setBody(body)
.build())
.build())
.setApnsConfig(ApnsConfig.builder()
.putHeader("apns-priority", "10")
.putHeader("apns-collapse-id", collapseKey)
.setAps(Aps.builder()
.setBadge(42)
.build())
.build()).putAllData(map);
}
}