I want to send data (String) from service to Activity.
How can I do that?
this is my service and I want to send the token to RegisterActivity, but it doesn't work
public class FirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
Log.d("My firebase id", "Refreshed token: " + token);
Intent intent = new Intent(getApplicationContext(), RegisterActivity.class);
intent.putExtra("TokenValue", token);
FirebaseInstanceIDService.this.startActivity(intent );
}
In RegisterActivity
Intent intent = getIntent();
String tokenValue = intent.getStringExtra("TokenValue");
Toast.makeText(RegisterActivity.this,tokenValue,Toast.LENGTH_SHORT).show();
Add flag FLAG_ACTIVITY_NEW_TASK in your intent before calling startActivity.
Intent intent = new Intent(getApplicationContext(), RegisterActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("TokenValue", token);
startActivity(intent);
using interface it can be done easily.first create a interface and then subscribe to this interface from activity or fragment from where you want to get the text.and then broadcast data from service
Try this:
This is my service class like this:
public class TokenService extends FirebaseInstanceIdService {
private static final String TAG = "FirebaseIDService";
public static String DeviceToc = "";
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.e(TAG, "Refreshed token: " + refreshedToken);
DeviceToc = refreshedToken;
Log.e("DeviceToc",""+refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// Utils.storeUserPreferences(this, DeviceToc,token);
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
SharedPreferences.Editor editor = pref.edit();
editor.putString("deviceToc",token); // Storing string
editor.apply();
Log.i("token",""+token);
// Add custom implementation, as needed.
}
And this is my login activity get token using Shared preference like this
#Override
protected Map<String, String> getParams()
{
Context c=LoginActivity.this;
SharedPreferences pref = c.getApplicationContext().getSharedPreferences("MyPref", 0);
String device_tok = pref.getString("deviceToc", null);
//Pass the parameters to according to the API.
Map<String, String> params = new HashMap<String, String>();
params.put("user_name", emailedit.getText().toString().trim());
params.put("userDeviceToken",device_tok);
params.put("deviceType","android");
params.put("user_login_password", passwordedit.getText().toString().trim());
Log.d("params",""+params);
it helps you.
Related
I had UrbanAirship implemented in version 1 of the app.
Now I extended FirebaseMessagingService in version 2 of the app.
I am not getting a call in onNewToken() to be able to send the token to my servers.
My boilerplate code looks like
AndroidManifest.xml
<service
android:name=".services.fcm.PushMessageReceiver"
android:enabled="true"
android:exported="true"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
and Receiver
public class PushMessageReceiver extends FirebaseMessagingService { ...
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
...
}
#Override
public void onNewToken(String s) {
Log.i(Config.LOGTAG, "######**** new token for fcm called");
Context ctx =ApplicationCustom.getContext();
SharedPreferences preferences = ctx.getSharedPreferences(Config.SHARED_PREFERENCES, Context.MODE_PRIVATE);
preferences.edit().putString(Config.SHARED_PREFS_DEVICE_TOKEN, s).apply();
Intent intent = new Intent(this, XmppConnectionService.class);
intent.setAction(XmppConnectionService.ACTION_FCM_TOKEN_REFRESH);
intent.putExtra("token", s);
startService(intent);
pushToServer();
}
public static void getToken() {
Log.i(Config.LOGTAG, "######**** get token for fcm called");
try {
Log.i(Config.LOGTAG, "######**** delete token for fcm called");
FirebaseInstanceId.getInstance().deleteInstanceId();
FirebaseInstanceId.getInstance().getInstanceId();
} catch (IOException e) {
e.printStackTrace();
Log.w(Config.LOGTAG, "######**** delete InstanceId failed", e);
}
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(task
-> {
if (!task.isSuccessful()) {
Log.w(Config.LOGTAG, "getInstanceId failed", task.getException());
return;
}
Log.i(Config.LOGTAG, "######**** getInstanceId successful");
// Get new Instance ID token
String token = task.getResult().getToken();
Context ctx = ApplicationCustom.getContext();
SharedPreferences preferences = ctx.getSharedPreferences(Config.SHARED_PREFERENCES, Context.MODE_PRIVATE);
preferences.edit().putString(Config.SHARED_PREFS_DEVICE_TOKEN, token).apply();
pushToServer();
});
}
public void pushToServer(){
// Logic to push token to a server reading from preferences
}
}
Observations:
1) onNewToken never gets called for apps that are being updated.
2) new installs get a token
3) after I added a call to FirebaseInstanceId.getInstance().deleteInstanceId()
OnComplete does not get called either.
4) A call to getToken(senderId, "FCM") on real phones (not emulators) invariably results in
java.io.IOException: TOO_MANY_REGISTRATIONS
at com.google.firebase.iid.zzr.zza(Unknown Source:66)
at com.google.firebase.iid.zzr.zza(Unknown Source:79)
at com.google.firebase.iid.zzu.then(Unknown Source:4)
at com.google.android.gms.tasks.zzd.run(Unknown Source:5)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
how do I fix observation 1. Is it because the token has already been delivered to UrbanAirship that onNewToken does not get called?
Fyi getToken is called in a service onCreate() method.
implementation 'com.google.firebase:firebase-messaging:17.3.4'
you can get fcm token by this:-
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (task.isSuccessful()) {
String firebaseToken = task.getResult().getToken();
} else {
getFirebaseToken();
}
}
});
That's okay if your onNewToken() is not called. You can get the latest token already made by firebase for your device. onNewToken() is called on specific occasions.
The registration token may change when:
-The app deletes Instance ID
-The app is restored on a new device
-The user uninstalls/reinstall the app
-The user clears app data.
Do read the firebase documentation :
https://firebase.google.com/docs/cloud-messaging/android/client#retrieve-the-current-registration-token
And for your second query, deleteInstanceId is a blocking call, so you will have to do it in a background thread. like this,
new Thread(new Runnable() {
#Override
public void run() {
try {
FirebaseInstanceId.getInstance().deleteInstanceId();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Some time onTokenRefresh() method call with some delay and it will generate token when new install happen that how its behave their for we need to implement functionality like below to overcome those issue maintain new user login also
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private String TAG = getClass().getName();
public static final String TOKEN_BROADCAST = "myfcmtokenbroadcast";
#Override
public void onTokenRefresh() {
//For registration of token
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
//To displaying token on logcat
Log.d("TOKEN: ", refreshedToken);
//calling the method store token and passing token
getApplicationContext().sendBroadcast(new Intent(TOKEN_BROADCAST));
storeToken(refreshedToken);
}
private void storeToken(String token) {
//we will save the token in sharedpreferences later
SharedPrefManager.getInstance(getApplicationContext()).saveDeviceToken(token);
}
}
In your onCreate method in MainActivity class call this methord
private void registerFCMToken(){
registerReceiver(broadcastReceiver, new IntentFilter(MyFirebaseInstanceIDService.TOKEN_BROADCAST));
final boolean isRegisterFcm = preferences.getBoolean("IS_REGISTER_FCM", false);
// FCM token Register when onTokenRefresh method call
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String fcmToken = SharedPrefManager.getInstance(MainActivity.this).getDeviceToken();
if(!isRegisterFcm) {
RegisterFcmTokenRequest request = new RegisterFcmTokenRequest();
request.setFcmtoken(fcmToken);
performRegisterFcmRequest(request);
}
}
};
// FCM token Register when new user Login
if(SharedPrefManager.getInstance(this).getDeviceToken() != null && !isRegisterFcm) {
String fcmToken = SharedPrefManager.getInstance(MainActivity.this).getDeviceToken();
RegisterFcmTokenRequest request = new RegisterFcmTokenRequest();
request.setFcmtoken(fcmToken);
performRegisterFcmRequest(request);
}
}
In the onDestroy method
unregisterReceiver(broadcastReceiver);
This class maintains the Shredpreferance for FCM token
public class SharedPrefManager {
private static final String SHARED_PREF_NAME = "FCMSharedPref";
private static final String TAG_TOKEN = "tagtoken";
private static SharedPrefManager mInstance;
private static Context mCtx;
private SharedPrefManager(Context context) {
mCtx = context;
}
public static synchronized SharedPrefManager getInstance(Context context) {
if (mInstance == null) {
mInstance = new SharedPrefManager(context);
}
return mInstance;
}
//this method will save the device token to shared preferences
public boolean saveDeviceToken(String token){
SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(TAG_TOKEN, token);
editor.apply();
return true;
}
//this method will fetch the device token from shared preferences
public String getDeviceToken(){
SharedPreferences sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
return sharedPreferences.getString(TAG_TOKEN, null);
}
}
I want to send push notifications to my android app.The problem is that when i run the app at my phone i can't get the reg id.But when i run it on my emulator runs perfectly and gets the regid.Any ideas?In case needed here is the code
MyFirebaseInstanceID.java
#Override
public void onTokenRefresh() {
super.onTokenRefresh();
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
// Saving reg id to shared preferences
storeRegIdInPref(refreshedToken);
// sending reg id to your server
sendRegistrationToServer(refreshedToken);
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(Config.REGISTRATION_COMPLETE);
registrationComplete.putExtra("token", refreshedToken);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
private void sendRegistrationToServer(final String token) {
// sending gcm token to server
Log.e(TAG, "sendRegistrationToServer: " + token);
}
private void storeRegIdInPref(String token) {
SharedPreferences pref = getApplicationContext().getSharedPreferences(Config.SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putString("regId", token);
editor.apply();
}
As according to Firebase FirebaseInstanceIdService is deprecated now.
You should try this to get Token !
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( MyActivity.this, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String newToken = instanceIdResult.getToken();
}
});
I am using FCM to send notification for downloading a file in my android app. When my app is not running and i send FCM then I get all the notifications that I send earlier and new one continuously.
How to overcome this?
Here is my MyFirebaseMessagingService class.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("data", "onMessageReceived: firebase called");
Map<String, String> data = remoteMessage.getData();
String url = data.get("file_url");
Intent broadcast_intent = new Intent();
broadcast_intent.putExtra(MainActivity.FIREBASE_URL, url); broadcast_intent.setAction(MainActivity.FIREBASE_URL_BROADCAST);
sendBroadcast(broadcast_intent);
}
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "MyFirebaseIIDService";
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
}
I am trying to understand the code behind Google's GCM quickstart example. Specifically, I don't understand how the code checks whether registration is already done.
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
RegistrationIntentService:
#Override
protected void onHandleIntent(Intent intent)
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
// [START register_for_gcm]
// Initially this call goes out to the network to retrieve the token, subsequent calls
// are local.
// [START get_token]
InstanceID instanceID = InstanceID.getInstance(this);
// R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
// See https://developers.google.com/cloud-messaging/android/start for details on this file.
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
// [END get_token]
Log.i(TAG, "GCM Registration Token: " + token);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);
// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
sharedPreferences.edit().putBoolean(AppSharedPreferences.SENT_TOKEN_TO_SERVER, true).apply();
// [END register_for_gcm]
} catch (Exception e) {
Log.d(TAG, "Failed to complete token refresh", e);
// If an exception happens while fetching the new token or updating our registration data
// on a third-party server, this ensures that we'll attempt the update at a later time.
sharedPreferences.edit().putBoolean(AppSharedPreferences.SENT_TOKEN_TO_SERVER, false).apply();
}
// Notify UI that registration has completed, so the progress indicator can be hidden.
Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}
In RegistrationIntentService, the comments say that initially the call goes to retrieve the token, but subsequent calls are local. Does this mean that it will simply check to see if the app already has the token and not make the call anymore? I really don't understand this portion and I don't see anywhere in this example code where it checks for the existence of the token.
For that logic, you can refer to my working sample code:
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private final String SENDER_ID = "425...."; // Project Number at https://console.developers.google.com/project/....
private final String SHARD_PREF = "com.example.gcmclient_preferences";
private final String GCM_TOKEN = "gcmtoken";
private final String LOG_TAG = "GCM";
public static TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
String token = appPrefs.getString(GCM_TOKEN, "");
if (token.isEmpty()) {
try {
getGCMToken();
} catch (Exception e) {
e.printStackTrace();
}
}
mTextView = (TextView) findViewById(R.id.textView);
}
private void getGCMToken() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
InstanceID instanceID = InstanceID.getInstance(mContext);
String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
if (token != null && !token.isEmpty()) {
SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = appPrefs.edit();
prefsEditor.putString(GCM_TOKEN, token);
prefsEditor.apply();
}
Log.i(LOG_TAG, token);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
}
You can read my answer at the following for more information
Adding Google Cloud Messagin (GCM) for Android - Registration process
Hope this helps!
InstanceID which is part of the Google Play Services library will check if there is a cached token and return that when getToken is called. If there is no cached token then it will go out to the network to retrieve a new token and return that.
Thus your application has to handle the possibility of that calling InstanceID.getToken will result in a network call. Hence the reason it is called in an IntentService.
I want to ask if is it possible to store a string globally for me to call in any other activity? Like for example the String email in my code, I want to save it globally so I can call it from other activity.
I tried using intent to carry data but it does not seem to work for my code.
private void checkLogin(final String email, final String password) {
// Tag used to cancel the request
String tag_string_req = "req_login";
pDialog.setMessage("Logging in ...");
showDialog();
StringRequest strReq = new StringRequest(Method.POST,
AppConfig.URL_REGISTER, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Login Response: " + response.toString());
hideDialog();
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
// Check for error node in json
if (!error) {
// user successfully logged in
// Create login session
session.setLogin(true);
// Launch main activity
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
startActivity(intent);
finish();
} else {
// Error in login. Get the error message
String errorMsg = jObj.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// JSON error
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Login Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_LONG).show();
hideDialog();
}
}) {
#Override
protected Map<String, String> getParams() {
// Posting parameters to login url
Map<String, String> params = new HashMap<String, String>();
params.put("tag", "login");
params.put("email", email);
params.put("password", password);
return params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
You can use global variable, but most of the time you shouldn't use this.
Are global variables bad?
You have to know if this variable is used in most of your application (lot of class need an access to it, and be careful about threads to not have a concurrency issue). If it's the case you can maybe use a global, which is a bad idea in my opinion. You also can do a singleton class.
But if you just try to send your variable between two view, I think you should use this
You can use SharedPreferences to save data to preference and use it any Activity.
You can use this method to save your email String into SharedPreferences.
public void saveValueToPrefrence(Context mContext, String key, String value) {
SharedPreferences pref = mContext.getSharedPreferences("UserData", 0);
SharedPreferences.Editor editor = pref.edit();
editor.putString(key, value);
editor.apply();
}
You can get email String in any other Activity using below method:
public String getValueFromPrefrence(Context mContext, String key) {
SharedPreferences pref = mContext.getSharedPreferences("UserData", 0);
return pref.getString(key, "");
}
You can use this method to save your email String:
saveValueToPrefrence(ActivityName.this,"email",email)
You can get email String like this:
String email = getValueFromPrefrence(ActivityName.this,"email")
Basically you need Activity's Context to save and get value from SharedPreferences.
I hope it helps you.
#FreeYourSoul is correct.
But as an answer to this question, there are multiple ways to do this. The easiest way would be to simply create a Static class that has a hashmap inside it that you can manipulate with any class.
Likely not your best choice, but it certainly is possible