your programing

Firebase 클라우드 메시징-로그 아웃 처리

lovepro 2020. 12. 30. 19:51
반응형

Firebase 클라우드 메시징-로그 아웃 처리


사용자가 내 응용 프로그램에서 로그 아웃하고 더 이상 장치에 대한 알림을받지 않기를 원하는 상황을 어떻게 처리합니까?

나는 시도했다

FirebaseInstanceId.getInstance().deleteToken(FirebaseInstanceId.getInstance().getId(), FirebaseMessaging.INSTANCE_ID_SCOPE)

하지만 여전히 내 장치의 registration_id.

또한 이것이 내가 삭제해야하는 토큰인지 확인했습니다.

FirebaseInstanceId.getInstance().getToken(FirebaseInstanceId.getInstance().getId(), FirebaseMessaging.INSTANCE_ID_SCOPE)

또는 단순히 FirebaseInstanceId.getInstance().getToken()).

나는 또한 시도 FirebaseInstanceId.getInstance().deleteInstanceId()했지만 다음에 내가 전화를 걸면 FirebaseInstanceId.getInstance.getTokennull을받습니다 (두 번째 시도에서 작동합니다).

이후 나는, 생각 deleteInstanceId나는 즉시 부를 수있는 getToken()다시,하지만 해킹처럼 보인다. 또한 수행해서는 안된다는 대답 이 있지만 분명히 작동하지 않는 토큰을 삭제할 것을 제안합니다.

그렇다면 이것을 처리하는 올바른 방법은 무엇입니까?


괜찮아. 그래서 몇 가지 테스트를 수행하고 다음을 결론지었습니다.

  1. deleteToken()은의 대응 getToken(String, String)이지만 getToken().

전달하는 발신자 ID가 다른 발신자 ID (google-services.json에서 볼 수있는 것과 동일한 ID가 아님) 인 경우에만 작동합니다. 예를 들어, 다른 서버는 전화 앱에 보낼 수 있도록하려면 getToken("THEIR_SENDER_ID", "FCM")그들을 제공하기 위해 인증 앱에 보낼 수 있습니다. 그러면 특정 발신자에게만 해당하는 다른 등록 토큰이 반환됩니다.

앞으로 앱으로 보낼 권한 을 제거하기로 선택한 경우 deleteToken("THEIR_SENDER_ID", "FCM"). 이렇게하면 해당 토큰이 무효화되고 보낸 사람이 의도 한대로 메시지를 보내려고하면 NotRegistered오류가 발생합니다.

  1. 자신의 발신자에 대한 토큰을 삭제하려면 올바른 처리 방법은 deleteInstanceId().

@Prince 의이 답변 , 특히 나를 돕는 코드 샘플을 특별히 언급 합니다.

MichałK @ 이미를 호출 한 후, 자신의 게시물에서 무엇으로 deleteInstanceId(), getToken()새로운 토큰에 대한 요청을 보내기 위해 호출해야합니다. 그러나 두 번째로 전화 할 필요는 없습니다. 너무 오래로 , 구현 자동으로 당신에게 새로운 토큰을 제공 방아쇠합니다.onTokenRefresh() onNewToken()

짧은 들어, deleteInstanceId()> getToken()> 확인 .onTokenRefresh() onNewToken()

참고 : 호출 deleteInstanceId()은 자신의 앱에 대한 토큰 만 삭제하는 것이 아닙니다. 모든 주제 구독 및 앱 인스턴스와 연결된 다른 모든 토큰이 삭제됩니다.


deleteToken()제대로 전화하고 있다고 확신 합니까? 청중에 대한 값은 (연결 한 내 답변에서도 볼 수 있음) "앱 서버의 보낸 사람 ID로 설정"이어야합니다. getId()보낸 사람 ID (앱 인스턴스 ID 값 포함)와 동일하지 않은 값을 전달하고 있습니다. 또한 메시지를 어떻게 보내나요 (앱 서버 또는 알림 콘솔)?

getToken()그리고 getToken(String, String)다른 토큰을 반환합니다. 여기 내 대답을 참조 하십시오 .

나는 또한 시도 FirebaseInstanceId.getInstance().deleteInstanceId()했지만 다음에 내가 전화를 걸면 FirebaseInstanceId.getInstance.getTokennull을받습니다 (두 번째 시도에서 작동합니다).

를 처음 호출 할 getToken()때 여전히 생성되고 있기 때문일 수 있습니다 . 의도 된 동작 일뿐입니다.

이후 나는, 생각 deleteInstanceId나는 즉시 부를 수있는 getToken()다시,하지만 해킹처럼 보인다.

별로. 새로 생성 된 (이미 생성 된 경우) 토큰을 얻는 방법입니다. 그래서 괜찮다고 생각합니다.


이전과 같이 모든 권한 (FCM 구독 및 구독 취소)을 되 찾을 수있는 가장 우아한 솔루션이 무엇인지에 대한 간략한 조사를 수행했습니다. 사용자가 로그인 또는 로그 아웃 한 후 FCM을 활성화 및 비활성화합니다.

1 단계.-자동 초기화 방지

