I've followed this method to send my fcm token in the URL.
Following is my custom launcher activity
public class LauncherActivity
extends com.google.androidbrowserhelper.trusted.LauncherActivity {
private String fcmToken;
#Override
protected Uri getLaunchingUrl() {
Uri uri = super.getLaunchingUrl();
return uri
.buildUpon()
.appendQueryParameter("fcmToken", fcmToken)
.build();
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
return;
}
fcmToken = task.getResult();
launchTwa();
}
});
}
#Override
protected boolean shouldLaunchImmediately() {
return false;
}
Problem is when i run the app for the first time it get stuck in the splash screen.Then after killing the app , second time onward it works.
This issues is discussed in here as well , but with no luck.Any help will be appreciated.
Since i didn't find and resolution to this , following is the way i found to overcome this issue.Now i don't have the stuck in initial step and already token is passed to my server.
LauncherActivity.java
public class LauncherActivity
extends com.google.androidbrowserhelper.trusted.LauncherActivity {
private String fcmToken;
#Override
protected Uri getLaunchingUrl() {
uri = super.getLaunchingUrl();
return uri
.buildUpon()
.appendQueryParameter("fcmToken", fcmToken)
.build();
}
#Override
protected boolean shouldLaunchImmediately() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
fcmToken = preferences.getString("fcmTokenNew", "");
Boolean res = false;
if(fcmToken != null && !fcmToken.trim().isEmpty()) {
res = true;
}
return res;
}
}
CustomFirebaseMessagingService.java
public class CustomFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onNewToken(String token) {
sendToSariroti(token);
}
protected void sendToServer(String fcmToken) {
try {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("fcmTokenNew",fcmToken);
editor.apply();
Intent intent = getBaseContext().getPackageManager().getLaunchIntentForPackage(
getBaseContext().getPackageName() );
intent .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
What is happening is when you first launch the app,
It checks whether the parameter(fcmToken) is not null/available inside shouldLaunchImmediately If it's available , no problem , continue with launching the app
If token not available stop launching the app
Inside onNewToken , it watches until token is received from Firebase.
After it received it will call sendToServer.
Inside sendToServer, it store the fcmToken in shared preference and re-launch the app again.
Hope this will help to someone.
This issue has been handled in version 2.2.2 of android-browser-helper. For versions before that you can call onEnterAnimationComplete() after calling launchTwa(). You can find more info about this workaround here
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 implement sign up with two activities with the help of firebase, first sign up activity contains email mobile and password, and in this activity i want to check whether the entered email ID or mobile is registered or not, if it does not then move the data(i.e. email, mobile no. and password) to next activity where final registration will happen. The two methods which are present in the code i.e. userMobileExists() and userEmailExists() to check the email and mobile. But the problem is these are asynchronous so when I go to next activity then the Toast appear that email is already registered.
I am returning valid, if all the valid are true then it goes to next activity , I debugged it and it returns valid before going inside the method. It is because of asynchronous code, Please suggest something how it can be achieved on the first activity only. Or tell if I should provide the whole code.
public class SignupActivity extends AppCompatActivity {
private static final String TAG = "SignupActivity";
private static final int REQUEST_SIGNUP = 0;
private Firebase mRef = new Firebase("https://abcdef.firebaseio.com/");
private User user;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private ProgressDialog mProgressDialog;
boolean valid = true;
String email;
String mobile;
String password;
#Bind(R.id.input_email)
EditText _emailText;
#Bind(R.id.input_mobile)
EditText _mobileText;
#Bind(R.id.input_password)
EditText _passwordText;
#Bind(R.id.btn_next)
Button _signupButton;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signup);
ButterKnife.bind(this);
//For Full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
mAuth = FirebaseAuth.getInstance();
//Back button initialization
Button backButton = (Button) findViewById(R.id.back_signup);
backButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent in = new Intent(view.getContext(), LoginActivity.class);
startActivity(in);
}
});
mAuth = FirebaseAuth.getInstance();
// mRef = Firebase(Config.FIREBASE_URL);
_signupButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
signup();
}
});
}
protected void setUpUser() {
user.setPhoneNumber(_mobileText.getText().toString());
user.setEmail(_emailText.getText().toString());
user.setPassword(_passwordText.getText().toString());
}
//private void
public void signup() {
Log.d(TAG, "Signup");
//showProgressDialog();
if (validate() && userEmailExist() && userMobileExist()) {
onSignupSuccess();
} else {
onSignupFailed();
return;
}
//_signupButton.setEnabled(false);
email = _emailText.getText().toString();
mobile = _mobileText.getText().toString();
password = _passwordText.getText().toString();
// TODO: Implement your own signup logic here.
}
public void onSignupSuccess() {
//_signupButton.setEnabled(true);
Log.d(TAG, "NEXT BUTTTON");
//hideProgressDialog();
Intent in = new Intent(this, SignupActivity2.class);
in.putExtra("Email", _emailText.getText().toString());
in.putExtra("Mobile", _mobileText.getText().toString());
startActivity(in);
/*setResult(RESULT_OK, null);
finish();*/
}
public void onSignupFailed() {
// hideProgressDialog();
Toast.makeText(getBaseContext(), "SignUp failed", Toast.LENGTH_LONG).show();
// _signupButton.setEnabled(true);
}
public boolean validate() {
email = _emailText.getText().toString();
mobile = _mobileText.getText().toString();
password = _passwordText.getText().toString();
if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
_emailText.setError("enter a valid email address");
valid = false;
} else {
_emailText.setError(null);
}
if (mobile.isEmpty() || mobile.length() != 10) {
_mobileText.setError("Enter Valid Mobile Number");
valid = false;
} else {
_mobileText.setError(null);
}
if (password.isEmpty() || password.length() < 4 || password.length() > 10) {
_passwordText.setError("between 4 and 10 alphanumeric characters");
valid = false;
} else {
_passwordText.setError(null);
}
return valid;
}
public boolean userEmailExist() {
//private Firebase mRef = new Firebase("https://.firebaseio.com/users/");
mRef.child("users").orderByChild("email").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue()== _emailText.getText().toString()) {
Toast.makeText(getBaseContext(), "Email already exist. Please choose a different one", Toast.LENGTH_SHORT).show();
_emailText.setError("Email already exist. Please choose a different one");
valid = false;
} else {
email = _emailText.getText().toString();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
return valid;
}
public boolean userMobileExist() {
mRef.child("users").
orderByChild("cellPhone").equalTo(_mobileText.getText().toString()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
_mobileText.setError("Mobile Number already exist");
valid = false;
} else {
mobile = _mobileText.getText().toString();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
return valid;
}
#Override
public void onBackPressed() {
// Disable going back to the MainActivity
moveTaskToBack(true);
}
public void showProgressDialog(){
if(mProgressDialog == null){
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("loading");
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
public void hideProgressDialog(){
if(mProgressDialog != null && mProgressDialog.isShowing()){
mProgressDialog.dismiss();
}
}
}
You need to grasp the concept of callbacks. You cannot return a variable that's assigned asynchronously.
As a quick solution to your problem, start with an interface
public interface OnUserActionListener {
void onExists(Boolean exists);
}
Then, make your methods be void and accept a parameter
public void userEmailExist(final String email, final OnUserActionListener listener) {
mRef.child("users")
.orderByChild("email")
.equalTo(email)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener.onExists( dataSnapshot.exists() );
}
...
// no return statement
}
Then, when you call that method, you can pass in the string value you want to search for, and implement your interface.
So replace this synchronous code
validate() && userEmailExist()
With the async version
if (validate()) { // This is synchonous
final String email = _emailText.getText().toString();
final String mobile = _mobileText.getText().toString();
// This is asynchronous
userEmailExist(email, new OnUserActionListener() {
#Override
public void onExists(Boolean exists) {
if (exists) {
Toast.makeText(getBaseContext(), "Email already exist. Please choose a different one", Toast.LENGTH_SHORT).show();
_emailText.setError("Email already exist. Please choose a different one");
onSignupFailed();
} else {
onSignupSuccess();
}
}
});
However you choose to define that interface is up to you
And again, worth repeating, don't assign a field valid within your callbacks. Try your best to implement all logic requiring a value to the callback itself
You can also implement the entire interface on the class, which is what I would recommend in this scenario as a SignUpActivity because you want to listen for user event actions such as success or error
Just an example using the method names you already have
public interface OnUserActionListener {
// Combine the email and phone into one action
void onUserExists(User user, Boolean exists);
void onSignupSuccess(User user);
void onSignupFailed(String reason);
}
public class SignupActivity extends AppCompatActivity
implements OnUserActionListner { // Implement this interface
// Define the needed methods
#Override
public void onUserExists(User user, Boolean exists) {
if (exists) {
onSignupFailed("User " + user + " already exists");
} else {
onSignupSuccess(user);
}
}
#Override
public void onSignupSuccess(User user) {
// Do something
}
#Override
public void onSignupFailed(String reason) {
Toast.makeText(this, reason, Toast.LENGTH_SHORT).show();
}
#Override
protected void onCreate(Bundle b) {
...
}
etc. etc.
Then, that other method call simply becomes.
if (validate()) { // This is synchonous
final String email = _emailText.getText().toString();
final String mobile = _mobileText.getText().toString();
// This is asynchronous & you defined the Activity as the interface
userEmailExist(email, SignupActivity.this);
I'm not satisfied with the accepted answer because when I used it in my project it still failed. After trying many thing I write my own code ... and it is working. If you want check whether user is already registered or not you can try the following code.
private void isUserAlreadySignUp(String phone){
firebaseAuth = FirebaseAuth.getInstance();
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("authUser");
// after getting reference of child, checked orderbykey so we get if phone is key we can get ref in dataSnapshot...
databaseReference.child( "userPhone" ).orderByKey().equalTo( phone ).addListenerForSingleValueEvent( new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Boolean isExists = dataSnapshot.exists();
if (isExists)
showToast( "This number is alredy Registerd..!!" );
else
{
// if mobile is not registered you can go ahead...
// You can write your further code here or call methods...
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
showToast("Error :" + databaseError);
wSignUpProgressBar.setVisibility( View.GONE );
}
} );
}
// For Toast msg...
private void showToast(String s){ Toast.makeText( getActivity(), s , Toast.LENGTH_SHORT ).show(); }
To register a users mobile number on the database after authenticating the user, you can call this method.
// Register User on the database --------------------------
private void registerUserOnDatabase( String userPhone){
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference userRef = database.getReference("authUser").child("userPhone");
userRef.child( userPhone ).setValue( userPhone );
}
Maybe I am doing a wrong step. I have 3 activities:
Launcher
Login
MainActivity
In the onCreate of my MainActivity, I am calling the service:
void iniciarServicioSendTokenFCM(){
servicioFCM= new Intent(this, IDService.class);
startService(servicioFCM);
}
And this is executed, because it gets to enter in onCreate of Service but onTokenRefresh() is never executed.
I have done these steps too. I have uninstalled and reinstalled the app but it didn't work.
public class IDService extends FirebaseInstanceIdService {
private ConnectionStatusSync ConnSync;//= new ConnectionStatusSync(this);
private DispositivoSync Sync;
private Integer dispositivoId;
private PreferenceUtil preferenceUtil ;
private String tokenDispositivo;
private DispositivoSync.OnFragmentInteractionListener listener;
public IDService() {
}
#Override
public void onCreate() {
super.onCreate();
Listener();
ConnSync = new ConnectionStatusSync(this);
Sync = new DispositivoSync(this);
preferenceUtil= new PreferenceUtil(this);
dispositivoId=preferenceUtil.getInt(getString(R.string.dispositivoID),0,null);
dispositivoId=(dispositivoId==0?null:dispositivoId);
tokenDispositivo= new IDUtil(this).getId();
}
private void Listener(){
listener = new DispositivoSync.OnFragmentInteractionListener() {
#Override
public void onFinished(boolean terminoBien, int dispositivoID) {
if(terminoBien){
preferenceUtil.savePreference(getString(R.string.dispositivoID),dispositivoID,null);
}
}
};
}
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
preferenceUtil.savePreference(getString(R.string.TokenFCM),refreshedToken,null);
//Log.d(TAG, "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
if(validaciones())
sendRegistrationToServer(refreshedToken);
}
private boolean validaciones(){
return dispositivoId!=null && MainActivity.mOperador!=null;
}
private void sendRegistrationToServer(final String token){
final Thread registrar = new Thread(new Runnable() {
#Override
public void run() {
Sync.EnviarDispositivo(MainActivity.mOperador.getOperadorIdServidor(),dispositivoId,token,tokenDispositivo,listener );
}
});
Thread hilo = new Thread(new Runnable() {
#Override
public void run() {
Command commandNull= new Command() {
#Override
public void execute() {
}
};
ConnSync.CheckConnection(registrar,commandNull);
}
});
hilo.start();
}
}
In an app that uses Firebase Cloud Messaging, the client immediately starts generating the token when the app starts.
Most likely the initial token has already been generated by the time you start listening for onTokenRefresh(). So you'll want to also immediately request and store the token in your iniciarServicioSendTokenFCM method:
sendRegistrationToServer(FirebaseInstanceId.getInstance().getToken());
I don't think it is very useful to store the token in shared preferences by the way, given that it is readily accessible from FirebaseInstanceId.getInstance().getToken().
So , this is the Launcher activity when I start the application I check if someone is logged In or not but ParseUser.getCurrentUser() always returns a null I think. When I logIn and then close the application without logging out and start it again, getCurrentUser() again returns a null, but it is not supposed to. The logIn function is in another class called HumLogModel which I written below this one.
public class LauncherActivity extends ActionBarActivity {
private Intent logInActivityIntent;
private Intent homeActivityIntent;
private HumLogController humLogController;
private HumLogModel humLogModel;
private String username;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
initializeParse();
username = getCurrentUser();
if (username.equalsIgnoreCase("null")) {
humLogModel = new HumLogModel();
humLogController = new HumLogController();
startLogInActivity();
}
else {
humLogModel = new HumLogModel();
humLogController = new HumLogController();
startHomeActivity();
}
}
private String getCurrentUser(){
ParseUser currentUser = ParseUser.getCurrentUser();
if (currentUser != null) {
return currentUser.getUsername();
} else {
return "null";
}
}
}
This is where we are starting the parse datastore.
private void initializeParse(){
Parse.enableLocalDatastore(this);
Parse.initialize(this, "LrAF8blaE0GR19ffsr78rHKEH50QBcnZFDSuj9BW", "2UBZlOgM78UNj7AcxcArmuOlxy5y3UstpJP1h9lb");
}
This is the Model class which have the logIn method which are called up when some one log's in and also the logOut method (but even logOut method is never called , user is logged out I think .!!!)
public class HumLogModel extends Application implements Serializable {
private transient ParseObject customer;
private transient ParseObject tradesman;
private transient ParseObject user;
public HumLogModel(){
customer = new ParseObject("Customer");
tradesman = new ParseObject("Tradesman");
user = new ParseObject("User");
}
public void createNewUser(String username, String password , String userType){
user.put("username" , username);
user.put("password", password);
user.put("userType", userType);
user.saveInBackground();
ParseUser newUser = new ParseUser();
newUser.setUsername(username);
newUser.setPassword(password);
newUser.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
// Hooray! Let them use the app now.
} else {
// Sign up didn't succeed. Look at the ParseException
// to figure out what went wrong
}
}
});
}
public void logIn(String username , String password){
ParseUser.logInInBackground(username, password, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The user is logged in.
} else {
// Signup failed. Look at the ParseException to see what happened.
}
}
});
}
public void logOut(){
ParseUser.logOut();
}
}
When I close the application and start it again it always starts with LogInactivity, but it is not supposed to if do not logOut
I'm follow this tutorial to make a small app to login and say hello + user name.
The issue is: I can only login using my account, but can't log in with other account.
This issue is happen with some sample code require login like HelloFacebookSample or Scrumptious.
The Logcat is not show any error.
So please help me to make it login with other account. Thanks in advance!
EDIT (SOLVED):
I just found the cause: My app is in Sandbox mode, just disable Sandbox mode solved problem. Thanks anyone for helps.
My code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start Facebook Login
Session.openActiveSession(this, true, new Session.StatusCallback() {
// callback when session changes state
#Override
public void call(Session session, SessionState state, Exception exception) {
if (session.isOpened()) {
// make request to the /me API
Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {
// callback after Graph API response with user object
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
TextView welcome = (TextView) findViewById(R.id.welcome);
welcome.setText("Hello " + user.getName() + "!");
}
}
});
}
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}
}
Screenshot when login with my account: Show hello + my name (Nguyễn Việt Anh)
Screenshot when login with other account: White screen
You can login with different Facebook user id, after that:
Go to developers.facebook.com
choose Apps from Top
select wanted App from left side
select Edit App
disable sandbox mode
This is expected behavior. Essentially the login for facebook is SSO (single sign on) so there is a strong expectation that the user has only one account on their device.
I myself have tried to find a way to get the Facebook SDK to allow the user to sign on to a different account but it doesn't work.
It might be possible fudge it by clearing the caches perhaps but this wouldn't help users who are using the genuine facebook app on their phone.
What I did in the end was went to the web workflow as opposed to native app. I can recommend scribe for this task.
https://github.com/fernandezpablo85/scribe-java
If you do choose to use Scribe, this is my activity for loggin in.
public class FacebookScribeLogin extends FragmentActivity{
private static final String TAG = FacebookScribeLogin.class.getSimpleName();
private final static String CALLBACK = "http://localhost:3000/";
private WebView mWebView;
private ProgressDialog mProgressDialog;
private OAuthService mAuthService;
private SyncStatusUpdaterFragment mSyncStatusUpdaterFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
mWebView = (WebView) findViewById(R.id.webview);
new GetLoginPage().execute();
}
private class GetLoginPage extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
//set up service and get request token as seen on scribe website
//https://github.com/fernandezpablo85/scribe-java/wiki/Getting-Started
mAuthService = new ServiceBuilder()
.provider(FacebookApi.class)
.apiKey(getString(R.string.facebook_api_key))
.apiSecret(getString(R.string.facebook_api_secret))
.scope("read_stream, publish_stream, manage_notifications, publish_actions, manage_pages")
.callback(CALLBACK)
.build();
return mAuthService.getAuthorizationUrl(null);
}
#Override
protected void onPostExecute(String authURL) {
//send user to authorization page
android.webkit.CookieManager.getInstance().removeAllCookie();
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//check for our custom callback protocol otherwise use default behavior
if (url.startsWith(CALLBACK)) {
GetAccessToken getAccessToken = new GetAccessToken(url);
getAccessToken.execute();
return true;
}
if(mProgressDialog == null){
mProgressDialog = ProgressDialog.show(FacebookScribeLogin.this, null,
String.format(getString(R.string.talking_to_x), getString(R.string.facebook)), true, false);
}
return super.shouldOverrideUrlLoading(view, url);
}
#Override
public void onPageFinished(WebView view, String url) {
if(mProgressDialog != null){
mProgressDialog.hide();
mProgressDialog = null;
}
}
});
mWebView.loadUrl(authURL);
}
}
private class GetAccessToken extends AsyncTask<Void, Void, Void>{
private String mUrl, mToken, mSecret;
private GetAccessToken(String url) {
mUrl = url;
}
#Override
protected Void doInBackground(Void... voids) {
Uri uri = Uri.parse(mUrl);
String verifierStr = uri.getQueryParameter("code");
Verifier verifier = new Verifier(verifierStr);
//save this token for practical use.
Token accessToken = mAuthService.getAccessToken(null, verifier);
mToken = accessToken.getToken();
mSecret = accessToken.getSecret();
return null;
}
#Override
protected void onPostExecute(Void s) {
//mToken - save your mToken somehwere and perhaps use a graph API call for user details
}
}
}