欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

firebase推送工具类 (Android iOS通用) java服务端

程序员文章站 2022-07-13 16:51:30
...

第一步   初始化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 *
 * @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: *
     * @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: *
     * @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: *
     * @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: *
     * @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: *
     * @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: *
     * @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: *
     * @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);
    }
}