透過Xamarin.Forms開發Android及iOS原生NFC APP

李政輝 C.H. Lee

  • 精誠資訊/恆逸教育訓練中心-資深講師
  • 技術分類:Mobile行動應用開發

 

 

一、 NFC簡介

NFC代表近場通信(Near Field Communication)。該技術於2003年被國際標準組織正式接受。NFC是基於NFC論壇創建和維護的標準。NFC根據現有的射頻識別標準(RFID)來連接和交換數據。出於安全的考量,NFC的運行距離其實並不長,大約只有10CM的距離,但這也是為什麼NFC被廣泛選擇為非接觸式支付技術的主要原因之一。

  • 有三種不同的NFC模式:
    1. 卡模擬(Card emulation)
    2. 實體卡已被NFC-enabled的設備取代。例如,您可以使用智能手機來打開門,而無需使用實體卡來打開酒店房間。如今,Card emulation也可用於付款。我們也稱為非接觸式付款。

    3. 讀和寫(Read and write)
    4. NFC-enabled的設備可以通過使用標籤tags和smart posters來交換數據。NFC Tag可以容納少量設備可以讀取的數據。NFC-enabled的設備還可以在標籤上寫入數據。基本上,Smart posters可以包含多個Tag。Smart posters廣泛用於營銷/廣告目的。

    5. 對等通信(Peer to peer communication)
    6. 確保兩個NFC-enabled的設備可以相互通信。兩個智能手機可以交換數據。

  • NFC現實生活中的例子
    • 使用NFC非接觸式支付的APP,如LINE Pay等。
    • 實際的酒店客房卡已由可以(解鎖)門鎖的APP取代。
    • Smart posters用於廣告和營銷目的。
    • 醫院為患者提供內置的NFC腕帶。NFC Tag上的數據包含患者編號/標識。醫院的員工可以掃描腕帶並立即獲取患者醫療檔案。
    • NFC Tag被放置在圖書館的書上。使用者可以使用圖書館應用程序掃描NFC Tag 來查看書的更多訊息。
    • NFC可以用於各種目的,利用您的想像力應用在更多的生活實例。
  • NFC連接
  • NFC適用於RFID標準。讓我們看看如何透過NFC-enabled的設備(智能手機)與NFC Tag 或smart post進行通信。通過NFC進行通信基本上有兩個部分:

    • 目標方(Target)
    • 目標方是NFC Tag 或smart post。那些儲存的少量數據可以由NFC-enabled的設備讀取/寫入。目標方還可以是在對等通信模式下啟用的NFC設備。

    • 發起方(Initiator)
    • 這是NFC-enabled的設備,例如智能手機。發起方啟動NFC連接。

      啟動NFC連接有兩種模式:被動(passive)和主動(active)。處於被動模式時,發起方將RF能量發送到目標方以為其供電,然後目標方就可以將數據發送回發起方。在主動模式期間,發起方和目標方都擁有電源。這意味著發起方和目標方都可以相互發送數據。

      當然,NFC並不是唯一用於無線發送和檢索數據的技術。RFID、低功耗藍牙、Wifi和QR碼都是可行替代方案。

  • NFC數據交換格式 NDEF(NFC Data Exchange Format)
  • NDEF格式是NFC論壇標準。此訊息格式可用於從標籤讀取或寫入,或與兩個NFC-enabled的設備一起使用。該訊息包含多個記錄:

    • 標頭Header
    • 標頭記錄包含相關的重要訊息。其中之一是類型名稱格式(Type Name Format ; TNF)。該字段指示有效負載(payload )中的數據類型(實際傳輸的數據)。這些是TNF字段的可能值:
      0 -> Empty
      1 -> Well-known (text, uri 等)
      2 -> Multipurpose Internet Mail Extension (MIME)
      3 -> Absolute Uniform Resource Identifier (URI)
      4 -> External
      5- > Unknown
      6 -> Unchanged (當有效負載字段中的數據太大時,該數據將在多個記錄中分塊)
      7 -> Reserved (當前不使用)
    • 標頭記錄中儲存的其他訊息是MB (message begin)、ME(消息結束)、CF、SR和IL。

    • 類型長度(Type length)
    • 有效負載類型的長度。

    • 有效負載長度(Payload length)
    • 有效負載字段的長度,再次在有效負載字段中儲存實際數據。

    • ID長度(ID length)
    • ID字段的長度。

    • 記錄類型(Record type)
    • 有效負載數據的類型,此值對應於標頭中的TNF字段。

    • 記錄ID(Record ID)
    • 記錄的ID,主要用於外部應用程序來標識訊息。

    • 有效負載(Payload)
    • 包含以字元(bytes)為單位儲存的實際數據。

