由于集成FCM的国内应用不是很多,导致网上解决问题的方法也很少,所以特此记录一下.
首先就是去Firebase 创建应用什么的这一步就不说了,需要用到的就是他的 google-service.json 文件,关于这个文件一定不要搞错了,想要知道怎么创建的话可以参考官方文档就可以( 需翻墙 )
说一下如何将FCM集成到Android项目
首先在根级别的build.gradle
文件添加一条规则。以包含Google服务插件
// ...
dependencies {
// ...
classpath 'com.google.gms:google-services:4.3.3'
}
然后在模块Gradle文件中,底部
添加apply plugin
行,以启用 Gradle 插件:由于这些firebase版本号是相互扶持依赖的所以如果只更改某一个版本号的话会造成编译失败的问题,需要去找对版本号可以兼容的相互版本来引入,以下是我自己的版本号,可以拿来用如果您的项目有其他的需求此版本号不支持的话
android {
// ...
}
dependencies {
// ...
implementation 'com.google.firebase:firebase-core:18.0.0'
implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.google.firebase:firebase-analytics:18.0.0'
implementation 'com.google.firebase:firebase-invites:17.0.0'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
releaseImplementation 'com.google.firebase:firebase-perf:19.0.10'
implementation 'com.google.firebase:firebase-appindexing:19.1.0'
}
// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
设置FCM客户端
- 自定义
MyFirebaseMessagingService
继承FirebaseMessagingService
,重写onMessageReceived
方法接收通知消息弹通知栏,FCM有两种消息,data message和 notification message,notification只有在后台的时候才会走这个方法,data message不管在后台还是前台都会走这个方法。
以下是官方的解释:
- 自定义
MyFirebaseInstanceIDService
集成FirebaseInstanceIdService
用户token的创建,转换和更新,在onTokenRefresh()
方法中获取token并上传到服务器。 - 获取token:
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(refreshedToken);
在AndroidManifest文件中配置:
<service
android:name="packagename.MyFirebaseMessagingService"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
MyFirebaseMessagingService.java文件
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private final static String TAG = MyFirebaseMessagingService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Timber.i("onCreate");
}
@Override
public void onDestroy() {
super.onDestroy();
Timber.i("onDestroy");
}
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
@Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
FirebaseMessageToken firebaseMessageToken = new FirebaseMessageToken();
firebaseMessageToken.setToken(token);
if (TextUtils.isEmpty(SPStaticUtils.getString(SPKeys.USER_TOKEN))) {
return;
}
//上传 token
HttpManager.getInstance().uploadFirebaseMessageToken(firebaseMessageToken)
.subscribeOn(Schedulers.io())
.safeSubscribe(new Observer<FirebaseMessageTokenResponse>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(FirebaseMessageTokenResponse firebaseMessageTokenResponse) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
//这个方法之后再前台的时候会响应
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (SPStaticUtils.getInt(SPKeys.USER_ID) <= 0) {
return;
}
if (remoteMessage.getNotification() == null || remoteMessage.getData() == null) return;
Timber.d("Message data: %s", remoteMessage.getData());
Timber.d("Message Notification Body: %s", remoteMessage.getNotification().getBody());
Timber.d("Message Notification Title: %s", remoteMessage.getNotification().getTitle());
JSONObject data = new JSONObject(remoteMessage.getData());
try {
data.put("body", remoteMessage.getNotification().getBody());
data.put("title", remoteMessage.getNotification().getTitle());
} catch (JSONException e) {
e.printStackTrace();
}
int type = data.optInt("type", 0);
//以下是自己的一些操作
switch (type) {
case Notiype.FCM_OFFICIAL_HOOKAR_TYPE:
case Notiype.FCM_OFFICIAL_PERSONAL_TYPE:
EventBus.getDefault().post(1, EventBusTags.ON_OFFICIAL_PUSH_RECEIVED);
break;
}
//自定义Notification提示
NotificationControl.getInstance(Utils.getApp()).messageReceived(data);
}
@Override
public void onDeletedMessages() {
super.onDeletedMessages();
}
}
至此FCM可以说是已经集成完成了,主要说一下会遇到的问题有哪些
- 推送消息只有当应用在后台或者杀死的情况下会推送到状态栏,当应用在前台运行的时候就需要用到上面代码的方法了,可以自己将推送数据写进Notification
- app收不到离线推送的消息,这个问题本质的原因就是因为你的手机是国内的手机,因为按照安卓系统的逻辑,如果一个 app 被"force stop",那么就不应该被任何行为唤醒,那么自然也就不应该收到通知.事实上大部份国外应用,按 home 键或者划掉,都不会后台常驻,而是留下缓存进程,这样就能收到 fcm 通知.所以归根结底还是国内环境给你的错觉.---------如果条件允许的情况下建议直接采购一个国外的手机回来,这样可以保证每个推送消息都可以 ,如果是国内的手机的话必须得打开google service 才可以而且到达率低的可怜
- 当应用在后台,点击状态栏却收不到数据,这个问题也是我在困扰的,因为这方面的资料实在是太少了,查了几天官网和问题,所有的解决方案都指向 click_action 这个参数,但是我这边一直还是获取不到数据,所以不了了之,感兴趣的话可以再找一下顺便如果找到的话也给我说一下谢谢
- 关于怎么测试国内的手机是否可用,这个可以利用facebook的推送,可以在手机上安装登录facebook账号,让另一个人给你的facebook账号发消息,如果你在杀死facebook后台的情况下还可以收到消息推送的话,一般而言你的手机测试FCM推送是没有问题的
- 关于在哪里可以拿到点击状态栏之后的数据 在启动页的onCreate 或者 onResume方法中 方法如下
Bundle extras = intent.getExtras();
Set<String> keySet = extras.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
Object value = extras.get(key);
LogUtils.e("key:"+key + ",value:" + value);
}
暂时能想到的问题就这么多,后续想到的话再补充
date:2020.09.18 17:08:21 (周五 北京 晴)