Fcm 으로 메시지를 수신하는 예제들은 많이 찾아 볼 수 있으나, 보내는 건 ? 그것도 안드로이드 앱으로 그런 예제는 없는 것 같아서 정리를 해 보겠다. 다만, 전체를 다 정리하는 것이 아니라 꼭 필요한 부분만...
- MainActivity 에 아래 함수를 넣고 앱이 실행 되는 동안에 처리를 하자.
- 목적은 allDevices 라는 것은 나중에 메시지 전송을 할 때 사용할 Topic 이다.
subscribeToTopoc 을 이용해서 내가 구동하는 메시지중에서 해당 Topic 으로 전송되는 것을 구독(?)할 수 있도록 등록을 해 두는 것이다.
- 두번째 목적은 getToken 함수를 이용해서 특정앱에게만 메시지를 보내고자 할 떄 token 값으로 구분 하여 메시지 수신자를 지정하기 위함이다.
public void onRegistryToken() {
FirebaseMessaging.getInstance().subscribeToTopic("allDevices")
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Log.e(TAG, "allDevices subscribed ...");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(getApplicationContext(), getString(R.string.nonSyncTopic), Toast.LENGTH_LONG).show();
}
});
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(@NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
getRegistryPhoneNumber(token);
}
});
}
2. 다음은 Message 전송을 위한 함수 코드을 만들어 두는 것이다.
- 아래는 전체 코드이고 package 이름만 숨김했다.
package com.bill..............tils;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.util.Log;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Scanner;
/**
Firebase 클라우드 메시징(FCM)을 사용하여 iOS, Android 및 웹의 클라이언트에 메시지를 보낼 수 있습니다.
이 샘플은 FCM을 사용하여 `news`를 구독하는 클라이언트에 두 가지 유형의 메시지를 보냅니다.
주제. 메시지의 한 유형은 단순 알림 메시지(디스플레이 메시지)입니다. 다른 하나는
플랫폼별 사용자 정의가 포함된 알림 메시지(알림 표시), 예를 들어,
iOS 장치로 전송되는 메시지에 배지가 추가됩니다.
*/
public class Messaging {
/**
* project_id 는 firebase 에 등록한 나의 project ID
*/
private static final String PROJECT_ID = "my-application-f80fb";
private static final String BASE_URL = "https://fcm.googleapis.com";
private static final String FCM_SEND_ENDPOINT = "/v1/projects/" + PROJECT_ID + "/messages:send";
private static final String MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
private static final String[] SCOPES = { MESSAGING_SCOPE };
private static final String TAG = "FCM Messaging";
public static String TITLE = "FCM Notification";
public static String BODY = "Notification from FCM";
public static String URL = "https://billcorea.tistory.com";
public static String IMAGEURL = "";
public static final String MESSAGE_KEY = "message";
public static String tokenExam = "fIkVvZbATHu6Ilv1PNhp_8:APA91bG2q8MmfQvNqeP5afzKZRuLsTu1Mu6MVuYXuGlBhhgXZ3QGvP5EjoUBhVmmaBsT3CTKwKpUy5odRhzp5N46NB01txhxOFTUZnP8-LwnUovCx3hMGqNZtYW9jZ7FT-kCV37m7V2r";
Context context ;
SharedPreferences sp ;
public Messaging(Context context) {
sp = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE) ;
this.context = context ;
}
/**
FCM REST에 대한 요청을 승인하는 데 사용할 수 있는 유효한 액세스 토큰을 검색합니다.
API.
*
* https://console.firebase.google.com/u/1/project/fcm.......40/settings/serviceaccounts/adminsdk
* 이 url 에서 비공개생성키 을 클릭 해서 생성된 파일은 assets 폴더에 넣는다.
* 파일 이름은 소문자로만 적용한다. (파일 이름이 너무 길면 줄이는 것이 좋다)
*
* @return Access token.
* @throws IOException
*/
// [START retrieve_access_token]
public String getAccessToken(Context context) throws IOException {
AssetManager assetManager = context.getAssets();
AssetFileDescriptor fileDescriptor = assetManager.openFd("fcmdemo.json");
FileInputStream fileInputStream = fileDescriptor.createInputStream();
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(fileInputStream)
.createScoped(Arrays.asList(SCOPES));
return googleCredentials.refreshAccessToken().getTokenValue();
}
// [END retrieve_access_token]
/**
* 검색 및 게시 모두에 사용할 수 있는 HttpURLConnection을 만듭니다.
*
* @return Base HttpURLConnection.
* @throws IOException
*/
public HttpURLConnection getConnection(Context context) throws IOException {
// [START use_access_token]
URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getAccessToken(context));
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;
// [END use_access_token]
}
/**
HTTP를 사용하여 FCM 메시지에 요청을 보냅니다.
UTF-8로 인코딩되고 특수 문자를 지원합니다.
*
* @param fcmMessage Body of the HTTP request.
* @throws IOException
*/
public void sendMessage(JsonObject fcmMessage, Context context) throws IOException {
HttpURLConnection connection = getConnection(context);
connection.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
writer.write(fcmMessage.toString());
writer.flush();
writer.close();
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
String response = inputstreamToString(connection.getInputStream());
Log.e(TAG, "Message sent to Firebase for delivery, response:");
Log.e(TAG, response);
} else {
Log.e(TAG, "Unable to send message to Firebase:");
String response = inputstreamToString(connection.getErrorStream());
Log.e(TAG, response);
}
}
/**
공통 FCM 필드를 사용하여 모든 사용자에게 알림 메시지를 보내는 메시지를 보냅니다.
플랫폼. 또한 플랫폼별 재정의는 메시지가 표시되는 방식을 사용자 지정하는 데 사용됩니다.
안드로이드와 iOS에서 받았습니다.
*
* @throws IOException
*/
public void sendOverrideMessage() throws IOException {
JsonObject overrideMessage = buildOverrideMessage();
Log.e(TAG, "FCM request body for override message:");
prettyPrint(overrideMessage);
sendMessage(overrideMessage, context);
}
/**
FCM 요청의 본문을 작성합니다. 이 본문은 공통 알림 개체를 정의합니다.
android 및 apns 개체를 사용하는 플랫폼별 사용자 정의도 가능합니다.
*
* @return JSON representation of the FCM request body.
*/
public JsonObject buildOverrideMessage() {
JsonObject jNotificationMessage = buildNotificationMessage();
JsonObject messagePayload = jNotificationMessage.get(MESSAGE_KEY).getAsJsonObject();
messagePayload.add("android", buildAndroidOverridePayload());
jNotificationMessage.add(MESSAGE_KEY, messagePayload);
return jNotificationMessage;
}
/**
* Android에서 메시지가 수신되는 방식을 사용자 지정하는 Android 페이로드를 빌드합니다.
*
* @return android payload of an FCM request.
*/
public JsonObject buildAndroidOverridePayload() {
/**
* 이부분은 notify 알림에 표시될 제목, 내용, 보여줄 이미지의 URL 경로
*/
JsonObject androidNotification = new JsonObject();
androidNotification.addProperty("body", BODY);
androidNotification.addProperty("title", TITLE);
androidNotification.addProperty("image", IMAGEURL);
/**
* 사용자 viewAcitivy 로 전달할 내용 과 URL
*
* FcmReceiveService 에서 URL, BODY 을 읽어서 ViewActivity 로 전달함.
*/
JsonObject data = new JsonObject();
data.addProperty("URL", URL);
data.addProperty("BODY", BODY);
JsonObject androidNotificationPayload = new JsonObject();
androidNotificationPayload.add("notification", androidNotification);
androidNotificationPayload.add("data", data);
return androidNotificationPayload;
}
/**
* iOS에서 메시지가 수신되는 방식을 사용자 지정하는 apns 페이로드를 빌드합니다.
*
* @return apns payload of an FCM request.
*/
public JsonObject buildApnsHeadersOverridePayload() {
JsonObject apnsHeaders = new JsonObject();
apnsHeaders.addProperty("apns-priority", "10");
return apnsHeaders;
}
/**
전송되는 메시지에 배지 필드를 추가할 앱 페이로드를 빌드합니다.
iOS 기기.
*
* @return JSON object with aps payload defined.
*/
public JsonObject buildApsOverridePayload() {
JsonObject badgePayload = new JsonObject();
badgePayload.addProperty("badge", 1);
JsonObject apsPayload = new JsonObject();
apsPayload.add("aps", badgePayload);
return apsPayload;
}
/**
* 등록된 장치에 전달하기 위해 FCM에 알림 메시지를 보냅니다.
*
* @throws IOException
*/
public void sendCommonMessage(Context context) throws IOException {
JsonObject notificationMessage = buildNotificationMessage();
Log.e(TAG, "FCM request body for message using common notification object:");
prettyPrint(notificationMessage);
sendMessage(notificationMessage, context);
}
/**
* 알림 메시지 요청의 본문을 구성합니다.
*
* @return JSON of notification message.
*/
public JsonObject buildNotificationMessage() {
/**
* notify 알림에 사용할 제목과 내용
*/
JsonObject jNotification = new JsonObject();
jNotification.addProperty("title", TITLE);
jNotification.addProperty("body", BODY);
JsonObject jMessage = new JsonObject();
if (sp.getBoolean("pushOne", false)) {
jMessage.addProperty("token", tokenExam);
} else {
jMessage.addProperty("topic", "allDevices");
}
jMessage.add("notification", jNotification);
JsonObject jFcm = new JsonObject();
jFcm.add(MESSAGE_KEY, jMessage);
return jFcm;
}
/**
* InputStream의 내용을 String으로 읽습니다.
*
* @param inputStream InputStream to read.
* @return String containing contents of InputStream.
* @throws IOException
*/
public String inputstreamToString(InputStream inputStream) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
Scanner scanner = new Scanner(inputStream);
while (scanner.hasNext()) {
stringBuilder.append(scanner.nextLine());
}
return stringBuilder.toString();
}
/**
* JsonObject를 예쁘게 인쇄하십시오.
*
* @param jsonObject JsonObject to pretty print.
*/
public void prettyPrint(JsonObject jsonObject) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Log.e(TAG, gson.toJson(jsonObject) + "\n");
}
}
이 소스는 사실 구글링을 통해서 github 에서 퍼온 자료인데, 한국어 번역만 구글 번역을 통해서 해 보았다.
이 소스에서 봐야할 부분은
- 서버인증을 위한 부분 인데... 여기서 중요한 것은 assetManager 의 자원을 가져오는 것이다. fcmdemo.json 이라고 적었는데, 그것은 firebase 의 프로젝트 설정에서 얻어온다. 이것을 얻어와서 저장을 하는 것은 FCM 전송을 위한 서버 구현을 하기 위해서는 FCM 에 인증을 받아야 하는데, 개발가이드를 보면 서버에 보내고 받고 하는 과정이 있어야 한다고 되어 있기도 하지만, 아래 함수를 이용해서 token 을 받아오면 서버 인증절차가 한번에 해소가 되는 것을 확인하였다.
public String getAccessToken(Context context) throws IOException {
AssetManager assetManager = context.getAssets();
AssetFileDescriptor fileDescriptor = assetManager.openFd("fcmdemo.json");
FileInputStream fileInputStream = fileDescriptor.createInputStream();
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(fileInputStream)
.createScoped(Arrays.asList(SCOPES));
return googleCredentials.refreshAccessToken().getTokenValue();
}
내 앱을 사용하기 위해서 구성한 firebase 의 프로젝트 설정에 보면 서비스 계정 이라고 있는데, 그곳에 보면 새 비공개키 생성이라고 버튼이 있다. 그 버튼을 클릭하면 기~인 이름의 json 파일 하나를 만들어 준다. 그럼 그것을 이름을 줄여서 저장하고.
내 앱 프로젝트에 assets 으로 넣어준다. 그런데, 여기서 하나 걸리는 부분이 그냥 넣어주고 빌드해 실행해 보면 오류가 발생한다.
json 파일이 들어 있는데, 찾을 수 없다는 것이다. 왜 ? 빌드를 하면 압축(?)을 하나 보다. 그래서 json 파일을 제대로 읽어서 처리를 할 수 없는 것이다. 그래서 앱의 gradle 설정에 다음과 같이 추가 하였다.
resources 는 noCompress 'json' 이라고... 압축을 하지 말라는 옵션이러니...
- 그 다음은 상수로 선언된 project-id : 이것은 나의 프로젝트 일반에 있는 것을 가져다 적는다.
/**
* project_id 는 firebase 에 등록한 나의 project ID
*/
private static final String PROJECT_ID = "my-application-f80fb";
그리고 인증을 하기 위해서는 HttpURLConnection 을 이용하고 있기 때문이기도 하지만, manifest 에 user-permission 을 설정해 주는 것도 있지는 말아야겠다.
다음은 메세지를 보내는 함수 부분인데, 난 android 로만 메시지를 전송할 것이라서 buildAndroidOverridePayload함수만 사용한다. 그리고 그안에서 전달하고자 하는 파라미터등을 설정한다. body, title, image, URL, BODY 을 key로 설정해서 전달하고자 하는 값을 넣어 준다. 값을 global 변수를 이용해서 넣을 수 도 있고... 뭐 암튼...
/**
FCM 요청의 본문을 작성합니다. 이 본문은 공통 알림 개체를 정의합니다.
android 및 apns 개체를 사용하는 플랫폼별 사용자 정의도 가능합니다.
*
* @return JSON representation of the FCM request body.
*/
public JsonObject buildOverrideMessage() {
JsonObject jNotificationMessage = buildNotificationMessage();
JsonObject messagePayload = jNotificationMessage.get(MESSAGE_KEY).getAsJsonObject();
messagePayload.add("android", buildAndroidOverridePayload());
jNotificationMessage.add(MESSAGE_KEY, messagePayload);
return jNotificationMessage;
}
/**
* Android에서 메시지가 수신되는 방식을 사용자 지정하는 Android 페이로드를 빌드합니다.
*
* @return android payload of an FCM request.
*/
public JsonObject buildAndroidOverridePayload() {
/**
* 이부분은 notify 알림에 표시될 제목, 내용, 보여줄 이미지의 URL 경로
*/
JsonObject androidNotification = new JsonObject();
androidNotification.addProperty("body", BODY);
androidNotification.addProperty("title", TITLE);
androidNotification.addProperty("image", IMAGEURL);
/**
* 사용자 viewAcitivy 로 전달할 내용 과 URL
*
* FcmReceiveService 에서 URL, BODY 을 읽어서 ViewActivity 로 전달함.
*/
JsonObject data = new JsonObject();
data.addProperty("URL", URL);
data.addProperty("BODY", BODY);
JsonObject androidNotificationPayload = new JsonObject();
androidNotificationPayload.add("notification", androidNotification);
androidNotificationPayload.add("data", data);
return androidNotificationPayload;
}
그럼 메시지 수신을 하는 FcmReceiveService 을 잠깐 살펴 보자. onMessageReceived 부분을 보면 payload 에서 들어간 내용 URL, BODY 이런 것들이 키로 수신이 되는 것을 볼 수 있다. 그래서 그것을 저정하거나 해서 잘 활용하면
수신된 메시지를 나의 앱으로 전달하는 방법으로 처리를 할 수 있을 것이다.
package com.bil.......................tils;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.billcoreatech.msgfcm1020.MainActivity;
import com.billcoreatech.msgfcm1020.R;
import com.billcoreatech.msgfcm1020.ViewActivity;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;
public class FcmReceiveService extends FirebaseMessagingService {
private static final String TAG = "FcmReceiveService";
SharedPreferences sp ;
SharedPreferences.Editor editor ;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
// 여기에 메시지가 수신되지 않습니까? 이것이 가능한 이유를 참조하십시오 : https://goo.gl/39bRNJ
Log.e(TAG, "From: " + remoteMessage.getFrom());
// 메시지에 데이터 페이로드가 포함되어 있는지 확인하십시오.
if (remoteMessage.getData().size() > 0) {
Log.e(TAG, "Message data payload: " + remoteMessage.getData());
sp = getSharedPreferences(getPackageName(), MODE_PRIVATE);
editor = sp.edit() ;
Map<String, String> strMap = remoteMessage.getData();
Log.e(TAG, "URL=" + strMap.get("URL"));
Log.e(TAG, "BODY=" + strMap.get("BODY"));
editor.putString("URL", strMap.get("URL").contains("http") ? strMap.get("URL") : "https://" + strMap.get("URL"));
editor.putString("BODY", strMap.get("BODY"));
editor.putBoolean("FcmTy", true) ;
editor.commit();
handleNow();
}
// 메시지에 알림 페이로드가 포함되어 있는지 확인합니다.
if (remoteMessage.getNotification() != null) {
Log.e(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
sendNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody()) ;
}
onDeletedMessages();
}
// [END receive_message]
@Override
public void onNewToken(String token) {
Log.e(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// FCM registration token to your app server.
sendRegistrationToServer(token);
}
// [END on_new_token]
/**
* BroadcastReceivers에 할당된 시간을 처리합니다.
*/
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
Intent intent = new Intent(FcmReceiveService.this, ViewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
/**
타사 서버에 토큰을 유지합니다.
이 방법을 수정하여 사용자의 FCM 등록 토큰을 임의의
애플리케이션에서 유지 관리하는 서버 측 계정.
*
* @param token The new token.
*/
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
/**
* 수신된 FCM 메시지가 포함된 간단한 알림을 만들고 표시합니다.
*
* @param messageBody FCM message body received.
*/
private void sendNotification(String msgTitle, String messageBody) {
sp = getSharedPreferences(getPackageName(), MODE_PRIVATE);
editor = sp.edit() ;
editor.putString("BODY", messageBody);
editor.putBoolean("FcmTy", true) ;
editor.commit();
Log.e(TAG, "---------------------------------------------------------------------");
Bundle bundle = new Bundle();
bundle.putString("TITLE", msgTitle);
bundle.putString("BODY", messageBody);
Intent notifyIntent = new Intent(this, MainActivity.class);
notifyIntent.putExtras(bundle);
// Set the Activity to start in a new, empty task
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent notifyPendingIntent = PendingIntent.getActivity(
this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT
);
String channelId = getString(R.string.default_notification_channel_id);
CharSequence channelName = getString(R.string.default_notification_channel_name);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId);
builder.setContentIntent(notifyPendingIntent)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(getString(R.string.fcm_message))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_HIGH);
channel.enableLights(true);
channel.enableVibration(true);
channel.setLightColor(Color.BLUE);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(Integer.parseInt(getString(R.string.default_notification_channel_id)), builder.build());
}
}
수신된 알림이 notification 으로 저장이 되는 경우, 사용자는 알림창에 나와 있는 알림을 클릭했을 때 내 앱이 실행 되면서 그 내용을 확인할 수 있을 것이다. 알려야 하는 내용을 전달하는 방법은 메시지만 전달하거나, 미리 전달할 내용을 realtimedatabase 등에 저장해 두었다가, 확인해 볼 수 있도록 앱을 구성해 볼 수 있을 것 같다.
알림 수신을 위한 FcmReceiveService는 manifest 에 service 로 등록해 주면 된다. 이런 부분들은 구글링을 해 보면 많이 나오고 해서 추가 설명은 생략해 보겠다.
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_launcher_foreground" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/purple_500" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
<service
android:name=".FcmUtils.FcmReceiveService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
3. MainActivity 에서 메시지 전송을 구현해 보자...
아래 소스 처럼 필요한 부분만 살펴 보도록 하겠다.
package co.......................020;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CompoundButton;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
........
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
......
String strFCM = "" ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Intent intent = getIntent();
Bundle extras = intent.getExtras();
# FcmreceiveService 에서 extra 로 전달하면 그 값을 확인하기 위해서 추가
if (extras != null) {
Log.e(TAG, "===" + extras.getString("BODY"));
.....
}
# 안드로이드 버전이후 에서는 channel ID 을 설정해 주어야 한다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create channel to show notifications.
String channelId = getString(R.string.default_notification_channel_id);
String channelName = getString(R.string.default_notification_channel_name);
NotificationManager notificationManager =
getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(new NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_LOW));
}
}
@Override
protected void onStart() {
super.onStart();
...
binding.btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (sp.getBoolean("pushOne", false) && getChkCnt(userInfos) < 1) {
Toast.makeText(getApplicationContext(), getString(R.string.msgCheckOnlyOne), Toast.LENGTH_LONG).show();
return;
}
pushBinding = PushentryBinding.inflate(getLayoutInflater());
pushBinding.edURL.setText("billcorea.tistory.com");
pushBinding.edMesg.setText("test send messages ");
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.myDialog);
builder.setTitle(getString(R.string.pushTitle))
.setMessage(getString(R.string.msgPushMessages))
.setView(pushBinding.getRoot())
.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
# 메시지 전송을 위한 호출
SendNotify(pushBinding.edMesg.getText().toString(),
pushBinding.edURL.getText().toString()) ;
}
})
.setNegativeButton(getString(R.string.CANCEL), null);
AlertDialog dialog = builder.create();
dialog.show();
}
});
}
/**
* 전송할 메시지와 url 을 입력 받아옴. fragment 에서 개인/전체 발송 구분은 선택해서 sp 에 저장 되어 있다고 봄
* @param msg
* @param url
*/
private void SendNotify(String msg, String url) {
# 쓰레드을 사용하는 건 http 전송을 하기 때문에...
new Thread(() -> {
Messaging messaging = new Messaging(getApplicationContext());
# 전송하고 싶은 값들을 여기서 선언해 준다.
# 추가가 필요하면 Message class 에 선언해 주면서 추가 하면됨.
messaging.TITLE = getString(R.string.app_name) ;
messaging.BODY = msg ;
messaging.URL = url ;
Log.e(TAG, "Send Messages " + msg);
Log.e(TAG, "pushOne=" + sp.getBoolean("pushOne", false));
Log.e(TAG, "pushAll=" + sp.getBoolean("pushAll", false));
Log.e(TAG, "userInfo=" + userInfo.getUserToken());
if (sp.getBoolean("pushOne", false)) {
if (userInfo == null) {
Toast.makeText(getApplicationContext(), getString(R.string.nonSelectUser), Toast.LENGTH_LONG).show();
return ;
}
if (!userInfo.isUseTy()) {
Toast.makeText(getApplicationContext(), getString(R.string.nonSelectUser), Toast.LENGTH_LONG).show();
return ;
}
/**
* 개인에게 만 전송할 떄 : 미리 수집된 token 값으로 전달하고
*/
messaging.tokenExam = userInfo.getUserToken() ;
try {
messaging.sendOverrideMessage();
} catch (IOException e) {
e.printStackTrace();
}
} else {
/**
* 전체에게 전송할 떄 : 앱 실행시 구독설정한 topic 으로 전송을 하게 됨
*/
try {
messaging.sendOverrideMessage();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
# 토근 얻어오기 및 구독 설정 하기
public void onRegistryToken() {
FirebaseMessaging.getInstance().subscribeToTopic("allDevices")
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Log.e(TAG, "allDevices subscribed ...");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(getApplicationContext(), getString(R.string.nonSyncTopic), Toast.LENGTH_LONG).show();
}
});
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(@NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
getRegistryPhoneNumber(token);
}
});
}
}
처음에 보았던 client 토큰 값을 이용해서 개별에게 전달을 하거나, 구독 설정한 topic 을 통해서 전체 전달을 할 수 있다.
여기서 중요한 것은 개별 전송을 위한 token 을 메시지를 보내는 쪽에서 알아야 한다는 것인데, 그걸 해소하기 위해서는 추천하는 방법으로는 realtime database 에 저장을 해서 공유하는 방법이 실시간으로 데이터를 공유할 수 있지 않을 까 생각이 든다. 관리자는 모든 사용자의 token 값을 알고 있어야 하고, 서로 모르는 상대방에게 메시지를 보낸다면 특정인의 token을 알 수 있는 방법이 있어야 하기 떄문이다 .
p.s : 2021.11.15 오늘 공개할 python 이야기도 잠시 참고해 보시길.
https://billcoreapython.tistory.com/29
'모바일 앱(안드로이드)' 카테고리의 다른 글
안드로이드 앱 만들기 : RecycleView.Adapter 에 클릭 이벤트 달아보기 (0) | 2021.11.03 |
---|---|
안드로이드 앱 만들기 : Recycleview 을 구현하다 벌어지는 흔한 실수 (0) | 2021.11.02 |
안드로이드 앱 만들기 Firebase 의 인증 기능 활용 (0) | 2021.10.18 |
안드로이드 앱 만들기 bottomnavigationview 의 기능 구현 등등 (4) | 2021.10.16 |
안드로이드 앱 만들기 Android Studio Update ... Bumblebee (0) | 2021.10.15 |