二、 開始使用Xamarin.Forms 的Plugin.NFC

  • 支援的手機平台
    • Android 4.4以後的版本
    • iOS 11以後的版本

步驟一:下載Plugin.NFC套件

在Solution方案按右鍵,點選[管理方案的Nuget套件],在[瀏覽]中輸入[Plugin.NFC]然後按右邊的[安裝]按鍵。如下圖所示。

(https://github.com/franckbour/Plugin.NFC)

步驟二:在Android專案Properties資料夾的AndroidManifest.xml添加NFC權限。

 <uses-permission android:name="android.permission.NFC" />
 <uses-feature android:name="android.hardware.nfc" android:required="true" />

如下圖所示:

步驟三:在Android專案的MainActivity.cs使用Plugin.NFC套件。

  • 3-1. 在MainActivity類別加入IntentFilter屬性標籤初始化NFC Tag。
  • 3-2. 在OnCreate方法中將CrossNFC初始化。
  • 3-3. 改寫OnNewIntent方法,啟動搜尋NFC Tag。

MainActivity.cs完整程式碼如下

using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Plugin.NFC;
using Android.Content;
using Android.Nfc;

namespace plugin_nfc.Droid
{
    [Activity(Label = "plugin_nfc", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    // 3-1在MainActivity類別加入IntentFilter屬性標籤初始化NFC Tag..
    //需using Android.Nfc;
    [IntentFilter(new[] { NfcAdapter.ActionNdefDiscovered }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/tw.com.companyname.plugin_nfc")]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);

            //3-2. 在OnCreate方法中將CrossNFC初始化
            //需using Plugin.NFC;
            CrossNFC.Init(this);

            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
        //3-3. 改寫OnNewIntent方法,啟動搜尋NFC Tag
        protected override void OnNewIntent(Intent intent)
        {
            base.OnNewIntent(intent);
            // Plugin NFC: Tag Discovery Interception
            CrossNFC.OnNewIntent(intent);
        }
    }
}

步驟四:在iOS專案的Entitlements.plist及Info.plist中添加使用NFC功能。

由於Apple的限制,僅支持NFC T Tag Reader。要在iOS設備上使用NFC,需要使用iPhone 7以後的手機和iOS 11以後的版本。

  • 4-1. 在Entitlements.plist按右鍵,點選[檢查程式碼],並加入NFC Tag Reader功能。
  • <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>NDEF</string>
    </array>

    如下列圖示的第6行至第9行程式碼:

  • 4-2. 在Info.plist按右鍵,點選[檢查程式碼],然後添加NFC功能描述。
  • <key>NFCReaderUsageDescription</key>
    <string>NFC tag to read NDEF messages into the application</string>

    如下列圖示的第6行至第7行程式碼:

步驟五:在Xamarin.Forms的共享專案中的MainPage.xaml,加入5個UI功能鍵按鈕的XAML程式碼。

MainPage.xaml完整程式碼如下:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:plugin_nfc"
             x:Class="plugin_nfc.MainPage">
    <!--5.Add UI in MainPage.xaml-->
    <ScrollView>
        <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
            <Label Text="Plugin NFC Sample" FontSize="Large" HorizontalOptions="CenterAndExpand" />
            <Button Text="Read Tag" Clicked="Button_Clicked_StartListening"/>
            <Button Text="Write Tag (Text)" Clicked="Button_Clicked_StartWriting" />
            <Button Text="Write Tag (Uri)" Clicked="Button_Clicked_StartWriting_Uri" />
            <Button Text="Write Tag (Custom)" Clicked="Button_Clicked_StartWriting_Custom" />
            <Button Text="Clear Tag" Clicked="Button_Clicked_FormatTag" />
        </StackLayout>
    </ScrollView>

</ContentPage>

步驟六:在Xamarin.Forms的共享專案中的MainPage.xaml.cs,加入功能鍵程式碼。

  • 6-1. 加入共用常數及變數
  • public const string ALERT_TITLE = "NFC";
    public const string MIME_TYPE = "application/tw.com.companyname.plugin_nfc";
    NFCNdefTypeFormat _type;
  • 6-2. 改寫OnAppearing(),檢查平台在具有 NFC 功能啟動NFC,並訂閱NFC事件: MessageReceived,MessagePublished ,TagDiscovered,OniOSReadingSessionCancelled事件。
  • protected async override void OnAppearing()
    {
        base.OnAppearing();
        //檢查平台是否支援 NFC 功能
        if (CrossNFC.IsSupported)
        {
        	 //檢查 CrossNFC.Current.IsAvailable 以確認 NFC 是否可用。
             if (!CrossNFC.Current.IsAvailable)
                await ShowAlert("NFC is not available");
           //檢查 CrossNFC.Current.IsEnabled 以確認是否啟用了 NFC。
             if (!CrossNFC.Current.IsEnabled)
                await ShowAlert("NFC is disabled");
                //訂閱NFC事件
                SubscribeEvents();
    
             if (Device.RuntimePlatform != Device.iOS)
             {
                // Start NFC tag listening manually
                  CrossNFC.Current.StartListening();
             }
        }
    }
    
    void SubscribeEvents()
    {
    //收到 ndef 消息時引發的事件。
      CrossNFC.Current.OnMessageReceived += Current_OnMessageReceived;
      //發布 ndef 消息時引發的事件。
      CrossNFC.Current.OnMessagePublished += Current_OnMessagePublished;
      //發現標記時引發的事件。用於發布。
      CrossNFC.Current.OnTagDiscovered += Current_OnTagDiscovered;
    
    if (Device.RuntimePlatform == Device.iOS)
        CrossNFC.Current.OniOSReadingSessionCancelled += Current_OniOSReadingSessionCancelled;
    }
    
  • 6-3. 改寫OnBackButtonPressed(),關閉NFC 伶聽,並取消訂閱NFC事件。
  • protected override bool OnBackButtonPressed()
    {
      UnsubscribeEvents();
      CrossNFC.Current.StopListening();
      return base.OnBackButtonPressed();
    }
    void UnsubscribeEvents()
    {
      CrossNFC.Current.OnMessageReceived -= Current_OnMessageReceived;
      CrossNFC.Current.OnMessagePublished -= Current_OnMessagePublished;
      CrossNFC.Current.OnTagDiscovered -= Current_OnTagDiscovered;
    
      if (Device.RuntimePlatform == Device.iOS)
          CrossNFC.Current.OniOSReadingSessionCancelled -= Current_OniOSReadingSessionCancelled;
    }
  • 6-4. 完成MessageReceived,MessagePublished ,TagDiscovered,OniOSReading SessionCancelled事件。
  • async void Current_OnMessageReceived(ITagInfo tagInfo)
    {
        if (tagInfo == null)
        {
            await ShowAlert("No tag found");
            return;
        }
    
        // Customized serial number
        var identifier = tagInfo.Identifier;
        var serialNumber = NFCUtils.ByteArrayToHexString(identifier, ":");
        var title = !string.IsNullOrWhiteSpace(serialNumber) ? $"Tag [{serialNumber}]" : "Tag Info";
    
        if (!tagInfo.IsSupported)
        {
            await ShowAlert("Unsupported tag", title);
        }
        else if (tagInfo.IsEmpty)
        {
            await ShowAlert("Empty tag", title);
        }
        else
        {
            var first = tagInfo.Records[0];
            await ShowAlert(GetMessage(first), title);
        }
    }
    string GetMessage(NFCNdefRecord record)
        {
            var message = $"Message: {record.Message}";
            message += Environment.NewLine;
            message += $"RawMessage: {Encoding.UTF8.GetString(record.Payload)}";
            message += Environment.NewLine;
            message += $"Type: {record.TypeFormat.ToString()}";
    
            if (!string.IsNullOrWhiteSpace(record.MimeType))
            {
                message += Environment.NewLine;
                message += $"MimeType: {record.MimeType}";
            }
    
                return message;
    }
    
    
    async void Current_OniOSReadingSessionCancelled(object sender, EventArgs e) => await ShowAlert("User has cancelled NFC reading session");
       
    async void Current_OnMessagePublished(ITagInfo tagInfo)
    {
        try
        {
            CrossNFC.Current.StopPublishing();
            if (tagInfo.IsEmpty)
            await ShowAlert("Formatting tag successfully");
        else
            await ShowAlert("Writing tag successfully");
        }
        catch (System.Exception ex)
        {
            await ShowAlert(ex.Message);
        }
    }
     
    async void Current_OnTagDiscovered(ITagInfo tagInfo, bool format)
    {
        if (!CrossNFC.Current.IsWritingTagSupported)
        {
            await ShowAlert("Writing tag is not supported on this device");
            return;
        }
    
        try
        {
            NFCNdefRecord record = null;
            switch (_type)
            {
                    case NFCNdefTypeFormat.WellKnown:
                    record = new NFCNdefRecord
                    {
                        TypeFormat = NFCNdefTypeFormat.WellKnown,
                        MimeType = MIME_TYPE,
                        Payload = NFCUtils.EncodeToByteArray("This is a text message!")
                    };
                    break;
                case NFCNdefTypeFormat.Uri:
                    record = new NFCNdefRecord
                    {
                        TypeFormat = NFCNdefTypeFormat.Uri,
                        Payload = NFCUtils.EncodeToByteArray("https://google.fr")
                    };
                    break;
                case NFCNdefTypeFormat.Mime:
                    record = new NFCNdefRecord
                    {
                        TypeFormat = NFCNdefTypeFormat.Mime,
                        MimeType = MIME_TYPE,
                        Payload = NFCUtils.EncodeToByteArray("This is a custom record!")
                    };
                    break;
                default:
                    break;
        }
    
        if (!format && record == null)
            throw new Exception("Record can't be null.");
    
        tagInfo.Records = new[] { record };
        
        if (format)
            //清除標籤
            CrossNFC.Current.ClearMessage(tagInfo);
        else
        {
            //寫標籤
             CrossNFC.Current.PublishMessage(tagInfo);
        }
    }
        catch (System.Exception ex)
        {
            await ShowAlert(ex.Message);
        }
    }
  • 6-5. 完成5個UI功能鍵按鈕的click事件及Publish共用方法程式碼。
  • async void Button_Clicked_StartListening(object sender, System.EventArgs e)
    {
        try
        {
            CrossNFC.Current.StartListening();
        }
        catch (Exception ex)
        {
            await ShowAlert(ex.Message);
        }
    }
    
    void Button_Clicked_StartWriting(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.WellKnown);
    
    void Button_Clicked_StartWriting_Uri(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.Uri);
    
    void Button_Clicked_StartWriting_Custom(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.Mime);
    
    void Button_Clicked_FormatTag(object sender, System.EventArgs e) => Publish();
    
    async void Publish(NFCNdefTypeFormat? type = null)
    {
        try
        {
            if (type.HasValue) _type = type.Value;
            CrossNFC.Current.StartPublishing(!type.HasValue);
        }
        catch (System.Exception ex)
        {
            await ShowAlert(ex.Message);
        }
    }
  • 6-6. 完成ShowAlert共用方法,使用 DisplayAlert對話方塊。
  • Task ShowAlert(string message, string title = null) => DisplayAlert(string.IsNullOrWhiteSpace(title) ? ALERT_TITLE : title, message, "Cancel");

MainPage.xaml.cs完整程式碼如下:

using Plugin.NFC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace plugin_nfc
{
    public partial class MainPage : ContentPage
    {   //6.1.加入共用常數及變數
        public const string ALERT_TITLE = "NFC";
        public const string MIME_TYPE = "application/tw.com.companyname.plugin_nfc";
        NFCNdefTypeFormat _type;

        public MainPage()
        {
            InitializeComponent();
        }
        //6.2  改寫OnAppearing(),檢查平台在具有 NFC 功能啟動NFC,並訂閱NFC事件
        //using Plugin.NFC;
        protected async override void OnAppearing()
        {
            base.OnAppearing();
            //檢查平台是否支援 NFC 功能
            if (CrossNFC.IsSupported)
            {
                //檢查 CrossNFC.Current.IsAvailable 以確認 NFC 是否可用。
                if (!CrossNFC.Current.IsAvailable)
                await ShowAlert("NFC is not available");
                //檢查 CrossNFC.Current.IsEnabled 以確認是否啟用了 NFC。
                if (!CrossNFC.Current.IsEnabled)
                await ShowAlert("NFC is disabled");
                //訂閱NFC事件
                SubscribeEvents();

                if (Device.RuntimePlatform != Device.iOS)
                {
                    // Start NFC tag listening manually
                    CrossNFC.Current.StartListening();
                }
            }
        }

        //6.3 改寫OnBackButtonPressed(),關閉NFC 聆聽,並取消訂閱NFC事件
        protected override bool OnBackButtonPressed()
        {
            UnsubscribeEvents();
            CrossNFC.Current.StopListening();
            return base.OnBackButtonPressed();

        }
        //6.2加入 MessageReceived,MessagePublished ,TagDiscovered,OniOSReadingSessionCancelled事件 Handler

        void SubscribeEvents()
        {
            //收到 ndef 消息時引發的事件。
            CrossNFC.Current.OnMessageReceived += Current_OnMessageReceived;
            //發布 ndef 消息時引發的事件。
            CrossNFC.Current.OnMessagePublished += Current_OnMessagePublished;
            //發現標記時引發的事件。用於發布。
            CrossNFC.Current.OnTagDiscovered += Current_OnTagDiscovered;

            if (Device.RuntimePlatform == Device.iOS)
                CrossNFC.Current.OniOSReadingSessionCancelled += Current_OniOSReadingSessionCancelled;
        }
        //6-3 取消MessageReceived,MessagePublished ,TagDiscovered,OniOSReadingSessionCancelled事件 Handler
        void UnsubscribeEvents()
        {
            CrossNFC.Current.OnMessageReceived -= Current_OnMessageReceived;
            CrossNFC.Current.OnMessagePublished -= Current_OnMessagePublished;
            CrossNFC.Current.OnTagDiscovered -= Current_OnTagDiscovered;

            if (Device.RuntimePlatform == Device.iOS)
                CrossNFC.Current.OniOSReadingSessionCancelled -= Current_OniOSReadingSessionCancelled;
        }
        //6-4. 完成MessageReceived,MessagePublished ,TagDiscovered,OniOSReading SessionCancelled事件 
        async void Current_OnMessageReceived(ITagInfo tagInfo)
        {
            if (tagInfo == null)
            {
                await ShowAlert("No tag found");
                return;
            }

            // Customized serial number
            var identifier = tagInfo.Identifier;
            var serialNumber = NFCUtils.ByteArrayToHexString(identifier, ":");
            var title = !string.IsNullOrWhiteSpace(serialNumber) ? $"Tag [{serialNumber}]" : "Tag Info";

            if (!tagInfo.IsSupported)
            {
                await ShowAlert("Unsupported tag", title);
            }
            else if (tagInfo.IsEmpty)
            {
                await ShowAlert("Empty tag", title);
            }
            else
            {
                var first = tagInfo.Records[0];
                await ShowAlert(GetMessage(first), title);
            }
        }
        //6.4  GetMessage方法
        string GetMessage(NFCNdefRecord record)
        {
            var message = $"Message: {record.Message}";
            message += Environment.NewLine;
            message += $"RawMessage: {Encoding.UTF8.GetString(record.Payload)}";
            message += Environment.NewLine;
            message += $"Type: {record.TypeFormat.ToString()}";

            if (!string.IsNullOrWhiteSpace(record.MimeType))
            {
                message += Environment.NewLine;
                message += $"MimeType: {record.MimeType}";
            }

            return message;
        }

        async void Current_OniOSReadingSessionCancelled(object sender, EventArgs e) => await ShowAlert("User has cancelled NFC reading session");
   
        async void Current_OnMessagePublished(ITagInfo tagInfo)
        {
            try
            {
                CrossNFC.Current.StopPublishing();
                if (tagInfo.IsEmpty)
                    await ShowAlert("Formatting tag successfully");
                else
                    await ShowAlert("Writing tag successfully");
            }
            catch (System.Exception ex)
            {
                await ShowAlert(ex.Message);
            }
        }
 
        async void Current_OnTagDiscovered(ITagInfo tagInfo, bool format)
        {
            if (!CrossNFC.Current.IsWritingTagSupported)
            {
                await ShowAlert("Writing tag is not supported on this device");
                return;
            }

            try
            {
                NFCNdefRecord record = null;
                switch (_type)
                {
                    case NFCNdefTypeFormat.WellKnown:
                        record = new NFCNdefRecord
                        {
                            TypeFormat = NFCNdefTypeFormat.WellKnown,
                            MimeType = MIME_TYPE,
                            Payload = NFCUtils.EncodeToByteArray("This is a text message!")
                        };
                        break;
                        case NFCNdefTypeFormat.Uri:
                        record = new NFCNdefRecord
                        {
                            TypeFormat = NFCNdefTypeFormat.Uri,
                            Payload = NFCUtils.EncodeToByteArray("https://google.fr")
                        };
                        break;
                        case NFCNdefTypeFormat.Mime:
                        record = new NFCNdefRecord
                        {
                            TypeFormat = NFCNdefTypeFormat.Mime,
                            MimeType = MIME_TYPE,
                            Payload = NFCUtils.EncodeToByteArray("This is a custom record!")
                        };
                        break;
                     default:
                        break;
                }

                if (!format && record == null)
                    throw new Exception("Record can't be null.");

                tagInfo.Records = new[] { record };

                if (format)
                    //清除標籤
                    CrossNFC.Current.ClearMessage(tagInfo);
                else
                {
                    //寫標籤
                    CrossNFC.Current.PublishMessage(tagInfo);
                }
            }
            catch (System.Exception ex)
            {
                await ShowAlert(ex.Message);
            }
        }


        //6.5 完成5個UI功能鍵按鈕的click事件程式碼

        async void Button_Clicked_StartListening(object sender, System.EventArgs e)
        {
            try
            {
                CrossNFC.Current.StartListening();
            }
            catch (Exception ex)
            {
                await ShowAlert(ex.Message);
            }
        }

        void Button_Clicked_StartWriting(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.WellKnown);

        void Button_Clicked_StartWriting_Uri(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.Uri);

        void Button_Clicked_StartWriting_Custom(object sender, System.EventArgs e) => Publish(NFCNdefTypeFormat.Mime);

        void Button_Clicked_FormatTag(object sender, System.EventArgs e) => Publish();

        //6.5 Publish
        async void Publish(NFCNdefTypeFormat? type = null)
        {
            try
            {
                if (type.HasValue) _type = type.Value;
                CrossNFC.Current.StartPublishing(!type.HasValue);
            }
            catch (System.Exception ex)
            {
                await ShowAlert(ex.Message);
            }
        }
        //6.6 完成ShowAlert共用方法,使用 DisplayAlert對話方塊
        Task ShowAlert(string message, string title = null) => DisplayAlert(string.IsNullOrWhiteSpace(title) ? ALERT_TITLE : title, message, "Cancel");

       
        //
        void Debug(string message) => System.Diagnostics.Debug.WriteLine(message);
       
    }
}

程式碼主要功能說明如下:

  1. 讀取標籤
    • 開始聆聽CrossNFC.Current.StartListening()
    • 收到NDEF訊息後,引發OnMessageReceived事件
  2. 寫標籤
    • 透過5個UI功能鍵按鈕的click事件呼叫 CrossNFC.Current.StartPublishing()
    • 在OnTagDiscovered事件時透過CrossNFC.Current.PublishMessage(ITagInfo)編寫標籤
  3. 清除標籤
    • 要清除標籤,請在OnTagDiscovered事件透過CrossNFC.Current.ClearMessage(ITagInfo) 清除標籤
    • 要清除標籤不要忘了在OnMessagePublished事件引發時呼叫CrossNFC.Current.StopPublishing()方法

原生APP執行畫面: