programing

Firebase Cloud Messaging - 로그아웃 처리

css3 2023. 6. 29. 20:18

Firebase Cloud Messaging - 로그아웃 처리

사용자가 응용프로그램에서 로그아웃하고 더 이상 장치에 대한 알림을 수신하지 않으려면 상황을 어떻게 처리해야 합니까?

나는 노력했다.

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(구글-services.json에서 볼 수 있는 동일한 ID가 아님)인 경우에만 작동합니다.예를 들어, 다른 서버가 앱으로 보낼 수 있도록 허용하려는 경우 호출합니다.getToken("THEIR_SENDER_ID", "FCM")사용자의 앱으로 전송할 수 있는 권한을 부여합니다.특정 발신인에게만 해당하는 다른 등록 토큰이 반환됩니다.

앞으로 앱으로 보내기 위해 사용자의 권한을 제거하기로 선택한 경우 다음을 사용해야 합니다.deleteToken("THEIR_SENDER_ID", "FCM")토큰이 할 때 메시지를 할 때, 은 이게하해토무효되, 고보사메고의다동니수메됩신가지시도로렇대작한때낸할내람시보이려를지화면당큰이▁a▁this,▁receive다▁will,니,됩▁a수신▁will▁they▁message이▁attempts가▁the메▁when▁invalid▁and▁the▁to지▁sender시렇▁send▁behavior▁token▁correspondingate를 받게 됩니다.NotRegisteredmessage

  1. 발신인 는 올바른 은 자의보낸사람대토삭다합사다니음용을 사용하는 입니다.deleteInstanceId().

@Prince의 답변, 특히 이것을 도와주기 위한 코드 샘플을 특별히 언급했습니다.

@MichauK가 이미 그의 게시물에서 하고 있듯이, 전화를 한 후.deleteInstanceId(),getToken()새 토큰에 대한 요청을 보내려면 호출해야 합니다.하지만, 두 번째로 부를 필요는 없습니다.하기만 하면 됩니다. onNewToken()구현되면 자동으로 새 토큰을 제공하도록 트리거됩니다.

간단히 말하면,deleteInstanceId()>getToken()> 확인 onNewToken().

참고: 호출deleteInstanceId()인스턴스모든 합니다.그러면 앱 인스턴스와 관련된 모든 항목 구독 및 기타 모든 토큰이 삭제됩니다.


당신은 당신이 전화하는 것이 확실합니까?deleteToken()제대로? 은 "앱보낸 ID로 이어야 합니다).대상 고객의 값은 "앱 서버의 보낸 사람 ID로 설정"이어야 합니다(링크한 제 답변에서도 확인 가능).당신은 통과하고 있습니다.getId()보낸 사람 ID와 다른 값(앱 인스턴스 ID 값 포함)입니다.또한 메시지를 어떻게 보내고 있습니까(앱 서버 또는 알림 콘솔)?

getToken()그리고.getToken(String, String)다른 토큰을 반환합니다.여기서 제 대답을 보세요.

저도 노력했습니다.FirebaseInstanceId.getInstance().deleteInstanceId()하지만 다음에 전화할 때는FirebaseInstanceId.getInstance.getTokennull을 받았습니다(두 번째 시도에서 작동함).

아마도 당신이 처음으로 전화를 건 이유일 것입니다.getToken()아직 생성 중입니다.의도된 행동일 뿐입니다.

다음에 다음에deleteInstanceId즉시 전화를 걸 수 있었습니다.getToken()다시 말하지만, 해킹처럼 보입니다.

사실 그렇지 않아요.이렇게 하면 새로 생성된 토큰(이미 생성된 경우)을 얻을 수 있습니다.그래서 저는 괜찮다고 생각합니다.

이전과 같이 완전한 통제권(FCM 가입 및 가입 해제)을 되찾기 위한 가장 우아한 솔루션이 무엇인지 간략하게 조사했습니다.사용자가 로그인 또는 로그아웃한 후 FCM을 활성화 및 비활성화합니다.

1단계 - 자동 초기화 방지

이제소가처다니합리대를 합니다.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(). 턴스 구든 정독보 ID에 할당된 구독됩니다.ID. 삭제할 때 모든 항목의 구독을 취소합니다. 이방로구수있다니습현할으를 구현할 수 .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
    }
}

저는 이 해결책이 명확하고 단순하며 투명하다고 생각합니다.저는 생산 환경에서 테스트를 해 보았는데 효과가 있었습니다.도움이 되었기를 바랍니다.

