Overview
Zebra VAS SDK is an Android library built on top of the existing Android NFC APIs and Apple VAS protocol. It offers streamlined configuration and management of the necessary procedures involved in accessing and processing data from the Apple VAS NFC pass stored in the Apple Wallet. For simplicity, "Apple VAS NFC pass" will be referred to as "NFC pass" in this document.
This section discusses the contents of the NFC pass, offers guidance on developing an application to read the NFC pass, and presents the available APIs within the Zebra VAS SDK.
Install SDK
Perform the steps below to set up the SDK and launch the developed application on the device:
- Download the SDK from the Zebra Support Portal and extract the files from the download.
- Import the Android .AAR file into the "libs" folder of the Android application project.
- Install the Zebra VAS Service .APK on the Zebra mobile computer. This is required to establish communication between the SDK and the Zebra device via the Zebra VAS Service.
SDK Objects
The main SDK components are:
- ZebraNfcVas - operational core
- VasConfig - configuration object
- Pass - an object representing the received NFC pass
ZebraNfcVas
ZebraNfcVAS object is the main component of the SDK that establishes a connection with the Zebra NFC VAS service, handles all the communication with the NFC passes, configures the NFC reader, and reads the pass from the Apple wallet. This object must be explicitly created and initialized. After the pass is successfully read, ZebraNfcVas decrypts the data (given that a private key is provided and all information is correct and intact) and returns the Pass object back to the caller. If a private key is not provided, the SDK returns the encrypted data.
VasConfig
VasConfig is a configuration object automatically generated by calling createAppleVasConfig method from the SDK. It contains configuration for the NFC pass, including pass type identifier, private key, etc. Only one configuration object can be created at a time. The configuration object contains one or more Pass Type Identifier(s), which identifies the pass to be returned, and may contain an associated private key, used to decrypt data from the pass.
Example 1 of a configuration object with one pass type identifier:
- Pass Type Identifier:
- pass.com.zebra.special_holiday_event_pass
- Private Key: decrypts the data from the pass
- Filter (optional)
- Merchant URL (optional)
Example 2 of a configuration object with 2 pass type identifiers:
- Pass Type Identifier:
- pass.com.zebra.customer_loyalty
- pass.com.zebra.cafe_loyalty
- Private Key: decrypts data from either of the two above pass types
- Filter (optional)
- Merchant URL (optional)
Pass
The Pass object encapsulates the information about the NFC pass that is read, including the payload data and supplementary metadata. The Pass object enables developers to validate the pass type and ensure that it is not a replay attack (i.e. the date and time is within 10 seconds of the actual date and time), adhering to Apple requirements.
Developer Guide
The following serves as a guide to develop an application that reads an NFC pass from Apple Wallet:
Implement IZebraServiceConnection Interface - It is required to implement IZebraServiceConnection Interface to receive callback methods from the Zebra NFC VAS service on the service connection/disconnection and NFC pass object. The 3 callback methods are: onServiceConnected, onServiceDisconnected, and onPassDetected.
public class AppleVASActivity extends AppCompatActivity implements IZebraServiceConnection { ... }
Replace "AppleVASActivity" with the name of the class implemented within your application.
Create a ZebraNFCVAS object and intialize the object - ZebraNfcVas object should be declared in onCreate() and initialized by calling init().
private ZebraNfcVas vasSDK; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); //UI Initialization
} private void vasSdkInit() { Log.e(TAG, "vasSdkInit"); vasSDK = new ZebraNfcVas(this); vasSDK.init(); }vasSdkInit();
After initialization, a callback to onServiceConnection is available. Proceed with the subsequent steps for implementation of this method.
@Override public void onServiceConnection() { Log.e(TAG,"onServiceConnection"); //Start with the app implemenation }
a. Create an AppleVasConfig object - This is the object that the SDK uses to know how to interact with a presented NFC pass.
vasSDK.createAppleVasConfig();
b. Set the appropriate configuration values in the AppleVasConfig object by using the following APIs:
- setPassTypeIds
- setPrivateKey
- setFilter
- setMerchantURL
c. Create the ZebraNFCVAS object. This holds the instance of a VasConfig object for pass detection operation.
vasSDK.createZebraNfcVasConfig();
d. Set the AppleVasConfig object into the ZebraNFCVAS object - This informs the SDK about the configuration data to use when reading the NFC pass.
vasSDK.setVasConfig();
e. Call connectToReader - This establishes the connection with the NFC reader.
vasSDK.connectToReader();
f. Call enableReadPassMode - Only reader/writer capabilities are enabled and polling is configure to read Type A and Type B cards.
vasSDK.enableReadPassMode();
g. When an NFC pass is read, onPassDetected() is called - This method receives the Pass object when a pass is read. Process the data read from the pass based on business needs.
public void onPassDetected(Pass pass) { Log.v(TAG, ">>> PASS DETECTED <<<"); // Process data read from the pass }
h. Call disableReadPassMode before the app goes to the background or when the activity ends - This returns the device to the default NFC Forum polling mode.
@Override public void onPause() { super.onPause(); Log.i(TAG, "onPause called & Reader Mode Deactivated ....."); vasSDK.disableReadPassMode(); }
APIs
APIs available:
- init
- onServiceConnected
- onServiceDisconnected
- createAppleVasConfig
- setPassTypeIds
- setPrivateKey
- setFilter
- setMerchantURL
- setVasConfig
- clearConfigs
- createZebraVasConfig
- connectToReader
- enableReadPassMode
- disableReadPassMode
- getType
- getMerchantUrl
- getTerminalMode
- onPassDetected
- getSdkVersion
init
public void init()
Initializes and binds to the Zebra NFC VAS Service.
Parameter: None
Return value: None
Throws: RuntimeException
if the service is not available or the security/signature does not match.
onServiceConnected
This is a callback method invoked when Zebra NFC VAS service is connected. IZebraServiceConnection interface must be implemented. When init() is called, it tries to connect to the Zebra NFC VAS service. If successful, it calls onServiceConnected.
onServiceDisconnected
This is a callback method invoked when Zebra NFC VAS service is disconnected. IZebraServiceConnection interface must be implemented. When init() is called, it tries to connect to the Zebra NFC VAS service. If unsuccessful, it calls onServiceDisconnected.
createAppleVasConfig
public void createAppleVasConfig()
Creates the VASConfig object and specific instance of a VasConfig object. This can only be called once.
Parameter: None
Return value: None
setPassTypeIds
public void setPassTypeIds(String[] passTypeIds)
Sets one or more Pass Type Identifiers in the app prior to reading the NFC pass. The Pass Type Identifier is provided by either the issuer of the NFC pass or Apple. This overwrites any existing values. The app uses these unique string values as identifiers to ensure that when it reads the NFC pass in the Apple Wallet, it can verify whether the pass type identifier matches the one that was used during the NFC pass creation process. These identifiers are typically in the form 'pass.com.companyname' or other similar reverse domain string. When an NFC reader specifies one or more Pass Type Identifiers, only passes that match those identifiers are retrieved.
Parameter: String[] passTypeIds
This is an array of one or more Pass Type IDs. For example, {“pass.com.pronto.zebra-wallet-pass.demo”} or {“pass.com.zebra”, “pass.com.xyz.somethingspecific”}. When attempting to read a pass, the pass being read is checked against each Pass Type ID in the array.
Return value: None
Throws:
InvalidParameterException
when there are null or empty strings in the array, invalid characters, or the array is empty in any of the Pass Type IDs.UnsupportedEncodingException
when a conversion encoding error occurs.NoSuchAlgorithmException
when a SHA256 conversion error occurs.
setPrivateKey
public void setPrivateKey(String key)
Sets the PEM-formatted private key used to decrypt the pass object. It overwrites any pre-existing value. The NFC pass on the Apple Wallet is encrypted prior to being communicated to the Zebra mobile computer. To decrypt the pass, the Zebra VAS SDK needs the associated private key. The private key is acquired during pass creation, either by the developer with Apple's permission to create the pass or from the company that issued the NFC-enabled pass. If a private key is not provided to the SDK, the SDK returns the message encrypted and it is the developer's responsibility to decrypt it. For example, this may include sending the encrypted pass to a backend server to be decrypted and processed.
Parameter: String key
Example:
-----BEGIN EC PARAMETERS-----\n
alkidnklde==\n
-----END EC PARAMETERS-----\n
-----BEGIN EC PRIVATE KEY——\n
Aslkdflhksdfjfkk728klxld...\n
ak7hjvgn9b8o3bv9hae98fn2...\
n 9asjh90fuh34n2uh33==\n
-----END EC PRIVATE KEY-----\n
Return value: None
Throws: InvalidParameterException
if the key is null, empty, or incorrectly formatted.
setFilter
public void setFilter(byte[] filter, FilterType type)
(Optional) Sets the filter information to be read for the NFC pass. The filter is supplied by the merchant of the NFC pass. This overwrites any pre-existing value. A company may issue passes for different reasons and/or uses. The filter offers the ability to issue numerous similar passes with distinguiahsable variations.
A sample use case could involve a company issuing a season of tickets to a sporting event. In this case, all the tickets originate from the same company, with each ticket sharing similarities except for access date, which serves as the sole distinguishing factor. This distinguishing factor is used as the filter to identify any combination of dates. For example, consider a scenario where there are 4 games taking place on different dates. The developer could assign each game a specific within the date filter. The Zebra VAS SDK SDK can support all 4 games by determining which bit is set. When using the NFC reader, a filter can be specified with one bit set for the current game, and it can be designated as a bit-mask. By doing so, any pass with the corresponding bit set for the present date can be read, while passes without the bit set can be skipped.
Parameter:
- byte[] filter - This is a 4-byte array that is the filter value used during the pass retrieval process.
- FilterType type - This is one of two constants:
- FILTER_TYPE_EXACT_MATCH - If the specified filter value exactly matches the merchant pass filter value, the match is successful.
- FILTER_TYPE_BIT_MASK - If the specified filter value is bitwise ANDed with the merchant pass filter value and the result equals the merchant pass filter value, the match is successful.
Return value: None
Throws: InvalidParameterException
if the filter value is not exactly 4 bytes in size.
setMerchantURL
public void setMerchantURL(String url)
(Optional) Sets the VAS Merchant URL where the Apple device should be directed if no pass is currently available on the device. This overwrites any pre-existing value.
Passes are often used as loyalty cards. In situations where a customer is not yet a loyalty member, the user could simply tap the reader, and the Merchant URL can be transmitted to the device, guiding the user to a sign-up page. This implementation requires specific server APIs and processes that are beyond the scope of this document.
Parameter: String url
This is the merchant URL string for the associated pass, which is generally used to sign-up for a pass. It must include "https://". The maximum string length is 64 bytes.
Return value: None
Throws: InvalidParameterException
if the length is too long or does not contain a valid "https://" header.
setVasConfig
public void setVASConfig()
Specifies the VASConfig object to be used for interacting with the passes. Prior to using this method,createAppleVasConfig() must be called to create the VasConfig object. To retrieve or pass data, call createZebraVasConfig().
Parameter: None
Return value: None
Throws: InvalidParameterException
or RuntimeException
if VasConfig object is null.
clearConfigs
public void clearConfigs()
Clears the VASConfig object that is used for interacting with passes. After clearing the object, data from the NFC passes cannot be retrieved until calling: setPrivateKey(), setFilter(), setPassIds(), and setVasConfig().
Parameter: None
Return value: None
Throws: RuntimeException
if VasConfig object is null.
createZebraVasConfig
public void createZebraVasConfig()
Creates the ZebraConfig object and holds the instance of a VasConfig object for pass detection operation.
Parameter: None
Return: None
connectToReader
pubilc void connectToReader()
Obtains a connection to the NFC adapter.
Parameter: None
Return value: Returns error code indicating success or failure:
ERROR_NFC_IS_DISABLED
- the NFC adapter is disabledERROR_NO_NFC_SUPPORT
- the hardware does not have NFC supportERROR_SUCCESS
- connection is successful
enableReadPassMode
pubilc void enableReadPassMode()
Limits the NFC controller to reader mode, disabling card emulation. Polling is configured for the Zebra NFC reader to read NFC Type A and Type B cards.
Since the NFC resources are fully allocated, no other application (running on the foreground or background) can request for NFC resources.
Parameter: None
Return value: None
disableReadPassMode
public void disableReadPassMode()
Returns to default NFC Forum polling mode. This method should be called whenever the app moves to the background or when the activity is terminated.
Parameter: None
Return value: None
getType
public String getType()
Returns the type of the object.
Return value: Static string: ‘APPLE_VAS’
getMerchantURL
public String getMerchantURL()
Gets the Merchant URL string which the Apple device should be directed if no pass is currently available on the device. Generally this is provided for the user to sign-up for a pass.
Parameter: None
Return value:
- If successful, returns the string of the merchant URL.
- If unsuccessful and no merchant URL has been set, returns null.
getTerminalMode
public AppleVasConfig.TerminalMode getTerminalMode()
Gets the current operating mode for the reader.
Parameter: None
Return value: TerminalMode.VasOnly
Throws: RuntimeException
when the Zebra NFC VAS service is not connected
onPassDetected()
public void onPassDetected(Pass pass)
The interface method onPassDetected is a callback that gets invoked when an NFC pass is read. The SDK passes the NFC pass and identifies whether the pass is encrypted or decrypted. Pass is a class where all Pass data can be accessed via getter methods:
public String getStatusWord()
– Returns the StatusWord of the NFC pass detectedpublic Result getResultCode()
- Returns the ResultCode of the NFC pass detectedpublic byte[] getMerchantId()
- Returns the MerchantID (Pass Type Identifier converted to SHA256) of the NFC pass detectedpublic String getPassTypeId()
- Returns the PassTypeID of the NFC pass detectedpublic Type getPassType()
- Returns the PassType of the NFC pass detectedpublic byte[] getPayloadMessage()
- Returns the PayloadMessage of the NFC pass detectedpublic Date getPayloadDate()
- Returns the PayloadDate of the NFC pass detectedpublic boolean isDecrypted()
– Returns the status of the payload message: decrypted or encrypted
Parameter: Pass object
Return value: None
getSdkVersion()
public String getSdkVersion()
Returns the version of the SDK formatted as MAJ.MIN.BUG.
Parameter: Activity activity
- This is the activity that registered for the NFC intent Response resp, the class that has implemented the response interface and receives the pass data.
Return value: String - the SDK version in MAJOR.MINOR.BUG_FIX format.
Security
Zebra VAS SDK implemented advanced security features to help protect the private key operation and communication between the authorized Zebra NFC VAS service and the line-of-business application. Since the Zebra NFC VAS service requires installation via the supplied .APK file, the enhanced security mechanism is designed to ensure the application connects with a genuine Zebra NFC VAS service.
The Zebra VAS SDK incorporates security measures to ensure the authenticity of the Zebra NFC VAS service. This includes but is not limited to the following:
- Since the Zebra VAS Service is not part of the device system software (OS), the Zebra NFC VAS service is signed by a Zebra key (unprivileged) to ensure it is obtained from a trusted source.
- The Zebra VAS SDK validates the Zebra NFC VAS service by checking the signature of the service.
- The Zebra NFC VAS service source code and binary are secured with an obfuscation tool.
Considering the SDK is an Android .AAR file that is imported into the application project, it is possible to decompile the .AAR file and regenerate it into a modified version that connects to a malicious service. This could compromise the security and encryption of the private key, as well as other essential data, introducing potential security vulnerabilities.
Zebra recommends application developers to implement the following integrity check to ensure the authenticity of Zebra VAS SDK: To ensure the authenticity of the Zebra VAS SDK, check whether the .AAR file checksum matches the checksum of the SDK provided by Zebra. The SDK is posted on the Zebra support portal along with its file checksum details. To run the checksum of the SDK, Zebra recommends using any free “sha512sum” verification tool. Compare the result checksum with the checksum for Zebra VAS SDK (.AAR), which is the following for version 1.0.0:
VAS SDK (.aar) version: 1.0.0
sha512 check sum:
d34da9a55d40bf6bd05b8120db9281d90ffe5f3857cfbd717a1ac24adce78f1d887b1993e05b92c
1f8dcc5657963ff3645c2edd727c18aa35e755a3c2eaa4d63
Best Practices
For optimal performance of the Apple VAS solution, set the Card Detection Mode (polling mode) to Standard in the Enterprise NFC Settings. To access these settings, go to device Settings > Connected Devices. For more information, refer to the product documentation posted on the Zebra support portal.
Card Detection Mode in Enterprise NFC Settings