programing

TokenRefresh()에서 호출할 Firebase FCM 힘

newstyles 2023. 6. 8. 19:27

TokenRefresh()에서 호출할 Firebase FCM 힘

저는 앱을 GCM에서 FCM으로 마이그레이션하고 있습니다.

앱을 때, " 사자내앱설을치면하새가용▁when"onTokenRefresh()자동으로 호출됩니다.문제는 사용자가 아직 로그인하지 않았다는 것입니다(사용자 ID 없음).

어떻게 작동시킬 수 있습니까?onTokenRefresh()사용자가 로그인한 후?

onTokenRefresh()메서드는 새 토큰이 생성될 때마다 호출됩니다.앱을 설치하면 바로 생성됩니다(확인하신 대로).토큰이 변경된 경우에도 호출됩니다.

『 』에 FirebaseCloudMessaging 드가이:

알림 대상을 특정 단일 장치로 지정할 수 있습니다.앱을 처음 시작할 때 FCM SDK는 클라이언트 앱 인스턴스에 대한 등록 토큰을 생성합니다.

스크린샷

소스 링크: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token

이는 토큰 등록이 앱별임을 의미합니다.사용자가 로그인한 후 토큰을 사용하고자 하는 것 같습니다.을 가제제것당것저입다니에 입니다.onTokenRefresh()내부 저장소 또는 공유 기본 설정에 대한 방법입니다.그런 다음 사용자가 로그인한 후 저장소에서 토큰을 검색하고 필요에 따라 서버에 토큰을 등록합니다.

으로 수으로강적는경우려용을 강제로 onTokenRefresh()IntentService를 만들고 토큰 인스턴스를 삭제할 수 있습니다.get 럼때를 때 get 을그때를 받습니다. 토큰, 더onTokenRefresh()메서드가 다시 호출됩니다.

코드 예제:

public class DeleteTokenService extends IntentService
{
    public static final String TAG = DeleteTokenService.class.getSimpleName();

    public DeleteTokenService()
    {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent)
    {
        try
        {
            // Check for current token
            String originalToken = getTokenFromPrefs();
            Log.d(TAG, "Token before deletion: " + originalToken);

            // Resets Instance ID and revokes all tokens.
            FirebaseInstanceId.getInstance().deleteInstanceId();

            // Clear current saved token
            saveTokenToPrefs("");

            // Check for success of empty token
            String tokenCheck = getTokenFromPrefs();
            Log.d(TAG, "Token deleted. Proof: " + tokenCheck);

            // Now manually call onTokenRefresh()
            Log.d(TAG, "Getting new token");
            FirebaseInstanceId.getInstance().getToken();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private void saveTokenToPrefs(String _token)
    {
        // Access Shared Preferences
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();

        // Save to SharedPreferences
        editor.putString("registration_id", _token);
        editor.apply();
    }

    private String getTokenFromPrefs()
    {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        return preferences.getString("registration_id", null);
    }
}

편집

파이어베이스InstanceId 서비스

공공 클래스 파이어베이스InstanceIdService가 서비스를 확장합니다.

이 클래스는 더 이상 사용되지 않습니다.Firebase Messaging Service에서 NewToken을 재정의하는 것에 찬성합니다.이 서비스가 구현되면 이 서비스를 안전하게 제거할 수 있습니다.

onTokenRefresh()는 더 이상 사용되지 않습니다.사용하다onNewToken()MyFirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {

@Override
public void onNewToken(String s) {
    super.onNewToken(s);
    Log.e("NEW_TOKEN",s);
    }

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    }
} 

구현시를 구현해 .FirebaseInstanceIdService새로 고침 토큰을 가져옵니다.

등록 토큰 액세스:

Firebase를 확장하여 토큰의 값에 액세스할 수 있습니다.InstanceIdService입니다.매니페스트에 서비스를 추가했는지 확인한 다음 전화하십시오.getToken의맥서에의 onTokenRefresh표시된 대로 값을 기록합니다.

     @Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.d(TAG, "Refreshed token: " + refreshedToken);

    // TODO: Implement this method to send any registration to your app's servers.
    sendRegistrationToServer(refreshedToken);
}

전체 코드:

   import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;


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

        // TODO: Implement this method to send any registration to your app's servers.
        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) {
        // Add custom implementation, as needed.
    }
}

여기서 제 대답을 보세요.

편집:

당신은 파이어베이스를 시작하면 안 됩니다.InstanceIdService를 직접 사용합니다.

시스템이 토큰을 새로 고쳐야 한다고 판단하면 호출됩니다.응용 프로그램에서 get을 호출해야 합니다.토큰()을 보내고 모든 응용프로그램 서버로 토큰을 보냅니다.

