GOOGLE ADS

lunes, 18 de abril de 2022

Comunicación de Xamarin.Forms entre dos páginas dentro de la misma aplicación en diferentes dispositivos

Tecnologías, marcos y dispositivos que estoy usando:


  • Marco: Xamarin.Forms

  • IDE: Visual Studio 2022

  • Dispositivo físico (teléfono inteligente): Zebra TC26 (Android 10)

  • Dispositivo físico (reloj inteligente): Samsung Galaxy Watch4 (Android 11)


Definición del problema

Actualmente tengo un proyecto de prueba de Xamarin.Forms que consta de dos interfaces de usuario diferentes (archivos XAML):


  • Interfaz de usuario 1: HomePage.XAML: esta pantalla debe mostrarse en el teléfono inteligente

  • Interfaz de usuario 2: WatchScreen.XAML: esta pantalla debe mostrarse en el reloj inteligente


Con el siguiente código, me aseguro de que HomePage.XAML se implemente en un teléfono inteligente y la pantalla de reloj se implemente en un reloj inteligente:

Page homePage = new NavigationPage(new HomePage());
// BuildVersionCodes.R is a reference to Android version 11 (mostly now used by Wear OS 3.x)
if (Build.VERSION.SdkInt == BuildVersionCodes.R)
{
// SM-R870 is a reference to the Samsung Galaxy Watch4
// Note: This is needed to ensure the UI is specific to the UI of a smartwatch
if (Build.Model == "SM-R870")
{
Page watchScreen = new NavigationPage(new WatchScreen());
MainPage = watchScreen;
}
}
else
{
MainPage = homePage;
}

Ahora quiero hacer que estas páginas en diferentes dispositivos se comuniquen entre sí. HomePage.xaml existe dentro del proyecto principal de Xamarin.Forms, así como en WatchScreen.xaml. La forma en que quiero que se comuniquen entre ellos es enviando un mensaje o algo así. Un proyecto de Xamarin.Forms también viene con un proyecto nativo. En este proyecto nativo de Xamarin.Android, intento recuperar dentro de MainActivity.cs el botón que existe dentro del proyecto principal usando (en WatchScreen.xaml este botón existe y en WatchScreen.xaml.cs tengo un método que devuelve este botón ).

Método en WatchScreen.xaml.cs que devuelve el botón:

public Button GetSendButtonFromWearableUI() => btnSendMessage;

En MainActivity.cs obtengo este método usando:

Button button = (App.Current.MainPage.Navigation.NavigationStack.LastOrDefault() as WatchScreen)
.GetSendButtonFromWearableUI();

Cada vez que hago clic en el botón haciendo esto:

button.Clicked += delegate
{
SendData();
};

Algunos datos deben enviarse desde MainActivity.cs y ser capturados por HomePage.xaml y mostrarse en él. Intenté varios enfoques, pero no logré lograr lo que debe suceder. Por lo tanto, me pregunto si podrían ayudarme con esto y se los agradecería mucho.


Solución del problema

Mientras tanto, he estado investigando este problema y encontré una solución. Siga los pasos a continuación para obtener el mismo resultado. Para que esta solución funcione, combiné la API de capa de datos portátiles de Google y MessagingCenter de Microsoft.

Además, el siguiente ejemplo muestra solo la comunicación entre el reloj inteligente y el teléfono inteligente. Para revertir los procesos, puede colocar el botón Enviar en la página de inicio en lugar de la pantalla del reloj inteligente y asegurarse de suscribirse a los mensajes correctos.

Una última nota: tenga en cuenta que el código de Google que se usa a continuación está obsoleto, pero aún funciona...

Referencias utilizadas para hacer este trabajo:
Sincronización de datos entre dispositivos portátiles y de mano usando Xamarin en Android

Dependencias instaladas en el proyecto Xamarin.Android dentro del proyecto Xamarin.Forms:


  • Xamarin.Android.Support.v4

  • Xamarin.GooglePlayServices.Base

  • Xamarin.GooglePlayServices.Wearable


MessageKeys.cs

