.NET Standard Library สำหรับสร้างแพ็คเกจ Passbook สำหรับ iOS Wallet (เดิมเรียกว่า Passbook)
หากคุณใช้ dotnet-passbook โปรดพิจารณาซื้อกาแฟให้ฉันสักแก้ว
dotnet-passbook พร้อมให้ดาวน์โหลดจาก NuGet
Install-Package dotnet-passbook
การสร้างบัตรผ่านสำหรับ Passbook ของ Apple นั้นค่อนข้างง่าย แต่ต้องใช้ PKI ในการลงนามไฟล์ Manifest ซึ่งไม่ง่ายนัก! ในระหว่างการสร้าง PassVerse.com (ไม่มีให้บริการอีกต่อไป) ฉันได้สร้างไลบรารี .Net ที่ดำเนินการทุกขั้นตอน ฉันตัดสินใจเปิดไลบรารี่นี้ให้กับนักพัฒนา .NET คนอื่นๆ
โซลูชันนี้ต้องใช้ Visual Studio 2017 หรือสูงกว่า ไลบรารีนี้สร้างขึ้นสำหรับ .NET Standard 2.0
ก่อนที่คุณจะเรียกใช้ PassGenerator คุณต้องแน่ใจว่าคุณได้ติดตั้งใบรับรองที่จำเป็นทั้งหมดแล้ว มีสองสิ่งที่จำเป็น
ประการแรก คุณต้องมีใบรับรอง Passbook ซึ่งคุณได้รับจากพอร์ทัลนักพัฒนา คุณต้องมีบัญชีนักพัฒนา iOS
ประการที่สอง คุณต้องมีใบรับรอง Apple WWDR (WorldWide Developer Relations) คุณสามารถดาวน์โหลดได้จากที่นี่http://www.apple.com/certificateauthority/
คุณจะต้องมีใบรับรอง G1 หรือ G4 ขึ้นอยู่กับว่าคุณสร้างใบรับรอง Passbook เมื่อใด หากคุณสร้างใบรับรองสมุดบัญชีเงินฝากภายในหรือก่อนวันที่ 27 มกราคม 2022 ให้ใช้ G1 มิฉะนั้นให้ใช้ G4
ใบรับรอง "ความสัมพันธ์ของนักพัฒนาทั่วโลก" อื่นๆ ที่ระบุในที่นี้ใช้ไม่ได้กับ Apple Wallet ("ขออภัย ไม่สามารถติดตั้ง Pass ของคุณลงใน Passbook ได้ในขณะนี้")
มีคำแนะนำในบล็อกของฉันในการสร้างใบรับรองโดยใช้ IIS หากคุณใช้เครื่อง Windows
หากคุณใช้ Linux/macOS หรือต้องการใช้ OpenSSL บน Windows โปรดดูที่การใช้-openssl.md เพื่อดูคำแนะนำเกี่ยวกับวิธีสร้างใบรับรองที่จำเป็นโดยใช้ OpenSSL
เมื่อย้ายใบรับรอง ตรวจสอบให้แน่ใจว่าใบรับรอง Passbook ของคุณมีส่วนประกอบคีย์ส่วนตัวอยู่เสมอ ไม่เช่นนั้นการลงนามจะล้มเหลว
หากต้องการสร้างบัตรผ่าน ให้เริ่มต้นด้วยการประกาศ PassGenerator
PassGenerator generator = new PassGenerator ( ) ;
จากนั้นสร้าง PassGeneratorRequest นี่เป็นคำขอดิบที่ให้สิทธิ์คุณอย่างเต็มที่ในการเพิ่มฟิลด์ทั้งหมดที่จำเป็นสำหรับบัตรผ่านที่คุณต้องการสร้าง แต่ละบัตรผ่านแบ่งออกเป็นหลายส่วน แต่ละส่วนได้รับการเรนเดอร์ด้วยวิธีที่แตกต่างกัน ขึ้นอยู่กับสไตล์ของบัตรผ่านที่คุณพยายามสร้าง สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ โปรดอ่านคู่มือการเขียนโปรแกรม Passbook ของ 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 และ 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 ID ของแอพลงในอาร์เรย์ AssociatedStoreIdentifiers ได้
request . AssociatedStoreIdentifiers . Add ( 551768478 ) ;
สุดท้าย สร้างบัตรผ่านโดยส่งคำขอไปยังอินสแตนซ์ของตัวสร้าง สิ่งนี้จะสร้างไฟล์ Manifest ที่ลงนามและจัดแพคเกจไฟล์รูปภาพทั้งหมดเป็น ZIP
byte [ ] generatedPass = generator . Generate ( request ) ;
ตัวอย่างเช่น หากคุณใช้ ASP.NET MVC คุณสามารถส่งคืนไบต์นี้[] เป็นแพ็คเกจ Passbook ได้
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
ของคุณผ่านสิ่งนี้ และอาจทำให้ทราบว่ามีอะไรผิดปกติ เครื่องมือนี้เป็นของใหม่ (ก.ค. 61) และไม่ได้ตรวจสอบทุกอย่างอย่างแน่นอน ฉันจะพยายามเพิ่มการตรวจสอบความถูกต้องให้กับตัวสร้างเองมากขึ้น
หากคุณใช้รหัสลงนามภายในแอปพลิเคชัน 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] หรือติดตามฉันบน Twitter @tomasmcguinness
dotnet-passbook เผยแพร่ภายใต้ใบอนุญาต MIT: http://tomasmcguinness.mit-license.org/