Xamarin android - push notification Intent extras lost - xamarin.forms

I have follow this guide to setup push notification in my Xamarin Forms app.
I have an app with two activity,
one splash activity
Activity(Theme = "#style/SplashTheme",
MainLauncher = true, ScreenOrientation = ScreenOrientation.Portrait, NoHistory = true)]
public class SplashAct: Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
StartActivity(typeof(MainActivity));
Finish();
}
}
and the MainActivity
[Activity(
ClearTaskOnLaunch = false,
FinishOnTaskLaunch = false,
Theme = "#style/MainTheme",
LaunchMode = LaunchMode.SingleTask,
ScreenOrientation = ScreenOrientation.Portrait,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public partial class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
in the main activity I have override the OnNewIntent method
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
ProcessNotificationActions(intent);
}
and I have tried to send a notification using a web api published on Azure with this body:
{
"text": "Test msg",
"action": "action_a"
}
on device the text is correctly shown, but when the code reach the OnNewIntent method the intent has not extras so I lost the "action" value.
How can I solve this?
NB. I can't use LaunchMode = LaunchMode.SingleTop otherwise the OnNewIntent is not called, the OnCreate is called and the app shows a blank screen.
This happens only if the application is in background or closed. If it is in foreground all works fine.
Attached a sample, a video and info to make the POSTMAN\RESTER request.
Archive.zip

Your SplashAct is set to be the MainLauncher which will be fired up when your push notification is tapped. The Intent recieved there first will not automatically pass the extras on when it launches MainActivity. You can manually transfer them over when you call StartActivity in your SplashAct:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
var intent = new Intent(Application.Context, typeof(MainActivity));
intent.PutExtras(Intent);
StartActivity(intent);
Finish();
}

Related

How to instantiate a BroadcastReceiver on just one page of my PCL project?

I am developing a xamarin cross platform application.
I need to get an activation code by SMS automatically on my login confirmation page. This answer works if I intanciate SmsReceiver in my MainActivity, but how can I instantiate the SmsReceiver class only on my login confirmation page?
SMS activation will only be used once on one page, I do not want it to be active for the lifetime of my app. It would be a waste.
I want my app to read incoming messages only when the login confirmation page is active. How can I do this?
If you don't want your BroadcastReceiver from being always "listening" you just need to mark it as Enabled=false in the declaration, this will prevent the BrodcastReceiver from being statically-registered in the Manifest.xml.
[BroadcastReceiver(Enabled = false, Label = "SMS Receiver")]
[IntentFilter(new string[] { "android.provider.Telephony.SMS_RECEIVED", Intent.CategoryDefault })]
public class SmsReceiver : BroadcastReceiver
{
// Code omitted for simplicity
....
}
Later on the Activity you want to be listening you will need to call
RegisterReceiver()
Passing the instance of the BroadcastReceiver and the IntentFilter.
something like:
[Activity(Label = "MainActivity", MainLauncher = true, Icon = "#mipmap/icon")]
public class MainActivity: Activity
{
private SmsReceiver _smsReceiver;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_smsReceiver = new SmsReceiver()
}
protected override OnResume()
{
base.OnResume();
RegisterReceiver(_smsReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
}
protected override OnPause()
{
UnregisterReceiver(_smsReceiver);
base.OnPause();
}
}
As you can see I am also unregistering when I don't need/want to be listening anymore.
This is done with the method:
UnregisterReceiver();
Hope this helps.

Login and sign up issue

