PKPASS not opennig in Passbook

2.2k views Asked by At

I'm new to passbook. I created an web application using PHP-PKPass library to create passes for Passbook. I used the necessary licences. When I submit to create the form, it creates a pass, but the pass doesn't work on passbook. If I send it as email attachment, it shows null. It works fine on android. I'm on Windows PC so I can't use the iphone simulator to view logs. Here is a link to a pass created by me - http://tanvir.tennisads.com/passbook/passes/pass-36252.pkpass

Can someone please help me identify what's wrong with the pass? Thanks in advance.

Update: I've removed the beacons and location part, but having the same issue. Here is the generated json code.

{
  "description": "Kenedy Store",
  "formatVersion": 1,
  "organizationName": "Kenedy Store",
  "passTypeIdentifier": "pass.com.retailness.testing.passbook",
  "serialNumber": "449925",
  "teamIdentifier": "NBN8H8W46L",
  "coupon": {
    "primaryFields": [
      {
        "key": "offer",
        "label": "Any purchase",
        "value": "25% off"
      }
    ],
    "auxiliaryFields": [
      {
        "key": "expires",
        "label": "EXPIRES",
        "value": "30-06-2015"
      }
    ],
    "backFields": [
      {
        "key": "terms",
        "label": "TERMS AND CONDITIONS",
        "value": "tos"
      }
    ]
  },
  "backgroundColor": "rgb(255,255,255)",
  "foregroundColor": "rgb(15, 15, 15)",
  "labelColor": "rgb(85, 85, 85)",
  "logoText": "Kenedy Store"
}

Here is the PHP code i used to create the pass...

<html>
<head>
    <title>Passbook Demo</title>
    <meta charset="UTF-8"> 
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles/bootstrap.min.css">
    <link rel="stylesheet" href="styles/smoke.min.css">
    <link rel="stylesheet" href="styles/custom.css">
    <script src='scripts/jquery.min.js'></script>
    <script src='scripts/bootstrap.min.js'></script>
    <script src='scripts/smoke.min.js'></script>
