The flow of execution is really easy (once setted-up everything):
- You get your data from somewhere
- You set the needed data in the pass through methods, overrides and data in fields
- You generate the pass stream through
.generate()
method - Hooray 😄🎉
Some details:
-
Properties will be checked against schemas, which are built to reflect Apple's specifications, that can be found on Apple Developer Portal, at PassKit Package Format Reference.
-
Here below are listed all the available methods that library will let you use.
-
In case of troubleshooting, you can start your project with "debug flag" as follows:
$ DEBUG=* node index.js
For other OSs, see Debug Documentation.
- Keep this as always valid for the reference:
const { Pass } = require("passkit-generator");
- Instance
- Localizing Passes
- Setting barcode
- Setting expiration / voiding the pass
- Setting relevance
- Setting NFC
- Getting remote resources
- Setting Pass Structure Keys (primaryFields, secondaryFields, ...)
- Generating the compiled pass.
var pass = new Pass(options);
Returns:
Object<Pass>
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
options | Object | The options to create the pass | false | - |
options.model | String/Path | The model path to be used to generate a new model. | false | - |
options.certificates | Object | The certificate object containing the paths to certs files. | false | - |
options.certificates.wwdr | String/Path | The path to Apple WWDR certificate or its content. | false | - |
options.certificates.signerCert | String/Path | The path to Developer certificate file or its content. | false | - |
options.certificates.signerKey | Object/String | The object containing developer certificate's key and passphrase. If string, it can be the path to the key file or its content. If object, must have keyFile key and might need passphrase . |
false | - |
options.certificates.signerKey.keyFile | String/Path | The path to developer certificate key or its content. | false | - |
options.certificates.signerKey.passphrase | String | Number | The passphrase to use to unlock the key. | false | - |
options.overrides | Object | Dictionary containing all the keys you can override in the pass.json file and does not have a method to get overridden. | true | { } |
options.shouldOverwrite | Boolean | Setting this property to false, will make properties in overrides and fields to be pushed along with the ones added through methods to the existing ones in pass.json. |
true | true |
Localizing Passes:
Following Apple Developer Documentation, localization (L10N) is done by creating a .lproj
folder for each language you want to translate your pass, each named with the relative ISO-3166-1 alpha-2 code (e.g. en.lproj
).
In this library, localization can be done in three ways: media-only (images), translations-only or both. The only differences stands in the way the only method below is used and how the model is designed.
If you are designing your pass for a language only, you can directly replace the placeholders in
pass.json
with translation.
pass.localize(lang, options);
Returns:
Object<Pass> (this)
Description:
You may want to create the folder and add translated media and no translations; else you may want to add only translations without different medias or maybe both.
In the first case, create the .lproj
folder in the model root folder and add the translated medias inside. Then use the method by passing only the first parameters, the code.
In the other two cases, you'll need to specify also the second argument (the translations to be added to pass.strings
file, which will be added later).
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
lang | String | The ISO-3166-1 language code | false | - |
options | Object | Translations in format PLACEHOLDER : TRANSLATED-VALUE. | true | undefined | { } |
Example:
pass
.localize("it", {
"EVENT": "Evento",
"LOCATION": "Posizione"
})
.localize("de", {
"EVENT": "Ereignis",
"LOCATION": "Ort"
})
.localize("en")
Setting barcodes:
pass.barcode(data);
Returns:
Improved Object<Pass> (this with some "private" methods available to be called under aliases, as below)
Description:
Each object in data
will be filtered against a schema (Apple reference) validation and used if correctly formed.
If the argument is an Object, it will be treated as one-element Array.
If the argument is a String or an Object with format
parameter missing, but message
available, the structure will be autogenerated complete of all the fallbacks (4 dictionaries).
To support versions prior to iOS 9, barcode
key is automatically supported as the first valid value of the provided (or generated) barcode. To change the key, see below.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
data | String | Array<Object> | Object | Data to be used in the barcode | false | - |
Examples:
pass.barcode("11424771526");
// or
pass.barcode({
message: "11424771526",
format: "PKBarcodeFormatCode128"
altText: "11424771526"
});
// or
pass.barcode([{
message: "11424771526",
format: "PKBarcodeFormatCode128"
altText: "11424771526"
}, {
message: "11424771526",
format: "PKBarcodeFormatQR"
altText: "11424771526"
}, {
message: "11424771526",
format: "PKBarcodeFormatPDF417"
altText: "11424771526"
}]);
See: PassKit Package Format Reference # Barcode Dictionary
pass.barcode(data).backward(format);
Returns:
Object<Pass> (this)
Description:
It will let you choose the format to be used in barcode property as backward compatibility.
Also it will work only if data
is provided to barcode()
method and will fail if the selected format is not found among barcodes dictionaries array.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
format | String | Format to be used. Must be one of these types: PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec | false | - |
Example:
// Based on the previous example
pass
.barcode(...)
.backward("PKBarcodeFormatQR");
// This won't set the property since not found.
pass
.barcode(...)
.backward("PKBarcodeFormatAztec");
pass.barcode(data).autocomplete();
Returns:
Improved Object<Pass> ("this" with backward() support and length prop. reporting how many structs have been added).
Description:
It will generate all the barcodes fallback starting from the first dictionary in barcodes
.
Setting expiration / void the pass:
pass.expiration(date [, format]);
Returns:
Object<Pass> (this)
Description:
It sets the date of expiration to the passed argument. The date will be automatically parsed in order in the following formats:
- MM-DD-YYYY hh:mm:ss,
- DD-MM-YYYY hh:mm:ss.
Otherwise you can specify a personal format to use.
Seconds are not optionals. If the parsing fails, the error will be emitted only in debug mode and the property won't be set.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
date | String/date | The date on which the pass will expire | false | - |
format | String | A custom format to be used to parse the date | true | undefined |
pass.void();
Returns:
Object<Pass> (this)
Description:
It sets directly the pass as voided (void: true).
Setting relevance:
pass.relevance(key, value [, relevanceDateFormat]);
Returns:
Improved Object<Pass> (this with length property)
Description:
It sets the relevance key in the pass among four: beacons, locations, relevantDate and maxDistance. See Apple Documentation dedicated page for more.
For the first two keys, the argument 'value' (which will be of type Array<Object>) will be checked and filtered against dedicated schema.
For relevantDate, the date is parsed in the same formats of #expiration(). For maxDistance, the value is simply converted as Number and pushed only with successful conversion.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
key | String | The relevance key to be set, among beacons, locations, relevantDate and maxDistance | false | - |
value | String | Number | Array<Object> | Type depends on the key. Please refer to the description above for more details | false | - |
relevanceDateFormat | String | Custom date format. Will be only used when using relevanceDate key |
true | undefined |
Example:
pass.relevance("location", [{
longitude: "73.2943532945212",
latitude: "-42.3088613015625",
]);
pass.relevance("maxDistance", 150);
// DD-MM-YYYY -> April, 10th 2021
pass.relevance("relevantDate", "10/04/2021", "DD-MM-YYYY");
// MM-DD-YYYY -> October, 4th 2021
pass.relevance("relevantDate", "10/04/2021");
NFC Support:
pass.nfc([data, ...])
Returns:
Object<Pass> (this)
Description:
It sets the property for nfc dictionary. An Object as argument will be treated as one-element array.
Notice: I had the possibility to test in no way this pass feature and, therefore, the implementation. If you need it and this won't work, feel free to contact me and we will investigate together 😄
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
data | Array<Object> | Object | The data regarding to be used for nfc | false | - |
See: PassKit Package Format Reference # NFC
Getting remote resources:
pass.load(resource, name);
Returns:
Object<Pass> (this)
Description:
Sets the resources to be downloaded in runtime to be pushed in the pass.
Use name
param to give your downloaded file a name or to provide the folder path it will be pushed into (with the name, obv.).
Requests are not cached and load method can only load pictures right now (no other types should be required). In case of conflict between downloaded files and model files, downloaded files will have the priority and will be putted in the zip file.
When in debug mode, file header is shown.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
resource | String | The URL where to fetch the picture | false | - |
name | String | The name / path to be used to call this | false | - |
Example:
pass.load("http://...", "icon.png");
pass.load("http://...", "en.lproj/icon.png");
Setting Pass Structure Keys (primaryFields, secondaryFields, ...):
Unlike method-set properties or overrides, to set fields inside areas (primaryFields, secondaryFields, auxiliaryFields, headerFields, backFields), this library make available a dedicated interface that extends native Array, to let you perform all the operations you need on the fields. Still, shouldOverride option, will determine whether default inserted fields should be kept or not.
Examples:
pass.headerFields.push({
key: "header1",
label: "Data",
value: "25 mag",
textAlignment: "PKTextAlignmentCenter"
}, {
key: "header2",
label: "Volo",
value: "EZY997",
textAlignment: "PKTextAlignmentCenter"
});
pass.primaryFields.pop();
See: Passkit Package Format Reference # Field Dictionary Keys
pass.transitType = "PKTransitTypeAir";
Description:
Since this property belongs to the "Structure Keys" but is not an "array of field dictionaries" like the other keys on the same level, a setter (and obv. also a getter) got included in this package to check it against a schema (which is like, "is a string and contains one of the following values: PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBus, PKTransitTypeGeneric, PKTransitTypeTrain", as described in Passkit Package Format Reference).
Generating the compiled Pass
Generating the pass is the last step of the process (before enjoying 🎉).
Since the file format is .pkpass
(which is a .zip
file with changed MIME), this method will return a Stream
, which can be used to be piped to a webserver response or to be written in the server.
As you can see in examples folder, to send a .pkpass file, a basic webserver uses MIME-type application/vnd.apple.pkpass
.
pass.generate();
Returns: Promise
Description:
The returned Promise will contain a stream or an error.
Examples:
pass.generate()
.then(stream => {
doSomethingWithPassStream();
})
.catch(error => {
doSomethingWithThrownError();
});
Thanks for using this library. ❤️ Every contribution is welcome.