I cannot publish my MAUI app
Hello
My MAUI app runs fine in Debug - in the emulator or while deployed on my Phone.
In Release mode, on both my emulator and my phone, after a looooong compile and deploy, it won't even start. The only message I get in the "Error List" in Visual Studio is
MSB3073: The command ""C:\Program Files (x86)\Android\android-sdk\platform-tools\adb" -s emulator-5554 uninstall -k "com.MyCompanyEtc.ExpensesMobile"" exited with code 1.
This is a simplified code
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute("Login", typeof(View.Login.Login));
Routing.RegisterRoute("DocumentScan", typeof(DocumentScan));
.....
CurrentItem = Login;
}
}
[QueryProperty(nameof(Login), "Login")]
public partial class Login_VM : Base_VM
{
public readonly LoginService loginService;
private readonly IConnectivity connectivity;
[ObservableProperty]
private string password;
public Login_VM(LoginService loginService, IConnectivity connectivity)
{
try
{
this.loginService = loginService;
this.connectivity = connectivity;
username = "MyName";
password = "000";
}
catch (Exception ex)
{
ErrorHandling.HandleError(ex);
}
}
[RelayCommand]
private async Task LoginAsync()
{
if (IsBusy)
{
return;
}
try
{
if (connectivity.NetworkAccess != NetworkAccess.Internet)
{
await Shell.Current.DisplayAlert(AppRes.MsgConnectivity1, AppRes.MsgConnectivity2, "OK"); //No connectivity....etc;
return;
}
IsBusy = true;
LoginStatus loginStatus = LoginService.Login(username, password);
if (loginStatus == LoginStatus.loginAcceptedAdmin)
{
Globals.User ??= new User()
{
Name = username
};
....
await Shell.Current.GoToAsync($"//{nameof(Pending)}");
}
else if (LoginService.Login(username, password) == LoginStatus.loginAcceptedRegularUser)
{
Globals.User ??= new User()
{
Name = username
};
....
await Shell.Current.GoToAsync($"//{nameof(Pending)}");
}
else if (LoginService.Login(username, password) == LoginStatus.loginRefused)
{
await Shell.Current.DisplayAlert(AppRes.Login, AppRes.LoginWrongUsernameOrPass, "OK"); //Wrong username and/or password !
}
Globals.loginStatus = loginStatus;
}
catch (Exception ex)
{
ErrorHandling.HandleError(ex);
}
finally
{
IsBusy = false;
}
}
}
In the Tools/Android/DeviceLog I have this (snip):
at ExpensesMobile.View.Login.Login..ctor(Login_VM viewModel)
at System.Reflection.RuntimeConstructorInfo.InternalInvoke(Object , Object[] , Boolean )
at System.Reflection.RuntimeConstructorInfo.DoInvoke(Object , BindingFlags , Binder , Object[] , CultureInfo )
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags , Binder , Object[] , CultureInfo )
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite , RuntimeResolverContext )
02-15 15:24:20.473 pixel_5_-_api_33 Info 5453 MonoDroid android.runtime.JavaProxyThrowable: System.FieldAccessException: Field `Microsoft.Maui.Controls.VisualElement:ZIndexProperty' is inaccessible from method `ExpensesMobile.View.Login.Login:InitializeComponent ()'
................
02-15 15:24:20.444 pixel_5_-_api_33 Error 5453 AndroidRuntime
at ExpensesMobile.View.Login.Login..ctor(Login_VM viewModel)
Thank you
Alex
Related
I want to implement IAP in my android game.
This is my code, it is from the official unity website:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.UI;
public class Purchaser : MonoBehaviour, IStoreListener {
private static IStoreController m_StoreController; // The Unity Purchasing system.
private static IExtensionProvider m_StoreExtensionProvider; // The store-specific Purchasing subsystems.
public Text text;
public static string kProductIDConsumable = "pile_shadycoin";
void Start() {
if (m_StoreController == null) {
InitializePurchasing();
}
}
public void InitializePurchasing() {
if (IsInitialized()) {
return;
}
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct(kProductIDConsumable, ProductType.Consumable);
UnityPurchasing.Initialize(this, builder);
}
private bool IsInitialized() {
return m_StoreController != null && m_StoreExtensionProvider != null;
}
public void BuyConsumable() {
BuyProductID(kProductIDConsumable);
}
void BuyProductID(string productId) {
if (IsInitialized()) {
Product product = m_StoreController.products.WithID(productId);
if (product != null && product.availableToPurchase) {
text.text = "Purchasing product asychronously: '{0}'";
m_StoreController.InitiatePurchase(product);
} else {
text.text = "BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase";
}
} else {
text.text = "BuyProductID FAIL. Not initialized.";
}
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
text.text = "OnInitialized: PASS";
m_StoreController = controller;
m_StoreExtensionProvider = extensions;
}
public void OnInitializeFailed(InitializationFailureReason error) {
text.text = "OnInitializeFailed InitializationFailureReason:" + error;
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args) {
if (String.Equals(args.purchasedProduct.definition.id, kProductIDConsumable, StringComparison.Ordinal)) {
text.text = "ProcessPurchase: PASS. Product: '{0}'";
} else {
text.text = "ProcessPurchase: FAIL. Unrecognized product: '{0}'";
}
return PurchaseProcessingResult.Complete;
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) {
text.text = failureReason + "";
}
}
I am using the consumable item pile_shadycoin.
In the picture you can see the id and that it's active (it's german)
Picture of Google Play
If I build my project and put it on my smartphone and press the button, which is linked to BuyConsumable() it opens the menu and says:
Fehler Der angeforderte Artikel kann nicht gekauft werden
In English:
Error The requested item cannot be purchased
I found my error. I didn't released the build on alpha or beta.
I pulled the APK directly to my phone.
With this logs:
WebSocket connection to 'wss://xxxxxx.net/' failed: WebSocket opening handshake was canceled"
"TransportWebSocket.errorHandler - Error {}"
"TransportWebSocket.closeHandler - Error {"code":1006,"text":""}"
Please help with this problem.
sp.external.TransportWebSocket = function () {
var self = this;
var socket = null;
var isOpen = false;
var listSendMsg = [];
this.openHandler = null;
this.closeHandler = null;
this.messageHandler = null;
this.errorHandler = null;
this.serverURL = '';
this.send = function (_data, _highPrioritetFlag) {
utils.logger.debug('TransportWebSocket', 'send', 'Open status:' + isOpen);
_highPrioritetFlag = _highPrioritetFlag || false;
if (isOpen) {
if (_data && typeof _data === 'object') {
try {
socket.send(JSON.stringify(_data));
}
catch (error) {
throw new Error('Invalid JSON stringify');
}
}
else {
throw new Error('The data sent must be an object');
}
}
else {
if (_highPrioritetFlag) {
listSendMsg.unshift(_data);
}
else {
listSendMsg.push(_data);
}
openSocket();
}
};
this.reopen = function () {
utils.logger.debug('TransportWebSocket', 'reopen');
openSocket();
};
this.close = function (_code) {
utils.logger.debug('TransportWebSocket', 'close');
socket.close(_code);
};
function procListMsg() {
utils.logger.debug('TransportWebSocket', 'procListMsg', 'Processing buffer messages, items:' + listSendMsg.length);
if (listSendMsg.length > 0) {
self.send(listSendMsg.shift());
setTimeout(procListMsg, 20);
}
}
function openHandler() {
utils.logger.debug('TransportWebSocket', 'openHandler', 'WebSocket.readyState:' + socket.readyState);
if (socket.readyState === WebSocket.OPEN) {
isOpen = true;
procListMsg();
if (self.openHandler) {
self.openHandler();
}
}
}
function closeHandler(error) {
utils.logger.debug('TransportWebSocket', 'closeHandler', 'Error', {code: error.code, text: error.reason});
isOpen = false;
if (socket.readyState === WebSocket.CLOSED) {
if (self.closeHandler) {
self.closeHandler(error);
}
}
}
function errorHandler(error) {
utils.logger.debug('TransportWebSocket', 'errorHandler', 'Error', {code: error.code, text: error.reason});
isOpen = false;
if (self.errorHandler) {
self.errorHandler(error);
}
}
function messageHandler(e) {
var msg = null;
if (self.messageHandler) {
try {
msg = JSON.parse(e.data);
}
catch (error) {
throw new Error('Invalid JSON format in response: ' + e.data);
}
self.messageHandler(msg);
}
}
function openSocket() {
utils.logger.debug('TransportWebSocket', 'openSocket', 'Opening');
socket = new WebSocket(self.serverURL);
socket.onopen = openHandler;
socket.onclose = closeHandler;
socket.onmessage = messageHandler;
socket.onerror = errorHandler;
}
};
I don't know if you have solved this issue, but for people encountering the same trouble and who find this thread, you may check this cordova "release" behaves differently to "debug" regarding SSL
In short, modify the file that is making the behavior different between debug and release:
platforms/android/CordovaLib/src/org/apache/cordova/engine/SystemWebViewClient.java
Comment out the content of the method onReceivedSslError and replace it with
handler.proceed();
return;
I need use SPP over Bluetooth on Xamarin.Android/iOS/Mono. This is the code I'm trying for Xamarin.Android but the behavior is the same if I go to iOS and Mono on Linux/Mac:
using System;
using System.Collections.Generic;
using System.Text;
using Android.Bluetooth;
using Java.Util;
using System.IO;
using System.Threading;
using PI.SDK.Devices.BC.Responses;
using System.Threading.Tasks;
namespace PI.SDK.Devices.BC
{
public class BluetoothDeviceConnectionChannel : IBCDeviceConnectionChannel
{
private Queue<ResponseBase> _dispatcher;
private bool _abort = false;
private BluetoothAdapter _adapter;
private BluetoothSocket _socket;
private BluetoothDevice _device;
private static UUID _uuid = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
private StreamReader _reader;
private StreamWriter _writer;
private string _deviceAddress;
public event Action<string> Notify;
public bool IsOpen { get { return _socket.IsConnected; } }
public BluetoothDeviceConnectionChannel(string deviceAddress)
{
_adapter = BluetoothAdapter.DefaultAdapter;
if (_adapter == null)
throw new PIDeviceManagerException("Bluetooth is not supported on this Android device");
_deviceAddress = deviceAddress;
}
public BluetoothDeviceConnectionChannel(BluetoothDevice device) : this(device.Address) { }
public void Close()
{
_socket.Close();
}
public bool Open()
{
if (!_adapter.IsEnabled)
{
throw new PIDeviceManagerException("Bluetooth is not enabled");
}
_adapter.CancelDiscovery();
_device = _adapter.GetRemoteDevice(_deviceAddress);
_socket = _device.CreateRfcommSocketToServiceRecord(_uuid);
_socket.Connect();
if (_socket.IsConnected)
{
_reader = new StreamReader(_socket.InputStream, Encoding.GetEncoding("Windows-1252"));
_writer = new StreamWriter(_socket.OutputStream, Encoding.GetEncoding("Windows-1252"));
_dispatcher = new Queue<ResponseBase>();
Task.Factory.StartNew(() => ReceiveData());
return true;
}
return false;
}
public void ReceiveData()
{
while (_socket != null && _socket.IsConnected)
{
var data = _reader.ReadToEnd();
if (string.IsNullOrWhiteSpace(data))
continue;
var dataBuffer = data.ToCharArray();
var synBuilder = new StringBuilder();
foreach (var c in dataBuffer)
{
switch (c)
{
case ControlChars.NACK:
case ControlChars.EOT:
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
_abort = true;
return;
case ControlChars.ACK:
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
continue;
case ControlChars.SYN:
synBuilder.Append(c);
break;
case ControlChars.ETB:
synBuilder.Append(c);
var cmdResponse = synBuilder.ToString();
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {cmdResponse.Dump()}");
#endif
var response = CommandResponseParser.Parse(cmdResponse);
if (response != null)
{
_dispatcher.Enqueue(response);
}
return;
default:
synBuilder.Append(c);
break;
}
}
}
}
public ResponseBase SendData(string data)
{
_abort = false;
try
{
_writer.Write(data);
}
catch
{
throw new PIException("Unable to send data to device");
}
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[APP -> PINPAD] {data.Dump()}");
#endif
if (data[0] == ControlChars.CAN)
{
Thread.Sleep(100);
return null;
}
while (!_abort)
{
if (_dispatcher.Count > 0)
{
var response = _dispatcher.Dequeue();
if (response != null)
{
if (response is PPNotifyResponse)
{
if (Notify != null && Notify.GetInvocationList().Length > 0)
Notify(response.Message);
continue;
}
return response;
}
}
}
throw new InvalidOperationException("invalidData");
}
public ResponseBase SendData(CommandBase data)
{
var cmd = data.ToBCCommandString();
return SendData(cmd);
}
}
}
I want to achieve he same behavior of the code bellow for Windows using SerialPort class and a COMxxx port where this port, is nothing more than a Serial-Over-Bluetooth COM with the target device.
using PI.SDK.Devices.BC.Responses;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
namespace PI.SDK.Devices.BC
{
public class SerialDeviceConnectionChannel : IBCDeviceConnectionChannel
{
private SerialPort _port;
private Queue<ResponseBase> _dispatcher;
private bool _abort = false;
public event Action<string> Notify;
public bool IsOpen { get { return _port.IsOpen; } }
public SerialDeviceConnectionChannel(string port)
{
_port = new SerialPort(port, 19200, Parity.None, 8, StopBits.One);
_port.ReadTimeout = 3 * 1000;
_port.WriteTimeout = 3 * 1000;
_port.Encoding = Encoding.GetEncoding(1252);
_port.DataReceived += DataReceived;
}
public void Close()
{
_port.Close();
}
public bool Open()
{
while (true)
{
try
{
_port.Open();
_port.DiscardInBuffer();
_port.DiscardInBuffer();
break;
}
catch { Console.WriteLine($"Trying to connect to {_port}"); }
}
_dispatcher = new Queue<ResponseBase>();
return _port.IsOpen;
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var data = _port.ReadExisting();
var dataBuffer = data.ToCharArray();
var synBuilder = new StringBuilder();
foreach (var c in dataBuffer)
{
switch (c)
{
case ControlChars.NACK:
case ControlChars.EOT:
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
_abort = true;
return;
case ControlChars.ACK:
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
continue;
case ControlChars.SYN:
synBuilder.Append(c);
break;
case ControlChars.ETB:
synBuilder.Append(c);
var cmdResponse = synBuilder.ToString();
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {cmdResponse.Dump()}");
#endif
var response = CommandResponseParser.Parse(cmdResponse);
if (response != null)
{
_dispatcher.Enqueue(response);
}
return;
default:
synBuilder.Append(c);
break;
}
}
}
public ResponseBase SendData(string data)
{
_abort = false;
try
{
_port.Write(data);
}
catch
{
throw new PIException("Unable to send data to device");
}
#if DEBUG
Console.WriteLine($"[APP -> PINPAD] {data.Dump()}");
#endif
if (data[0] == ControlChars.CAN)
{
Thread.Sleep(100);
return null;
}
while (!_abort)
{
if (_dispatcher.Count > 0)
{
var response = _dispatcher.Dequeue();
if (response != null)
{
if (response is PPNotifyResponse)
{
if (Notify != null && Notify.GetInvocationList().Length > 0)
Notify(response.Message);
continue;
}
return response;
}
}
}
throw new InvalidOperationException("invalidData");
}
public ResponseBase SendData(CommandBase data)
{
var cmd = data.ToBCCommandString();
return SendData(cmd);
}
}
}
This code hangs when calling _reader.ReadToEnd(); on all other platforms except on Windows. Looks like I'm not getting the response back somehow.
Note that the Android/iOS/Mono version, must respect the serial connection configuration as stated on the ctor of the Windows classe, and the Encoding for the messages and the Serial communication, must be Windows-1252.
Any help pointing the mistakes or how to get it work the same way as on Windows would be appreciated, since there is no SerialPort class, I'm kinda lost on those devices and looks like bluetooth comm is something obscure when talking about xamarin/mobile devices.
Thanks!
Best regards,
Gutemberg
Found the problem. While in Windows the calls to serialPort.Read() can be async and on other thread, in Android/iOS/Mono, it can't.
If I start reading just after the _writer.Write(), in other words, on the same thread, I can get it working just fine.
I have a asp.net web forms site which runs well in PC. However when I try to access it from mobile it gives an object reference error. The site is asp.net 4.5.1 and used normal asp.net server controls.
public partial class index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
LoginView lView = (LoginView)this.Master.FindControl("LoginView1");
lView.Visible = false;
if (Request.QueryString["exp"] != null)
{
string msg = "Session expired please login.";
ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(), "$(function() { LoginFail('" + msg + "'); });", true);
}
}
protected void btnLogin_Click(object sender, EventArgs e)
{
ManchesterContext context = new ManchesterContext();
if (Membership.ValidateUser(txtUserId.Text, txtPassword.Text))
{
MembershipUser user = Membership.GetUser(txtUserId.Text);
aspnet_Users dbUser = context.aspnet_Users.Where(u => u.UserName.Equals(user.UserName)).FirstOrDefault();
if (dbUser.PassUpdated)//This means user has already changed default password. Perform login.
{
SetAuthenticationCookie(user);
aspnet_Users dbEntry = context.aspnet_Users.Where(u => u.UserName == user.UserName).FirstOrDefault();
SessionInfo.InitSession(dbEntry.UserId, dbEntry.UserName);
Session.Add("USR_KEY", dbEntry.UserId);
FormsAuthentication.RedirectFromLoginPage(user.UserName,false);
}
else //User has not updated default password.
{
Session.Add("TEMP_USR", txtUserId.Text);
Session.Add("TEMP_PASS", txtPassword.Text);
Response.Redirect("ChangePassword.aspx");
}
}
else
{
string msg = "Invalid User Id or Password.";
ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(), "$(function() { LoginFail('" + msg + "'); });", true);
}
}
public void SetAuthenticationCookie(MembershipUser user)
{
Response.Cookies.Clear();
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName)
{
Expires = System.DateTime.Now.AddDays(-1),
HttpOnly = true
};
HttpContext.Current.Response.Cookies.Add(cookie);
return;
}
}
This is regarding the usage of Cordova plugin "me.apla.cordova.app-preferences", which is used for saving to and retrieving from application preferences (SharedPreferences in Android and NSUserDefaults in iOS). While trying to fetch a previously saved value, some times success callback or failure callback is not being fired for both iOS and Android. But sometimes it fires successfully. Its a strange behavior. Here is the snippet of the JS code that I've used for retrieving value using the plugin:
var prefs = window.plugins.appPreferences; prefs.fetch(prefReadSucess, prefReadFailed, 'key');
function prefReadSucess(value) {
// handle success call back
}
function prefReadFailed(error) {
// handle failure callback
}
The jave code for the plugin is,
private boolean fetchValueByKey(final String key, final CallbackContext callbackContext) {
cordova.getThreadPool().execute(new Runnable() {public void run() {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(cordova.getActivity());
String returnVal = null;
if (sharedPrefs.contains(key)) {
Object obj = sharedPrefs.getAll().get(key);
String objClass = obj.getClass().getName();
if (objClass.equals("java.lang.Integer")) {
returnVal = obj.toString();
} else if (objClass.equals("java.lang.Float") || objClass.equals("java.lang.Double")) {
returnVal = obj.toString();
} else if (objClass.equals("java.lang.Boolean")) {
returnVal = (Boolean)obj ? "true" : "false";
} else if (objClass.equals("java.lang.String")) {
if (sharedPrefs.contains("_" + key + "_type")) {
// here we have json encoded string
returnVal = (String)obj;
} else {
String fakeArray = null;
try {
fakeArray = new JSONStringer().array().value((String)obj).endArray().toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
callbackContext.error(0);
return;
}
returnVal = fakeArray.substring(1, fakeArray.length()-1);
// returnVal = new JSONStringer().value((String)obj).toString();
}
} else {
Log.d("", "unhandled type: " + objClass);
}
// JSONObject jsonValue = new JSONObject((Map) obj);
callbackContext.success(returnVal);
} else {
}
}});
return true;
}
It is working properly when I comment the line from the java code,
cordova.getThreadPool().execute(new Runnable() {public void run() {
I tried to print the value of returnVal just before the line,
callbackContext.success(returnVal);
I am getting the values always. But some time the success call back is not firing,
I've ensured that the plugin is being accessed on or after the 'device ready' event. Any kind of help is appreciated.