jPasskit is an Java™ implementation of the Apple™ PassKit Web Service.
There are two separate projects:
Current stable release: 0.1.1
Development Version: 0.2.0-SNAPSHOT
<dependency>
<groupId>de.brendamour</groupId>
<artifactId>jpasskit</artifactId>
</dependency>
or:
<dependency>
<groupId>de.brendamour</groupId>
<artifactId>jpasskit.server</artifactId>
</dependency>
The released artifacts are now available at Maven Central
Snapshot versions can be found here: https://oss.sonatype.org/content/repositories/snapshots/
Using jPasskit is pretty straight forward:
The class PKPass is the toplevel class. It represents the pass.json file. Everything else can just be added like one would add it on the JSON side.
Example:
PKPass pass = new PKPass();
PKBarcode barcode = new PKBarcode();
PKStoreCard storeCard = new PKStoreCard();
List<PKField> primaryFields = new ArrayList<PKField>();
PKField balanceField = new PKField();
balanceField.setKey( "balance" );
balanceField.setLabel( "balance" );
balanceField.setValue( 20.0 );
balanceField.setCurrencyCode( "EUR" );
primaryFields.add( balanceField );
barcode.setFormat( PKBarcodeFormat.PKBarcodeFormatQR );
barcode.setMessage( "ABCDEFG" );
barcode.setMessageEncoding( Charset.forName( "utf-8" ) );
storeCard.setPrimaryFields( primaryFields );
pass.setFormatVersion( 1 );
pass.setPassTypeIdentifier( "pass.some.passTypeIdentifier" );
pass.setSerialNumber( "000000001" );
pass.setTeamIdentifier( "myTeamId" );
pass.setBarcode( barcode );
pass.setOrganizationName( "OrgName" );
pass.setLogoText( "MyPass" );
pass.setStoreCard( storeCard );
pass.setDescription( "My PassBook" );
pass.setBackgroundColorAsObject( Color.BLACK );
pass.setForegroundColor( "rgb(255,255,255 )" );
...
Usually, passes contain additional information that need to be included in the final, signed pass, e.g.
jPasskit provides a flexible mechanism to provide such templates:
PKPassTemplateFolder
)PKPassTemplateInMemory
)IPKPassTemplate
)In order to use an existing folder on the file system as you pass's template, you create an instance of PKPassTemplateFolder
using the path to your folder as argument:
IPKPassTemplate pkPassTemplateFolder = new PKPassTemplateFolder(PASS_TEMPLATE_FOLDER);
The content of this directory is defined in the PassKit Developer Documentation.
That's it. When signing the pass, the contents of this folder will be copied into the pass.
This approach requires more code, but is also more flexible. The template is stored as a list of input streams, whose content gets copied into the pass when it is signed and packaged.
It does not matter, where the stream comes from, but the data needs to be available when the template is used. For convenience, we provide methods to add several additional data types to the template:
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_BACKGROUND, stream);
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_BACKGROUND_RETINA, stringBuffer);
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON, file);
pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, url);
As you can see, we're also providing static variables for the most common file names.
You can also add an optional locale parameter to the call, in which case the file will automatically be added only for the given language: pkPassTemplateInMemory.addFile(PKPassTemplateInMemory.PK_ICON_RETINA, Locale.ENGLISH, url); //content from URL will be placed in "en.lproj/icon@2x.png"
Note: There are no checks, that the content of a provided file is valid. So if you'd provide a PDF file but store it as icon.png, it will not work.
The PKSigningUtil contains all necessary methods to:
Example to do it all in one step: PKSigningInformation pkSigningInformation = new PKSigningInformationUtil().loadSigningInformationFromPKCS12AndIntermediateCertificate(keyStorePath, keyStorePassword, appleWWDRCA); PKPassTemplateFolder passTemplate = new PKPassTemplateFolder(template_path); PKFileBasedSigningUtil pkSigningUtil = new PKFileBasedSigningUtil(); byte[] signedAndZippedPkPassArchive = pkSigningUtil.createSignedAndZippedPkPassArchive(pass, passTemplate, pkSigningInformation);
The jPasskit Server doesn't provide a full fledged PassKit Web Service but merely the basics you need implement your own standalone server. Things like storing passes and registrations still need to be implemented according to your own needs (or added to an existing Application).
The set up and start the Server you need two things:
The IPKRestletServerResourceFactory is used to create instances of three classes: PKDeviceResource. PKPassResource, PKLogResource. You'll need to subclass each of these and provide your own implementations.
PKDeviceResource is used to register/unregister devices and to get the serialNumbers of changed passes.
PKPassResource is used to fetch the latest version of a pass.
PKPersonalizePassResource is used to store the signup information for a rewards program (see https://developer.apple.com/library/prerelease/content/documentation/UserExperience/Conceptual/PassKit\_PG/PassPersonalization.html)
PKLogResource is used for the log messages, that the devices send in case of an error.
Then you create the server instance:
Properties serverConfigurationProperties = new Properties();
serverConfigurationProperties.put("rest.bindIP", "::");
serverConfigurationProperties.put("rest.bindPort", "8082");
IPKRestletServerResourceFactory pkRestletServerResourceFactory = new MyOwnPKRestletServerResourceFactory();
PKRestServer pkRestServer = new PKRestServer(serverConfigurationProperties, pkRestletServerResourceFactory);
try {
pkRestServer.start();
} catch (Exception e) {
e.printStackTrace();
}
That's it. Your web service is running. Just point your passes to the URL where the server is running.
Apple provides a handy, albeit short, guide about how this works: https://developer.apple.com/library/prerelease/content/documentation/UserExperience/Conceptual/PassKit\_PG/PassPersonalization.html
The process in broad strokes works as follows:
serialNumber
webServiceURL/version/passes/passTypeIdentifier/serialNumber/personalize
which ends up in the PKPersonalizePassResource
.serialNumber