アプリを GCM から FCM に移行しています。
新しいユーザーがアプリをインストールすると、onTokenRefresh()
が自動的に呼び出されます。問題は、ユーザーがまだログインしていないことです (ユーザー ID がありません)。
onTokenRefresh()
ユーザーがログインした後にトリガーするにはどうすればよいですか?
アプリを GCM から FCM に移行しています。
新しいユーザーがアプリをインストールすると、onTokenRefresh()
が自動的に呼び出されます。問題は、ユーザーがまだログインしていないことです (ユーザー ID がありません)。
onTokenRefresh()
ユーザーがログインした後にトリガーするにはどうすればよいですか?
このonTokenRefresh()
メソッドは、新しいトークンが生成されるたびに呼び出されます。アプリのインストール時に、すぐに生成されます (実際にそうであることがわかっています)。トークンが変更されたときにも呼び出されます。
FirebaseCloudMessaging
ガイドによると:
単一の特定のデバイスに通知を送信できます。アプリの最初の起動時に、FCM SDK はクライアント アプリ インスタンスの登録トークンを生成します。
ソースリンク: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token
これは、トークンの登録がアプリごとであることを意味します。ユーザーがログインした後にトークンを利用したいようです。私が提案するのは、onTokenRefresh()
メソッド内のトークンを内部ストレージまたは共有設定に保存することです。次に、ユーザーがログインした後にストレージからトークンを取得し、必要に応じてトークンをサーバーに登録します。
を手動で強制するonTokenRefresh()
場合は、IntentService を作成してトークン インスタンスを削除できます。その後、getToken を呼び出すと、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);
}
}
編集
FirebaseInstanceIdService
public class FirebaseInstanceIdService extends Service
このクラスは非推奨です。FirebaseMessagingService で onNewToken をオーバーライドすることを支持します。実装が完了したら、このサービスを安全に削除できます。
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
リフレッシュトークンを取得する実装を試みます。
登録トークンにアクセスします。
FirebaseInstanceIdServiceを拡張することで、トークンの値にアクセスできます。マニフェストにサービスを追加したことを確認してから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.
}
}
ここで私の答えを見てください。
編集:
自分でFirebaseInstanceIdServiceを開始するべきではありません。
トークンを更新する必要があるとシステムが判断したときに呼び出されます。アプリケーションは getToken() を呼び出し、すべてのアプリケーション サーバーにトークンを送信する必要があります。
これはあまり頻繁には呼び出されません。キーのローテーションと、次の理由によるインスタンス ID の変更を処理するために必要です。
システムは、トークンの更新でアプリケーション サーバーが過負荷になるのを避けるために、すべてのデバイスで更新イベントを抑制します。
以下の方法を試してください:
メインスレッドのどこか (サービス、AsyncTask など) でFirebaseInstanceID.getToken()を呼び出し、返されたトークンをローカルに保存してサーバーに送信します。その後、 が呼び出されるたび に、 FirebaseInstanceID.getToken()
onTokenRefresh()
を再度呼び出し 、新しいトークンを取得し、それをサーバーに送信します (おそらく古いトークンも含めて、サーバーがそれを削除し、新しいものに置き換えることができます)。 .
FirebaseMessaging.getInstance().getToken().addOnSuccessListener(new
OnSuccessListener<String>() {
@Override
public void onSuccess(String newToken) {
....
}
});
この回答はインスタンス 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);
}
MyFirebaseInstanceIdService.java (FirebaseInstanceIdService を拡張)
@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
のサービスは、自動起動時に呼び出されません ( source )。代わりonStartCommand
にオーバーライドされて使用されます。しかし、実際の FirebaseInstanceIdService では final として宣言されており、オーバーライドできません。ただし、startService() を使用してサービスを開始すると、サービスが既に実行されている場合は、その元のインスタンスが使用されます(これは良いことです)。onCreate() (上記で定義) も呼び出されました。
これは、MainActivity の開始時、またはインスタンス 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())
startservice() コードを getFirebaseInstanceId メソッドに移動することで、これをさらに強化できることに注意してください。