Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Mobile Pass Laravel Package

spatie/laravel-mobile-pass

Generate Apple Wallet and Google Wallet passes in Laravel (tickets, boarding passes, coupons, membership cards). Create and sign pass files, serve them to users, and push updates to installed passes to keep details current across devices.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-mobile-pass
    php artisan vendor:publish --provider="Spatie\MobilePass\MobilePassServiceProvider"
    php artisan migrate
    
  2. Configure Environment:

    • Set MOBILE_PASS_APPLE_WEBSERVICE_HOST (HTTPS required) and MOBILE_PASS_APPLE_CERTIFICATE_PATH in .env.
    • For Google Wallet, configure MOBILE_PASS_GOOGLE_ISSUER_ID and MOBILE_PASS_GOOGLE_PRIVATE_KEY_PATH.
  3. First Pass:

    use Spatie\MobilePass\PassBuilders\Apple\BoardingPassBuilder;
    
    $pass = (new BoardingPassBuilder)
        ->setPassSerialNumber('USER123')
        ->setPassTypeIdentifier('pass.com.yourcompany.boarding')
        ->setTeamIdentifier('YOUR_TEAM_ID')
        ->setOrganizationName('Your Company')
        ->setHeaderFields(['primary': 'Flight 123'])
        ->setStoreCardFields(['primary': 'Boarding Pass'])
        ->setBarcode('123456789', 'QR')
        ->setForegroundColor('#FF0000')
        ->setBackgroundColor('#FFFFFF')
        ->setLogoText('YOUR_COMPANY')
        ->setDescription('Boarding pass for flight 123')
        ->setWebServiceURL('https://your-app.com/mobile-pass/apple/webservice');
    
    $pass->save();
    
  4. Download Link:

    return redirect()->away($pass->addToWalletUrl());
    

Key First Use Case

Generate a boarding pass for a flight and push it to Apple Wallet. Use the addToWalletUrl() method to trigger the download and installation flow.


Implementation Patterns

Core Workflow: Pass Creation & Updates

  1. Builder Pattern: Use platform-specific builders (BoardingPassBuilder, EventTicketBuilder, etc.) for Apple/Google passes.

    $boardingPass = (new BoardingPassBuilder)
        ->setPassSerialNumber($userId)
        ->setBarcode($ticketNumber, 'QR')
        ->setExpirationDate(now()->addDays(7))
        ->setHeaderFields(['primary': 'Flight ' . $flightNumber])
        ->build();
    
  2. Dynamic Content: Fetch real-time data (e.g., flight status) and update passes via:

    $boardingPass->update([
        'headerFields' => ['primary' => 'Flight ' . $updatedFlightNumber],
        'barcode' => $newTicketNumber,
    ]);
    
  3. Platform-Specific Logic:

    • Apple: Uses .pkpass bundles with pass.json manifest.
    • Google: Uses Google Wallet API with JSON payloads.
    • Example for Google:
      $eventTicket = (new EventTicketBuilder)
          ->setPassSerialNumber($userId)
          ->setClassId('YOUR_CLASS_ID')
          ->setObjectId('TICKET_' . $eventId)
          ->setEventName('Concert 2024')
          ->setStartDate(now())
          ->setEndDate(now()->addHours(3))
          ->setLocation('Venue X')
          ->build();
      
  4. Queue Updates: Enable async updates via MOBILE_PASS_QUEUE_CONNECTION in .env:

    $boardingPass->update([...]); // Triggers PushPassUpdateJob
    

Integration Tips

  • User-Specific Passes: Tie passes to users via pass_serial_number (e.g., user_id@email.com).

    $pass->setPassSerialNumber($user->email);
    
  • Webhooks for Google: Handle GoogleMobilePassSaved/GoogleMobilePassRemoved events:

    event(new GoogleMobilePassSaved($pass));
    
  • Remote Images: Use Image::fromUrl() for dynamic assets:

    $boardingPass->setLogoImage(Image::fromUrl('https://example.com/logo.png'));
    
  • NFC Support (Apple): Add NFC fields for contactless interactions:

    $boardingPass->setNFCFields([
        'message' => 'Tap to board',
        'messageEncoding' => 'utf-8',
    ]);
    
  • Localization: Set language in builders for multilingual passes:

    $boardingPass->setLanguage('fr');
    

