PassKitHelper 4.0.0

dotnet add package PassKitHelper --version 4.0.0                
NuGet\Install-Package PassKitHelper -Version 4.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PassKitHelper" Version="4.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add PassKitHelper --version 4.0.0                
#r "nuget: PassKitHelper, 4.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install PassKitHelper as a Cake Addin
#addin nuget:?package=PassKitHelper&version=4.0.0

// Install PassKitHelper as a Cake Tool
#tool nuget:?package=PassKitHelper&version=4.0.0                

PassKit Helper

Helper library for all your Apple PassKit (Apple Wallet, Apple Passbook) needs: create passes, sign pass packages, receive [de]install notifications and send pass updates.

Attention: Apple Developer Account required!

NuGet .NET 9.0 .NET 8.0 .NET 6.0 .NET Standard 2.0

Features

  1. Create pass packages (*.pkpass files):
    • With Fluent-styled PassInfoBuilder and PassPackageBuilder
    • Using byte[] and/or Stream as content images
    • Using byte[] or Stream or X509Certificate2 as certificates
    • Receive MemoryStream as result (save it to file or write to HttpResponse)
  2. Receive notifications from Apple about pass [de]installations and send updates:
    • Add UsePassKitMiddleware into your Startup.Configure()
    • Implement IPassKitService for real processing.

Samples

1. Configure to create passes

For console app
var options = new PassKitOptions()
{
    PassCertificate = new X509Certificate2(File.ReadAllBytes("pass.pfx")),
    AppleCertificate = new X509Certificate2(File.ReadAllBytes("AppleWWDRCA.cer")),
    ConfigureNewPass =
        p => p.Standard
                .PassTypeIdentifier("your-pass-type-identifier")
                .TeamIdentifier("your-team-identifier")
                // Add more "defaults" here if needed
};

IPassKitHelper passKitHelper = new PassKitHelper(options);
For web app
public void ConfigureServices(IServiceCollection services)
{
    services.AddPassKitHelper(options =>
    {
        options.PassCertificate = new X509Certificate2(File.ReadAllBytes("pass.pfx"));
        options.AppleCertificate = new X509Certificate2(File.ReadAllBytes("AppleWWDRCA.cer"));
        options.ConfigureNewPass =
            p => p.Standard
                    .PassTypeIdentifier("your-pass-type-identifier")
                    .TeamIdentifier("your-team-identifier")
                    // Add more "defaults" here if needed
    });
}

2. Creat pass and pass package file

Check Apple's PassKit Package Format Reference for detailed description of all fields and valid values.

Also, check Pass Design and Creation for accepted image types and sizes.

var pass = passKitHelper.CreateNewPass()
    // Ths pass already have `PassTypeIdentifier`, `TeamIdentifier` 
    //   and all other values you configured in options.
    .Standard
        .SerialNumber("PassKitHelper")
        .OrganizationName("PassKit")
        .Description("PassKitHelper demo pass")
    .VisualAppearance
        .Barcodes("1234567890128", BarcodeFormat.Code128)
        .LogoText("PassKit Helper demo pass")
        .ForegroundColor("rgb(44, 62, 80)")
        .BackgroundColor("rgb(149, 165, 166)")
        .LabelColor("rgb(236, 240, 241)")
    .StoreCard
        .PrimaryFields
            .Add("version")
                .Label("Library version")
                .Value(libraryVersion)
        .AuxiliaryFields
            .Add("github")
                .Label("GitHub link")
                .Value("https://github.com/justdmitry/PassKitHelper");

var passPackage = passKitHelper.CreateNewPassPackage(pass)
    .Icon(await File.ReadAllBytesAsync("images/icon.png"))
    .Icon2X(await File.ReadAllBytesAsync("images/icon@2x.png"))
    .Icon3X(await File.ReadAllBytesAsync("images/icon@3x.png"))
    .Logo(await File.ReadAllBytesAsync("images/logo.jpg"))
    .Strip(await File.ReadAllBytesAsync("images/strip.jpg"))
    .Strip2X(await File.ReadAllBytesAsync("images/strip@2x.jpg"))
    .Strip3X(await File.ReadAllBytesAsync("images/strip@3x.jpg"));

