Appcenter push: dynamic navigation based on custom data - xamarin.forms

I'm wondering if I could get some help using AppCenter push in my Xamarin Forms app that targets Android & iOS.
Essentially, I've followed the instructions and I'm able to see the push notifications in my testing on Android. I understand that there are different behaviors between foreground and background notifications and have stepped through via the debugger when the PushNotificationReceived event happens..
The issue I'm having is I cannot find a reliable way to isolate when a user is entering the app because they tapped on a notification when the app is not loaded.
In my App.xaml.cs, I have the following:
protected override async void OnInitialized()
{
InitializeComponent();
Push.PushNotificationReceived += Push_PushNotificationReceived;
AppCenter.Start("ios={ios ID}" +
"uwp={Your UWP App secret here};" +
"android={android ID}",
typeof(Analytics), typeof(Crashes), typeof(Push));
await NavigationService.NavigateAsync("Splash"); // this is my splash screen that shows
}
private async void Push_PushNotificationReceived(object sender, PushNotificationReceivedEventArgs e)
{
if (e.CustomData != null)
{
if (e.CustomData.ContainsKey("roundId"))
{
string roundId = e.CustomData["roundId"];
//I want to navigate directly to this UI
await NavigationService.NavigateAsync($"IconNavigationPage/HomeView/Round?roundId={roundId}");
}
}
}
So, as you can see, under normal circumstances, the app will load the Splash view which does some loading, and redirects to a home view. When the notification is received and the user has the app running in the background, on Android, it's working fine. I changed my launch mode to SingleTop and added the following to my MainActivity.cs
protected override void OnNewIntent(Android.Content.Intent intent)
{
base.OnNewIntent(intent);
Push.CheckLaunchedFromNotification(this, intent);
}
The issue is, when the app is not running in the background, and I tap the notification, the Splash screen navigation call is called, then my navigation call in the PushNotificationReceived event. This essentially causes the app to load the UI that is defined in the event, for a second, then Splash UI redirects happen. This is due to the fact that OnInitialize() gets ran when the app is loaded from the Tap of the notification, when the app is not running in the background.
I have experimented in trying to implement the PushNotificationReceived event handler in the Android MainActivity.cs file, and I do see that this fires before the same PushNotificationReceived event handlers in the Shared project. Unfortunately it runs after the call to the LoadApplication, so my shared project's OnInitialize() gets fired first (which has that navigation call to Splash)
I guess what I'm looking for is some guidance, or maybe a point to a tutorial, on how I can accomplish notifying the Shared project's OnInitialize not to do the standard navigation to Splash, but rather do the navigation necessary for the Push Notification instead. I've search high and low, but all of tutorials / docs simply do a debug write to console proving that that the custom data that was passed is there, which I too can see, I cannot find anything that handles real-world use cases of a viable workflow to control navigation based on the tap of a notification.
Any help or guidance would be greatly appreciated.
Thank-you in advance.

Related

Android WebView does not use manually installed certificates

