I have a cross platform Xamarin Forms project which works fine when ran on Android or Windows Mobile.
Now I need to run it on iOS but I get an exception when the application is launched on an iPhone emulator:
"System.TypeLoadException: Could not load type 'XamarinMO.Services.DataServices' from assembly 'XamarinMO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'."
The exception occurs early in the code , in the iOS AppDelegate on LoadApplication(new App());:
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App()); -- <<*** EXCEPTION THROWN HERE ***
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
return base.FinishedLaunching(app, options);
}
I am unable to use the debugger to step into the code and the stack trace is as helpful as a chocolate kettle.
The exception does not seem to be related to the code inside my DataServices class as the execution does not even progress that far. My DataServices class seem not to even be instantiated - when I put a break point on the first line in DataServices constructor, the execution does not even get there. This indicates to me the issue is not related to the code inside the class per se (which works fine across a wide range of Android and Windows Mobile devices)
I found the cause.
I had to swap the System.Net.Http in the PCL with Microsoft.Net.Http. Apparently standard .NET System.Net.Http works fine with Android or WinPhone but not iOS.
Now the projects runs fine on all platforms.
Related
I am trying to create a Xamarin.Forms app that will run on both iOS and Android. Eventually I need instances of the app to communicate with each other via Bluetooth, but I'm stuck on getting the iOS side to do anything with Bluetooth. I originally tried to work with Plugin.BluetoothLE and Plugin.BLE, but after a week and a half I was not able to get advertising or scanning to work on either OS with either plugin, so I decided to try implementing simple Bluetooth interaction using the .NET wrappers of the platform APIs, which at least are well documented. I did get scanning to work fine on the Android side. With iOS, though, what I have right now builds just fine, and runs on my iPad without errors, but the DiscoveredPeripheral handler is never called, even though the iPad is just a few inches from the Android tablet and presumably should be able to see the same devices. I have verified this by setting a breakpoint in that method, which is never reached; and when I open the Bluetooth Settings on the iPad to make it discoverable the app version on the Android tablet can see it, so I don't think it's an iPad hardware issue.
It seems obvious that there is simply some part of the process I don't know to do, but it's not obvious (to me) where else to look to find out what it is. Here is the code for the class that interacts with the CBCentralManager (as far as I understand from what I've read, this should include everything necessary to return a list of peripherals):
using MyBluetoothApp.Shared; // for the interfaces and constants
using CoreBluetooth;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Forms;
[assembly: Dependency(typeof(MyBluetoothApp.iOS.PeripheralScanner))]
namespace MyBluetoothApp.iOS
{
public class PeripheralScanner : IPeripheralScanner
{
private readonly CBCentralManager manager;
private List<IPeripheral> foundPeripherals;
public PeripheralScanner()
{
this.foundPeripherals = new List<IPeripheral>();
this.manager = new CBCentralManager();
this.manager.DiscoveredPeripheral += this.DiscoveredPeripheral;
this.manager.UpdatedState += this.UpdatedState;
}
public async Task<List<IPeripheral>> ScanForService(string serviceUuid)
{
return await this.ScanForService(serviceUuid, BluetoothConstants.DEFAULT_SCAN_TIMEOUT);
}
public async Task<List<IPeripheral>> ScanForService(string serviceUuid, int duration)
{
CBUUID uuid = CBUUID.FromString(serviceUuid);
//this.manager.ScanForPeripherals(uuid);
this.manager.ScanForPeripherals((CBUUID)null); // For now I'd be happy to see ANY peripherals
await Task.Delay(duration);
this.manager.StopScan();
return this.foundPeripherals;
}
private void DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs args)
{
this.foundPeripherals.Add(new CPeripheral(args.Peripheral));
}
private void UpdatedState(object sender, EventArgs args)
{
CBCentralManagerState state = ((CBCentralManager)sender).State;
if (CBCentralManagerState.PoweredOn != state)
{
throw new Exception(state.ToString());
}
}
}
}
Can anyone point me in the direction of understanding what I'm missing?
EDIT: O...K, I've discovered quite by accident that if I do this in the shared code:
IPeripheralScanner scanner = DependencyService.Get<IPeripheralScanner>();
List<IPeripheral> foundPeripherals = await scanner.ScanForService(BluetoothConstants.VITL_SERVICE_UUID);
twice in a row, it works the second time. I feel both more hopeful and much more confused.
The underlying problem was that in the first instantiation of PeripheralScanner, ScanForService was being called before State was updated. I tried many ways of waiting for that event to be raised so I could be sure the state was PoweredOn, but nothing seemed to work; polling loops simply never reached the desired state, but if I threw an Exception in the UpdatedState handler it was thrown within milliseconds of launch and the state at that time was always PoweredOn. (Breakpoints in that handler caused the debugging to freeze with the output Resolved pending breakpoint, which not even the VS team seems to be able to explain).
Reading some of the Apple developer blogs I found that this situation is most often avoided by having the desired action occur within the UpdatedState handler. It finally soaked into my thick head that I was never seeing any effects from that handler running because the event was being raised and handled on a different thread. I really need to pass the service UUID to the scanning logic, and to interact with a generic List that I can return from ScanForService, so just moving it all to the handler didn't seem like a promising direction. So I created a singleton for flagging the state:
internal sealed class ManagerState // .NET makes singletons easy - Lazy<T> FTW
{
private static readonly Lazy<ManagerState> lazy = new Lazy<ManagerState>(() => new ManagerState());
internal static ManagerState Instance { get { return ManagerState.lazy.Value; } }
internal bool IsPoweredOn { get; set; }
private ManagerState()
{
this.IsPoweredOn = false;
}
}
and update it in the handler:
private void updatedState(object sender, EventArgs args)
{
ManagerState.Instance.IsPoweredOn = CBCentralManagerState.PoweredOn == ((CBCentralManager) sender).State;
}
then poll that at the beginning of ScanForService (in a separate thread each time because, again, I will not see the updates in my base thread):
while (false == await Task.Run(() => ManagerState.Instance.IsPoweredOn)) { }
I'm not at all sure this is the best solution, but it does work, at least in my case. I guess I could move the logic to the handler and create a fancier singleton class for moving all the state back and forth, but that doesn't feel as good to me.
I am using MAF for my Addin development. All seems to be working fine, but one issue needs be sorted...
I activate the plugin in their own process, i,e, using
var process = new AddInProcess();
myAddinToken.Activate(process,AddInSecurityLevel.FullTrust);
When an unhandled exception occurs in the add-in, my host crashes!
Since i am running the addin in a seperate process, why i am i still seeing my host app crash because of an unhandled exception in the ad-in?
Is it not supposed to simply crash the add-in specific dedicated process, and leave the host process as-is live?
Any ideas how to fix this?
What is the exception that crashes your app?
Do you have an UI element coming from your AddIn?
With the UI I had to close / dispose the UI elements on the host side properly and also catch RemotingException
Maybe this helps you a bit:
AddInToken grailAddInToken = addInTokens[0];
AddInProcess addInProcess = new AddInProcess();
addInProcess.Start();
Process process = Process.GetProcessById(addInProcess.ProcessId);
process.EnableRaisingEvents = true;
process.Exited += (s, e) => synchronizationService.Invoke(() =>
{
window.Close();
});
In my MonoDroid application, when an unhandled exception occurs the application terminates without any messages. If I can reproduce the error on my local device I can debug it through Visual Studio without any problems.
However, on remote devices I am stuck for a solution.
I have tried the following in the Application class but it does not actually write my log file, unless I am running through the debugger in Visual Studio.
public override void OnCreate()
{
base.OnCreate();
AndroidEnvironment.UnhandledExceptionRaiser += new EventHandler<RaiseThrowableEventArgs>(AndroidEnvironment_UnhandledExceptionRaiser);
}
void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
// Write Log File
}
I disagree with #SpiritMachine's answer.
Mono documentation tells us:
Note: You cannot rely on the AppDomain.UnhandledException event as managed exceptions are never unhandled in MonoDroid; they are always intercepted at the Android/managed boundary within a catch(Exception) block.
Instead, I recommend that you do the following:
AndroidEnvironment.UnhandledExceptionRaiser += (sender, args) =>
{
// Do something...
};
Try something like this:
EDIT : This code cannot handle caught errors. Please see #Jim G.'s answer....
Personally, I would localise error handling to where you need it. The reason being, you don't know what your application state will be when this handler is recruited - you may be without resources that you're depending on to do the handling...
Recently, I've noticed that for any BlackBerry project I run, the JDE throws an error with message
Exception thrown: no application instance...
I've even checked with a sample hello world project, which ends up with the same problem.
I did run clean.bat file, erase file system etc. work arounds to clear the archives, but no luck till now.
Could someone please guide me correctly what should be the fix for this?
I'm assuming the full exception is: "IllegalStateException: no application instance". Since you didn't give us many details of your code, I'll just talk about where I've commonly run into this Exception.
This is commonly caused by trying to get an application instance before you have called the Application's constructor. For example the following code will create that error:
public class HelloWorld extends UiApplication
{
public HelloWorld(){
pushScreen(new HelloWorldScreenBlank());
}
public static void main(String[] args) {
Application app = Application.getApplication();
HelloWorld theApp = new HelloWorld();
theApp.enterEventDispatcher();
}
}
This code produces the following console code:
llegalStateException
no application instance
net_rim_cldc-8(4B84A78F)
Application
getApplication
0x2EFA
HW_5$2e0(4D1A6F55)
HelloWorld
main
0x167
But the following code doesn't produce the exception:
public class HelloWorld extends UiApplication
{
public HelloWorld(){
Application app = Application.getApplication();
pushScreen(new HelloWorldScreenBlank());
}
public static void main(String[] args) {
HelloWorld theApp = new HelloWorld();
theApp.enterEventDispatcher();
}
}
This works because the Application instance is instantiated inside the constructor for the UiApplication object. Were as in the previous code we were trying to get the instance before an Application object existed.
I've commonly run into this trying to startup GPS from main() or in a static block. But there are a few classes which implicitly call getApplicaiton, so if you aren't explicitly calling getApplication then maybe one the API calls your making is. I would try to move code out of main and into your Application's constructor if you can.
Here is a Google search which will produce a list of classes from the 6.0 API which produce this exception:
throws IllegalStateException
Blackberry
site:www.blackberry.com/developers/docs/6.0.0api
This is driving me nuts...
Two assemblies/projects in play:
An Infrastructure project, which has an interface in it:
IDtoMapping<in TDto, out TDomain>
And an app project, referencing Infx, with an implementation:
PatientMapping : IPatientMapping
...and a marker interface, just to be clear:
public interface IPatientMapping : IDtoMapping<PatientDTO, Patient> {}
When the app boots, this gets run:
_container.RegisterType<IPatientMapping, PatientMapping> ( new ContainerControlledLifetimeManager () );
This happens in the app project, through a system-wide bootstrapping process.
(Immediately after this line runs, (through a watch), I can successfully resolve it.)
Finally, we try to resolve it (in a WCF service, in the app projec)
public PatientService (
IPatientRepository patientRepository,
ISessionSource session,
IPatientMapping patientDtoToDomainMapper )
{
.. and it fails. With the ResolutionFailedException "Cannot instantiate an interface, etc.." I've put break points at the .Resolve call, the registration, etc.. everything is getting hit as expected. But when the app tries to Resolve/BuildUp the WCF Service, Unity can't resolve the IPatientMapping parameter... it's like it forgot.
I'm at a loss.. I upgraded to Unity 2.0, added that intermediate marker interface, removed the generic interface and just used the vanilla one.. all to no avail.
Other dependencies in the system resolve just fine, including the other parameters on that same WCF constructor.
The only thing my gut is telling me is could it have something to do with the assemblies? That the .Resolve call is happening in the Infx project, but the implementation actually lives in the app-project? At runtime, all assemblies are loaded, so it shouldn't really matter, right?
Thanks for any ideas!