A comprehensive Flutter plugin for creating and managing wallet cards on both iOS (Apple Wallet) and Android (Google Wallet). This plugin provides a unified API for generating, adding, and managing wallet passes across platforms.
- iOS: Full Apple Wallet (Passkit) integration
- Android: Google Wallet integration
- Unified API: Single codebase for both platforms
- β Check wallet availability
- β Add cards to wallet
- β Check if card is already added
- β View cards in wallet
- β Generate card files from data
- β Parse existing card files
- β Download cards from URLs
- Generic Cards: General purpose cards
- Boarding Passes: Flight tickets
- Coupons: Discount and promotional cards
- Event Tickets: Concert, sports, and event passes
- Store Cards: Loyalty and membership cards
- π¨ Custom colors and styling
- π Location-based relevance
- π Date-based relevance
- π Secure certificate signing (iOS)
- π Network download support
- π§ͺ Comprehensive test coverage
Add this to your package's pubspec.yaml
file:
dependencies:
flutter_wallet_card: ^4.0.0
Then run:
flutter pub get
-
Enable Wallet capability in your iOS project:
- Open
ios/Runner.xcworkspace
in Xcode - Select your target β Signing & Capabilities
- Add "Wallet" capability
- Open
-
Configure your Apple Developer account:
- Create a Pass Type ID in Apple Developer Console
- Generate certificates for pass signing
-
Add Google Wallet API to your project:
- Enable Google Wallet API in Google Cloud Console
- Configure OAuth 2.0 credentials
-
Update Android manifest (automatically handled by plugin):
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
import 'package:flutter_wallet_card/flutter_wallet_card.dart';
import 'package:flutter_wallet_card/models/wallet_card.dart';
// Check if wallet is available
bool isAvailable = await FlutterWalletCard.isWalletAvailable();
if (isAvailable) {
// Create a wallet card
final card = WalletCard(
id: 'my-card-123',
type: WalletCardType.generic,
platformData: {
// iOS specific data
'passTypeIdentifier': 'pass.com.yourcompany.yourpass',
'teamIdentifier': 'YOUR_TEAM_ID',
// Android specific data
'issuerId': 'your-issuer-id',
'classId': 'your-class-id',
},
metadata: WalletCardMetadata(
title: 'My Awesome Card',
description: 'This is a sample wallet card',
organizationName: 'Your Company',
serialNumber: 'CARD123',
),
visuals: WalletCardVisuals(
backgroundColor: '#1E88E5',
foregroundColor: '#FFFFFF',
labelColor: '#E3F2FD',
),
);
// Add card to wallet
bool success = await FlutterWalletCard.addToWallet(card);
if (success) {
print('Card added successfully!');
}
}
final cardWithLocation = WalletCard(
id: 'location-card',
type: WalletCardType.storeCard,
platformData: {
'passTypeIdentifier': 'pass.com.yourcompany.store',
'teamIdentifier': 'YOUR_TEAM_ID',
},
metadata: WalletCardMetadata(
title: 'Store Loyalty Card',
description: 'Get rewards at our store',
organizationName: 'Your Store',
locations: [
WalletCardLocation(
latitude: 37.7749,
longitude: -122.4194,
altitude: 100.0,
relevantText: 'Welcome to our San Francisco store!',
),
],
),
visuals: WalletCardVisuals(
backgroundColor: '#4CAF50',
foregroundColor: '#FFFFFF',
),
);
// Generate a card file for sharing or storage
File cardFile = await FlutterWalletCard.generateCardFile(
card,
outputDirectory: await getApplicationDocumentsDirectory(),
);
print('Card file created at: ${cardFile.path}');
// Download and add a card from a URL
try {
File downloadedCard = await FlutterWalletCard.downloadFromUrl(
'https://example.com/mycard.pkpass',
);
// Parse the downloaded card
WalletCard card = await FlutterWalletCard.parseFromFile(downloadedCard.path);
// Add to wallet
await FlutterWalletCard.addToWallet(card);
} catch (e) {
print('Failed to download card: $e');
}
// iOS: Add multiple cards at once
if (Platform.isIOS) {
List<WalletCard> cards = [card1, card2, card3];
bool success = await FlutterWalletCard.addMultipleToWallet(cards);
}
// Android: Save pass with JWT
if (Platform.isAndroid) {
String jwt = 'your-google-wallet-jwt';
bool success = await FlutterWalletCard.savePassWithJwt(jwt);
// Create a pass link
String link = await FlutterWalletCard.createPassLink({
'objectId': 'your-object-id',
});
}
Method | Description | Returns |
---|---|---|
isWalletAvailable() |
Check if wallet is available on device | Future<bool> |
isCardAdded(String cardId) |
Check if specific card is added | Future<bool> |
addToWallet(WalletCard card) |
Add card to wallet | Future<bool> |
viewInWallet(String cardId) |
Open card in wallet app | Future<bool> |
generateCardFile(WalletCard card) |
Generate card file | Future<File> |
parseFromFile(String path) |
Parse card from file | Future<WalletCard> |
downloadFromUrl(String url) |
Download card from URL | Future<File> |
Method | Description | Returns |
---|---|---|
addMultipleToWallet(List<WalletCard> cards) |
Add multiple cards | Future<bool> |
Method | Description | Returns |
---|---|---|
savePassWithJwt(String jwt) |
Save pass using JWT | Future<bool> |
createPassLink(Map<String, dynamic> data) |
Create pass link | Future<String> |
The main model representing a wallet card:
class WalletCard {
final String id;
final WalletCardType type;
final Map<String, dynamic> platformData;
final WalletCardMetadata metadata;
final WalletCardVisuals visuals;
final File? file;
}
Card information and content:
class WalletCardMetadata {
final String title;
final String description;
final String? organizationName;
final String? serialNumber;
final DateTime? expirationDate;
final DateTime? relevantDate;
final List<WalletCardLocation>? locations;
final Map<String, dynamic>? additionalData;
}
Card appearance and styling:
class WalletCardVisuals {
final String backgroundColor;
final String foregroundColor;
final String? labelColor;
final Map<String, dynamic>? additionalStyles;
}
The plugin throws WalletException
for wallet-related errors:
try {
await FlutterWalletCard.addToWallet(card);
} on WalletException catch (e) {
print('Wallet error: ${e.message}');
if (e.details != null) {
print('Details: ${e.details}');
}
} catch (e) {
print('General error: $e');
}
Run the test suite:
flutter test
For comprehensive testing:
flutter test test/test_all.dart
If you're upgrading from version 3.x, here are the key changes:
- New unified API: Replace platform-specific calls with unified methods
- Updated models: Use new
WalletCard
model instead of separate iOS/Android models - Method names: Some method names have changed for consistency
Old (v3.x):
// iOS
await FlutterWalletCard.addPasskit(passData);
// Android
await FlutterWalletCard.addGoogleWallet(walletData);
New (v4.x):
// Unified
final card = WalletCard(/* ... */);
await FlutterWalletCard.addToWallet(card);
- GitHub Actions Workflows - CI/CD and automation
- Publishing Scripts - Package publishing tools
# Validate package before publishing
./scripts/publish-package.sh validate
# Run comprehensive tests
./scripts/publish-package.sh test
# Create a new release
./scripts/publish-package.sh release --version 1.0.0
# Publish to pub.dev (manual)
./scripts/publish-package.sh publish
This project includes comprehensive GitHub Actions workflows:
-
CI/CD Pipeline - Automated testing, validation, and quality checks
-
Package Publishing - Automated pub.dev releases
-
Release Management - Version bumping and changelog generation
See GitHub Actions Documentation for details.
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
- Fork the repository
- Clone your fork:
git clone https://github.com/your-username/flutter_wallet_card.git
- Install dependencies:
flutter pub get
- Run tests:
flutter test
- Start documentation server:
./scripts/deploy-docs.sh dev
- Run
./scripts/publish-package.sh validate
to ensure quality - Update documentation if needed
- Add tests for new features
- Follow existing code style
This project is licensed under the MIT License - see the LICENSE file for details.
- π§ Email: michal.makowski97@gmail.com
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
See CHANGELOG.md for a detailed list of changes.
Made with β€οΈ for the Flutter community