Xamarin.Forms NFC: автоматический запуск приложения и чтение данных тегов на Android и iOSAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Xamarin.Forms NFC: автоматический запуск приложения и чтение данных тегов на Android и iOS

Сообщение Anonymous »

Я создаю приложение Xamarin.Forms, в котором при помещении карты NFC в телефон приложение должно запускаться автоматически и немедленно считывать все данные тега (по крайней мере идентификатор и полезные данные) за один цикл.На некоторых устройствах Android приложение запускается должным образом, но OnNewIntent в MainActivity не запускается. И оно также запускает мое приложение без чтения каких-либо данных. Почему-то метка не обнаруживается.
На других телефонах Android приложение вообще не запускается при помещении карты NFC в устройство.
Я использую следующий код, адаптированный из этого проекта, но в него внесены существенные изменения.
Мой первый вопрос: как я могу обеспечить надежный запуск приложения и чтение данных на устройствах Android? Нужны ли какие-либо изменения, чтобы обеспечить согласованность срабатывания OnNewIntent?
Мой второй вопрос касается достижения такого же поведения на iOS. Можно ли запустить приложение и прочитать данные NFC за один цикл на iOS с помощью Xamarin.Forms, учитывая ограничения iOS NFC?

NativeNFCAdapterService

Код: Выделить всё

using System;
using System.Linq;
using System.Threading.Tasks;
using NfcAdapter = Android.Nfc.NfcAdapter;
using Android.Content;
using Android.Nfc.Tech;
using Android.Nfc;
using Android.OS;
using NFCTestApp.Interfaces;
using NFCTestApp.Droid.Services;
using Xamarin.Essentials;
using Xamarin.Forms;
using NFCTestApp.Droid.Enums;
using System.IO;

[assembly: Dependency(typeof(NativeNFCAdapterService))]

