مكتبة .NET القياسية لإنشاء حزم Passbook لـ iOS Wallet (المعروف سابقًا باسم Passbook)
إذا كنت تستخدم dotnet-passbook، فيرجى التفكير في شراء فنجان من القهوة لي
يتوفر أيضًا dotnet-passbook للتنزيل من NuGet
Install-Package dotnet-passbook
يعد إنشاء تصاريح لدفتر حسابات Apple أمرًا بسيطًا جدًا، ولكنه يتطلب استخدام PKI لتوقيع ملفات البيان، وهو أمر ليس بهذه البساطة! أثناء إنشاء موقع PassVerse.com (لم يعد متوفرًا)، قمت بإنشاء مكتبة .Net تنفذ كافة الخطوات. قررت فتح هذه المكتبة لمطوري .NET الآخرين.
يتطلب الحل Visual Studio 2017 أو أعلى. تم إنشاء المكتبة لـ .NET Standard 2.0.
قبل تشغيل PassGenerator، عليك التأكد من تثبيت جميع الشهادات الضرورية. هناك نوعان مطلوبان.
أولاً، تحتاج إلى شهادة دفتر الحسابات الجاري الخاصة بك، والتي تحصل عليها من بوابة المطور. يجب أن يكون لديك حساب مطور iOS.
ثانيًا، أنت بحاجة إلى شهادة Apple WWDR (علاقات المطورين العالمية). يمكنك تنزيل ذلك من هنا http://www.apple.com/certificateauthority/.
اعتمادًا على وقت إنشاء شهادة دفتر الحسابات الجاري، ستحتاج إما إلى شهادة G1 أو G4. إذا قمت بإنشاء شهادة دفتر الحسابات الجاري الخاص بك في 27 يناير 2022 أو قبله، فاستخدم G1. وإلا استخدم G4.
لن تعمل شهادات "علاقات المطورين العالمية" الأخرى المدرجة هنا مع Apple Wallet. ("عذرًا، لا يمكن تثبيت بطاقة المرور الخاصة بك على Passbook في الوقت الحالي.")
توجد تعليمات على مدونتي لإنشاء شهادة باستخدام IIS إذا كنت تستخدم جهازًا يعمل بنظام Windows
إذا كنت تستخدم نظام التشغيل Linux/macOS أو كنت تفضل استخدام OpenSSL على نظام التشغيل Windows، فراجع استخدام openssl.md للحصول على إرشادات حول كيفية إنشاء الشهادات اللازمة باستخدام OpenSSL.
عند نقل الشهادات، تأكد من أن شهادة دفتر الحسابات الجاري الخاصة بك تتضمن دائمًا مكون المفتاح الخاص، وإلا فسيفشل التوقيع.
لإنشاء بطاقة مرور، ابدأ بإعلان PassGenerator.
PassGenerator generator = new PassGenerator ( ) ;
بعد ذلك، قم بإنشاء طلب PassGeneratorRequest. هذا طلب أولي يمنحك القدرة الكاملة لإضافة جميع الحقول اللازمة لبطاقة المرور التي ترغب في إنشائها. يتم تقسيم كل تمريرة إلى عدة أقسام. يتم عرض كل قسم بطريقة مختلفة، بناءً على نمط التمريرة التي تحاول إنتاجها. لمزيد من المعلومات حول هذا الأمر، يرجى الرجوع إلى دليل برمجة دفتر الحسابات الجاري الخاص بشركة Apple. سيوضح المثال أدناه كيفية إنشاء بطاقة صعود أساسية للغاية.
نظرًا لأن كل تصريح يحتوي على مجموعة من البيانات الإلزامية، قم بملءها أولاً.
PassGeneratorRequest request = new PassGeneratorRequest ( ) ;
request . PassTypeIdentifier = " pass.tomsamcguinness.events " ;
request . TeamIdentifier = " RW121242 " ;
request . SerialNumber = " 121212 " ;
request . Description = " My first pass " ;
request . OrganizationName = " Tomas McGuinness " ;
request . LogoText = " My Pass " ;
يمكن تحديد الألوان بتنسيق HTML أو بتنسيق RGB.
request . BackgroundColor = " #FFFFFF " ;
request . LabelColor = " #000000 " ;
request . ForegroundColor = " #000000 " ;
request . BackgroundColor = " rgb(255,255,255) " ;
request . LabelColor = " rgb(0,0,0) " ;
request . ForegroundColor = " rgb(0,0,0) " ;
يجب عليك تقديم كل من Apple WWDR وشهادة Passbook كمثيلات X509Certificate. ملاحظة: هذا تغيير عن الإصدارات السابقة.
request . AppleWWDRCACertificate = new X509Certificate ( .. . ) ;
request . PassbookCertificate = new X509Certificate ( .. . ) ;
عندما تقوم بإنشاء مثيلات X509Certificate في السحابة، قد تواجه مشكلات في عملية التوقيع. أنصحك باستخدام MachineKeySet وExportable X509KeyStorageFlags.
X509KeyStorageFlags flags = X509KeyStorageFlags . MachineKeySet | X509KeyStorageFlags . Exportable ;
X509Certificate2 certificate = new X509Certificate2 ( bytes , password , flags ) ;
بعد ذلك، حدد الصور التي تريد استخدامها. يجب عليك دائمًا تضمين الصور ذات الحجم القياسي وحجم شبكية العين. يتم توفير الصور بالبايت [].
request . Images . Add ( PassbookImage . Icon , System . IO . File . ReadAllBytes ( Server . MapPath ( " ~/Icons/icon.png " ) ) ) ;
request . Images . Add ( PassbookImage . Icon2X , System . IO . File . ReadAllBytes ( Server . MapPath ( " ~/Icons/[email protected] " ) ) ) ;
request . Images . Add ( PassbookImage . Icon3X , System . IO . File . ReadAllBytes ( Server . MapPath ( " ~/Icons/[email protected] " ) ) ) ;
يمكنك الآن تقديم المزيد من المعلومات المحددة للتمرير. يجب تعيين النمط ثم تتم إضافة جميع المعلومات إلى الحقول إلى الأقسام المطلوبة. بالنسبة لبطاقة الصعود إلى الطائرة، يتم تقسيم الحقول إلى ثلاثة أقسام؛ الابتدائية والثانوية والمساعدة.
request . Style = PassStyle . BoardingPass ;
request . AddPrimaryField ( new StandardField ( " origin " , " San Francisco " , " SFO " ) ) ;
request . AddPrimaryField ( new StandardField ( " destination " , " London " , " LDN " ) ) ;
request . AddSecondaryField ( new StandardField ( " boarding-gate " , " Gate " , " A55 " ) ) ;
request . AddAuxiliaryField ( new StandardField ( " seat " , " Seat " , " G5 " ) ) ;
request . AddAuxiliaryField ( new StandardField ( " passenger-name " , " Passenger " , " Thomas Anderson " ) ) ;
request . TransitType = TransitType . PKTransitTypeAir ;
يمكنك إضافة الباركود.
request . AddBarcode ( BarcodeType . PKBarcodeFormatPDF417 , " 01927847623423234234 " , " ISO-8859-1 " , " 01927847623423234234 " ) ;
بدءًا من نظام التشغيل iOS 9، يتم الآن دعم الرموز الشريطية المتعددة. تدعم هذه الطريقة المساعدة هذه الميزة الجديدة. إذا كنت تريد دعم نظام التشغيل iOS 8 والإصدارات الأقدم، فيمكنك استخدام الطريقة SetBarcode().
لربط البطاقة بتطبيق موجود، يمكنك إضافة معرف Apple الخاص بالتطبيق إلى مصفوفة AssociatedStoreIdentifiers.
request . AssociatedStoreIdentifiers . Add ( 551768478 ) ;
وأخيرًا، قم بإنشاء المرور عن طريق تمرير الطلب إلى مثيل المولد. سيؤدي هذا إلى إنشاء البيان الموقع وتجميع جميع ملفات الصور في ملف مضغوط.
byte [ ] generatedPass = generator . Generate ( request ) ;
إذا كنت تستخدم ASP.NET MVC على سبيل المثال، فيمكنك إرجاع هذا البايت[] كحزمة دفتر الحسابات الجاري
return new FileContentResult ( generatedPass , " application/vnd.apple.pkpass " ) ;
قدم iOS 15 القدرة على تجميع وتوزيع تمريرات متعددة باستخدام ملف .pkpasses فردي. يمكنك إنشاء حزم المرور أيضًا عن طريق تمرير قاموس قيم الطلبات ومفاتيح السلسلة التي تمثل اسم الملف لكل طلب على حدة.
PassGeneratorRequest myFirstRequest = new PassGeneratorRequest ( ) ;
PassGeneratorRequest mySecondRequest = new PassGeneratorRequest ( ) ;
// Build out your requests
List < PassGeneratorRequest > requests = new List < PassGeneratorRequest > ;
requests . Add ( myFirstRequest ) ;
request . Add ( mySecondRequest ) ;
byte [ ] generatedBundle = generator . Generate ( requests ) ;
يتم التعامل مع مصفوفة البايت الناتجة بشكل مماثل تقريبًا لملف .pkpass
المفرد، ولكن بامتداد مختلف ونوع MIME ( pkpasses )
return new FileContentResult ( generatedBundle , " application/vnd.apple.pkpasses " )
{
FileDownloadName = " tickets.pkpasses.zip "
} ;
تتوافق فئة PassGenerator
مع واجهة IPassGenerator
التي تكشف عن الأساليب المستخدمة لإنشاء التمريرات. إذا كان لديك بعض المنطق المخصص الذي ينشئ طلب إنشاء المرور، فيمكنك استخدام محاكاة واجهة IPassGenerator
بسهولة باستخدام أي مكتبة وهمية واختبار ما إذا كان المنطق الخاص بك يستدعي طريقة Generate
مع طلب المولد الصحيح.
لنفترض أن لديك خدمة تتلقى طلب المولد من خلال DI وتقوم بإنشاء تصريح بناءً على الطلب.
class PassGeneratorService ( IPassGenerator passGenerator )
{
public byte [ ] GeneratePassWithLogoTextAndBackgroundColor ( String logoText , String backgroundColor )
{
// make a request based on parameters
....
passGenerator . Generate ( request ) ;
}
}
يمكنك اختبار هذه الخدمة بسهولة عن طريق الاستهزاء بواجهة IPassGenerator
والتحقق من استدعاء طريقة Generate
بالطلب الصحيح. وإليك عينة باستخدام NSubstitute وxUnit.
[ Fact ]
void ServiceUsesPassedParamsForRequest ( )
{
// Arrange
var passGeneratorMock = Substitute . For < IPassGenerator > ( ) ;
var sut = new PassGeneratorService ( passGeneratorMock ) ;
// Act
sut . GeneratePassWithLogoTextAndBackgroundColor ( " Cup'o'Joe " , " #0CAFE0 " ) ;
// Assert/Verify
passGeneratorMock . Received ( ) . Generate ( Arg . Is < PassGeneratorRequest > ( r =>
{
r . LogoText == " Cup'o'Joe " && r . BackgroundColor == " #0CAFE0 "
} ) ) ;
}
هناك طريقة أخرى لاختبار ما إذا كان المنطق الخاص بك يعمل بشكل جيد وهي اختبار كائن PassGeneratorRequest
نفسه. يمكنك إنشاء كائن طلب وتعيين الخصائص بناءً على المنطق الخاص بك ثم اختبار ما إذا تم إنشاء كائن الطلب بشكل صحيح. ضع في اعتبارك منشئ الطلب الأساسي هذا:
class PassGeneratorRequestBuilder
{
public PassGeneratorRequest BuildRequestWithLogoTextAndBackgroundColor ( String logoText , String backgroundColor )
{
var request = new PassGeneratorRequest ( ) ;
request . LogoText = logoText ;
request . BackgroundColor = backgroundColor ;
return request ;
}
}
يمكنك اختبار هذا المنشئ عن طريق إنشاء كائن طلب والتحقق من تعيين الخصائص بشكل صحيح.
[ Fact ]
void RequestBuilderSetsPropertiesCorrectly ( )
{
// Arrange
var sut = new PassGeneratorRequestBuilder ( ) ;
// Act
var request = sut . BuildRequestWithLogoTextAndBackgroundColor ( " Cup'o'Joe " , " #0CAFE0 " ) ;
// Assert
Assert . Equal ( " Cup'o'Joe " , request . LogoText ) ;
Assert . Equal ( " #0CAFE0 " , request . BackgroundColor ) ;
}
الآن عليك فقط التأكد من عدم تغيير/تحور الطلب في طريقه إلى فئة PassGenerator
.
إذا كان يبدو أن التمريرات التي قمت بإنشائها لا تفتح على نظام التشغيل iOS أو في جهاز المحاكاة، فمن المحتمل أن تكون الحمولة غير صالحة. للمساعدة في استكشاف الأخطاء وإصلاحها، قمت بإنشاء هذه الأداة البسيطة - https://pkpassvalidator.azurewebsites.net - فقط قم بتشغيل ملف pkpass
الخاص بك من خلال هذا وقد يعطي فكرة عن الخطأ. الأداة جديدة (18 يوليو) ولا تتحقق من كل شيء على الإطلاق. سأحاول إضافة المزيد من التحقق من الصحة إلى المولد نفسه.
إذا كنت تقوم بتشغيل رمز التوقيع داخل تطبيق IIS، فقد تواجه بعض المشكلات في الوصول إلى المفتاح الخاص لشهاداتك. لحل هذه المشكلة، افتح MMC => الأداة الإضافية لإضافة شهادات (كمبيوتر محلي) => الشهادات (كمبيوتر محلي) => شخصي => الشهادات => انقر بزر الماوس الأيمن على الشهادة محل الاهتمام => جميع المهام => إدارة المفتاح الخاص => إضافة IIS AppPoolAppPoolName ومنحه التحكم الكامل. استبدل "AppPoolName" باسم تجمع التطبيقات الذي يعمل تطبيقك ضمنه. (أحيانًا IIS_IUSRS
)
لتتمكن من تحديث تصريح المرور الخاص بك، يجب عليك تقديم رد اتصال به. عند إنشاء طلبك، يجب عليك تزويده بـ AuthenticationToken وWebServiceUrl. كل من هذه القيم مطلوبة. يجب أن يكون WebServiceUrl HTTPS افتراضيًا، ولكن يمكنك تعطيل هذا المتطلب في خيارات مطور iOS على أي جهاز تختبره.
رمز المصادقة عبارة عن سلسلة سيتم تضمينها في رأس جميع الطلبات المقدمة إلى واجهة برمجة التطبيقات (API) الخاصة بك. إنها مسؤوليتك التحقق من صحة هذا الرمز المميز.
request . AuthenticationToken = " <a secret to ensure authorized access> " ;
request . WebServiceUrl = " https://<your api> " ;
يجب أن تدعم خدمة الويب التي تشير إليها بروتوكول Apple، الموضح في مرجع خدمة الويب PassKit
اعتبارًا من الإصدار 2.0.1، أصبحت مفاتيح NFC مدعومة الآن. لاستخدامها، ما عليك سوى تعيين خاصية NFC باستخدام كائن NFC جديد. تعتبر كل من الرسالة وقيم المفتاح العام المشفرة إلزامية.
PassGeneratorRequest request = new PassGeneratorRequest ( ) ;
request . Nfc = new Nfc ( " THE NFC Message " , " <encoded private key> " ) ;
لسوء الحظ، لا أستطيع تقديم أي معلومات حول القيم المطلوبة لأنها غير متاحة للعامة. إذا كان أي شخص يعرف ما يحدث هنا، سأكون سعيدًا جدًا بإضافة تغييرات إلى مكتبتي لدعم هذا المفتاح.
نرحب بجميع طلبات السحب! إذا واجهت مشكلة لا يمكنك حلها، فيرجى إثارة مشكلة أو مراسلتي عبر البريد الإلكتروني على [email protected] أو متابعتي على تويتر @tomasmcguinness
يتم توزيع dotnet-passbook بموجب ترخيص MIT: http://tomasmcguinness.mit-license.org/