# Integrate_Google_GcmFcmAndMap
**Repository Path**: stanhe/Integrate_Google_GcmFcmAndMap
## Basic Information
- **Project Name**: Integrate_Google_GcmFcmAndMap
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-03-12
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 配置GCM 、FCM 、 Google-Map (全程科学上网)
## 1. API
[API管理器(配置入口)](https://console.developers.google.com/apis/library?project=hauyan-8b259)

---
## 2. GCM
[真のGCM文档](https://developers.google.com/cloud-messaging/gcm?hl=zh-cn)
通过 API管理器 进入的是FCM 的配置文档,FCM 兼容GCM 同时更加简洁,并提供更多的可用服务。
以下配置参照[GCM设置文档](https://developers.google.com/cloud-messaging/android/client?hl=zh-cn)和 [GoogleSamples](https://github.com/googlesamples/google-services/tree/master/android/gcm/app/src/main/java/gcm/play/android/samples/com/gcmquickstart),找代码也是一个复杂的过程,索性一并贴出。
### 2.1 Set up a GCM Client App on Android
[GCM Clients 传送门](https://developers.google.com/cloud-messaging/android/client?hl=zh-cn)
假设你的设备支持GCM,这里有一份缩减版:
### 2.1.1.在Firebase控制台注册
对应文档(Create an API project)
1.[注册项目](https://console.firebase.google.com/?hl=zh-cn),已有相关项目点击导入.没有点击新建.
2.点击添加Firebase到你的应用,然后继续,注意包名,一定要对应app的build.gradle中的applicationId,SHA1(android studio 右边gradle task面板 :app-->Tasks-->android-->signingReport 或者:Android studio 下方控制台 ./gradlew signingReport),完成后下载配置文件。如果要重新下载配置文件:项目右上角->管理->下载最新配置文件(下载该项目的google-servers.json)
3.将下载好的google-services.json添加到app/目录下
### 2.1.2 配置project
对应文档(Add the configuration file to your project)
1.添加依赖到 project-level **build.gradle**:
```
classpath 'com.google.gms:google-services:3.0.0'
```
2.添加插件和依赖库到 app-level **build.gradle**
```
apply plugin: 'com.google.gms.google-services'
dependencies {
compile "com.google.android.gms:play-services-gcm:9.6.1"
}
```
注意插件是添加在顶部,不要放到Android内,依赖默认版本 9.6.1,编译不过建议改为 9.0.0
### 2.1.3
对应文档(Edit Your Application's Manifest)
1.添加权限 和 service
```
//support pre-4.4 KitKat devices
```
注意:< your-package-name > 这里要设置为gradle中的applicationId.
2.自定义service类及Activiy开启服务
从manifest中看到需要实现3个service类
PreferCode.java
```
public class PreferCode {
public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
public static final String REGISTRATION_COMPLETE = "registrationComplete";
}
```
MyGcmListenerService.java
```
public class MyGcmListenerService extends GcmListenerService {
public static final String TAG = "MyGcmListenerService";
/**
* Called when message is received.
*
* @param from SenderID of the sender.
* @param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
String message = "";
try {
if(data!=null) {
message = data.getString("message");
Log.d("received message", "From: " + from);
Log.d("received message", "Message: " + message);
}
}catch (Exception e){
e.printStackTrace();
}
if (from.startsWith("/topics/")) {
// message received from some topic.
} else {
// normal downstream message.
}
// [START_EXCLUDE]
/**
* Production applications would usually process the message here.
* Eg: - Syncing with server.
* - Store message in local database.
* - Update UI.
*/
/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
if (Paper.book().read(Utility.NOTIFICATION,Utility.NOTIFICATION_OPEN).equals(Utility.NOTIFICATION_OPEN) && !TextUtils.isEmpty(message))
sendNotification(message);
// [END_EXCLUDE]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* @param message GCM message received.
*/
private void sendNotification(String message) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.homepage_image)
.setContentTitle(getApplicationName(this))
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
public static String getApplicationName(Context context) {
int stringId = context.getApplicationInfo().labelRes;
return context.getString(stringId);
}
}
```
MyInstanceIDListenerService.java
```
public class MyInstanceIDListenerService extends InstanceIDListenerService {
public static final String TAG = "MyInstanceIDListenerService";
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. This call is initiated by the
* InstanceID provider.
*/
// [START refresh_token]
@Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
// [END refresh_token]
}
```
RegistrationIntentService.java
```
public class RegistrationIntentService extends IntentService{
public static final String TAG = "RegistrationIntentService";
private static final String[] TOPICS = {"global"};
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public RegistrationIntentService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
// [START register_for_gcm]
// Initially this call goes out to the network to retrieve the token, subsequent calls
// are local.
// R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
// See https://developers.google.com/cloud-messaging/android/start for details on this file.
// [START get_token]
InstanceID instanceID = InstanceID.getInstance(getApplicationContext());
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// [END get_token]
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);
// Subscribe to topic channels
subscribeTopics(token);
// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
sharedPreferences.edit().putBoolean(PreferCode.SENT_TOKEN_TO_SERVER, true).apply();
// [END register_for_gcm]
} catch (Exception e) {
Log.i(TAG, "Failed to complete token refresh", e);
// If an exception happens while fetching the new token or updating our registration data
// on a third-party server, this ensures that we'll attempt the update at a later time.
sharedPreferences.edit().putBoolean(PreferCode.SENT_TOKEN_TO_SERVER, false).apply();
}
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(PreferCode.REGISTRATION_COMPLETE);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
/**
* Persist registration to third-party servers.
*
* Modify this method to associate the user's GCM registration token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private void sendRegistrationToServer(String token) {
Map params = new HashMap<>();
params.put("device","android");
params.put("token",token);
HttpUtils.simplePost(Api.sendToken, this, params, new RequestCBK() {
@Override
public void onResponse(JSONObject response) {
Log.i(TAG,response.toString());
}
@Override
public void onErrorResponse() {
}
});
}
/**
* Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
*
* @param token GCM token
* @throws IOException if unable to reach the GCM PubSub service
*/
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
GcmPubSub pubSub = GcmPubSub.getInstance(this);
for (String topic : TOPICS) {
pubSub.subscribe(token, "/topics/" + topic, null);
}
}
// [END subscribe_topics]
}
```
Acitivity中设置监听开启服务
```
public class MainActivity extends AppCompatActivity {
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private static final String TAG = "MainActivity";
private BroadcastReceiver mRegistrationBroadcastReceiver;
private ProgressBar mRegistrationProgressBar;
private TextView mInformationTextView;
private boolean isReceiverRegistered;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRegistrationProgressBar = (ProgressBar) findViewById(R.id.registrationProgressBar);
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
boolean sentToken = sharedPreferences
.getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
if (sentToken) {
mInformationTextView.setText(getString(R.string.gcm_send_message));
} else {
mInformationTextView.setText(getString(R.string.token_error_message));
}
}
};
mInformationTextView = (TextView) findViewById(R.id.informationTextView);
// Registering BroadcastReceiver
registerReceiver();
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
@Override
protected void onResume() {
super.onResume();
registerReceiver();
}
@Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
isReceiverRegistered = false;
super.onPause();
}
private void registerReceiver(){
if(!isReceiverRegistered) {
LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
isReceiverRegistered = true;
}
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show();
} else {
Log.i(TAG, "This device is not supported.");
finish();
}
return false;
}
return true;
}
}
```
---
## 3 FCM
添加FCM SDK到项目中。
获取google-services.json同GCM,**build.gradle** 配置和 **2.1.2** 略有不同
### 3.1 FCM gradle配置
首先,请向您的根级 build.gradle 文件添加一条规则,以包含 Google 服务插件:
```
buildscript {
// ...
dependencies {
// ...
classpath 'com.google.gms:google-services:3.0.0'
}
}
```
然后在您的模块 Gradle 文件(通常为 app/build.gradle)中,在文件底部添加 apply plugin 行,以启用 Gradle 插件:
```
apply plugin: 'com.android.application'
android {
// ...
}
dependencies {
// ...
compile 'com.google.firebase:firebase-core:9.6.1' // Firebase sdk
compile 'com.google.firebase:firebase-messaging:9.6.1' // FCM 依赖
}
// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
```
您还应为自己想使用的 [Firebase SDK](https://firebase.google.com/docs/android/setup) 添加依赖项
### 3.2 FCM Mainifests及类设置
下面是FCM的简洁之处 [示例](https://firebase.google.com/docs/samples/#android)
贴代码:
AndroidManifest.xml
```
//继承FirebaseMessagingService 的自定义类
//继承FirebaseInstanceIDService 的自定义类
```
可以看到需要自定义的实现类更少MyFirebaseMessagingService 和MyFirebaseInstanceIDService
MyFirebaseMessagingService.java
```
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
```
MyFirebaseInstanceIDService.java
```
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
/**
* 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.
*/
// [START refresh_token]
@Override
public void onTokenRefresh() {
// 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);
}
// [END refresh_token]
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* @param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
}
```
Activiy 中依然需要检测设备 方法同GCM Activity
再来看FCM中的Activity
```
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// If a notification message is tapped, any data accompanying the notification
// message is available in the intent extras. In this sample the launcher
// intent is fired when the notification is tapped, so any accompanying data would
// be handled here. If you want a different intent fired, set the click_action
// field of the notification message to the desired intent. The launcher intent
// is used when no click_action is specified.
//
// Handle possible data accompanying notification message.
// [START handle_data_extras]
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d(TAG, "Key: " + key + " Value: " + value);
}
}
// [END handle_data_extras]
Button subscribeButton = (Button) findViewById(R.id.subscribeButton);
subscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// [START subscribe_topics]
FirebaseMessaging.getInstance().subscribeToTopic("news");
// [END subscribe_topics]
// Log and toast
String msg = getString(R.string.msg_subscribed);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
Button logTokenButton = (Button) findViewById(R.id.logTokenButton);
logTokenButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Get token
String token = FirebaseInstanceId.getInstance().getToken();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
}
```
不需要自行监测服务
至此GCM和FCM的APP端就都以配置完成,保证测试机科学上网,便可以通过FCM控制台推送消息测试。下面是配置过程中可能遇到的问题和一些解决方法。
1.是否配置正确,首先看应用中是否能取得token,不能-->确定所有需要包名的地方填写了正确的包名,确认科学上网。
2.不能接收到通知,参照1.
---
## 4 Google Map
[Map API](https://developers.google.com/maps/documentation/android-api/?hl=zh_CN)
[配置](https://developers.google.com/maps/documentation/android-api/signup)
### 4.1 在 Google Developers Console 中创建 API 项目
[启用API](https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID)

注:来自 Google 地图 Android v1 应用的现有密钥通常称为 MapView,它们无法与 v2 API 配合使用。 Google Maps Android API 采用了全新的密钥管理系统。
### 4.2 向您的应用添加 API 密钥
1.在 AndroidManifest.xml 中,通过在 结束标记前插入以下元素,将其添加为 元素的子元素:
```
```
用您的 API 密钥替代 value 属性中的 YOUR_API_KEY。该元素会将密钥 com.google.android.geo.API_KEY 设置为您的 API 密钥的值。
注:如上所示,com.google.android.geo.API_KEY 是建议使用的 API 密钥元数据名称。可使用具有该名称的密钥向 Android 平台上的多个基于 Google Maps 的 API(包括 Google Maps Android API)验证身份。出于向后兼容性上的考虑,该 API 还支持 com.google.android.maps.v2.API_KEY 名称。该旧有名称只允许向 Android Maps API v2 验证身份。应用只能指定其中一个 API 密钥元数据名称。如果两个都指定,API 会抛出异常。
### 4.3 [导入](https://developers.google.com/maps/documentation/android-api/map)和特殊显示的[samples](https://github.com/googlemaps/android-samples/tree/master/ApiDemos/app/src/main/java/com/example/mapdemo)
File--> new--> Google-->Google Maps Activity
自动导入依赖和mainifest配置,这里manifests文件需要手动合并,依赖默认导入最新版本,编译不过建议 9.0.0。之后可以自己手动调整