</head>
<body>
<?php

    function RandomString($length)
    {
        $characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
        $randstring = '';
        for ($i = 0; $i < $length; $i++) {
            $randstring .= $characters[rand(0, strlen($characters))];
        }
        return $randstring;
    }

    $flag = false;

    $name = urldecode($_POST['name']);
    $amount = urldecode($_POST['amount']);
    $message = urldecode($_POST['message']);
    $expires = urldecode($_POST['expires']);
    $email = urldecode($_POST['email']);
    $uuid = urldecode($_POST['uuid']);
    $major = urldecode($_POST['major']);
    $minor = urldecode($_POST['minor']);
    $tos = urldecode($_POST['tos']);
    $appURL = urldecode($_POST['appURL']);
    $lat = urldecode($_POST['lat']);
    $lon = urldecode($_POST['lon']);
    $beacon_msg = urldecode($_POST['beacon_msg']);
    $location_msg = urldecode($_POST['location_msg']);

    $target = "";

    if($_FILES['file']['name']){

        $flag = true;
        $file = $_FILES['file'];
        $n = $file['name'];
        $ext = end((explode(".", $n)));

        $target = "images/up/logo." .$ext;
        move_uploaded_file($file['tmp_name'], $target);

    }   

    require 'includes/PKPass/PKPass.php';

    $pass = new PKPass\PKPass();

    $pass->setCertificate('certificates/Certificate.p12');
    $pass->setCertificatePassword('tanvir123');
    $pass->setWWDRcertPath('certificates/AppleWWDRCA.pem');


    $standardKeys         = array(
        'description'        => "{$name}",
        'formatVersion'      => 1,
        'organizationName'   => "{$name}",
        'passTypeIdentifier' => 'pass.com.retailness.testing.passbook', // 4. Set to yours
        'serialNumber'       => RandomString(6), //CHANGE IT TO RANDOMIZE
        'teamIdentifier'     => 'NBN8H8W46L'
    );

    $associatedAppKeys    = array(
    );
    $relevanceKeys        = array(
    );
    $styleKeys            = array(
        'coupon' => array(
            'primaryFields' => array(
                array(
                    'key'   => 'offer',
                    'label' => "{$message}",
                    'value' =>  "{$amount}% off"
                )
            ),
            'auxiliaryFields' => array(
                array(
                    'key'   => 'expires',
                    'label' => 'EXPIRES',
                    'value' => "{$expires}"
                )
            ),
            'backFields' => array(
                array(
                    'key'   => 'terms',
                    'label' => 'TERMS AND CONDITIONS',
                    'value' => "{$tos}"
                )
            )
        )
    );

    $visualAppearanceKeys = array(
        'backgroundColor' => 'rgb(255,255,255)',
        'foregroundColor' => 'rgb(15, 15, 15)',
        'labelColor' => 'rgb(85, 85, 85)',
        'logoText'        => "{$name}"

    );

    $webServiceKeys       = array();

    // Merge all pass data and set JSON for $pass object
    $passData = array_merge(
        $standardKeys,
        $associatedAppKeys,
        $relevanceKeys,
        $styleKeys,
        $visualAppearanceKeys,
        $webServiceKeys
    );
    $pass->setJSON(json_encode($passData));

    // Add files to the PKPass package
    $pass->addFile('images/icon.png');
    $pass->addFile('images/[email protected]');

    if($flag == false) $pass->addFile('images/logo.png');
    else $pass->addFile($target);
    $pass->addFile($target);

    $data = $pass->create(true);
    $path = 'passes/pass-'.RandomString(5).'.pkpass';

    file_put_contents($path, $data);
    //unlink($new_file_path);

    $fullpath = 'http://' . $_SERVER['SERVER_NAME'] . '/passbook/' . $path;

    ?>

    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="col-md-2">
                    <img src="images/logo.png" height="93" width="156" alt="">
                </div>
                <div class="col-md-10 text-center">
                    <h2>Passbook / iBeacon Demo</h2>
                </div>
            </div>
        </div>
        <div class="col-md-6 col-md-offset-3 text-center">
            <a href="<?php echo $fullpath; ?>">Download</a> the pass.<br>
            Or use the QR Code instead: <br>
    <?php
        require 'includes/phpqrcode/qrlib.php';
        QRCode::png($fullpath, $path . '.png');
    ?>
            <img src="<?php echo $path . '.png'; ?>" width=500>

        </div>
    </div>
</body>
</html>

And here is the screenshot of what's hapenning when i try to download the pass from iphone: https://i.stack.imgur.com/gnP2r.jpg

1

There are 1 answers

3
PassKit On BEST ANSWER

Looking at your pass.json I can see two errors.

"beacons": [{
    "proximityUUID": "",
    "relevantText": "",
    "major": "0",
    "minor": "0"
}],
"locations": [{
    "longitude": "90.42607140943142",
    "latitude": "23.7636902410487",
    "relevantText": "office"
}],

The first error is that your beacons dictionary contains an invalid entry. You have not supplied a proximityUUID or relevantText.

The second error is being caught by Xcode.

Jun 10 09:09:02 pfr MobileSafari[4660] <Warning>: Invalid data error reading pass pass.com.retailness.testing.passbook/314548. Value for key 'latitude' must be of class NSNumber, but is actually of class __NSCFString.

You are providing your latitude and longitude values as strings when they need to be provided as decimals.

Drop the beacons array and the quotes around the lat and long values and you should be ok.


Update

Your new pass is fine. It is not loading on the phone because your web server is not applying a Content-Type header and therefore iOS does not recognise this file as a pass.

HTTP/1.1 200 OK
Date: Fri, 12 Jun 2015 17:25:58 GMT
Server: Apache
Last-Modified: Thu, 11 Jun 2015 07:44:56 GMT
Accept-Ranges: bytes
Content-Length: 20604

Add a Content-Type: application/vnd.apple.pkpass header to this file and you should find that it loads ok.

For more info on how to add the header, see the answers to this question.