이제 Firebase InstanceID가 등록 토큰을 생성하는 데 필요한 모든 것을 처리합니다 . 우선 자동 초기화 를 방지해야합니다 . 공식 설정 문서 에 따라 다음 메타 데이터 값을 에 추가해야 합니다 AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<application>

  <!-- FCM: Disable auto-init -->
  <meta-data android:name="firebase_messaging_auto_init_enabled"
             android:value="false" />
  <meta-data android:name="firebase_analytics_collection_enabled"
             android:value="false" />

  <!-- FCM: Receive token and messages -->
  <service android:name=".FCMService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
  </service>

</application>

이제 자동 토큰 요청 프로세스를 비활성화했습니다. 동시에 런타임에 코드로 다시 활성화 할 수있는 옵션이 있습니다.

2 단계-구현 enableFCM()disableFCM()기능

자동 초기화를 다시 활성화하면 즉시 새 토큰을 받았으므로 enableFCM()메서드 를 구현하는 완벽한 방법입니다. InstanceID에 할당 된 모든 구독 정보이므로 삭제하면 모든 주제의 구독 취소를 시작합니다. 이 방법으로 disableFCM()메소드 를 구현할 수 있습니다. 삭제하기 전에 자동 초기화를 해제하십시오.

public class FCMHandler {

    public void enableFCM(){
        // Enable FCM via enable Auto-init service which generate new token and receive in FCMService
        FirebaseMessaging.getInstance().setAutoInitEnabled(true);
    }

    public void disableFCM(){
        // Disable auto init
        FirebaseMessaging.getInstance().setAutoInitEnabled(false);
        new Thread(() -> {
            try {
                // Remove InstanceID initiate to unsubscribe all topic
                // TODO: May be a better way to use FirebaseMessaging.getInstance().unsubscribeFromTopic()
                FirebaseInstanceId.getInstance().deleteInstanceId();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

}

3 단계- FCMService구현-토큰 및 메시지 수신

마지막 단계에서 새 토큰을 받고 서버로 직접 보내야합니다. 다른 한편으로는 데이터 메시지를 받고 원하는대로 수행 할 수 있습니다.

public class FCMService extends FirebaseMessagingService {

    @Override
    public void onNewToken(String token) {
        super.onNewToken(token);
        // TODO: send your new token to the server
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        String from = remoteMessage.getFrom();
        Map data = remoteMessage.getData();
        if (data != null) {
            // TODO: handle your message and data
            sendMessageNotification(message, messageId);
        }
    }

    private void sendMessageNotification(String msg, long messageId) {
        // TODO: show notification using NotificationCompat
    }
}

I think this solution is clear, simple and transparent. I tested in a production environment and it's works. I hope it was helpful.


I was working on the same problem, when I had done my logout() from my application. But the problem was that after logging out, I was still getting push notifications from Firebase. I tried to delete the Firebase token. But after deleting the token in my logout() method, it is null when I query for it in my login() method. After working 2 days I finally got a solution.

  1. In your logout() method, delete the Firebase token in the background because you can not delete Firebase token from the main thread

    new AsyncTask<Void,Void,Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try
            {
                FirebaseInstanceId.getInstance().deleteInstanceId();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Call your Activity where you want to land after log out
        }
    }.execute();
    
  2. In your login() method, generate the Firebase token again.

    new AsyncTask<Void,Void,Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            String token = FirebaseInstanceId.getInstance().getToken();
            // Used to get firebase token until its null so it will save you from null pointer exeption
            while(token == null) {
                token = FirebaseInstanceId.getInstance().getToken();
            }
            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
        }
    }.execute();
    

Developers should never unregister the client app as a mechanism for logout or for switching between users, for the following reasons:

  • A registration token isn't associated with a particular logged in user. If the client app unregisters and then re-registers, the app can receive the same registration token or a different registration token.
  • Unregistration and re-registration may each take up to five minutes to propagate. During this time messages may be rejected due to the unregistered state, and messages may go to the wrong user. To make sure that messages go to the intended user:

  • The app server can maintain a mapping between the current user and the registration token.

  • The client app can then check to ensure that messages it receives match the logged in user.

this was from a deprecated google documentation: https://developers.google.com/cloud-messaging/registration#unregistration-and-unsubscription

but there is reasons to believe this is still available

check this firebase code https://github.com/firebase/functions-samples/blob/master/fcm-notifications/functions/index.js

and this one https://github.com/firebase/friendlychat-web/blob/master/cloud-functions/public/scripts/main.js


Since the getToken() is deprecated, use getInstanceId() to regenerate new token instead. It has same effect.

public static void resetInstanceId() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                FirebaseInstanceId.getInstance().deleteInstanceId();
                FirebaseInstanceId.getInstance().getInstanceId();   
                Helper.log(TAG, "InstanceId removed and regenerated.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

I know I am late for the party. deleteInstanceId() should be called from the background thread since it's a blocking call. Just check the method deleteInstanceId() in FirebaseInstanceId() class.

@WorkerThread
public void deleteInstanceId() throws IOException {
    if (Looper.getMainLooper() == Looper.myLooper()) {
        throw new IOException("MAIN_THREAD");
    } else {
        String var1 = zzh();
        this.zza(this.zzal.deleteInstanceId(var1));
        this.zzl();
    }
}  

You can start an IntentService to delete the instance id and the data associated with it.

ReferenceURL : https://stackoverflow.com/questions/43193215/firebase-cloud-messaging-handling-logout

반응형