Firebase FCM 官方文档:群发Push的时候使用的是:
FirebaseMessaging.getInstance().sendMulticast(message);
or:
FirebaseMessaging.getInstance().sendAll(messages);
Firebase新版本中发现上面两个方法已经弃用了,并且在强行调用的时候会报错:No enum constant com.google.firebase.ErrorCode.UNIMPLEMENTED
java.lang.IllegalArgumentException: No enum constant com.google.firebase.ErrorCode.UNIMPLEMENTED
at java.lang.Enum.valueOf(Enum.java:238)
at com.google.firebase.messaging.FirebaseMessagingClientImpl$MessagingBatchCallback.createFirebaseException(FirebaseMessagingClientImpl.java:271)
at com.google.firebase.messaging.FirebaseMessagingClientImpl$MessagingBatchCallback.onFailure(FirebaseMessagingClientImpl.java:258)
at com.google.firebase.messaging.FirebaseMessagingClientImpl$MessagingBatchCallback.onFailure(FirebaseMessagingClientImpl.java:243)
at com.google.api.client.googleapis.batch.BatchUnparsedResponse.parseAndCallback(BatchUnparsedResponse.java:209)
at com.google.api.client.googleapis.batch.BatchUnparsedResponse.parseNextResponse(BatchUnparsedResponse.java:149)
at com.google.api.client.googleapis.batch.BatchRequest.execute(BatchRequest.java:269)
at com.google.firebase.messaging.FirebaseMessagingClientImpl.sendBatchRequest(FirebaseMessagingClientImpl.java:138)
at com.google.firebase.messaging.FirebaseMessagingClientImpl.sendAll(FirebaseMessagingClientImpl.java:118)
at com.google.firebase.messaging.FirebaseMessaging$3.execute(FirebaseMessaging.java:512)
at com.google.firebase.messaging.FirebaseMessaging$3.execute(FirebaseMessaging.java:509)
at com.google.firebase.internal.CallableOperation.call(CallableOperation.java:36)
at com.google.firebase.messaging.FirebaseMessaging.sendAll(FirebaseMessaging.java:388)
at com.google.firebase.messaging.FirebaseMessaging.sendMulticast(FirebaseMessaging.java:467)
at com.google.firebase.messaging.FirebaseMessaging.sendMulticast(FirebaseMessaging.java:438)
at com.example.firebaseserver.utils.FireBaseUtil.pushBatch(FireBaseUtil.java:367)
at com.example.firebaseserver.control.FirebaseController.pushBatch(FirebaseController.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
遇到这个问题第一时间也是有点懵,根据报错日志去跟踪Firebase admin sdk源码,也没有找出报错的原因:
于是就去Google 搜索:No enum constant com.google.firebase.ErrorCode.UNIMPLEMENTED
发现确实好多人遇到这个问题,同时Github : firebase-admin-java 还有人提出了Issues,下面也没找到有用的答案,无奈继续看源码。
既然sendMulticast()和sendAll弃用了,代码中一定会告诉新的方法,可是查看了源码,有些失望:
这里只告诉了我们该方法已弃用,但是没有告诉我们替代的方法是哪个,于是接着在文档中查找可可能的新方法,功夫不负有心人,终于测试出来了,最后发现:
如果一条信息同时给多人群发,可以使用:
public BatchResponse sendEachForMulticast(@NonNull MulticastMessage message) throws FirebaseMessagingException {
return this.sendEachForMulticast(message, false);
}
public BatchResponse sendEachForMulticast(@NonNull MulticastMessage message, boolean dryRun) throws FirebaseMessagingException {
Preconditions.checkNotNull(message, "multicast message must not be null");
return this.sendEach(message.getMessageList(), dryRun);
}
public ApiFuture<BatchResponse> sendEachForMulticastAsync(@NonNull MulticastMessage message) {
return this.sendEachForMulticastAsync(message, false);
}
public ApiFuture<BatchResponse> sendEachForMulticastAsync(@NonNull MulticastMessage message, boolean dryRun) {
Preconditions.checkNotNull(message, "multicast message must not be null");
return this.sendEachAsync(message.getMessageList(), dryRun);
}
如果一次推送多条不同的Push 消息,可以使用:
public BatchResponse sendEach(@NonNull List<Message> messages) throws FirebaseMessagingException {
return this.sendEach(messages, false);
}
public BatchResponse sendEach(@NonNull List<Message> messages, boolean dryRun) throws FirebaseMessagingException {
try {
return (BatchResponse)this.sendEachOpAsync(messages, dryRun).get();
} catch (ExecutionException | InterruptedException var4) {
throw new FirebaseMessagingException(ErrorCode.CANCELLED, SERVICE_ID);
}
}
public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages) {
return this.sendEachOpAsync(messages, false);
}
public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages, boolean dryRun) {
return this.sendEachOpAsync(messages, dryRun);
}
private ApiFuture<BatchResponse> sendEachOpAsync(List<Message> messages, boolean dryRun) {
List<Message> immutableMessages = ImmutableList.copyOf(messages);
Preconditions.checkArgument(!immutableMessages.isEmpty(), "messages list must not be empty");
Preconditions.checkArgument(immutableMessages.size() <= 500, "messages list must not contain more than 500 elements");
List<ApiFuture<SendResponse>> list = new ArrayList();
Iterator var5 = immutableMessages.iterator();
while(var5.hasNext()) {
Message message = (Message)var5.next();
ApiFuture<SendResponse> messageId = this.sendOpForSendResponse(message, dryRun).callAsync(this.app);
list.add(messageId);
}
ApiFuture<List<SendResponse>> responsesFuture = ApiFutures.allAsList(list);
return ApiFutures.transform(responsesFuture, (responses) -> {
return new BatchResponseImpl(responses);
}, MoreExecutors.directExecutor());
}
总结:如果大家使用FCM 群发消息,可以使用:sendEach()
, sendEachAsync()
, sendEachForMulticast()
, and sendEachForMulticastAsync()。
作为Firebase GDE 一员,也积极的把这个问题反馈给 Google Firebase研发团队,及时更新官方文档,过时那里代码加个新方法的替代注释。也期待Firebase的新版本。
最后把这个解决方案也放在了Firebase-Admin-Java Issues上了