namespace NFCTestApp.Droid.Services
{
class NativeNFCAdapterService : INfcAdapter
{
private readonly MainActivity mainActivity = (MainActivity)Platform.CurrentActivity;
private Lazy lazynfcAdapter = new Lazy(() => NfcAdapter.GetDefaultAdapter(Platform.CurrentActivity));
private NfcAdapter NfcAdapter => lazynfcAdapter.Value;
private PendingIntent pendingIntent;
private IntentFilter[] writeTagFilters;
private string[][] techList;
private ReaderCallback readerCallback;

public event Action TagDiscovered;
public event Action AllDataRead;

private NfcStatus NfcStatus => NfcAdapter == null ?
NfcStatus.Unavailable : NfcAdapter.IsEnabled ?
NfcStatus.Enabled : NfcStatus.Disabled;

public static Tag DetectedTag { get; set; }

public NativeNFCAdapterService()
{
Platform.ActivityStateChanged += Platform_ActivityStateChanged;
}

private void Platform_ActivityStateChanged(object sender, ActivityStateChangedEventArgs e)
{
switch (e.State)
{
case ActivityState.Resumed:
EnableForegroundDispatch();
break;

case ActivityState.Paused:
DisableForegroundDispatch();
break;
}
}

public void ConfigureNfcAdapter()
{
IntentFilter tagdiscovered = new IntentFilter(NfcAdapter.ActionTagDiscovered);
IntentFilter ndefDiscovered = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
IntentFilter techDiscovered = new IntentFilter(NfcAdapter.ActionTechDiscovered);
tagdiscovered.AddCategory(Intent.CategoryDefault);
ndefDiscovered.AddCategory(Intent.CategoryDefault);
techDiscovered.AddCategory(Intent.CategoryDefault);

var intent = new Intent(mainActivity, mainActivity.Class).AddFlags(ActivityFlags.SingleTop);
pendingIntent = PendingIntent.GetActivity(mainActivity, 0, intent, PendingIntentFlags.Immutable);

techList = new string[][]
{
new string[] { nameof(NfcA) },
new string[] { nameof(NfcB) },
new string[] { nameof(NfcF) },
new string[] { nameof(NfcV) },
new string[] { nameof(IsoDep) },
new string[] { nameof(NdefFormatable) },
new string[] { nameof(MifareClassic) },
new string[] { nameof(MifareUltralight) },
};

readerCallback = new ReaderCallback();
readerCallback.OnTagDiscoveredEvent += HandleTagDiscovered;

writeTagFilters = new IntentFilter[] { tagdiscovered, ndefDiscovered, techDiscovered };
}

public void DisableForegroundDispatch()
{
NfcAdapter?.DisableForegroundDispatch(Platform.CurrentActivity);
NfcAdapter?.DisableReaderMode(Platform.CurrentActivity);
}

public void EnableForegroundDispatch()
{
if (pendingIntent == null || writeTagFilters == null || techList == null) { return; }

NfcAdapter?.EnableForegroundDispatch(Platform.CurrentActivity, pendingIntent, writeTagFilters, techList);
NfcAdapter?.EnableReaderMode(Platform.CurrentActivity, readerCallback, NfcReaderFlags.NfcA, null);

Task.Run(async () =>  await ReadAllTagInfoAsync());
}

public void UnconfigureNfcAdapter()
{
Platform.ActivityStateChanged -= Platform_ActivityStateChanged;
}

public void HandleTagDiscovered(string tagId)
{
TagDiscovered?.Invoke(tagId);
}

public async Task SendAsync(byte[] bytes)
{
Ndef ndef = null;
try
{
if (DetectedTag == null)
DetectedTag = await GetDetectedTag();

ndef = Ndef.Get(DetectedTag);
if (ndef == null) return;

if (!ndef.IsWritable)
{
await Application.Current.MainPage.DisplayAlert("Error", "Tag is readonly", "Ok");
return;
}

if (!ndef.IsConnected)
{
await ndef.ConnectAsync();
}

await WriteToTag(ndef, bytes);
}
catch (IOException)
{
await Application.Current.MainPage.DisplayAlert("Error", "Transmission error - possibly due to movement.", "Ok");
}
catch (Exception)
{
await Application.Current.MainPage.DisplayAlert("Error", "Request error", "Ok");
}
finally
{
if (ndef?.IsConnected == true) ndef.Close();
ndef = null;
DetectedTag = null;
}
}

private async Task GetDetectedTag()
{
mainActivity.NfcTag = new TaskCompletionSource();
readerCallback.NFCTag = new TaskCompletionSource();
var tagDetectionTask = await Task.WhenAny(mainActivity.NfcTag.Task, readerCallback.NFCTag.Task);
return await tagDetectionTask;
}

private async Task WriteToTag(Ndef ndef, byte[] chunkedBytes)
{
var ndefRecord = new NdefRecord(NdefRecord.TnfWellKnown, NdefRecord.RtdText?.ToArray(), Array.Empty(), chunkedBytes);
NdefMessage message = new NdefMessage(new[] { ndefRecord });
ndef.WriteNdefMessage(message);
await Application.Current.MainPage.DisplayAlert("NFC", "Write Successful", "Ok");
}

public async Task ReadAllTagInfoAsync()
{
if (DetectedTag == null)
{
DetectedTag = await GetDetectedTag();
}

var info = new System.Text.StringBuilder();
info.AppendLine("Tech List:");
foreach (var tech in DetectedTag.GetTechList())
{
info.AppendLine($"- {tech}");
}

Ndef ndef = Ndef.Get(DetectedTag);
if (ndef != null)
{
info.AppendLine("NDEF Supported: Yes");
info.AppendLine($"NDEF Type: {ndef.Type}");
info.AppendLine($"Is Writable: {ndef.IsWritable}");
info.AppendLine($"Max Size: {ndef.MaxSize} bytes");

var ndefMessage = ndef.CachedNdefMessage;
if (ndefMessage != null && ndefMessage.GetRecords().Any())
{
foreach (var ndefRecord in ndefMessage.GetRecords())
{
info.AppendLine($"Payload: {System.Text.Encoding.UTF8.GetString(ndefRecord.GetPayload())}");
}
}
}
else
{
info.AppendLine("NDEF Supported: No");
}

AllDataRead?.Invoke(info.ToString());

return info.ToString();
}
}
}
ReaderCallback.cs

Код: Выделить всё

public class ReaderCallback : Java.Lang.Object, NfcAdapter.IReaderCallback
{
public TaskCompletionSource NFCTag { get; set; }
public event Action  OnTagDiscoveredEvent;

public void OnTagDiscovered(Tag tag)
{
var isSuccess = NFCTag?.TrySetResult(tag);
if (NFCTag == null || !isSuccess.Value)
NativeNFCAdapterService.DetectedTag = tag;

byte[] tagIdBytes = tag.GetId();
string tagId = BitConverter.ToString(tagIdBytes).Replace("-", "");
OnTagDiscoveredEvent?.Invoke(tagId);
}
}
MainActivity.cs

Код: Выделить всё

[MetaData(NfcAdapter.ActionTechDiscovered, Resource = "@xml/nfc_tech_filter")]
[IntentFilter(new[] { NfcAdapter.ActionTechDiscovered }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "text/plain")]
[IntentFilter(new[] { NfcAdapter.ActionNdefDiscovered }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "text/plain")]
[IntentFilter(new[] { NfcAdapter.ActionTagDiscovered }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "text/plain")]
[Activity(Label = "NFCTestApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public TaskCompletionSource NfcTag { get; set; }

protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);

Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}

protected override void OnNewIntent(Intent intent)
{
System.Diagnostics.Debug.WriteLine("It is here");
base.OnNewIntent(intent);

Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
{
await Xamarin.Forms.Application.Current.MainPage.DisplayAlert("NFC Tag Discovered", "A1", "OK");
});
}
}
AndroidManifest.xml
вот информация о карте
Изображение


Подробнее здесь: https://stackoverflow.com/questions/791 ... id-and-ios
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»