Я разрабатываю приложение .NET MAUI, и сканирование тегов NFC является одним из требований. Я уже завершил разработку для Android, которая была простой и понятной. В Android все работает: от обнаружения тега NFC, получения полезных данных до их обработки.
В iOS я не могу обнаружить тег NFC. Вот что я сделал.
Служба чтения NFC iOS
Я реализовал очень простой сервис NFC для iOS, который выглядит следующим образом.
using CoreFoundation;
using CoreNFC;
using Foundation;
using MSS.App.Services.Interfaces;
using System;
using UIKit;
namespace OurAppNamespace.Platforms.iOS.Services
{
public class IosNfcService : NFCTagReaderSessionDelegate, INfcService
{
private readonly ILogService? _logService;
private NFCTagReaderSession? _nfcSession;
public IosNfcService(ILogService? logService)
{
_logService = logService;
}
public async void Enable()
{
_logService?.LogInfo($"{this}.Enable");
try
{
var isNfcAvailable = UIDevice.CurrentDevice.CheckSystemVersion(13, 0);
_logService?.LogInfo($"{this}.Enable > {nameof(isNfcAvailable)} = {isNfcAvailable}");
if (isNfcAvailable)
{
_nfcSession = new NFCTagReaderSession(NFCPollingOption.Iso14443 | NFCPollingOption.Iso15693, this, DispatchQueue.CurrentQueue)
{
AlertMessage = "Test123"
};
_nfcSession.BeginSession();
_logService?.LogInfo($"{this}.Enable > Session started.");
}
}
catch (Exception exception)
{
_logService?.LogError($"{this}.Enable > Starting Reader Session failed.", exception);
}
}
public override void DidBecomeActive(NFCTagReaderSession session)
{
_logService?.LogInfo($"{this}.DidBecomeActive");
}
public override void DidInvalidate(NFCTagReaderSession session, NSError error)
{
_logService?.LogInfo($"{this}.DidInvalidate");
}
public override void DidDetectTags(NFCTagReaderSession session, INFCTag[] tags)
{
_logService?.LogInfo($"{this}.DidDetectTags");
}
public void Disable()
{
_logService?.LogInfo($"{this}.Disable");
_nfcSession?.InvalidateSession();
}
}
}
Он основан на нескольких примерах кода, которые я нашел в Интернете. Основная идея (насколько я понимаю) заключается в том, что вы создаете экземпляр NFCTagReaderSession, если версия iOS 13 или выше, запускаете сеанс чтения, пока представление открыто, и как только что-то обнаружено, вызывается соответствующая функция. Насколько я понимаю, мне должен вызвать DidDetectTags
, как только я прикреплю свой телефон к метке NFC, но я этого не делаю.
Инфо.plist
Я отредактировал файл Info.plist, расположенный в разделе «Платформы/iOS» в моем проекте .NET MAUI, чтобы добавить разрешения для тегов NFC. Строки, которые я добавил в файл:
<key>NFCReaderUsageDescription</key>
<string>NFC tag to read NDEF messages into the application</string>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>com.apple.developer.nfc.readersession.iso7816.select-identifiers</string>
<string>D2760000850100</string>
</array>
Права.plist
Это мое первое приложение, предназначенное для iOS, и я узнал о правах, необходимых для iOS. Я выполнил все шаги официального руководства .
Это добавило следующие тексты в конфигурацию моего проекта.
<PropertyGroup Condition = "'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
</PropertyGroup>
<PropertyGroup Condition = "'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
</PropertyGroup>
Результат
Я удалил папки bin и obj своего решения, удалил ранее развернутую тестовую версию приложения с устройства iOS, перезапустил устройство, а затем пересобрал все решение. Если я открою приложение сейчас, я смогу его открыть, но не получу никаких событий для NFC. Я вижу вывод журнала из функции Enable
, но не вызов DidDetectTags
.
Я добавил Entitlements.plist, но не установил флажок «Чтение тегов беспроводной связи ближнего радиуса действия» в файле. Если я это сделаю, я больше не смогу запустить приложение. Вывод Visual Studio мало что мне говорит, но файлы журналов Xamarin указывают на проблему с профилем обеспечения. Я исследовал ошибку, упомянутую ниже, но не был уверен, как действовать дальше. Если я снимаю флажок из Entitlements.plist, приложение работает нормально, но я не обнаруживаю никаких тегов NFC.
Xamarin.Messaging.IDB.Local.DeployAppMessageHandler Error: 0 : An error occurred while trying to deploy the app '[APP_NAME]'. Details: Could not install the application '[PATH]\[APP_NAME]\out\[APP].ipa' on the device [TEST_DEVICE]. Details: ApplicationVerificationFailed|0xE8008015 - Failed to verify code signature of /var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.59k3xO/extracted/Payload/[APP_NAME] : 0xe8008015 (A valid provisioning profile for this executable was not found.)
Xamarin.iOS.Windows.WindowsiOSException: Could not install the application '[LOCAL_PATH]\[APP_NAME]\out\[APP].ipa' on the device [TEST_DEVICE]. Details: ApplicationVerificationFailed|0xE8008015 - Failed to verify code signature of /var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.59k3xO/extracted/Payload/[APP_NAME] : 0xe8008015 (A valid provisioning profile for this executable was not found.)
at Xamarin.iOS.Windows.Installer.ApplicationSession.InstallApp(String appPath, String appBundleId) in D:\a\_work\1\s\src\Tools\Xamarin.iOS.Windows.Client\Installer\ApplicationSession.cs:line 276
at Xamarin.iOS.Windows.Installer.ApplicationSession.Deploy(String appRootFolder, String appBundleId, String appName) in D:\a\_work\1\s\src\Tools\Xamarin.iOS.Windows.Client\Installer\ApplicationSession.cs:line 95
at Xamarin.iOS.Windows.HotRestartClient.Deploy(AppleDevice nativeDevice, String appBundleId, String appBundleName, Boolean& incremental) in D:\a\_work\1\s\src\Tools\Xamarin.iOS.Windows.Client\HotRestartClient.cs:line 250
at Xamarin.Messaging.IDB.Local.DeployAppMessageHandler.<ExecuteAsync>d__5.MoveNext() in D:\a\_work\1\s\src\Messaging\Xamarin.Messaging.IDB.Local\Handlers\DeployAppMessageHandler.cs:line 43: 04/04/2024 16:20:09Z
DateTime=2024-04-04T16:20:09.7343180Z: 04/04/2024 16:20:09Z
Если вы посмотрите мой блог здесь: https://medium.com/stackademic/nfc-ndef-communication-with-maui-and-xamarin-forms-fae28632c2d3
Я показал, как создать собственный сеанс, позволяющий получать обратные вызовы:
public class SessionDelegate : NFCNdefReaderSessionDelegate
{
private readonly byte[] bytes;
public TaskCompletionSource<NfcTransmissionStatus> WasDataTransmitted { get; set; }
public SessionDelegate(byte[] bytes)
{
this.bytes = bytes;
WasDataTransmitted = new TaskCompletionSource<NfcTransmissionStatus>();
}
public override void DidDetect(NFCNdefReaderSession session, NFCNdefMessage[] messages)
{
}
public override void DidDetectTags(NFCNdefReaderSession session, INFCNdefTag[] tags)
{
MainThread.BeginInvokeOnMainThread(() =>
{
session.AlertMessage = "Tag detected";
try
{
if (tags.Length != 1)
{
session.InvalidateSession(errorMessage: "Cannot write on multiple tags at the same time");
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
return;
}
var NdefTag = tags.First();
session.ConnectToTag(NdefTag, (error) =>
{
if (error != null)
{
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("There was an error while making this request");
return;
}
});
NdefTag?.QueryNdefStatus((status, capacity, error) =>
{
if (error != null)
{
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("Could not query status of tag");
}
switch (status)
{
case NFCNdefStatus.NotSupported:
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("This is an unsupported tag");
break;
case NFCNdefStatus.ReadOnly:
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("This tag is readonly");
break;
case NFCNdefStatus.ReadWrite:
var isNfcWriteAvailable = UIDevice.CurrentDevice.CheckSystemVersion(13, 0);
if (isNfcWriteAvailable)
{
var chunkString = Encoding.UTF8.GetString(bytes);
var textPayload = NFCNdefPayload.CreateWellKnownTypePayload(chunkString);
var ndefpayloadArray = new NFCNdefPayload[] { textPayload };
var ndefMessage = new NFCNdefMessage(ndefpayloadArray);
NdefTag.WriteNdef(ndefMessage, (tagError) =>
{
if (tagError != null)
{
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("Falied to write this message");
}
else
{
session.AlertMessage = "Write successful";
session.InvalidateSession();
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Success);
}
});
}
else
{
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
session.InvalidateSession("There was an error while trying to write on this tag");
}
break;
default:
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Unknown);
session.InvalidateSession("Tag status unkoown");
break;
}
});
}
catch
{
session.InvalidateSession();
WasDataTransmitted.TrySetResult(NfcTransmissionStatus.Failed);
}
});
}
public override void DidInvalidate(NFCNdefReaderSession session, NSError error)
{
if (error.Code == (int)NFCReaderError.ReaderSessionInvalidationErrorSessionTimeout)
{
MainThread.BeginInvokeOnMainThread(async () =>
{
await Application.Current.MainPage.DisplayAlert("Error ", "Tag search timed out", "Ok");
});
}
}
}
Затем используйте это с TaskCompletionSource, и вы сможете получить свои обратные вызовы.
Есть ли у вашего профиля обеспечения разрешения NFC?
Я использую автоматическую подготовку, и, согласно MSDN, она поддерживает NFC. Я работаю над машиной Windows для создания своего программного обеспечения. Как вы думаете, это может быть проблемой?
Компьютер с Windows не должен вызывать никаких проблем. Можете ли вы просмотреть связанный блог и посмотреть, не пропустили ли вы какие-либо шаги из упомянутых?
Мой код выглядит немного иначе, но все упомянутые вами конфигурации для Info.plist или Entitlements.plist я выполнил. Мне также удалось запустить Mac и подключить к нему свою Visual Studio. Но даже это мне не помогло. Я все еще получаю ту же ошибку, о которой написал в конце исходного сообщения. Я использую автоматическую подготовку и использую учетную запись разработчика Apple нашей компании.
Я смог решить эту проблему и опубликовал ответ. Большое спасибо вам за вашу поддержку.
Я смог решить проблему. Как оказалось, проблема заключалась не в том, что я разрабатывал программу на ПК с Windows, в наличии плохого кода, пропущенных конфигурациях и т. д., а в учетной записи, используемой при автоматической подготовке. Убедившись, что я все сделал правильно, я создал новый ключ команды в Apple App Store Connect API и использовал эти учетные данные в Visual Studio для автоматической подготовки. Я создал их так же, как и в прошлый раз, но на этот раз это сработало. Я не могу сказать, в чем разница, но теперь я, наконец, могу развернуть свое приложение на iOS даже с разрешениями NFC, и я смог завершить всю функцию в течение нескольких часов после того, как развертывание на iOS сработало.
Спасибо FreakyAli за поддержку в моих усилиях по выяснению этой проблемы.
Что вам нужно было сделать, чтобы запустить Entitlements? Как я писал в своей теме, как только я устанавливаю флажок NFC на экране «Права» (или добавляю строки вручную), я больше не могу запустить приложение на iOS.