Integrating Apple Wallet and Google Wallet in .NET MAUI: A Production-Grade Cross-Platform Strategy

✍️ Introduction

Digital wallet ecosystems such as Apple Wallet and Google Wallet have evolved far beyond simple payment tools. Today, they serve as secure containers for:

  • Boarding passes
  • Event tickets
  • Loyalty cards
  • Membership credentials
  • Access control passes For mobile developers working with .NET MAUI, integrating these capabilities introduces a paradox:

You are building a single cross-platform app, but interacting with two completely different ecosystems.

This guide goes far beyond a basic integration. We’ll design a production-ready architecture, covering:

  • Platform abstractions in MAUI
  • Backend responsibilities (critical)
  • Pass generation pipelines
  • Security considerations
  • Real-world pitfalls
  • Scalability patterns

🧠 Understanding the Core Problem

Before writing any code, internalize this: πŸ‘‰ Apple Wallet and Google Wallet are not UI features
πŸ‘‰ They are secure, platform-governed ecosystems This means:

  • You cannot β€œjust add a card”
  • You must follow strict signing + validation flows
  • The mobile app is only a delivery mechanism

βš™οΈ Platform Differences in Depth

Capability Apple Wallet Google Wallet
Data Format .pkpass (ZIP package) JSON (Wallet Objects API)
Signing PKI Certificates JWT (Signed with Service Account)
Distribution File / URL API + Save URL
Update Mechanism Push Notification (APNs) REST API updates
Security Model Certificate trust chain OAuth2 + JWT

πŸ—οΈ High-Level Architecture

A correct architecture separates concerns clearly:

[ MAUI App ]  
     |  
     | (Request pass)  
     v  
[ Backend API ]  
     |  
     |-- Apple Pass Generator (.pkpass)  
     |-- Google Wallet API (JWT)  
     |  
     v  
[ Wallet Platform ]

🧱 Step 1 – MAUI Abstraction Layer

Your MAUI app should never contain platform-specific logic directly in UI code. Define a contract:

public interface IWalletService  
{  
    Task AddPassAsync(WalletRequest request);  
}

Where:

public class WalletRequest  
{  
    public string PassId { get; set; }  
    public string PlatformPayload { get; set; }  
}

πŸ“± Platform Implementations

🍎 iOS – Apple Wallet (PassKit)

Apple uses the PassKit framework, exposed via native bindings.

using PassKit;  
using Foundation;  
  
public class AppleWalletService : IWalletService  
{  
    public async Task AddPassAsync(WalletRequest request)  
    {  
        var url = NSUrl.FromString(request.PlatformPayload);  
        var data = NSData.FromUrl(url);  
  
        var pass = new PKPass(data, out NSError error);  
  
        if (pass == null)  
            throw new Exception(error?.LocalizedDescription);  
  
        var library = new PKPassLibrary();  
        library.AddPass(pass);  
    }  
}

πŸ” Key Observations

  • The app does NOT create the pass
  • It only downloads and installs it
  • Apple enforces strict signature validation

πŸ€– Android – Google Wallet

Google Wallet works differently: no file, only API + JWT.

public class GoogleWalletService : IWalletService  
{  
    public Task AddPassAsync(WalletRequest request)  
    {  
        var intent = new Intent(Intent.ActionView, Android.Net.Uri.Parse(request.PlatformPayload));  
        Platform.CurrentActivity.StartActivity(intent);  
  
        return Task.CompletedTask;  
    }  
}

πŸ” Key Observations

  • Payload is a JWT URL
  • The Wallet UI is handled externally
  • No local pass storage like iOS

πŸ”„ Dependency Injection Wiring

#if ANDROID  
builder.Services.AddSingleton<IWalletService, GoogleWalletService>();  
#elif IOS  
builder.Services.AddSingleton<IWalletService, AppleWalletService>();  
#endif

☁️ Step 2 – Backend Responsibilities (Critical Section)