이는 자주 호출되지 않으며, 다음과 같은 이유로 인해 키를 회전하고 인스턴스 ID 변경을 처리하는 데 필요합니다.

  • 앱이 인스턴스 ID를 삭제합니다.
  • 앱이 새 장치에 복원됨 사용자
  • 앱 제거/제거
  • 사용자가 앱 데이터 지우기

시스템은 토큰 업데이트로 응용 프로그램 서버에 과부하가 걸리지 않도록 모든 장치에서 새로 고침 이벤트를 제한합니다.

아래 방법을 사용해 보십시오.

당신은 파이어베이스에 전화할 것입니다.인스턴스ID.getToken()은 기본 스레드(서비스, AsyncTask 등) 밖의 모든 위치에서 반환된 토큰을 로컬로 저장하고 서버로 보냅니다.그럼 언제든지onTokenRefresh()라고 하면, 당신은 파이어베이스에 전화할 것입니다.인스턴스ID.getToken()을 다시 가져와서 서버로 보냅니다(아마도 서버가 이전 토큰을 제거하고 새 토큰으로 바꿀 수 있도록 이전 토큰도 포함).

여러분, 아주 간단한 해결책이 있습니다.

https://developers.google.com/instance-id/guides/android-implementation#generate_a_token

참고: 앱에서 deleteInstance에 의해 삭제된 토큰을 사용한 경우ID, 앱에서 대체 토큰을 생성해야 합니다.

인스턴스 ID를 삭제하는 대신 토큰만 삭제:

String authorizedEntity = PROJECT_ID;
String scope = "GCM";
InstanceID.getInstance(context).deleteToken(authorizedEntity,scope);

토큰을 강제로 새로 고치고 새 토큰이 생성되었기 때문에 호출되는 NewToken에서 이 방법을 사용할 방법을 찾고 있는 사용자는 필요할 때마다 이를 호출하기만 하면 됩니다.

FirebaseMessaging.getInstance().deleteToken().addOnSuccessListener {
  FirebaseMessaging.getInstance().token
}

단순성을 위해 My Firebase Messaging Service에 정적 함수로 다음과 같이 썼습니다.

class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        if (remoteMessage.data.isNotEmpty()) {
            Log.d(TAG, "Message data payload: ${remoteMessage.data}")
        }

        // do your stuff.
    }

    override fun onNewToken(token: String) {
        Log.d(TAG, "FCM token changed: $token")
        
        // send it to your backend.
    }

    companion object {
        private const val TAG = "MyFirebaseMessagingService"

        fun refreshFcmToken() {
            FirebaseMessaging.getInstance().deleteToken().addOnSuccessListener {
                FirebaseMessaging.getInstance().token
            }
        }
    }
}

삭제만 호출 중새 토큰은 요청될 때만 생성되므로 토큰()만으로는 충분하지 않습니다. 물론 앱을 열 때마다 요청되므로 삭제를 호출하면 됩니다.토큰()은 사용자가 다음 번에 앱을 열 때 생성되지만, 사용자가 앱을 처음 사용하는 동안 또는 사용한 후 바로 알림을 보내야 하는 경우 문제가 발생할 수 있습니다.

삭제 직후 토큰() 호출토큰()은 둘 다 비동기 작업이기 때문에 동시성 문제를 발생시키며 토큰()은 삭제하기 전에 항상 실행을 종료합니다.Token()(아직 삭제되지 않았기 때문에 토큰이 이미 존재한다고 보고 삭제 중에 새 토큰을 생성하려고 하지도 않습니다.토큰()이 Firebase 서버에 현재 토큰 삭제를 요청하고 있습니다.

삭제 후 토큰()을 호출해야 하는 이유입니다.토큰() 스레드가 성공적으로 완료되었습니다.

FirebaseMessaging.getInstance().getToken().addOnSuccessListener(new 
OnSuccessListener<String>() {
    @Override
    public void onSuccess(String newToken) {
        ....
    }
});

gcm 토큰이 서버로 전송되었는지 여부를 나타내는 하나의 플래그를 공유 pref에 유지하고 있습니다.스플래시 화면에서 한 메소드를 호출할 때마다 sendDevicetokenToServer.이 메서드는 사용자 ID가 비어 있지 않은지 확인하고 gcm 보내기 상태를 확인한 다음 토큰을 서버로 보냅니다.

public static void  sendRegistrationToServer(final Context context) {

if(Common.getBooleanPerf(context,Constants.isTokenSentToServer,false) ||
        Common.getStringPref(context,Constants.userId,"").isEmpty()){

    return;
}

String token =  FirebaseInstanceId.getInstance().getToken();
String userId = Common.getUserId(context);
if(!userId.isEmpty()) {
    HashMap<String, Object> reqJson = new HashMap<>();
    reqJson.put("deviceToken", token);
    ApiInterface apiService =
            ApiClient.getClient().create(ApiInterface.class);

    Call<JsonElement> call = apiService.updateDeviceToken(reqJson,Common.getUserId(context),Common.getAccessToken(context));
    call.enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> serverResponse) {

            try {
                JsonElement jsonElement = serverResponse.body();
                JSONObject response = new JSONObject(jsonElement.toString());
                if(context == null ){
                    return;
                }
                if(response.getString(Constants.statusCode).equalsIgnoreCase(Constants.responseStatusSuccess)) {

                    Common.saveBooleanPref(context,Constants.isTokenSentToServer,true);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable throwable) {

            Log.d("", "RetroFit2.0 :getAppVersion: " + "eroorrrrrrrrrrrr");
            Log.e("eroooooooorr", throwable.toString());
        }
    });

}

}

