franckbour / Plugin.NFC

A Cross-Platform NFC (Near Field Communication) plugin to easily read and write NFC tags in your application.
MIT License
235 stars 68 forks source link

Wrong behavior with Navigation #27

Open EvilKingStone opened 4 years ago

EvilKingStone commented 4 years ago

I use navigation in my xamarin.forms app and "OnAppearing" calling again when tag is detected by device. And I get 'Tag is missing' when try to write tag. Everything will be ok in singlepage application.

To reproduce error you can change App.xaml.cs in your sample: MainPage = new NavigationPage(new MainPage()); and try to write tag

franckbour commented 4 years ago

You probably have to subscribe on NFC events elsewhere than OnAppearing. A quick fix for the sample will be like this:

bool _eventsAlreadySubscribed = false;
void SubscribeEvents()
{
    if (_eventsAlreadySubscribed)
        return;
    _eventsAlreadySubscribed = true;

    CrossNFC.Current.OnMessageReceived += Current_OnMessageReceived;
    [...]
}
dm-CaT commented 4 years ago

It doesn't matter where the subscription is done.

  1. Create blank Xamarin Forms Project.
  2. Init CrossNFC in Android project, set required permissions.
  3. Change in the shared project app.xaml.cs Main page to the navigation page

        public App()
        {
            InitializeComponent();
    
            MainPage = new NavigationPage(new MainPage());
        }
  4. Add button to the MainPage. Bind to ListenCommand

    
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="Catyari.Xam.Nfc.Mobile.MainPage">
    
    <StackLayout>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin.Forms!" 
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />
    
        <Button Text="Listen" Command="{Binding ListenCommand}"/>
    </StackLayout>

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        this.ListenCommand = new Command(() => 
        {
            CrossNFC.Current.StartListening();
            CrossNFC.Current.OnMessageReceived += this.OnNfcMessage;
        });
        this.BindingContext = this;

        InitializeComponent();
    }

    private void OnNfcMessage(ITagInfo tagInfo)
    {
    }

    public ICommand ListenCommand { get; }

    protected override void OnAppearing()
    {
        base.OnAppearing(); // set breakpoint here
    }
}

5. Run app
6. Set breakpoint in OnAppearing method.
7. Click Listen button.
8. Place card on phone NFC sensor.

Current result: app stops on the breakpoint in OnAppearing method
dm-CaT commented 4 years ago

I did some googling about that. The reason is that the MainActivity is paused before new intent processing.

dm-CaT commented 4 years ago

The only one way I found to avoid it is to push page in modal navigation stack. This case OnAppearing is not called.

timothy-gibson commented 4 years ago

I'm also encountering this issue. OnDisappearing() is called before the event is handled and OnAppearing() is called after the event is handled. @dm-CaT did you find any other way around it?

franckbour commented 4 years ago

@dm-CaT, @timothy-gibson

  1. Create blank Xamarin Forms Project.
  2. Init CrossNFC in Android project, set required permissions.
  3. Change in the shared project app.xaml.cs Main page to the navigation page
  4. Add button to the MainPage. Bind to ListenCommand
  5. Run app
  6. Set breakpoint in OnAppearing method.
  7. Click Listen button.
  8. Place card on phone NFC sensor.

Current result: app stops on the breakpoint in OnAppearing method

I followed these reproduction steps but I didn't reproduce the final result, app didn't stop. This is my test project: TestIssue27.zip

But I maybe misunderstood the issue... If so, please provide a reproduction sample and some clear explanations.

dm-CaT commented 4 years ago

@franckbour, I took your test project and the issue is reproduced. Here is video with your project: youtube

The problem is when you read a NFC card the page in non-modal navigation stack disappears and appears (OnDisapearing and OnAppearing are called). OnAppearing method is used primarily to load some data. And loading occurs every time when a NFC is read.

dm-CaT commented 4 years ago

@timothy-gibson,

@dm-CaT did you find any other way around it?

No, I didn't. To way around I took a look into Xamarin Forms source code. I was looking for a place where OnDisappearing/OnAppearing are called as the result of the MainActivity deactivation and activation back. But I didn't find such code because XF source code is too entangled. I think if we'll find this piece of code we'll be able avoid somehow OnAppearing/OnDesappearing calls.

saamerm commented 4 years ago

@dm-CaT and @timothy-gibson I made it work in my ViewModel perfectly in a stable app. All i did was ensure that I assigned the event handlers only once, and then in the destructor of the viewmodel, and every navigation away from the page, i unassigned the event handlers

pazunino commented 3 years ago

Hi @saamerm I am stuck with this issue. Can you explain how do you workaround it? I didn't understand your last message. Thanks.

saamerm commented 3 years ago

@pazunino if you see @dm-CaT ‘s comment, you cannot reliably use the OnAppearing and OnDisappearing from Android. So instead try to use a view model and use the constructor and destructor of the view model instead

Senso4sLab commented 3 years ago

Is any progress with this issue? I think that this issue limited the usage of NFC in Xamarin.Forms. I tested with AppShell and the same problem occurred.

AlanGusLive commented 2 years ago

I use another workaround for my MAUI application. In the OnAppearing() and OnDisappearing() functions, I directly return when the application is not navigating between pages (called when NFC is used). In AppShell.xaml.cs, I set a static bool to true in the function OnNavigating(ShellNavigatingEventArgs args). After in All OnAppearing(), I test this bool to directly return or to set it to false and execute all lines in OnAppearing(). In All OnDisappearing() I test this bool to directly return or execute all lines. So with a card on phone NFC, the 2 functions OnAppearing() and OnDisappearing() are called but there is a return.

This is the MAUI sample code tested in Android: Plugin.NFCWorkaround.zip

image

image