MemoryStream packageFile = await passPackage.SignAndBuildAsync();

// Now you have to "deliver" package file to user using any channel you have
//   (save as attachment in email, download from your webapp etc)
await File.WriteAllBytesAsync("Sample.pkpass", packageFile.ToArray());

Code above will create this beautiful pass:

alternate text is missing from this package README image

3. Implementing WebService for interaction

Apple's server can call your endpoint/server to notify about user installed/deinstalled your pass, to fetch updated version of pass (when user 'pulls down' pass in Wallet). You will be able to send pushes when you want to update pass in user's wallet. Check Apple's PassKit Web Service Reference for technical details.

3.1. Implement IPassKitService
public class PassKitService : IPassKitService
{
    public Task<int> RegisterDeviceAsync(…) {…}

    public Task<int> UnregisterDeviceAsync(…) {…}

    public Task<(int Status, string[]? Passes, string? Tag)> GetAssociatedPassesAsync(…) {…}

    public Task<(int StatusCode, MemoryStream? PassData)> GetPassAsync(…) {…}

    public Task ProcessLogsAsync(…) {…}
}
3.2. Register in Startup
public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<IPassService, PassService>();
}

public void Configure(IApplicationBuilder app)
{
    ...
    app.UsePassKitMiddleware("/callbacks/passkit");
    ...
}
3.3 Add information inside your passes

You need publicly-accessible url/hostname for your server, and it must be secured with https/ssl.

Add this information into your passes:


var pass = passKitHelper.CreateNewPass()
     // your 
     // original 
     // pass content 
     // goes here
   .WebService
       .AuthenticationToken("some-random-secret-string")
       .WebServiceURL("https://you.server.com/callbacks/passkit")

AuthenticationToken is some "secret" string that you use to differentiate legal pass owners and malicious hackers.

WebServiceURL is hostname of your server and path that equal to one in UsePassKitMiddleware in previous step.

3.4. Send push updates

When users install your pass packge to their iOS and Mac devices - Apple server call your RegisterDeviceAsync. Save pushToken value in database, and when you need to update pass on user device - call IPassKitHelper.SendPushNotificationAsync(pushToken).

Installation

Use NuGet package PassKitHelper.

Dependencies

For netstandard2.0:

  • Microsoft.AspNetCore.Http.Abstractions, v2.1.1
  • Microsoft.Extensions.Http, v2.1.1
  • Newtonsoft.Json, v13.0.1
  • System.Security.Cryptography.Pkcs, v4.7.0
  • System.Text.Encodings.Web, v4.7.2

For net6.0 / net8.0 / net9.0:

  • Microsoft.Extensions.Http, v6.0.1 / v8.0.1 / v9.0.0
  • System.Security.Cryptography.Pkcs, v6.0.5 / v8.0.1 / v9.0.0
  • System.Text.Json, v6.0.11 / v8.0.5 / v9.0.0

Dvelopment & Testing

Tests can be run with dotnet test.

Credits

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.0.0 152 12/13/2024
3.5.0 86 12/8/2024
3.4.0 171 11/28/2024
3.3.0 1,825 9/18/2024
3.2.0 11,643 4/24/2023
3.1.2 12,107 9/6/2022
3.0.3 42,897 7/29/2020
3.0.0-RC1 422 2/14/2020
2.1.0 635 1/29/2020
2.0.0 646 10/7/2019
1.0.1 620 10/7/2019
1.0.0 529 10/4/2019
0.9.0 515 9/17/2019

Switch to `System.Text.Json` (for net6 and later), fix tuple elements names in `IPassKitService` (BREAKING CHANGE!).