I have a WebView in a Xamarin Forms application. It shows generated HTML which has references to resources on the intranet. These resources are TLS protected and a self signed certificate backs the secure communication.
The root-certificate is installed on the android device. Accessing it with google chrome works. However accessing it from WebView fails with an SSL error (3, untrusted).
For testing purposes, I changed the WebViewClient and overwrote OnReceiveSslError. There I check for my self signed certificate, allowing it manually (handler.Proceed). This works.
However this gives me new issues such as that the Navigating-event on the Xamarin.Forms.WebView does no more fire. Probably, I could also circumvent this problem, but everything seems a bit wrong.
To me it looks like as if the Android WebView does not use the same certificate store as that Google Chrome does. Is this correct and is there a fix to this behavior, hopefully without the necessity to create a custom renderer for the WebView control and introducing a whole bunch of potential new issues (such as the missing Navigating-event)?
Update according to Jessie Zhang's request
Broken Navigating Event
Attach in XAML a Navigating event. Assign a custom renderer for the WebView and in OnElementChanged assign a custom WebviewClient via SetWebViewClient. This step breaks the Navigating event, regardless whether the OnReceiveSslError is overriden or not (see code below).
Certificate Error
Use a WebView and assign it a custom built HTML via HtmlWebViewSource and embed some images which reference a https:// resource on a server with a self signed root-certificate (OpenSSL). Add the root certificate to the Android certificate store (via the User certificates applet). Although chrome and other clients accept now the https-resources, WebView does not. It seems as it does not consider the manually installed root certificate.
As an additional information: When overriding the OnReceiveSslEvent in WebViewClient, the certificate is available in the SslError parameter, however not accepted.
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e) {
base.OnElementChanged(e);
if (e.NewElement != null) {
Control.SetWebViewClient(
new BreakingWebViewClient()
);
}
}
class BreakingWebViewClient : WebViewClient{
// ... some code, but for breaking the Navigating-event, no code is necessary
}

ASP.NET MVC5 code event in Controller should reload View

In my MVC5 application, users log in from external software without a separate login. After some times the external application can be closed and in this case a login form should appear.
I receive an event
Software.DataChange + = delegate ()
{
.... code goes here
IsUserLoggedIn = false;
};
And now the globally defined variable IsUserLoggedIn changes.
Now the login view should be called. And that's where my problems begin.
Can I do this in the controller?
Or can I assign a field via SignalR and then trigger a reload of the page? SignalR is already used for some progress bars.
Thanks
Ottilie

Azure AD B2C Xamarin Forms - After Successful login OnAppearing method executing again

This is iOS specific issue.
I have completed all the steps suggested in document over here https://azure.microsoft.com/en-in/resources/samples/active-directory-b2c-xamarin-native/
In Andtoid it is working fine. But in iOS it is not returning back to application after successful login.
Yes, Login page is displaying properly we can enter the credentials over there but once login in successful then browser is closed but debugger not attaching back to application.
I have Eneabled Keychain access, Added Url Types in info.plist and also added below code to AppDelegate.cs
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return true;
}
And on FInishLaunching event I have added below code
var authenticationService = DependencyService.Get();
// Default system browser
authenticationService.SetParent(null);
Actually I am calling SignInAsync method from OnAppearing event of view. So after successful validation OnAppearing event is firing again and it lost the previous flow.
Please let me know if I am missing something. Your help is much appreciated.
Thanks.

Modify Xamarin.Forms page from Xamarin.iOS file

I'm working on a Xamarin.Forms app that uses Firebase Authentication. In order to make Firebase work, I have to create two different platform-specific files (iOS and Android) to process the Authentication tasks (like CreateNewUser and Login). I have a Xamarin.Forms page called "Payment Page" that asks a user to enter their e-mail and password, and submitting this page triggers the DependencyService to create the user account. On the Payment Page, I also have a small window that will appear if something goes wrong with the account creation process (specifically in this case, if a duplicate e-mail already exists in the Auth database).
My question is, if one of the Dependency files for iOS or Android catches a 'ERROR_EMAIL_ALREADY_IN_USE', how can I set the error dialog on the Payment Page to show (in other words, set its 'isVisible' property to 'true'). I've tried a number of things but so far cannot seem to reference elements in the PaymentPage (a Xamarin.Forms page) from the Xamarin.iOS Authentication page.
My Dependency code is as follows:
public void CreateNewUser(string email, string password, System.Collections.Specialized.NameValueCollection userData)
{
Auth.DefaultInstance.CreateUser(email, password, HandleAuthDataResultHandler);
}
async void HandleAuthDataResultHandler(AuthDataResult authResult, Foundation.NSError error)
{
if(error.UserInfo["error_name"].ToString() == "ERROR_EMAIL_ALREADY_IN_USE")
{
//What goes here to modify the Xamarin.Forms page??
}
else { }
}
MessagingCenter might be a good way to go https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/messaging-center
You can suscribe your viewmodel and post a message from the handler with the result.
in your XAML code behind
try {
// call your dependency service
} catch (Exception ex)
{
// update the UI
}
then in your DependencyService method, it should throw an exception when an error condition occurs