Gotchas and Tips

Pitfalls

  1. HTTPS Requirement for Apple:

    • mobile-pass.apple.webservice.host must be HTTPS. Non-HTTPS URLs will fail silently during pass generation.
    • Fix: Use a valid SSL certificate or a tool like ngrok for local testing.
  2. Pass Serial Number Uniqueness:

    • Apple/Google require pass_serial_number to be unique per user. Reuse can cause conflicts.
    • Solution: Use user_id or email + timestamp (e.g., user123@2024-05-20).
  3. Google Callback Verification:

    • Ensure MOBILE_PASS_GOOGLE_CALLBACK_SECRET is set and matches the Google Wallet API expectations.
    • Debug: Check storage/logs/laravel.log for GoogleCallbackVerificationFailed errors.
  4. Image Hosting:

    • Remote images (Image::fromUrl()) must be publicly accessible. Private URLs will break pass rendering.
    • Tip: Use a CDN or ensure CORS headers allow access.
  5. Apple Certificate Cache:

    • The package caches signed .pkpass files. Clear cache if updates aren’t reflecting:
      php artisan mobile-pass:clear-cache
      
  6. Time Zones:

    • Dates in passes use the server’s time zone. Explicitly set time zones in builders:
      $boardingPass->setExpirationDate(now()->setTimezone('UTC')->addDays(7));
      

Debugging Tips

  • Apple Webservice Lookup:

    • Test the webservice endpoint manually:
      curl -X GET https://your-app.com/mobile-pass/apple/webservice/lookup?passSerialNumber=USER123
      
    • Expected response: JSON with pass data.
  • Google Wallet Debugging:

    • Use the Google Wallet Test App to simulate installations.
    • Check GoogleMobilePassSaved events for installation status.
  • Pass Validation:

Extension Points

  1. Custom Pass Types: Extend Spatie\MobilePass\PassBuilders\PassBuilder to create custom pass types:

    class CustomPassBuilder extends PassBuilder {
        public function setCustomField(string $value): self {
            $this->customField = $value;
            return $this;
        }
    }
    
  2. Override MobilePass Model: Publish the model and migrate:

    php artisan vendor:publish --tag=mobile-pass-models
    

    Then extend Spatie\MobilePass\Models\MobilePass:

    class CustomMobilePass extends MobilePass {
        protected $table = 'custom_mobile_passes';
    }
    

    Update .env:

    MOBILE_PASS_MODEL=App\Models\CustomMobilePass
    
  3. Custom Webservice Logic: Override the webservice handler:

    // app/Providers/AppServiceProvider.php
    public function boot() {
        MobilePass::boot(function ($pass) {
            // Custom logic before pushing updates
        });
    }
    
  4. Queue Job Customization: Extend PushPassUpdateJob to add pre/post-update logic:

    class CustomPushPassUpdateJob extends PushPassUpdateJob {
        protected function handleUpdate(MobilePass $pass) {
            // Custom update logic
            parent::handleUpdate($pass);
        }
    }
    

    Bind it in AppServiceProvider:

    $this->app->bind(PushPassUpdateJob::class, CustomPushPassUpdateJob::class);
    

Configuration Quirks

  • Apple Team Identifier: Must match your Apple Developer account’s Team ID. Find it in Apple Developer Account.

  • Google Issuer ID: Must be a valid Google Wallet Merchant ID (e.g., issuer123456789). Apply for one here.

  • Pass Type Identifiers: Apple requires passTypeIdentifier to follow the format: pass.com.yourcompany.[type] Example: pass.com.yourcompany.boarding.

  • Barcode Types: Supported types: PKBarcodeFormatQR, `PKBarcodeFormatPDF417

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai