spatie/laravel-mobile-pass

repository·main·Indexed 43 days ago

https://github.com/spatie/laravel-mobile-pass

A Laravel package for generating and managing mobile passes for Apple Wallet and Google Wallet. It supports various use cases including tickets, coupons, and membership cards, and allows developers to push updates to issued passes to ensure devices display current information.

Tokens
38.7K
Snippets
118
Records
160
Agent score
56%

What's inside laravel-mobile-pass

  1. Generate mobile passes for Apple Wallet and Google Wallet

    main
    The spatie/laravel-mobile-pass package allows you to generate mobile passes for both Apple Wallet (iOS) and Google Wallet (Android). It supports various use cases such as boarding passes, event tickets, coupons, store cards, membership cards, and gift cards. Additionally, the package enables you to push updates to already issued passes to ensure user devices always display current information.
  2. How pass relevance works in Apple Wallet

    main

    Pass relevance is an Apple-exclusive feature that surfaces a pass on the lock screen at the optimal moment (e.g., a boarding pass before a flight or a loyalty card when entering a shop).

    Relevance is driven by two primary factors:

    1. Time: Using relevantDates to trigger the pass around a specific moment.
    2. Location: Using GPS coordinates (addLocation) or iBeacons (addBeacon) to trigger the pass when a user is physically near a venue.

    Best Practice: Combining both a date and a location provides the strongest relevance. For example, a concert ticket with both the showtime and the stadium coordinates will surface as the user travels to the venue and drop out once the event is over.

  3. Choose the correct builder for your pass type

    main

    The package provides specialized builders for every pass type supported by Apple Wallet and Google Wallet. Because Apple and Google use different naming conventions and data structures, you must select the builder corresponding to the specific platform you are targeting.

    Each builder provides type-specific setters, while all builders share common methods: save(), addToWalletUrl(), and expire().

    Important: Builders are not interchangeable between platforms. Apple builders reside in the Spatie\\LaravelMobilePass\\Builders\\Apple\\... namespace, and Google builders reside in the Spatie\u005cLaravelMobilePass\\Builders\\Google\\... namespace. To support both platforms for a single conceptual pass (e.g., a loyalty card), you must implement the logic twice using both the Apple and Google builders.

    | Apple Builder | Google Builder | Typical Use Case |
    | :--- | :--- | :--- |
    | `AirlinePassBuilder` | `BoardingPassBuilder` | Flight boarding passes |
    | `TrainPassBuilder` | — | Train/rail boarding passes |
    | `EventTicketPassBuilder` | `EventTicketPassBuilder` | Concerts, festivals, sports events |
    | `CouponPassBuilder` | `OfferPassBuilder` | Discount codes, limited-time offers |
    | `StoreCardPassBuilder` | `LoyaltyPassBuilder` | Loyalty cards, membership programs |
    | `GenericPassBuilder` | `GenericPassBuilder` | Anything that doesn't fit the above |
  4. Understand Apple Wallet field zones

    main

    Apple Wallet passes are organized into five distinct zones, each with specific typography and visibility characteristics. Choosing the correct zone ensures information is presented with the appropriate hierarchy:

    • Header fields: Top right of the pass. Stays visible when passes are stacked. Best for glanceable info (e.g., flight number, balance). Max 3.
    • Primary fields: Largest size on the front. Best for main identity (e.g., event name, origin/destination). Max 3 (or 2 for boarding passes).
    • Secondary fields: Below primary fields, smaller size. Best for the next layer of important info. Max 4.
    • Auxiliary fields: Below secondary fields, even smaller. Best for less important details (e.g., seat number, gate). Max 4 (or 5 for boarding passes).
    • Back fields: Located on the back of the pass. Supports long text, line breaks, URLs, and phone numbers. Best for terms, policies, or customer service info. No length limit.
  5. How Google Wallet Classes and Objects work together

    main

    Google Wallet uses a two-part model: a Class and an Object.

    • Class: A shared template representing the common data for a group of passes (e.g., a specific concert event, a loyalty program, or a flight). You declare this once.
    • Object: An individual pass for a specific user that points to a Class.

    Unlike Apple Wallet, where every pass is self-contained, Google Wallet requires you to define the Class first. The package handles the full Class ID by prefixing your provided suffix with your {issuer-id} (e.g., {issuer-id}.beatles-shea-1965).

  6. When to override actions vs. using events

    main

    Deciding whether to override an action or listen to an event depends on your goal:

    Use Events (MobilePassAdded, MobilePassRemoved, PassPersonalized) when:

    • You want to perform side effects like logging, analytics, or sending notifications.
    • You want a lightweight implementation that won't break if the package's internal action logic changes.

    Override Actions when:

    • The event hook is insufficient.
    • You need to change the persistence shape (e.g., using different columns or models).
    • You need to swap a transport layer (e.g., using a custom APNs client).
    • You need to reject an operation outright (e.g., anti-abuse checks during registration).
  7. Apple Wallet NFC Entitlement Requirement

    main

    To use NFC functionality in Apple Wallet passes, you must obtain the PassKit NFC Credentials Entitlement from Apple. Apple restricts NFC access to specific use cases like loyalty, transit, and access control.

    Important Notes:

    • NFC is Apple-only: Google Wallet manages its own NFC flow and does not expose equivalent configuration fields.
    • Development behavior: You can still set an NFC payload and generate valid pass bundles without the entitlement. However, an iPhone without the entitlement will simply not transmit any data when the pass is tapped against a reader.
  8. Security considerations for Wi-Fi credentials in passes

    main

    When adding Wi-Fi credentials to a pass, keep the following security implications in mind:

    1. Plain Text Storage: Passwords are stored in plain text within the pass. Any method of exporting the pass (email attachments, screenshots, iCloud backups) will expose the credentials.
    2. Use Case: Only use this feature for networks where sharing the password is intended. Avoid using it for corporate or high-security networks.
    3. Updating Credentials: If a network password changes, you must update the pass to push the new credentials to the user's device. Devices that have already joined will retain the old password in their cache until the network is manually forgotten.
  9. Understanding pass expiration behavior on iOS and Android

    main

    It is important to note that neither Apple nor Google allows for the remote deletion of a pass from a user's device.

    When you call expire(), you are not deleting the pass, but rather transitioning it to an expired state. This results in the following platform behaviors:

    • The pass is greyed out in the wallet app.
    • The pass is demoted from the lock screen.
    • The pass stops being surfaced in relevant moments (like location-based notifications).

    The user retains control over whether they actually delete the pass from their device.

  10. Declare a Google Wallet Class

    main

    To create a shared template, use the make() method on a specific Class builder with a unique suffix, configure the template fields, and call save(). Google stores these Classes on its own servers, not in your local database.

    Example using EventTicketPassClass:

    use Spatie\
    LaravelMobilePass\\Builders\\Google\\EventTicketPassClass;
    
    EventTicketPassClass::make('beatles-shea-1965')
        ->setIssuerName('Fab Four Promotions')
        ->setEventName('The Beatles | Live at Shea')
        ->setVenueName('Shea Stadium')
        ->setVenueAddress('126th Street & Roosevelt Avenue, Flushing, NY')
        ->setStartDate(Carbon::parse('1965-08-15 20:00'))
        ->setLogoUrl('https://example.com/beatles-logo.png')
        ->setHeroImageUrl('https://example.com/beatles-hero.png')
        ->setBackgroundColor('#1a1a1a')
        ->save();
    use Spatie\LaravelMobilePass\Builders\Google\EventTicketPassClass;
    
    EventTicketPassClass::make('beatles-shea-1965')
        ->setIssuerName('Fab Four Promotions')
        ->setEventName('The Beatles | Live at Shea')
        ->setVenueName('Shea Stadium')
        ->setVenueAddress('126th Street & Roosevelt Avenue, Flushing, NY')
        ->setStartDate(Carbon::parse('1965-08-15 20:00'))
        ->setLogoUrl('https://example.com/beatles-logo.png')
        ->setHeroImageUrl('https://example.com/beatles-hero.png')
        ->setBackgroundColor('#1a1a1a')
        ->save();
  11. Set up the database migrations

    main

    The package requires several tables to track generated passes, Apple device registrations, and Google events. To set these up, publish the migrations and run them:

    ```bash
    php artisan vendor:publish --tag="mobile-pass-migrations"
    php artisan migrate

    This creates the following tables:

    • mobile_passes
    • apple_mobile_pass_devices
    • apple_mobile_pass_registrations
    • mobile_pass_google_events
  12. Configure asynchronous pass updates via queues

    main

    By default, pass updates are pushed to Apple (via APNs) or Google (via REST API) synchronously. For high-traffic applications or bulk updates, you should move these operations to a background queue to prevent HTTP latency from affecting your web requests.

    To enable queuing, set the MOBILE_PASS_QUEUE_CONNECTION and MOBILE_PASS_QUEUE_NAME environment variables. The package uses a standard Laravel ShouldQueue job called PushPassUpdateJob.

    # Example configuration for Redis
    MOBILE_PASS_QUEUE_CONNECTION=redis
    MOBILE_PASS_QUEUE_NAME=wallet