내 파이어베이스에서사례ID 서비스 클래스

    @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.
    Common.saveBooleanPref(this,Constants.isTokenSentToServer,false);
    Common.sendRegistrationToServer(this);
    FirebaseMessaging.getInstance().subscribeToTopic("bloodRequest");
}

파이어베이스InstanceId 서비스

이 클래스는 더 이상 사용되지 않습니다.Firebase Messaging Service에서 NewToken을 재정의하는 것에 찬성합니다.이 서비스가 구현되면 이 서비스를 안전하게 제거할 수 있습니다.

이를 위한 새로운 방법은 다음을 무시하는 것입니다.onNewToken의 방법.FirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onNewToken(String s) {
        super.onNewToken(s);
        Log.e("NEW_TOKEN",s);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
    }
} 

또한 Manifest.xml에 서비스를 추가하는 것도 잊지 마십시오.

<service
    android:name=".MyFirebaseMessagingService"
    android:stopWithTask="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

한 사용자가 앱에서 로그아웃하고 다른 사용자가 로그인하는 시나리오에서 RxJava2에 해당합니다(동일한 앱) 로그인을 다시 생성하고 호출하려면(사용자의 장치가 활동을 시작할 때 이전에 인터넷에 연결되어 있지 않고 로그인 api에서 토큰을 보내야 하는 경우).

Single.fromCallable(() -> FirebaseInstanceId.getInstance().getToken())
            .flatMap( token -> Retrofit.login(userName,password,token))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(simple -> {
                if(simple.isSuccess){
                    loginedSuccessfully();
                }
            }, throwable -> Utils.longToast(context, throwable.getLocalizedMessage()));

로그 인.

@FormUrlEncoded
@POST(Site.LOGIN)
Single<ResponseSimple> login(@Field("username") String username,
                         @Field("password") String pass,
                         @Field("token") String token

);

이 답변은 인스턴스 ID를 삭제하지 않고 현재 ID를 가져올 수 있습니다.또한 새로 고침된 항목을 공유 환경설정에 저장합니다.

Strings.xml

<string name="pref_firebase_instance_id_key">pref_firebase_instance_id</string>
<string name="pref_firebase_instance_id_default_key">default</string>

Utility.java(기본 설정을 설정하거나 가져올 모든 클래스)

public static void setFirebaseInstanceId(Context context, String InstanceId) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor;
    editor = sharedPreferences.edit();
    editor.putString(context.getString(R.string.pref_firebase_instance_id_key),InstanceId);
    editor.apply();
}

public static String getFirebaseInstanceId(Context context) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    String key = context.getString(R.string.pref_firebase_instance_id_key);
    String default_value = context.getString(R.string.pref_firebase_instance_id_default_key);
    return sharedPreferences.getString(key, default_value);
}

내 파이어베이스InstanceIdService.java(Firebase 확장)InstanceIdService)

@Override
public void onCreate()
{
    String CurrentToken = FirebaseInstanceId.getInstance().getToken();

    //Log.d(this.getClass().getSimpleName(),"Inside Instance on onCreate");
    String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
    String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);

    if(CurrentToken != null && !savedToken.equalsIgnoreCase(defaultToken))
    //currentToken is null when app is first installed and token is not available
    //also skip if token is already saved in preferences...
    {
        Utility.setFirebaseInstanceId(getApplicationContext(),CurrentToken);
    }
    super.onCreate();
}

