рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рддрдерд╛рдХрдерд┐рдд
рд╣реЛрд╕реНрдЯ-рдЖрдзрд╛рд░рд┐рдд рдХрд╛рд░реНрдб рдЗрдореНрдпреВрд▓реЗрд╢рди (HCE, рдмреИрдВрдХ рдХрд╛рд░реНрдб рдПрдореБрд▓реЗрд╢рди рдСрди рдж рдлреЛрди) рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВрдЧреЗред рдиреЗрдЯрд╡рд░реНрдХ рдореЗрдВ рдЗрд╕ рддрдХрдиреАрдХ рдХрд╛ рд╡рд┐рд╕реНрддреГрдд рд╡рд┐рд╡рд░рдг рд╣реИ, рдпрд╣рд╛рдВ рдореИрдВрдиреЗ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдПрдореБрд▓реЗрдЯрд░ рдФрд░ рд░реАрдбрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдХрдИ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд┐рдпрд╛ред рд╣рд╛рдВ, рдЖрдкрдХреЛ nfc рдХреЗ рд╕рд╛рде 2 рдЙрдкрдХрд░рдгреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред
рдмрд╣реБрдд рд╕рд╛рд░реЗ рдЙрдкрдпреЛрдЧ рдкрд░рд┐рджреГрд╢реНрдп рд╣реИрдВ:
рдкрд╛рд╕ рд╕рд┐рд╕реНрдЯрдо , рд▓реЙрдпрд▓реНрдЯреА рдХрд╛рд░реНрдб, рдЯреНрд░рд╛рдВрд╕рдкреЛрд░реНрдЯ рдХрд╛рд░реНрдб, рд╕рдВрдЧреНрд░рд╣рд╛рд▓рдп рдореЗрдВ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛,
рдкрд╛рд╕рд╡рд░реНрдб рдореИрдиреЗрдЬрд░ ред
рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдХрд╛рд░реНрдб рдХрд╛ рдЕрдиреБрдХрд░рдг рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдлреЛрди рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВ рдФрд░ рдЖрдкрдХреЗ рдлреЛрди рдХреА рд╕реНрдХреНрд░реАрди рд▓реЙрдХ рд╣реЛ рд╕рдХрддреА рд╣реИред
рдЬрд╝рдорд╛рд░рд┐рди рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рд▓рд┐рдП,
рдХрд╛рд░реНрдб рдПрдореБрд▓реЗрдЯрд░ рдФрд░
рд░реАрдбрд░ рдХреЗ рддреИрдпрд╛рд░ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВред
рдЖрдЗрдП рдЗрди рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ 2 Xamarin Forms рдПрдкреНрд▓рд┐рдХреЗрд╢рди, рдПрдХ рдПрдореБрд▓реЗрдЯрд░ рдФрд░ рд░реАрдбрд░ рдмрдирд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ, рдФрд░ рдЙрдирдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░реЗрдВ:
- рд░реАрдбрд░ рд╕реНрдХреНрд░реАрди рдкрд░ рдПрдореБрд▓реЗрдЯрд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ
- рдПрдореБрд▓реЗрдЯрд░ рд╕реНрдХреНрд░реАрди рдкрд░ рд░реАрдбрд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ
- рдПрдореБрд▓реЗрдЯрд░ рдХреЛ рдЕрдкреНрд░рдмрдВрдзрд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдФрд░ рд▓реЙрдХ рд╕реНрдХреНрд░реАрди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП
- рдПрдореБрд▓реЗрдЯрд░ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░реЗрдВ
- рдПрдХ рдкрд╛рдардХ рдХрд╛ рдкрддрд╛ рдЪрд▓рдиреЗ рдкрд░ рдПрдореБрд▓реЗрдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
- nfc рдПрдбреЗрдкреНрдЯрд░ рдХреА рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░рдирд╛ рдФрд░ nfc рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдирд╛
рдпрд╣ рд▓реЗрдЦ рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЖрдИрдУрдПрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╡реЗрджрди рднреА рд╣реИ, рддреЛ рдПрдХ рдЕрд▓рдЧ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рд╕рд┐рджреНрдзрд╛рдВрдд рдХреА рдиреНрдпреВрдирддрдоред
рдЬреИрд╕рд╛ рдХрд┐
рдПрдВрдбреНрд░реЙрдЗрдб рдбреЙрдХреНрдпреВрдореЗрдВрдЯ рдореЗрдВ рд▓рд┐рдЦрд╛ рд╣реИ, рд╕рдВрд╕реНрдХрд░рдг 4.4 (рдХрд┐рдЯрдХреИрдЯ) рд╕реЗ рд╢реБрд░реВ рд╣реЛрдХрд░, рдЖрдИрдПрд╕рдУ-рдбреАрдИрдкреА рдХрд╛рд░реНрдб рдХрд╛ рдЕрдиреБрдХрд░рдг рдХрд░рдиреЗ рдФрд░ APDU рдХрдорд╛рдВрдб рдХреЛ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИред
рдХрд╛рд░реНрдб рдПрдореБрд▓реЗрд╢рди "рдПрдЪрд╕реАрдИ рд╕реЗрд╡рд╛рдУрдВ" рдХреЗ рд░реВрдк рдореЗрдВ рдЬрд╛рдиреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдПрдВрдбреНрд░реЙрдЗрдб рд╕реЗрд╡рд╛рдУрдВ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред
рдЬрдм рдХреЛрдИ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдПрдХ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЛ рдПрдирдПрдлрд╕реА рд░реАрдбрд░ рд╕реЗ рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рддреЛ рдПрдВрдбреНрд░реЙрдЗрдб рдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдХрд┐ рдкрд╛рдардХ рдХрд┐рд╕ рдПрдЪрд╕реАрдИ рд╕реЗрд╡рд╛ рд╕реЗ рдЬреБрдбрд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИред рдЖрдИрдПрд╕рдУ / рдЖрдИрдИрд╕реА 7816-4 рдПрдкреНрд▓реАрдХреЗрд╢рди рдЖрдИрдбреА (рдПрдЖрдИрдбреА) рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдЖрд╡реЗрджрди рдЪрдпрди рд╡рд┐рдзрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИред
рдпрджрд┐ рдмрд╛рдЗрдЯ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рд╕реБрдВрджрд░ рджреБрдирд┐рдпрд╛ рдореЗрдВ рддрд▓реНрд▓реАрди рдХрд░рдирд╛ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рддреЛ
рдпрд╣рд╛рдВ рдФрд░
рдпрд╣рд╛рдВ APDU рдЖрджреЗрд╢реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддреГрдд рд╣реИред рдпрд╣ рдЖрд▓реЗрдЦ рдбреЗрдЯрд╛ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдЖрджреЗрд╢реЛрдВ рдХреЗ рдХреЗрд╡рд▓ рдПрдХ рдЬреЛрдбрд╝реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред
рдкрд╛рдардХ рдЖрд╡реЗрджрди
рдкрд╛рдардХ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рд░рд▓ рд╣реИред
рд╣рдо "рдореЛрдмрд╛рдЗрд▓ рдРрдк (Xamarin.Forms)" рдЬреИрд╕реЗ рд╡рд┐рдЬрд╝реБрдЕрд▓ рд╕реНрдЯреВрдбрд┐рдпреЛ рдореЗрдВ рдПрдХ рдирдИ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВ, рдлрд┐рд░ "рдмреНрд▓реИрдВрдХ" рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ рдФрд░ "рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо" рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдХреЗрд╡рд▓ "рдПрдВрдбреНрд░реЙрдЗрдб" рдЪреЗрдХрдорд╛рд░реНрдХ рдЫреЛрдбрд╝ рджреЗрдВред
Android рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗ:
- CardReader рд╡рд░реНрдЧ - рдЗрд╕рдореЗрдВ рдХрдИ рд╕реНрдерд┐рд░рд╛рдВрдХ рдФрд░ OnTagDiscovered рд╡рд┐рдзрд┐ рд╢рд╛рдорд┐рд▓ рд╣реИ
- MainActivity - рдЖрд╡реЗрджрди рдХреЛ рдЫреЛрдЯрд╛ рдХрд░рддреЗ рд╕рдордп рд░реАрдбрд░ рдХреЛ рдЪрд╛рд▓реВ / рдмрдВрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП CardReader рд╡рд░реНрдЧ, рд╕рд╛рде рд╣реА OnPause рдФрд░ OnResume рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдЖрд░рдВрднреАрдХрд░рдгред
- AndroidManifest.xml - nfc рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐рдпрд╛рдВ
рдФрд░ App.xaml.cs рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ:
- рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐
рдХрд╛рд░реНрдбрд┐рдпрд░ рдХреНрд▓рд╛рд╕
using Android.Nfc; using Android.Nfc.Tech; using System; using System.Linq; using System.Text; namespace ApduServiceReaderApp.Droid.Services { public class CardReader : Java.Lang.Object, NfcAdapter.IReaderCallback {
Nfc рдПрдбреЗрдкреНрдЯрд░ рдХреЗ рд░реАрдб рдореЛрдб рдореЗрдВ, рдЬрдм рдХрд╛рд░реНрдб рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ OnTagDiscovered рдореЗрдердб рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдореЗрдВ, IsoDep рдПрдХ рдРрд╕рд╛ рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рд╣рдо рдореИрдк рдХреЗ рд╕рд╛рде рдХрдорд╛рдВрдб рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░реЗрдВрдЧреЗ (isoDep.Transceive (рдХрдорд╛рдВрдб))ред рдХрдорд╛рдВрдб рдмрд╛рдЗрдЯ рд╕рд░рдгрд┐рдпрд╛рдБ рд╣реИрдВред
рдХреЛрдб рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдПрдореБрд▓реЗрдЯрд░ рдХреЛ рдПрдХ рдЕрдиреБрдХреНрд░рдо рднреЗрдЬрддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ SELECT_APDU_HEADER рд╣реЗрдбрд░, рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рд╣рдорд╛рд░реЗ AID рдХреА рд▓рдВрдмрд╛рдИ рдФрд░ рд╕реНрд╡рдпрдВ AID рд╢рд╛рдорд┐рд▓ рд╣реИ:
0 164 4 0 // SELECT_APDU_HEADER 5 // AID 241 35 69 103 137 // SAMPLE_LOYALTY_CARD_AID (F1 23 45 67 89)
MainActivity Reader
рдпрд╣рд╛рдБ рдЖрдкрдХреЛ рдкрд╛рдардХ рдХреНрд╖реЗрддреНрд░ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
public CardReader cardReader;
рдФрд░ рджреЛ рд╕рд╣рд╛рдпрдХ рддрд░реАрдХреЗ:
private void EnableReaderMode() { var nfc = NfcAdapter.GetDefaultAdapter(this); if (nfc != null) nfc.EnableReaderMode(this, cardReader, READER_FLAGS, null); } private void DisableReaderMode() { var nfc = NfcAdapter.GetDefaultAdapter(this); if (nfc != null) nfc.DisableReaderMode(this); }
рдСрдирдХреНрд░рд┐рдПрдЯ () рд╡рд┐рдзрд┐ рдореЗрдВ, рдкрд╛рдардХ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВ рдФрд░ рд░реАрдб рдореЛрдб рдХреЛ рд╕рдХреНрд╖рдо рдХрд░реЗрдВ:
protected override void OnCreate(Bundle savedInstanceState) { ... cardReader = new CardReader(); EnableReaderMode(); LoadApplication(new App()); }
рдФрд░, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЫреЛрдЯрд╛ / рдЦреЛрд▓рддреЗ рд╕рдордп рд░реАрдбрд┐рдВрдЧ рдореЛрдб рдХреЛ рд╕рдХреНрд╖рдо / рдЕрдХреНрд╖рдо рдХрд░реЗрдВ:
protected override void OnPause() { base.OnPause(); DisableReaderMode(); } protected override void OnResume() { base.OnResume(); EnableReaderMode(); }
App.xaml.cs
рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдереИрддрд┐рдХ рд╡рд┐рдзрд┐:
public static async Task DisplayAlertAsync(string msg) => await Device.InvokeOnMainThreadAsync(async () => await Current.MainPage.DisplayAlert("message from service", msg, "ok"));
AndroidManifest.xml
Android рдкреНрд░рд▓реЗрдЦрди рдХрд╣рддрд╛ рд╣реИ рдХрд┐ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдореЗрдВ nfc рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдФрд░ рдЗрд╕рдХреЗ рд╕рд╛рде рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░реЗрдВ, рдЖрдкрдХреЛ AndroidManifest.xml рдореЗрдВ рдЗрди рддрддреНрд╡реЛрдВ рдХреЛ рдШреЛрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
<uses-permission android:name="android.permission.NFC" /> <uses-sdk android:minSdkVersion="10"/> <uses-sdk android:minSdkVersion="14"/> <uses-feature android:name="android.hardware.nfc" android:required="true" />
рдЙрд╕реА рд╕рдордп, рдпрджрд┐ рдЖрдкрдХрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди nfc рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдЖрд╡рд╢реНрдпрдХ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рдЙрдкрдпреЛрдЧ-рд╕реБрд╡рд┐рдзрд╛ рддрддреНрд╡ рдХреЛ рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдСрдкрд░реЗрд╢рди рдХреЗ рджреМрд░рд╛рди nfc рдХреА рдЙрдкрд▓рдмреНрдзрддрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдкрд╛рдардХ рдХреЗ рд▓рд┐рдП рдмрд╕ рдЗрддрдирд╛ рд╣реАред
рдПрдореБрд▓реЗрдЯрд░ рдЖрд╡реЗрджрди
рдлрд┐рд░ рд╕реЗ, "рдореЛрдмрд╛рдЗрд▓ рдРрдк (Xamarin.Forms)" рдЬреИрд╕реЗ рд╡рд┐рдЬрд╝реБрдЕрд▓ рд╕реНрдЯреВрдбрд┐рдпреЛ рдореЗрдВ рдПрдХ рдирдпрд╛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ, рдлрд┐рд░ "рдмреНрд▓реИрдВрдХ" рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ рдФрд░ "рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо" рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдХреЗрд╡рд▓ "рдПрдВрдбреНрд░реЙрдЗрдб" рдЪреЗрдХрдорд╛рд░реНрдХ рдЫреЛрдбрд╝ рджреЗрдВред
Android рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ, рдирд┐рдореНрди рдХрд╛рд░реНрдп рдХрд░реЗрдВ:
- рдХрд╛рд░реНрдбрд╕реН рд╕реЗрд╡рд╛ рд╡рд░реНрдЧ - рдпрд╣рд╛рдБ рдЖрдкрдХреЛ рд╕реНрдерд┐рд░рд╛рдВрдХ рдФрд░ ProcessCommandApdu () рд╡рд┐рдзрд┐, рд╕рд╛рде рд╣реА SendMessageToActivity () рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ
- рд╕рд╣рд╛рдпрддрд╛_рд╕реВрдЪреА.xml рдореЗрдВ рд╕реЗрд╡рд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг
- рдореИрдиреНтАНрдпреВрдПрдХреНтАНрдЯрд┐рд╡рд┐рдЯреА рдореЗрдВ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рд╡рд╛рд▓рд╛ рддрдВрддреНрд░
- рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓реЙрдиреНрдЪ (рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ)
- AndroidManifest.xml - nfc рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐рдпрд╛рдВ
рдФрд░ App.xaml.cs рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ:
- рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐
рдХрд╛рд░реНрдбрд╕реЗрд╡рд╛ рд╡рд░реНрдЧ
using Android.App; using Android.Content; using Android.Nfc.CardEmulators; using Android.OS; using System; using System.Linq; using System.Text; namespace ApduServiceCardApp.Droid.Services { [Service(Exported = true, Enabled = true, Permission = "android.permission.BIND_NFC_SERVICE"), IntentFilter(new[] { "android.nfc.cardemulation.action.HOST_APDU_SERVICE" }, Categories = new[] { "android.intent.category.DEFAULT" }), MetaData("android.nfc.cardemulation.host_apdu_service", Resource = "@xml/aid_list")] public class CardService : HostApduService {
рд░реАрдбрд░ рд╕реЗ APDU рдХрдорд╛рдВрдб рдорд┐рд▓рдиреЗ рдкрд░, ProcessCommandApdu рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдХрдорд╛рдВрдб рдХреЛ рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рдВрджреЗрд╢ SELECT_APDU_HEADER рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдкрд╛рдардХ рдХреЛ рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд▓рд┐рдЦреЗрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдПрдХ рд╡рд┐рдирд┐рдордп рдХрдИ рдЪрд░рдгреЛрдВ рдореЗрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд╕рд╡рд╛рд▓-рдЬрд╡рд╛рдм рд╕рд╡рд╛рд▓-рдЬрд╡рд╛рдм, рдЖрджрд┐ред
рд╡рд░реНрдЧ рд╕реЗ рдкрд╣рд▓реЗ, рд╕реЗрд╡рд╛ рд╡рд┐рд╢реЗрд╖рддрд╛ Android рд╕реЗрд╡рд╛ рдХреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреА рд╣реИред рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ рд╕рдордп, xamarin рдЗрд╕ рд╡рд┐рд╡рд░рдг рдХреЛ AndroidManifest.xml рдореЗрдВ рдРрд╕реЗ рддрддреНрд╡ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддрд╛ рд╣реИ:
<service name='md51c8b1c564e9c74403ac6103c28fa46ff.CardService' permission='android.permission.BIND_NFC_SERVICE' enabled='true' exported='true'> <meta-data name='android.nfc.cardemulation.host_apdu_service' resource='@res/0x7F100000'> </meta-data> <intent-filter> <action name='android.nfc.cardemulation.action.HOST_APDU_SERVICE'> </action> <category name='android.intent.category.DEFAULT'> </category> </intent-filter> </service>
рд╕рд╣рд╛рдпрддрд╛_рд╕реВрдЪреА.xml рдореЗрдВ рд╕реЗрд╡рд╛ рдХрд╛ рд╡рд┐рд╡рд░рдг
Xml рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ, рд╕рд╣рд╛рдпрддрд╛_рд╕реВрдЪреА рдмрдирд╛рдПрдБред Xml рдлрд╝рд╛рдЗрд▓:
<?xml version="1.0" encoding="utf-8"?> <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/service_name" android:requireDeviceUnlock="false"> <aid-group android:description="@string/card_title" android:category="other"> <aid-filter android:name="F123456789"/> </aid-group> </host-apdu-service>
рдЗрд╕рдХрд╛ рд╕рдВрджрд░реНрдн рдХрд╛рд░реНрдбрд╕реЗрд╡рд╛ рд╡рд░реНрдЧ рдореЗрдВ рд╕реЗрд╡рд╛ рд╡рд┐рд╢реЗрд╖рддрд╛ рдореЗрдВ рд╣реИ - рд╕рдВрд╕рд╛рдзрди = "@ xml / рд╕рд╣рд╛рдпрддрд╛_рд╕реВрдЪреА"
рдпрд╣рд╛рдВ рд╣рдордиреЗ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ AID рд╕реЗрдЯ рдХрд┐рдпрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкрд╛рдардХ рдЗрд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд░реЗрдЧрд╛ рдФрд░ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИDeviceUnlock = "рдЭреВрдареА" рддрд╛рдХрд┐ рдХрд╛рд░реНрдб рдПрдХ рдЕрдирд▓реЙрдХ рд╕реНрдХреНрд░реАрди рдХреЗ рд╕рд╛рде рдкрдврд╝рд╛ рдЬрд╛рдПред
рдХреЛрдб рдореЗрдВ 2 рд╕реНрдерд┐рд░рд╛рдВрдХ рд╣реИрдВ:
@string/service_name
рдФрд░
@string/card_title
ред рд╡реЗ рдорд╛рди / strings.xml рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд┐рдП рдЧрдП рд╣реИрдВ:
<resources> <string name="card_title">My Loyalty Card</string> <string name="service_name">My Company</string> </resources>
рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХрд╛ рддрдВрддреНрд░:
рдЗрд╕ рд╕реЗрд╡рд╛ рдХрд╛ MainActivity рд╕реЗ рдХреЛрдИ рд╕рдВрдмрдВрдз рдирд╣реАрдВ рд╣реИ, рдЬреЛ рдХрд┐ APDU рдЖрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд╕рдордп рд╢реБрд░реВ рднреА рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдмреНрд░реЙрдбрдХрд╛рд╕реНрдЯрд╕реАрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдб рд╕реЗрд╡рд╛ рд╕реЗ рдореЗрдирдРрдХреНрдЯрд┐рд╡рд┐рдЯреА рддрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬрддреЗ рд╣реИрдВ:
рдХрд╛рд░реНрдбрд╕реЗрд╡рд╛ рд╕реЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреА рд╡рд┐рдзрд┐:
private void SendMessageToActivity(string msg) { Intent intent = new Intent("MSG_NAME"); intent.PutExtra("MSG_DATA", msg); SendBroadcast(intent); }
рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
MessageReceiver рд╡рд░реНрдЧ рдмрдирд╛рдПрдБ:
using Android.Content; namespace ApduServiceCardApp.Droid.Services { public class MessageReceiver : BroadcastReceiver { public override async void OnReceive(Context context, Intent intent) { var message = intent.GetStringExtra("MSG_DATA"); await App.DisplayAlertAsync(message); } } }
рдореИрд╕реЗрдЬрдРрдХреНрдЯрд┐рд╡ рдХреЛ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВ
protected override void OnCreate(Bundle savedInstanceState) { ... var receiver = new MessageReceiver(); RegisterReceiver(receiver, new IntentFilter("MSG_NAME")); LoadApplication(new App()); }
App.xaml.cs
рдПрдХ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рдардХ рд╡рд┐рдзрд┐ рдХреЗ рд╕рдорд╛рди рд╣реА:
public static async Task DisplayAlertAsync(string msg) => await Device.InvokeOnMainThreadAsync(async () => await Current.MainPage.DisplayAlert("message from service", msg, "ok"));
AndroidManifest.xml
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" /> <uses-feature android:name="FEATURE_NFC_HOST_CARD_EMULATION"/> <uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.BIND_NFC_SERVICE" /> <uses-sdk android:minSdkVersion="10"/> 14
рдлрд┐рд▓рд╣рд╛рд▓, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдирд┐рдореНрди рдХрд╛рд░реНрдп рд╣реИрдВ:
- рд░реАрдбрд░ рд╕реНрдХреНрд░реАрди рдкрд░ рдПрдореБрд▓реЗрдЯрд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ
- рдПрдореБрд▓реЗрдЯрд░ рд╕реНрдХреНрд░реАрди рдкрд░ рд░реАрдбрд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ
- рдПрдореБрд▓реЗрдЯрд░ рдХреЛ рдЪрд▓ рд░рд╣реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рд╕реНрдХреНрд░реАрди рдмрдВрдж рд╣реЛрдиреЗ рдХреЗ рд╕рд╛рдеред
рдЕрдЧрд▓рд╛ред
рдПрдореБрд▓реЗрдЯрд░ рдирд┐рдпрдВрддреНрд░рдг
рдореИрдВ Xamarin.Essentials рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реВрдВрдЧрд╛ред
рдЖрдЗрдП рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ: рдЬрдм рд╣рдо рдПрдореБрд▓реЗрдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╕реЗрдЯрд┐рдВрдЧ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВрдЧреЗ:
Xamarin.Essentials.Preferences.Set("key1", Guid.NewGuid().ToString());
рдФрд░ ProcessCommandApdu рд╡рд┐рдзрд┐ рдореЗрдВ рд╣рдо рдЗрд╕ рдореВрд▓реНрдп рдХреЛ рд╣рд░ рдмрд╛рд░ рдлрд┐рд░ рд╕реЗ рд▓реЗрдВрдЧреЗ:
var messageToReader = $"Hello Reader! - {Xamarin.Essentials.Preferences.Get("key1", "key1 not found")}";
рдЕрдм рд╣рд░ рдмрд╛рд░ рдЬрдм рдЖрдк рдПрдореБрд▓реЗрдЯрд░ рдПрдкреНрд▓реАрдХреЗрд╢рди рдХреЛ рд░рд┐рд╕реНрдЯрд╛рд░реНрдЯ (рдХрдо рд╕реЗ рдХрдо рдирд╣реАрдВ) рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рдирдИ рдЧрд╛рдЗрдб рджреЗрдЦрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
Hello Reader! - 76324a99-b5c3-46bc-8678-5650dab0529d
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рдПрдореБрд▓реЗрдЯрд░ рдЪрд╛рд▓реВ / рдмрдВрдж рдХрд░реЗрдВ:
Xamarin.Essentials.Preferences.Set("IsEnabled", false);
рдФрд░ ProcessCommandApdu рд╡рд┐рдзрд┐ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
var IsEnabled = Xamarin.Essentials.Preferences.Get("IsEnabled", false); if (!IsEnabled) return UNKNOWN_CMD_SW;
рдпрд╣ рдПрдХ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рд╣реИ, рд▓реЗрдХрд┐рди
рдЕрдиреНрдп рд╣реИрдВ ред
рдПрдХ рдкрд╛рдардХ рдХрд╛ рдкрддрд╛ рдЪрд▓рдиреЗ рдкрд░ рдПрдореБрд▓реЗрдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЪрд▓рд╛рдирд╛
рдпрджрд┐ рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдПрдореБрд▓реЗрдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЦреЛрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ ProcessCommandApdu рд╡рд┐рдзрд┐ рдореЗрдВ рд▓рд╛рдЗрди рдЬреЛрдбрд╝реЗрдВ:
StartActivity(typeof(MainActivity));
рдпрджрд┐ рдЖрдкрдХреЛ рдЖрд╡реЗрджрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЗрд╕ рддрд░рд╣:
var activity = new Intent(this, typeof(MainActivity)); intent.PutExtra("MSG_DATA", "data for application"); this.StartActivity(activity);
рдЖрдк рдСрдирдХреНрд░реАрдЯ рд╡рд┐рдзрд┐ рдореЗрдВ MainActivity class рдореЗрдВ рдЙрддреНрддреАрд░реНрдг рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ:
... LoadApplication(new App()); if (Intent.Extras != null) { var message = Intent.Extras.GetString("MSG_DATA"); await App.DisplayAlertAsync(message); }
Nfc рдПрдбреЗрдкреНрдЯрд░ рдХреА рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░рдирд╛ рдФрд░ nfc рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдирд╛
рдпрд╣ рдЦрдВрдб рдкрд╛рдардХ рдФрд░ рдПрдореБрд▓реЗрдЯрд░ рджреЛрдиреЛрдВ рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИред
Android рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ NfcHelper рдмрдирд╛рдПрдВ рдФрд░ рдЗрд╕реЗ MainPage рдкреЗрдЬ рдХреЛрдб рд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП DependencyService рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
using Android.App; using Android.Content; using Android.Nfc; using ApduServiceCardApp.Services; using Xamarin.Forms; [assembly: Dependency(typeof(ApduServiceCardApp.Droid.Services.NfcHelper))] namespace ApduServiceCardApp.Droid.Services { public class NfcHelper : INfcHelper { public NfcAdapterStatus GetNfcAdapterStatus() { var adapter = NfcAdapter.GetDefaultAdapter(Forms.Context as Activity); return adapter == null ? NfcAdapterStatus.NoAdapter : adapter.IsEnabled ? NfcAdapterStatus.Enabled : NfcAdapterStatus.Disabled; } public void GoToNFCSettings() { var intent = new Intent(Android.Provider.Settings.ActionNfcSettings); intent.AddFlags(ActivityFlags.NewTask); Android.App.Application.Context.StartActivity(intent); } } }
рдЕрдм рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ, INfcHelper рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЬреЛрдбрд╝реЗрдВ:
namespace ApduServiceCardApp.Services { public interface INfcHelper { NfcAdapterStatus GetNfcAdapterStatus(); void GoToNFCSettings(); } public enum NfcAdapterStatus { Enabled, Disabled, NoAdapter } }
рдФрд░ рдпрд╣ рд╕рдм MainPage.xaml.cs рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
protected override async void OnAppearing() { base.OnAppearing(); await CheckNfc(); } private async Task CheckNfc() { var nfcHelper = DependencyService.Get<INfcHelper>(); var status = nfcHelper.GetNfcAdapterStatus(); switch (status) { case NfcAdapterStatus.Enabled: default: await App.DisplayAlertAsync("nfc enabled!"); break; case NfcAdapterStatus.Disabled: nfcHelper.GoToNFCSettings(); break; case NfcAdapterStatus.NoAdapter: await App.DisplayAlertAsync("no nfc adapter found!"); break; } }
рдЧрд┐рдЯрд╣рдм рд▓рд┐рдВрдХ
рдПрдореБрд▓реЗрдЯрд░рдкрд╛рдардХ