This is where 90% of the complexity lives.


🍎 Apple Wallet Backend Pipeline

### 1. Create `pass.json`

{  
  "description": "Event Ticket",  
  "formatVersion": 1,  
  "organizationName": "Your Company",  
  "serialNumber": "123456",  
  "teamIdentifier": "ABCDE12345",  
  "barcode": {  
    "format": "PKBarcodeFormatQR",  
    "message": "USER123"  
  }  
}

2. Add Assets

  • icon.png
  • logo.png
  • background.png

3. Generate Manifest

SHA-1 hashes of all files:

{  
  "pass.json": "abc123...",  
  "icon.png": "def456..."  
}

4. Sign the Manifest

Using Apple-issued certificate:

openssl smime -sign ...

5. Zip Everything β†’ .pkpass


πŸ€– Google Wallet Backend Pipeline

1. Create Pass Class

{  
  "id": "issuerId.loyaltyClass",  
  "programName": "My Loyalty Program"  
}

2. Create Pass Object

{  
  "id": "issuerId.user123",  
  "classId": "issuerId.loyaltyClass",  
  "state": "ACTIVE"  
}

3. Generate JWT

{  
  "iss": "service-account@project.iam.gserviceaccount.com",  
  "aud": "google",  
  "typ": "savetowallet",  
  "payload": {  
    "loyaltyObjects": [ ... ]  
  }  
}

4. Return Save URL

https://pay.google.com/gp/v/save/<JWT>

πŸ” Security Considerations

This is not optional β€” it’s mandatory.

Apple Wallet

  • Certificates expire yearly ⚠️
  • Private keys must NEVER be exposed
  • Use secure backend storage (Key Vault, HSM)

Google Wallet

  • JWT must be signed with service account
  • Never generate JWT on device
  • Use short-lived tokens

🚨 Common Mistakes (Real-World)

❌ Generating passes in MAUI app

πŸ‘‰ Wrong. Always backend.

❌ Embedding certificates in mobile app

πŸ‘‰ Critical security flaw.

❌ Treating both platforms the same

πŸ‘‰ Architecturally incorrect.

❌ Not handling pass updates

πŸ‘‰ Breaks real-world scenarios (tickets, loyalty)


πŸ”„ Handling Pass Updates

Apple Wallet

  • Uses APNs push notifications
  • Device pulls updated pass from your server

Google Wallet

  • Update via REST API
  • Changes reflect instantly

πŸ“Š Performance Considerations

Concern Recommendation
Pass generation Cache static templates
Signing Use background workers
API latency Pre-generate where possible
Scaling Queue-based processing (Azure Queue)

☁️ Recommended Backend Stack

Given your ecosystem, a strong setup would be:

  • ASP.NET Core API
  • Azure Functions (for pass generation)
  • Azure Key Vault (certificates)
  • Azure Storage (pkpass hosting)

πŸ§ͺ Testing Strategy

iOS

  • Test on real device (simulator limited)
  • Validate certificate chain

Android

  • Test multiple accounts
  • Validate JWT expiration

πŸš€ Advanced Scenarios

🎟️ Dynamic Event Tickets

  • QR changes every X minutes

πŸ† Loyalty Systems

  • Points updated in real-time

πŸ” Secure Access Passes

  • Time-limited authentication

πŸ“ Location-Based Triggers

  • Wallet surfaces pass automatically

🧾 Final Thoughts

Integrating Apple Wallet and Google Wallet in .NET MAUI is less about writing code and more about designing a distributed, secure system. If you approach it correctly: βœ… Clean MAUI abstraction
βœ… Strong backend pipeline
βœ… Proper security handling You end up with a feature that feels native, powerful, and production-grade.


πŸ”— Closing Insight

The real skill is not β€œadding a pass” β€”
it’s designing the system that makes that pass trustworthy.

An unhandled error has occurred. Reload πŸ—™