FireDAC query->Open crashes on Android - firemonkey

I have a multi-device FMX Form that I'm building in Embarcadero C++Builder. The app opens a local SQLite database file (my_local.db) and performs queries against it.
It works fine on iOS, but crashes on Android. No error to catch. The SQLite file exists and the ShowMessage inside the #if statement returns "/data/user/0/com.embarcadero.Project1/files/my_local.db".
If I comment out the query->Open() statement, the code runs and the app won't crash.
#if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)
Form1->FDConnection1->Params->Values["ColumnMetadataSupported"] = "False";
Form1->FDConnection1->Params->Values["Database"] = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "my_local.db");
if (FileExists(Form1->FDConnection1->Params->Values["Database"])) {
ShowMessage(Form1->FDConnection1->Params->Values["Database"]); // if file there show its path
}
#endif
TFDQuery *query;
query = new TFDQuery(NULL);
query->Connection = Form1->FDConnection1;
query->SQL->Text = "SELECT * FROM info";
query->Open();
Any pointers or suggestions on how to catch this error?

Remy's suggestion to move the code out of the Form's constructor solved the unknown crash on Android. Now it runs but gives the error shown below (this is probably the error that was causing the crash originally that I wasn't able to catch). The error message is shown below. The solution is simple - put a TFDGUIxWaitCursor on the form. After doing that it runs fine.

Related

Need to store handled exceptions globally without calling the save log method inside Every catch in xamarin.forms

try
{
int c = 0;
int a = 5 / c;
}
catch (Exception ex)
{
}
Need to write Handled Exceptions globally in one place and without calling the errorlog method in each and every catch block in xamarin.forms and expect to get details in mainactivity for android and appdelegate for ios or any comman place in xamarin.forms
In your case you could use App Center . App Center Crashes will automatically generate a crash log every time your app crashes. The log is first written to the device's storage and when the user starts the app again, the crash report will be sent to App Center. Collecting crashes works for both beta and live apps, i.e. those submitted to the App Store. Crash logs contain valuable information for you to help fix the crash.
App Center Crashes provides you with an API to generate a test crash for easy testing of the SDK. This API checks for debug vs release configurations. So you can only use it when debugging as it won't work for release apps.
Crashes.GenerateTestCrash();
If your app crashed previously, you can get details about the last crash.
ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();
Set this callback if you want to decide if a particular crash needs to be processed or not. For example, there could be a system level crash that you'd want to ignore and that you don't want to send to App Center.
Crashes.ShouldProcessErrorReport = (ErrorReport report) =>
{
// Check the report in here and return true or false depending on the ErrorReport.
return true;
};
For more details about App Center you could check Get Started with Xamarin .

How do I deal with a possible exception in a Xamarin Forms application deployed to iOS or Android?

I have a finished application which I would like to make available to run on the iOS and Android platforms.  I have tested the application as much as possible and it works without problem.  But I know there is always the chance that something might go wrong and I could get an exception.
My question is how can I deal with this or what should I do. What happens on the phone, if a Forms application is deployed and there is an exception.
Would appreciate any advice or even links as to how this is handled.
If an exception is thrown and not handled by your code, the app will stop working (i.e. crash).
In order to handle these crashes we are using MS AppCenter (the successor to HockeyApp/Xamarin AppInsights).
You'll have to create a project there (one for each platform), and add the NuGet package to your projects. Afterwards you can initialize it with
AppCenter.Start("ios={Your App Secret};android={Your App Secret}",
typeof(Crashes)); // you'll get the app secrets from appcenter.ms
Crashes will be logged to AppCenter now and you'll be informed whenever there is a new crash.
Please note that it's best practice (if not required by law), that you ask the user for consent before sending the crash report (see here). You are using the delegate Crashes.ShouldAwaitUserConfirmation for that matter. You could for example show an action sheet with Acr.UserDialogs
private bool AwaitUserConfirmation()
{
// you should of course use your own strings
UserDialogs.Instance.ActionSheet(
new ActionSheetConfig
{
Title = "Oopsie",
Message = "The app crashed. Send crash to developers.",
Options = new List<ActionSheetOption>
{
new ActionSheetOption("Sure", () => Crashes.NotifyUserConfirmation(UserConfirmation.Send)),
new ActionSheetOption("Yepp, and don't bug be again.", () => Crashes.NotifyUserConfirmation(UserConfirmation.AlwaysSend)),
new ActionSheetOption("Nope", () => Crashes.NotifyUserConfirmation(UserConfirmation.DontSend))
}
});
return true;
}

How to prevent app from crashing on uncaughtErrorEvent

Is there a way to prevent the app from crashing when JS uncaught errors occur?
Already tried to wrap app.start(...) inside try/catch, but it sure doesn't work:)
There is indeed, you can register an uncaughtErrorEvent listener.
Refer to the official documentation - https://docs.nativescript.org/core-concepts/application-lifecycle#use-application-events
You can drop the following in your app.js before bootstrapping the application
var application = require("application");
application.on(application.uncaughtErrorEvent, function (args) {
if (args.android) {
// For Android applications, args.android is an NativeScriptError.
console.log("NativeScriptError: " + args.android);
} else if (args.ios) {
// For iOS applications, args.ios is NativeScriptError.
console.log("NativeScriptError: " + args.ios);
}
});
There's no way to prevent the app from crashing. You can catch the error in the uncaughtError application event but the app will crash afterwards regardless.
Attempting to navigate to an error page won't work.
According to the comments on this GitHub issue:
Ability to specify custom error pages on uncaughtErrors · Issue #1718 · NativeScript/NativeScript
there is a way to customize the error page shown, but only on Android. Apparently there isn't anything similar available for iOS.
This is an older question but there is a documented way to prevent this using Nativescript older than 4.2 (you should be on 6+ now)
Disable rethrowing of uncaught js exceptions to native
Basically, catch the JS errors but do not crash the native app.
Note the disclaimer there as well. The script will be unstable at this point. Yes, it did not crash, but wherever it dies did not continue, so you might be worse off for stability. Putting the app in a bad state or just quitting/recrashing might be safer.

ACR Reactive BluetoothLE Plugin Invalid State when starting server

I am building an iOS app with Xamarin and MvvmCross the required the use of Bluetooth LE. I am trying to use this plugin:
https://github.com/aritchie/bluetoothle
Here is my code:
var server = CrossBleAdapter.Current.CreateGattServer();
await server.Start(new AdvertisementData()); // throws exception
It throws an exception when trying to start the server:
{System.ArgumentException: Invalid State - Unknown at
Plugin.BluetoothLE.Server.GattServer.Start
(Plugin.BluetoothLE.Server.AdvertisementData adData) [0x0005f] in
<4281c4bd57f24525b20baae1afdf610b>:0
Apparently this plugin is easy to use so I must be missing something obvious?
That Exception indicates that the hardware is in invalid or initializing state and can be seen here: https://github.com/aritchie/bluetoothle/blob/master/Plugin.BluetoothLE.Apple.Shared/Server/GattServer.cs#L74
if (this.manager.State != CBPeripheralManagerState.PoweredOn)
throw new ArgumentException("Invalid State - " + this.manager.State);
I believe this is a bug in the code as it does not wait for the delegate to signal that the State has changed.
I found a solution. Instead of placing the code in my Core project, I placed it inside the iOS project itself, in a ViewDidAppear function, and placed a global variable in my UIViewController class:
private IGattServer server = CrossBleAdapter.Current.CreateGattServer();
I think you need to access the adapter with the appropriate thread, or at the appropriate time (after other initialization), hence why it was crashing before. I couldn't find an appropriate place to put this in my Core project, so I'm not sure if I have to put this code in each platform. Anyhow here's a solution for anyone else with this problem.

How to check whether an UI element exists without failing Xamarin Test Cloud?

I am using Visual Studio C# with Xamarin to develop an iOS app. I have an UI automation which runs in Xamarin Test Cloud.
I want to check if a pop up window exists, and if it exists I want to dismiss it, othervise test should just continue. The code I am using in the test method is like below:
try
{
app.WaitForElement(x => x.Text("Update available"));
app.Tap(x => x.Marked("Ignore"));
}
catch (TimeoutException)
{
// TODO: This catch doesn't work. Test in cloud still fails.
}
The problem is that the catch doesn't work. When the test runs in Xamarin Test Cloud, the test still fails with time out error finding the element.
Does anyone know how to do it without failing the test?
You can use the app.Query method to check if the element exist if you want to avoid using the WaitForElement
The app.Query returns array of elements for the query

Resources