I'm trying to use a Xamarin.AccountStore
to retain a user's login credentials so that they don't have to type them out every time they use the app.
Saving credentials looks something like this:
Account account = new Account(...);
AccountStore store = AccountStore.Create();
store.Save(account, appName);
When emulating the app from VS, this works exactly as I expected. When running on an actual phone through Xamarin Live, the Save
method throws an exception for what looks to be a missing method in the Android library.
Exception Message:
Constructor on type 'Java.Security.KeyStore+SecretKeyEntry' not found.
Stack Trace:
at System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark) [0x00213] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
at System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x000ba] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0
at NInterpret.Interpreter.newobj (System.Collections.Generic.Dictionary`2[TKey,TValue] gargs, Mono.Cecil.MethodReference m, System.Object[] createInstanceArgs) [0x00305] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpretBlock (System.Object[] args, System.Object[] locals, Mono.Cecil.Cil.Instruction initialInstruction, Microsoft.FSharp.Collections.FSharpSet`1[T] inTries, Microsoft.FSharp.Core.FSharpOption`1[T] lastException) [0x03d5b] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpret (System.Object[] args) [0x00099] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.callAMethod (NInterpret.AMethod m, NInterpret.AType[] ptypes, NInterpret.AType[] genericMethodArgs, System.Collections.Generic.Dictionary`2[TKey,TValue] genericArgsIndex, System.Object[] args, System.Collections.Generic.List`1[T] byRefArgs, Microsoft.FSharp.Core.FSharpOption`1[T] byRefTarget, System.Object target, System.Boolean virtualCall) [0x00184] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.callMethodReference (System.Collections.Generic.Dictionary`2[TKey,TValue] gargs, Mono.Cecil.MethodReference ms, System.Boolean virtualCall) [0x00384] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpretBlock (System.Object[] args, System.Object[] locals, Mono.Cecil.Cil.Instruction initialInstruction, Microsoft.FSharp.Collections.FSharpSet`1[T] inTries, Microsoft.FSharp.Core.FSharpOption`1[T] lastException) [0x03c6e] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpret (System.Object[] args) [0x00099] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.callAMethod (NInterpret.AMethod m, NInterpret.AType[] ptypes, NInterpret.AType[] genericMethodArgs, System.Collections.Generic.Dictionary`2[TKey,TValue] genericArgsIndex, System.Object[] args, System.Collections.Generic.List`1[T] byRefArgs, Microsoft.FSharp.Core.FSharpOption`1[T] byRefTarget, System.Object target, System.Boolean virtualCall) [0x00184] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.callMethodReference (System.Collections.Generic.Dictionary`2[TKey,TValue] gargs, Mono.Cecil.MethodReference ms, System.Boolean virtualCall) [0x00384] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpretBlock (System.Object[] args, System.Object[] locals, Mono.Cecil.Cil.Instruction initialInstruction, Microsoft.FSharp.Collections.FSharpSet`1[T] inTries, Microsoft.FSharp.Core.FSharpOption`1[T] lastException) [0x03c6e] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
at NInterpret.Interpreter.interpretBlock (System.Object[] args, System.Object[] locals, Mono.Cecil.Cil.Instruction initialInstruction, Microsoft.FSharp.Collections.FSharpSet`1[T] inTries, Microsoft.FSharp.Core.FSharpOption`1[T] lastException) [0x0013c] in <5a7d38ec7eef0f2aa7450383ec387d5a>:0
I've tested this on several Android devices, all with the same results. The emulator is running Android 7.1, and the phones run 6.* and 7.1, so it doesn't seem like this is an Android version issue.
I've also tried clearing out my bin
and obj
folders, reinstalling the related Nuget packages, restarting VS and my PC, etc., none of which have helped.
What's causing these behavioral differences between emulated and real devices?
Potentially Unrelated:
At one point, I wrapped the Save
expression in a try
/catch
and returned a bool
to indicate whether the save had succeeded. In the emulator, this returns true
after a successful save. On a "real" device, the catch
statement is tripped (and should return false
), but after returning to the calling code, the returned value is not false
, but rather (null)
. This is frustrating for lots of reasons (How did a non-nullable bool
get assigned a value other than true/false? How can I do anything with confidence if I can't trust the return types of my functions? etc.). I have no idea whether or not this behavior is related to the question at hand, but I include it here for completeness' sake.