<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.mobile.push.apns">
    <title>Zend_Mobile_Push_Apns</title>

    <para>
        <classname>Zend_Mobile_Push_Apns</classname> provides the ability to
        send push notifications to <acronym>APNS</acronym> generally in
        conjunction with <classname>Zend_Mobile_Push_Message_Apns</classname>;
        however there is a case when it would not be utilized is when getting
        feedback from the APNS server.
    </para>

    <sect2 id="zend.mobile.push.apns.server">
        <title>Pushing Messages</title>

        <note>
            <para>Prior to pushing messages; you must follow the
                <ulink
                    url="http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ProvisioningDevelopment/ProvisioningDevelopment.html">provisioning and deployment steps outlined by Apple</ulink>.</para>
        </note>

        <para>
            When implementing APNS; you have a few components that
            you will utilize.  <classname>Zend_Mobile_Push_Apns</classname>
            which contains the server components and
            <classname>Zend_Mobile_Push_Message_Apns</classname> which contains
            the message that you would like to send.  Generally when sending
            push notifications to Apple you should do so in a batch.
        </para>

        <para>
            The actual implementation of the code is fairly minimal; however,
            considerations to error handling must be taken.
        </para>

        <programlisting language="php"><![CDATA[
$message = new Zend_Mobile_Push_Message_Apns();
$message->setAlert('Zend Mobile Push Example');
$message->setBadge(1);
$message->setSound('default');
$message->setId(time());
$message->setToken('ABCDEF0123456789');

$apns = new Zend_Mobile_Push_Apns();
$apns->setCertificate('/path/to/provisioning-certificate.pem');
// if you have a passphrase on your certificate:
// $apns->setCertificatePassphrase('foobar');

try {
    $apns->connect(Zend_Mobile_Push_Apns::SERVER_SANDBOX_URI);
} catch (Zend_Mobile_Push_Exception_ServerUnavailable $e) {
    // you can either attempt to reconnect here or try again later
    exit(1);
} catch (Zend_Mobile_Push_Exception $e) {
    echo 'APNS Connection Error:' . $e->getMessage();
    exit(1);
}

try {
    $apns->send($message);
} catch (Zend_Mobile_Push_Exception_InvalidToken $e) {
    // you would likely want to remove the token from being sent to again
    echo $e->getMessage();
} catch (Zend_Mobile_Push_Exception $e) {
    // all other exceptions only require action to be sent
    echo $e->getMessage();
}
$apns->close();
]]></programlisting>

        <table id="zend.mobile.push.apns.server.exceptions">
            <title>Exceptions and Remediation Techniques</title>
            <tgroup cols="3" align="left" colsep="1" rowsep="1">
                <thead>
                    <row>
                        <entry>Exception</entry>
                        <entry>Meaning</entry>
                        <entry>Handling</entry>
                    </row>
                </thead>
                <tbody>
                    <row>
                        <entry>Zend_Mobile_Push_Exception</entry>
                        <entry>These types of exceptions are more generic in nature
                        and are thrown either from APNS or internally on input
                        validation</entry>
                        <entry>Read the message and determine remediation steps.</entry>
                    </row>
                    <row>
                        <entry>Zend_Mobile_Push_Exception_InvalidPayload</entry>
                        <entry>Generally the payload will not throw an exception
                        unless the size of the payload is too large or it is missing
                        required content.</entry>
                        <entry>Check the size of the payload is within the
                        requirements of APNS</entry>
                    </row>
                    <row>
                        <entry>Zend_Mobile_Push_Exception_InvalidToken</entry>
                        <entry>Any form of an invalid token will be if the token is
                        no longer registered; you are missing a token or it is in an
                        invalid format.</entry>
                        <entry>You should remove the token and not attempt to send
                        to it again.</entry>
                    </row>
                    <row>
                        <entry>Zend_Mobile_Push_Exception_InvalidTopic</entry>
                        <entry>An invalid topic simply means that the message id was
                        too long or not an integer.</entry>
                        <entry>Ensure that the message ID is an integer.</entry>
                    </row>
                </tbody>
            </tgroup>
        </table>

        <warning>
            <para>
                When sending in batches and you are sending a large amount of push
                notifications out; you should ensure to usleep from time to time.  This
                will ensure that your messages will be delivered and APNS will not simply
                hang up on you.
        </para>
        </warning>
    </sect2>

    <sect2 id="zend.mobile.push.apns.feedback">
        <title>Getting Feedback</title>
        <para>
            APNS has a feedback service that you <emphasis>must</emphasis>
            listen to.  Apple states that they monitor providers to ensure that they
            are listening to this service.
        </para>

        <para>
            The feedback service simply returns an array of device tokens and
            the time.  You can use the time to ensure that the device has not
            re-registered for push notifications since the last send.
        </para>

        <programlisting language="php"><![CDATA[
$apns = new Zend_Mobile_Push_Apns();
$apns->setCertificate('/path/to/provisioning-certificate.pem');

try {
    $apns->connect(Zend_Mobile_Push_Apns::SERVER_FEEDBACK_SANDBOX_URI);
} catch (Zend_Mobile_Push_Exception_ServerUnavailable $e) {
    // you can either attempt to reconnect here or try again later
    exit(1);
} catch (Zend_Mobile_Push_Exception $e) {
    echo 'APNS Connection Error:' . $e->getMessage();
    exit(1);
}

$tokens = $apns->feedback();
while(list($token, $time) = each($tokens)) {
    echo $time . "\t" . $token . PHP_EOL;
}
$apns->close();
]]></programlisting>
        
    </sect2>

    <sect2 id="zend.mobile.push.apns.message">

        <title>Advanced Messages</title>

        <para>
            APNS provides the ability for sending more advanced messages; for
            instance the examples above show the most basic implementation of a
            message.  <classname>Zend_Mobile_Push_Message_Apns</classname>
            allows you to do far more advanced messaging outlined below.
        </para>

        <sect3 id="zend.mobile.push.apns.message.alerts">

            <title>Alerts</title>

            <para>
                Alerts can contain anything from a simple body message to having an
                action key and a launch image (iOS 4).  You may only want to provide
                an action key when only a confirmation is necessary OR you are
                looking to localize the button with non-standard text (aka not
                "View").
            </para>

            <para>
                The following code example shows alerts from the <ulink
                url="http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html">APNS
                payload examples</ulink>.
            </para>

            <programlisting language="php"><![CDATA[
    $message = new Zend_Mobile_Push_Message_Apns();

    // message with different button
    $message->setAlert('Bob wants to play poker', 'PLAY');
    // message using apps localized strings w/ string replacements
    $message->setAlert(null, null, 'GAME_PLAY_REQUEST_FORMAT', array('Jenna', 'Frank'));
    ]]></programlisting>

        </sect3>

        <sect3 id="zend.mobile.push.apns.message.custom-data">

            <title>Custom Data</title>

            <para>
                You can send your app custom data which allows you to make decisions
                based on the notifications; such as synchronizing data.
            </para>

            <programlisting language="php"><![CDATA[
                $message = new Zend_Mobile_Push_Message_Apns();
                $message->addCustomData('foo', 'bar');
                $message->addCustomData('foo', array('bar' => 1));
                $message->addCustomData('bar', 'foo');
]]></programlisting>

            <warning>
                <para>
                    You may not use a custom key of 'aps' as it is reserved by Apple and
                    leveraged for the main push data.
                </para>
            </warning>

        </sect3>
    </sect2>
</sect1>