저는 같은 문제를 연구하고 있었습니다, 제가 일을 했을 때.logout()내 신청으로 부터.하지만 문제는 로그아웃한 후에도 여전히 Firebase에서 푸시 알림을 받고 있다는 것입니다.Firebase 토큰을 삭제하려고 했습니다.하지만 내 토큰을 삭제한 후에logout()은 법방, 그은입니다.null에서 때.login()ㅠㅠ. 이틀을 일한 후에 저는 마침내 해결책을 얻었습니다.

  1. 의 신의에서.logout()method,할 수 합니다.

    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. 의 신의에서.login()메서드, Firebase 토큰을 다시 생성합니다.

    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();
    

개발자는 다음과 같은 이유로 로그아웃 또는 사용자 간 전환을 위한 메커니즘으로 클라이언트 앱의 등록을 취소해서는 안 됩니다.

  • 등록 토큰이 로그인한 특정 사용자와 연결되어 있지 않습니다.클라이언트 앱이 등록을 취소한 후 다시 등록하면 앱은 동일한 등록 토큰 또는 다른 등록 토큰을 받을 수 있습니다.
  • 등록 취소 및 재등록은 각각 전파되는 데 최대 5분이 걸릴 수 있습니다.이 시간 동안 메시지는 등록되지 않은 상태로 인해 거부될 수 있으며 메시지는 잘못된 사용자에게 전달될 수 있습니다.메시지가 대상 사용자에게 전달되도록 하려면 다음과 같이 하십시오.

  • 앱 서버는 현재 사용자와 등록 토큰 간의 매핑을 유지할 수 있습니다.

  • 그런 다음 클라이언트 앱이 수신한 메시지가 로그인한 사용자와 일치하는지 확인할 수 있습니다.

이 인용문은 더 이상 사용되지 않는 구글 문서에서 나온 것입니다.

그러나 위의 문서가 더 이상 사용되지 않더라도 이것이 여전히 사실이라고 믿을 만한 이유가 있습니다.

당신은 여기에서 이것을 관찰할 수 있습니다 - 이 코드랩에서 그들이 어떻게 그것을 하는지 확인하세요.

그리고 여기 https://github.com/firebase/friendlychat-web/blob/master/cloud-functions/public/scripts/main.js .

getToken()사용되지 않음, 사용getInstanceId()대신 새 토큰을 재생성합니다.같은 효과가 있습니다.

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();
}

이 방법을 사용합니다.이것이 저의 해결책이며, 저는 여기서 이것을 언급했습니다. 당신이 가입할 때, initFirebaseMessage를 사용하고, 로그아웃하거나 삭제할 때 removeFirebaseMessage()를 사용하세요.

    private fun removeFirebaseMessage(){
        CoroutineScope(Dispatchers.Default).launch {
            FirebaseMessaging.getInstance().isAutoInitEnabled = false
            FirebaseInstallations.getInstance().delete()
            FirebaseMessaging.getInstance().deleteToken()
        }
    }

    private fun initFirebaseMessage(){
        val fcm = FirebaseMessaging.getInstance()
        fcm.isAutoInitEnabled = true
        fcm.subscribeToTopic("all")
        fcm.subscribeToTopic("")
    }

Firebase Messaging.getInstance()를 사용하여 Firebase 토큰을 지우고 새 토큰을 재생성하는 또 다른 편리한 방법

fun clearFirebaseToken() {
    FirebaseMessaging.getInstance().apply {
        deleteToken().addOnCompleteListener { it ->
            Log.d("TAG++", "firebase token deleted ${it.result}")
            token.addOnCompleteListener {
                Log.d("TAG++", "firebase token generated ${it.result}")
                if (it.result != null) saveTokenGenerated(it.result!!)
            }
        }
    }
}

삭제 호출만 합니다.로그아웃 시 백그라운드 스레드의 토큰 메서드:

https://firebase.google.com/docs/reference/android/com/google/firebase/iid/FirebaseInstanceId.html#public-void-deletetoken-string-senderid,-string-scope

 FirebaseInstanceId.getInstance().deleteToken(getString(R.string.gcm_defaultSenderId), "FCM")

첫 번째 인수는 Sender를 사용합니다.FireBase 콘솔에 정의된 ID

enter image description here

업데이트하는 데 몇 초 정도 걸립니다. 그 후에는 FCM 알림이 더 이상 표시되지 않습니다.