@Override
public void onTokenRefresh() {
     .... prev code
      Utility.setFirebaseInstanceId(getApplicationContext(),refreshedToken);
     ....

}

Android 2.0 이상onCreate서비스가 자동으로 시작될 때(소스) 호출되지 않습니다.대신onStartCommand이 재정의되어 사용됩니다.하지만 실제 파이어베이스에서는InstanceIdService 최종으로 선언되었으며 재정의할 수 없습니다.그러나 startService()를 사용하여 서비스를 시작할 때 서비스가 이미 실행 중인 경우 원래 인스턴스가 사용됩니다(좋은 경우).위에서 정의한 onCreate()도 호출되었습니다!

기본 활동을 시작할 때 또는 인스턴스 ID가 필요하다고 생각되는 시점에 이 옵션을 사용합니다.

MyFirebaseInstanceIdService myFirebaseInstanceIdService = new MyFirebaseInstanceIdService();
Intent intent= new Intent(getApplicationContext(),myFirebaseInstanceIdService.getClass());
//Log.d(this.getClass().getSimpleName(),"Starting MyFirebaseInstanceIdService");
startService(intent); //invoke onCreate

그리고 마지막으로,

Utility.getFirebaseInstanceId(getApplicationContext())

참고로 시작 서비스() 코드를 Firebase로 이동하여 이 기능을 더욱 향상시킬 수 있습니다.InstanceId 메서드입니다.

    [Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
class MyFirebaseIIDService: FirebaseInstanceIdService
{
    const string TAG = "MyFirebaseIIDService";
    NotificationHub hub;

    public override void OnTokenRefresh()
    {
        var refreshedToken = FirebaseInstanceId.Instance.Token;
        Log.Debug(TAG, "FCM token: " + refreshedToken);
        SendRegistrationToServer(refreshedToken);
    }

    void SendRegistrationToServer(string token)
    {
        // Register with Notification Hubs
        hub = new NotificationHub(Constants.NotificationHubName,
                                    Constants.ListenConnectionString, this);
        Employee employee = JsonConvert.DeserializeObject<Employee>(Settings.CurrentUser);
        //if user is not logged in 
        if (employee != null)
        {
            var tags = new List<string>() { employee.Email};
            var regID = hub.Register(token, tags.ToArray()).RegistrationId;

            Log.Debug(TAG, $"Successful registration of ID {regID}");
        }
        else
        {
            FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance).DeleteInstanceId();
            hub.Unregister();
        }
    }
}

단말기 업데이트 방법상품권

먼저 로그인할 때 사용자 컬렉션 아래의 첫 번째 장치 토큰과 현재 로그인한 사용자를 보냅니다.

그 후에, 나는 그냥 오버라이드를 합니다.onNewToken(token:String)내 안에서FirebaseMessagingService() 새 하십시오.

class MyFirebaseMessagingService: FirebaseMessagingService() {
    override fun onMessageReceived(p0: RemoteMessage) {
        super.onMessageReceived(p0)
    }

    override fun onNewToken(token: String) {
    super.onNewToken(token)
    val currentUser= FirebaseAuth.getInstance().currentUser?.uid
    if(currentUser != null){
        FirebaseFirestore.getInstance().collection("user").document(currentUser).update("deviceToken",token)
    }
 }
} 

하고, 하지 않은 , 에는 " 앱이때새토확을인다합니큰열마다릴▁a다▁for니▁each확▁check▁opens합앱"를 확인할 수 있습니다. 사용자가 아직 로그인하지 않은 경우 토큰을 업데이트하지 않습니다. 사용자가 이미 로그인한 경우 다음을 확인할 수 있습니다.newToken

이러한 문제를 해결하기 위한 일반적인 접근 방식:나는 스택 오버플로 기사들로 이 문제에 대한 나의 버전을 해결할 수 없었습니다.하지만 제게 도움이 된 것은 안드로이드 스튜디오-툴-파이어베이스의 어시스턴트를 사용한 것입니다.제 경우 빌드 크래들 파일에서 라이브러리가 누락되었습니다.

간단한 대답은 만약 당신이 당신의 내부에서 하고 싶은 것이 있다면.onTokenRefresh()에서는 사용자가 로그인한 다음 모든 사용자를 다음과 같이 래핑해야 합니다.

if (FirebaseAuth.instance.currentUser != null) {
  // All code that requires a logged in user
}

이렇게 하면 사용자가 로그인할 때까지 아무 일도 일어나지 않으며, 이때 메소드가 다시 실행되고 작업이 수행됩니다.:)

언급URL : https://stackoverflow.com/questions/37454501/firebase-fcm-force-ontokenrefresh-to-be-called