I am currently trying to build a new app (complete Novice) I have run into a strange issue on the login page.The sign up process works fine connects to firebase and returns to the login screen, then allows you to login and goes to the next activity. The problem occurs when you reload the app and use the details to re-login the login button does not work until you go into the sign up activity and come out of it then the login button works fine and allows you to sign in.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button button = findViewById(R.id.signupbtn);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
openSignupActivity();
}
});
}
private void openSignupActivity() {
Intent intent = new Intent(LoginActivity.this, SignupActivity.class);
startActivity(intent);
setContentView(R.layout.activity_login);
LoginEmail = findViewById(R.id.LoginEmail);
LoginPassword = findViewById(R.id.LoginPassword);
Loginprogressbar = findViewById(R.id.Loginprogressbar);
mAuth = FirebaseAuth.getInstance();
findViewById(R.id.Loginbtn).setOnClickListener(this);
if conditions between
if(task.isSuccessful()){
Toast.makeText(getApplicationContext(),"Login Successful",Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(LoginActivity.this,MainActivity.class));
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.Loginbtn:
Loginuser();
break;`enter code here`

Xamarin.Forms - OnStop(), OnExit(), OnClose()

I'm developing an app and I need to know when the app gets Stopped, Closed, Exited, whatever interrupts it, in order to stop some services such as WebSocket. How can I get 'access' to those events?
Thanks!
I have tested the following in a small example. (Tested it on UWP and works, the OnSleep() is called, when i close the App). The OnSleep() Method which can be overridden in the App.xaml.cs is the Method you are looking for.
The Xamarin Application LifeCycle offers some methods for your needs.
OnStart - Called when the application starts.
OnSleep - Called each time the application goes to the background.
OnResume - Called when the application is resumed, after being sent to the background.
Note that there is no method for application termination. Under normal
circumstances (ie. not a crash) application termination will happen
from the OnSleep state, without any additional notifications to your
code.
Example:
using System;
using System.Diagnostics;
using Xamarin.Forms;
namespace App1
{
public partial class App : Application
{
public App()
{
InitializeComponent();
if (Device.RuntimePlatform == Device.iOS)
MainPage = new MainPage();
else
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart() {
Debug.WriteLine("OnStart");
}
protected override void OnSleep() {
Debug.WriteLine("OnSleep");
}
protected override void OnResume() {
Debug.WriteLine("OnResume");
}
}
}
Update
According to this you have to catch unhandled exceptions in the native code. That makes it a lil complicated to shutdown your services.
Example:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity {
protected override void OnCreate(Bundle bundle) {
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs) {
//crashed by exception
}
}
Further Reading on Unhandled Exceptions: here

Change user with Firebase Google user authentication

When using Firebase Google user authentication the user is immediately logged in if they have already authorized the application and only logged in to one Google account.
Is there a way to force the "Choose an account" dialog to appear so that the user has the opportunity to login to a different Google account or create a new one?
Currency as far as I know the user has to manually logout of the current Google account (or login to > 1) from Google.com to make the dialog appear.
You can force to choose an account with 'prompt' provider parameter.
var googleAuthProvider = new firebase.auth.GoogleAuthProvider();
googleAuthProvider.setCustomParameters({
prompt: 'select_account'
});
firebase.auth().signInWithRedirect(googleAuthProvider)
Tested with Firebase JavaScript SDK v4.1.2
You should sign out from Google explicitly:
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(status -> {
mFirebaseAuth.signOut();
});
Found the solution here
I'm trying to figure out the same thing. According to some Google documentation, it appears that you can force the account chooser with a "prompt" command (of "none", "select_account" or "consent"):
Force google account chooser
...however there appears to be no way to set the "prompt" value in any of Firebase's authentication methods (specifically authWithOAuthRedirect and authWithOAuthPopup).
Were you ever able to figure it out?
In my following code, the gooogle sign-in button every time prompts for choosing account...
public class MainActivity extends AppCompatActivity {
Button btn_signOut;
private GoogleSignInClient mGoogleSignInClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_signOut = findViewById(R.id.btnSignOut);
btn_signOut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
signOut();
}
});
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
}
private void signOut() {
mGoogleSignInClient.signOut()
.addOnCompleteListener(this, new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
finish();
}
});
}
}
Use this way to signout.
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(new
ResultCallback<Status>()
{
#Override
public void onResult(#NonNull Status status)
{
mAuth.signOut();
}
});
In flutter, use: GoogleSignIn().signOut();
(assumming you used the google_sign_in package)

NotificationCompat.Builder not working in Gingerbread

I'm attempting to use the NotificationCompat.Builder class in my app. The following code runs perfectly fine on an ICS phone, but not Gingerbread. From my understanding, doesn't the support library allow access to the Builder from phones as low as API level 4? Am I doing something fundamentally wrong?
public class MainActivity extends Activity implements OnClickListener {
NotificationCompat.Builder builder;
NotificationManager nm;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
builder = new NotificationCompat.Builder(this);
nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder.setContentTitle("Test Notification")
.setContentText("This is just a test notification")
.setTicker("you have been notified")
.setSmallIcon(R.drawable.ic_stat_example)
.setWhen(System.currentTimeMillis());
findViewById(R.id.btn_notify).setOnClickListener(this);
}
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(arg0.getId() == R.id.btn_notify){
nm.notify(1, builder.build());
}
}
}
You have to supply the Intent which will be triggered when the notification is clicked. Otherwise, the notification will not be displayed on Gingerbread.
If you do not want to start the Activity when the notification is clicked, you can just pass an empty Intent as following.
Intent intent = new Intent();
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
builder.setContentTitle("Test Notification")
.setContentText("This is just a test notification")
.setTicker("you have been notified")
.setSmallIcon(R.drawable.ic_stat_example)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent); // add this

Resources