Esta clase se usa para declarar claves de mensajes que se usan para enviar y recibir mensajes entre dispositivos.

public class MessageKeys
{
public const string Smartwatch = "Smartwatch";
public const string Smartphone = "Smartphone";
}

Xamarin.Forms (proyecto base) - App.xaml.cs

En App.xaml.cs, como se indicó anteriormente, me aseguro de que la interfaz de usuario portátil muestre WatchScreen.xaml y cualquier otro dispositivo muestre la interfaz de usuario normal de Android -> HomePage.xaml.

Xamarin.Forms (proyecto base) - WatchScreen.xaml.cs

Envíe un mensaje desde el dispositivo portátil al teléfono inteligente Android.

private void btnSendMessage_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch);
}

Xamarin.Forms (proyecto base) - HomePage.xaml.cs

public HomePage()
{
InitializeComponent();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartphone, (sender) =>
{
DisplayAlert("Message", "Wearable message received!", "OK");
});
}

Xamarin.Forms (Proyecto nativo de Android) - MainActivity.cs

Dentro de MainActivity.cs implemento las siguientes interfaces:

public class MainActivity: WearableActivity, DataClient.IOnDataChangedListener,
GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener

Variables:

private GoogleApiClient client;
const string syncPath = "/[project name]/[subdirectory for watch]";

Clase interna 'MessageReceiver' para recibir mensajes de difusión:

[BroadcastReceiver]
public class MessageReciever: BroadcastReceiver
{
MainActivity main;
public MessageReciever() { }
public MessageReciever(MainActivity owner) { this.main = owner; }
public override void OnReceive(Context context, Intent intent)
{
main.ProcessMessage(intent);
}
}

Registrar receptor (para recibir a través de la API de capa de datos portátiles), crear un cliente de Google y suscribirse al mensaje del reloj inteligente (para recuperar el mensaje a través de MessagingCenter)

protected override void OnCreate(Bundle bundle)
{
IntentFilter filter = new IntentFilter(Intent.ActionSend);
MessageReciever receiver = new MessageReciever(this);
LocalBroadcastManager.GetInstance(this).RegisterReceiver(receiver, filter);
client = new GoogleApiClient.Builder(this, this, this)
.AddApi(WearableClass.Api)
.Build();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch, (sender) =>
{
SendData();
});
}

Método ProcessMessage: envía el mensaje recibido desde el dispositivo portátil al teléfono inteligente

public void ProcessMessage(Intent intent)
{
// For now I'm not sending the payload...
string message = intent.GetStringExtra("WearMessage");
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartphone);
}

SendData(), OnStart(), OnStop(), OnDataChanged (no hice nada con esta parte, porque esto es para recibir mensajes fuera del proyecto y no lo necesito por ahora), OnConnected(), OnConnectionSuspended(), Al fallar la conexión():

Consulte la referencia para ver qué código se ha utilizado, ya que el código es exactamente el mismo... PD: se ha cambiado una cosa para SendData. Si desea seguir enviando datos, elimine 'client.Disconenct()' de finalmente después del bloque try and catch.

Xamarin.Forms (proyecto nativo de Android): WearableService hereda de WearableListenerService:

WearableService es una clase nueva y se creó dentro del proyecto nativo. También para esta parte, vea la referencia, porque es exactamente el mismo código que se usa en mi proyecto.

Para obtener una visión general de lo que está sucediendo, lo visualicé en el siguiente diagrama: (el ejemplo muestra cómo funciona la comunicación entre el reloj inteligente y el teléfono inteligente)

SW a SP

Si desea comunicarse desde un teléfono inteligente a un reloj inteligente, puede hacer algo como esto:

SP a SW

Eso es todo chicos. Ahora recibirá mensajes dentro de la misma aplicación utilizando la API de capa de datos portátiles y MessagingCenter. En lugar de tener proyectos separados, solo usamos interfaces de usuario separadas para que esto suceda...

No hay comentarios.:

Publicar un comentario

Flutter: error de rango al acceder a la respuesta JSON

Estoy accediendo a una respuesta JSON con la siguiente estructura. { "fullName": "FirstName LastName", "listings...