Search code examples
iosmauinfccore-nfc

Scanning NFC Tags with .NET MAUI on iOS devices


I am developing a .NET MAUI App and scanning NFC Tags is one of the requirements. I already completed the development for Android which was straightforward and very simple. For Android, everything works from detecting the NFC Tag, getting the payload to processing the payload.

For iOS, I am not able to get detect an NFC Tag. Here is what I have done.

iOS NFC Reader Service

I implemented a very simple NFC Service for iOS that looks like this.

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();
        }
    }
}

It is based on several code samples I found online. The base idea (as far as I understand) is that you create an instance of NFCTagReaderSession if the iOS version is 13 or above, start a reader session as long as the view is opened and once something is detected, the appropriate function is called. From my understanding, I should get a call of DidDetectTags once I put my phone on an NFC Tag - but I don't.

Info.plist

I have edited the Info.plist that is located under Platforms/iOS in my .NET MAUI project to add permissions for NFC Tags. The lines I have added to the file are:

<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>

Entitlements.plist

This is my first App that targets iOS and I learned about the Entitlements that are required for iOS. I followed all steps of the official guide.

  1. I added an empty Entitlements.plist file to my project next to my Info.plist under Platforms/iOS.
  2. I opened the project's settings, went to the category "iOS" and then "Bundle Signing" and added the just added Entitlements.plist under "Custom Entitlements".

This added the following texts to my project's configuration.

<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>

Result

I have deleted the bin and obj folders of my solution, deleted the previously deployed test version of the App from the iOS device, restarted the device and then rebuilt the entire solution. If I open the App now, I can open the App, but I do not get any events for NFCs. I see my log output from the Enable function, but not call of DidDetectTags.

I have added the Entitlements.plist, but I did not set the check box for "Near Field Communication Tag Reading" in the file. If I do, I am not able to launch the application anymore. The output from Visual Studio does not tell me much, but the log files from Xamarin indicate an issue with the provisioning profile. I researched the error mentioned below but I was not sure on how to proceed. If I remove the check box from the Entitlements.plist, the App runs normally - but I do not get any NFC Tags detected.

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

Solution

  • I was able to solve the issue. As it turned out the issue was neither me developing on a Windows PC, having bad code, missed configurations, etc. but it was the account used in the Automatic Provisioning. After I was pretty sure I did everything right, I created a new Team Key in Apple's App Store Connect API and used these credentials in Visual Studio for Automatic Provisioning. I created them in the same way as the last time, but this time it worked. I cannot tell what the difference is, but I am now finally able to deploy my App on iOS even with NFC permissions and I was able to complete the entire feature within a few hours once the deployment on iOS worked.

    Thanks to FreakyAli for supporting me in my efforts to track down this issue.