저는 제가 파티에 늦었다는 것을 압니다. deleteInstanceId()차단 호출이므로 백그라운드 스레드에서 호출해야 합니다. 그방법을냥하확인세요.deleteInstanceId()파이어베이스에서InstanceId() 클래스입니다.

@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();
    }
}  

IntentService를 시작하여 인스턴스 ID와 관련된 데이터를 삭제할 수 있습니다.

firebase.iid가 된 패키지FirebaseInstanceId이제 더 이상 사용되지 않습니다.자동 초기화가 Firebase 인스턴스 ID에서 Firebase 클라우드 메시징으로 마이그레이션되었습니다.또한 그것의 행동은 약간 변했습니다.전에, 전화가.deleteInstanceId()자동 초기화를 사용하도록 설정한 경우 새 토큰이 자동으로 생성됩니다.됩니다. 또는 app-start일 에만 생성됩니다.getToken()이 명시적으로 호출됩니다.

private suspend fun loginFCM() = withContext(Dispatchers.Default) {
    val fcm = FirebaseMessaging.getInstance()
    fcm.isAutoInitEnabled = true
    fcm.token.await()
}

private suspend fun logoutFCM() = withContext(Dispatchers.Default) {
    val fcm = FirebaseMessaging.getInstance()
    fcm.isAutoInitEnabled = false // To prevent a new token to be generated automatically in the next app-start (remove if you don't care)
    fcm.deleteToken().await()
}

Firebase에서 완전히 로그아웃하려면 나중에 전체 설치를 삭제하면 됩니다.

private suspend fun logoutFirebase() = withContext(Dispatchers.Default) {
    logoutFCM()
    val firebase = FirebaseInstallations.getInstance()
    firebase.delete().await()
}

모든 것을 마무리하려면 백그라운드 스레드를 사용하여 인스턴스를 삭제합니다.ID, 다음에 로그인할 때 Firestore/Realtime DB(토큰을 저장할 경우)를 주의하십시오.

public void Logout() {

        new Thread(){
            @Override
            public void run() {
                super.run();
                try {
                    FirebaseInstanceId.getInstance().deleteInstanceId();
                    FirebaseInstanceId.getInstance().getInstanceId();
                } catch (final IOException e) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(Flags.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        }.start();
        FirebaseMessaging.getInstance().setAutoInitEnabled(false);
        FirebaseAuth.getInstance().signOut();
        SharedPreferences sharedPreferences = getDefaultSharedPreferences(Flags.this);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.clear();
        editor.apply();
        startActivity(new Intent(Flags.this, MainActivity.class));
        Flags.this.finish();
    }

아래 이 코드를 사용했는데 도움이 되고 새 스레드 개체를 만드는 것보다 비용이 적게 들기 때문에 스레드(Runnable{}).start() 대신 Kotlin coroutine을 사용했습니다.

 private fun logoutFromFCM() {
    GlobalScope.launch(Dispatchers.IO) {
        FirebaseInstallations.getInstance().delete()
        FirebaseMessaging.getInstance().deleteToken()

        FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
            if (!task.isSuccessful) {
                Log.w(TAG, "Fetching FCM registration token failed", task.exception)
                return@OnCompleteListener
            }

            // Get new FCM registration token
            val token = task.result
            saveFirebaseToken(token)
            Log.w(TAG, "Token Updated - newToken> $token")
        })
    }
}

알림 요구 사항이 간단한 대부분의 경우 로그아웃 처리 문제를 훨씬 쉽게 구현할 수 있습니다.예를 들어, 내 경우 모든 사용자는 다음 두 가지 항목만 구독합니다.

  • 기업alerts
  • 이메일로 )@와 함께-@항목 문자열에는 사용할 수 없음)

이러한 간단한 시나리오의 경우 로그아웃 시 원하지 않는 항목을 등록 취소합니다.

Future<void> signOut() async {
  messaging.unsubscribeFromTopic(emailToTopic(_firebaseAuth.currentUser.email));
  await _firebaseAuth.signOut();
}

물론 성공적으로 로그인하거나 등록한 경우에만 항목을 구독하십시오.

Future<String> signIn({String email, String password}) async {
  try {
    await _firebaseAuth.signInWithEmailAndPassword(
        email: email, password: password);
    messaging.subscribeToTopic(emailToTopic(email));
    return "Signed in";
  } on FirebaseAuthException catch (e) {
    return e.message;
  }
}

언급URL : https://stackoverflow.com/questions/43193215/firebase-cloud-messaging-handling-logout