Creating a new MobileServiceClient() freezes VS and Android app

Working on a Xamarin Forms app (Android & iOS)
When trying to create my connection to an easy table I have in an Azure Mobile App my Visual Studio Freezes for around 7 seconds and then when it comes back it has exited the code and the Android app, running in debug is permanently frozen.
When stepping through the code it steps over
client = new MobileServiceClient(appUrl);
and then when it hits the next line it freezes. But it doesn't matter what the next line is. I have put many different things after and it still freezes. Also, this is in a try/catch block, yet no exception is thrown.
I also wanted to see if the problem was server side. But both Post and Get with PostMan works fine. So I think my server is fine. Not completely sure though...
Here is some of the code:
public class ChatStorageAzureService : IChatStorageAzureService
{
public MobileServiceClient client { get; set; }
private IMobileServiceSyncTable<MessageViewModel> chatTable;
public static bool UseAuth { get; set; } = false;
private static ChatStorageAzureService instance;
public static ChatStorageAzureService Instance => instance ?? (instance = new ChatStorageAzureService());
public async Task InitializeAsync()
{
if (client?.SyncContext?.IsInitialized ?? false)
return;
var appUrl = "http://"MY-WEBSITE".azurewebsites.net/";
try
{
client = new MobileServiceClient(appUrl);
var path = "syncstore.db";
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<MessageViewModel>();
await client.SyncContext.InitializeAsync(store);
chatTable = client.GetSyncTable<MessageViewModel>();
}
catch (Exception e)
{
Debug.WriteLine("Exception thrown in Initialize: " + e);
throw;
}
}
The InitializeAsync has been called in Async methods. It has been called with .Wait() method in a constructor. It has been called with button presses or in page creations. I have tried a ton of different ways to call. But it always freezes.
One thing that I think is weird is that my server code, is one project containing both the SignalR hub code and the Easy Table, yet you access them through different web addresses, For example
"http://"SignalR".azurewebsites.net/"
and
"http://"EasyTable".azurewebsites.net/"
Again PostMan is able to access both the tables and the SignalR and the SignalR works on the Android project. But I dont know if having to domains is bad. I am new... if you could not tell already, lol!
I followed this Tutorial for the Easy Table integration and when I did it in a separate project it worked fine. I am trying to integrate it into my actual project and that is where I am having all these problems.
I also turned on debugging with Azure and it doesnt seem like my app ever even reaches the service. No call is ever met. I think. But again I am new to debugging with Azure, so I might not know how to do it right. I followed this Tutorial for setting up Azure debugging
Thanks for any and all help!
Your path is incorrect. It needs to be a directory path, for example on iOS it is /<AppHome>/Library/<YourAppName>/syncstore.db.
We can leverage MobileServiceClient.DefaultDatabasePath to get the default database path in a cross-platform manner.
var path = Path.Combine(MobileServiceClient.DefaultDatabasePath, "syncstore.db");
Feel free to reference this Xamarin.Forms Sample App that uses Azure Mobile Service Client:
https://github.com/brminnick/UITestSampleApp/blob/master/Src/UITestSampleApp/Services/AzureService.cs
So I finally got it to work!!! "How?" you ask. I went on 2 week vacation, came back, started a again. Copied the new URL of the tut project into my actual project, did some testing. And then this is the big thing, I then put the same address I had been using back into my app, and... it just worked.... I did NOTHING to the code, and now it seems to work... So almost a month of work time lost and all I had to do was just put a different URL in, run it, and then put the original URL back in.... Lovely. I am guessing it cleared out some weird temp file that was messing up the program or something... even though I erased the temp files countless times... I don't get it, but onward I go!

Resources