Сервис push-уведомлений Pushover для Android и iOS в связке с PHP

в 12:30, , рубрики: android, php, pushover, уведомления, метки: ,

Сервис push уведомлений Pushover для Android и iOS в связке с PHP
Вкратце, push-уведомления — это небольшие по объему важные сообщения от программы или сервиса, отображаемые операционной системой тогда, когда вы непосредственно не работаете с указанным приложением или сервисом. Преимущество таких уведомлений в отсутствии необходимости держать программу вечно в памяти, тратя на нее процессорные мощности и память.
Не буду здесь расписывать всю технологию доставки удаленного уведомления, ибо это уже сделано до меня. Выглядит примерно так: периодически демон опрашивает сервер и в случае появления сообщения, показывает его нам.
Для iOS придумали APNS, для Android-а — C2DM-GCM, я же хочу рассказать про кроссплатформенный (громко) сервис Pushover и связке его с php-сайтом.

Пример задачи

Предположим, что раз в день мы хотим знать что-либо о количестве заказов на сайте за день и их стоимости.
Сайт крутится на некоторой CMS на PHP и mySQL, принимающая сторона имеет стильные iPhone и Android-телефоны.
Срочность доставки сообщения не относится к жизненно-важным показателям.
Надо найти условно безгеморройное решение.

Pushover

Pushover — это скромный сервис уведомлений, а также приложения для iOS и Android, планируются поделки и для BlackBerry и OS X Mountain Lion. Сервис имеет свой API, позволяет отправлять бесплатно до 7.5 тысяч сообщений в месяц.

Сервис push уведомлений Pushover для Android и iOS в связке с PHP
Сообщение, помимо основного текста сообщения длиной 512 символов, может содержать крупный заголовок, URL (тогда длина сообщения увеличивается до 500) и его тайтл (все отображается отдельными сформированными блоками, потому такое разграничение). Сообщение можно доставить под неким выбранным указанным приоритетом. Пользователь может указать «тихие» часы, когда его не стоить будить уведомления, а также подключать и отключать устройства, на которые будут приходить уведомления.
Уведомление может быть доставлено пользователям, предоставившим свой код, всем устройствам этого пользователя или по выбору. Для приема сообщения пользователю необходимо быть зарегистрированным в сервисе и обладать хотя бы одним рабочим устройством.

Добавление пользователя

Сервис push уведомлений Pushover для Android и iOS в связке с PHP
После прохождения регистрации, каждый пользователь попадает в свой кабинет, где он сразу видит свой хэш-токен. Это уникальный идентификатор пользователя, на который в последствии и отправляются уведомления.
Пользователю, желающему принимать сообщения, необходимо поставить на свой телефон/планшет/абы что приложение из соответствующего магазина.

Добавление сервиса

Добавление сервиса ничуть не сложнее. Из личного кабинета надо перейти на страницу создания приложения, где предлагается описать продукт:
Сервис push уведомлений Pushover для Android и iOS в связке с PHP
После заполнения соответствующих полей, нам становится известен токен приложения. В принципе, это все, что необходимо для отправки сообщения.
На странице приложения в последующем будет красивый график успешно отправленных сообщений.

Связывание приложений и получателей

… не выполняется никак. Любое приложение может отправить любому пользователю уведомление, если знает его токен. Прием токенов от населения остается на совести приложения. Также как и отписка от рассылок.

API

Небольшое, емкое и понятное. Для отправки сообщения в POST-запросе к api.pushover.net/1/messages.json или api.pushover.net/1/messages.xml минимально необходимо указать:

  • token — хэш-токен вашего приложения или сервиса.
  • user — хэш-токен пользователя, которому вы отправляете уведомление.
  • message — текстовая часть сообщения.

Дополнительно к этому можно добавить:

  • device — идентификатор устройства пользователя, дабы не отсылать уведомления сразу на все его устройства
  • title — заголовок сообщения, если не указан, будет показано название сервиса
  • url — ссылка на web-страницу, если в этом есть необходимость
  • url_title — заголовок к ссылке
  • priority — приоритет сообщения, ставится в 1 для высокого приоритета, обходящего все «тихие» часы и -1 для тихого уведомления.
  • timestamp — UNIX метка времени, когда это уведомлениебыло создано. Расписания доставки сообщений сервисом не предусмотрено.
Ответ сервера

Ответ сервера будет представлен в json или xml формате (в зависимости от расширения вызываемого скрипта).
Если все прошло удачно будет отдан объект содержанием поля status, равном 1.
Иначе, поле status будет содержать нечто иное, а поле errors — массив описания ошибок. Вот примеры ответов удачной и неудачной отправок в формате XML:

<?xml version="1.0" encoding="UTF-8"?>
<hash>
  <status type="integer">1</status>
</hash>

и

<?xml version="1.0" encoding="UTF-8"?>
<hash>
  <token>invalid</token>
  <errors type="array">
    <error>application token is invalid</error>
  </errors>
  <status type="integer">0</status>
</hash>

PHP

На главной странице и в факе в разделах «смотрите, как легко!» приводятся коды простейшего скрипта на различных языках для отправки и есть ссылка на 3rd-party php-класс от Chris Schalenborgh.
Везде используется сURL, что впрочем, понятно.

Зафигарим свой класс

Куда ж нынче без велосипедов?
На самом деле, мне не слишком понравилось, что успех отправки уведомления определяется либо как true/false, либо выводится сразу вся простыня ответа сервера. Да вообще обработки ошибок нет. Считаю, что если посетителю сайта не обязательно, то разработчику надо знать, почему не отправлено то или иное сообщение.
В общем, существенно меняем все, классы уехали на GitHub.

class PushoverException

class PushoverException extends Exception
{
	/**
	 * Messages array
	 * @var array
	 */
	private $fMessages;

	/**
	 * Exception constructor
	 * @param array $aMessages An array of messages
	 */
	public function __construct(array $aMessages)
	{
		parent::__construct('PushoverException exception');
		$this->fMessages = $aMessages;
	}

	/**
	 * Get messages array
	 * @return array
	 */
	public function getMessages()
	{
		return empty($this->fMessages) ? array() : $this->fMessages;
	}
}

class Pushover
class Pushover
{
	/*
	 * Pushover json api service url
	 */
	const C_API_URL = 'https://api.pushover.net/1/messages.json';

	/**
	 * Properties storage array
	 * @var array
	 */
	private $fProperties;

	/**
	 * cURL instance
	 */
	private $fCurl;

	//--------------------------------------------------------------------------//

	/**
	 * Properties getter
	 * @param string $aPropertyName Property name
	 * @return mixed
	 */
	public function __get($aPropertyName)
	{
		if(array_key_exists($aPropertyName, $this->fProperties))
			return $this->fProperties[$aPropertyName];
		return null;
	}

	/**
	 * Properties setter
	 * @param string $aPropertyName Property name
	 * @param mixed $aValue Property value
	 */
	public function __set($aPropertyName, $aValue)
	{
		$this->fProperties[$aPropertyName] = $aValue;
	}

	//--------------------------------------------------------------------------//

	/**
	 * Class constructor
	 * @param string $aApplicationToken Application token
	 */
	public function __construct($aApplicationToken = null)
	{
		if(!empty($aApplicationToken))
			$this->applicationToken = $aApplicationToken;

		$this->fCurl = curl_init();
		curl_setopt($this->fCurl, CURLOPT_URL,            self::C_API_URL);
		curl_setopt($this->fCurl, CURLOPT_HEADER,         false);
		curl_setopt($this->fCurl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($this->fCurl, CURLOPT_SSL_VERIFYPEER, false);		
	}

	/**
	 * Class destructor
	 */
	public function __destruct()
	{
		curl_close($this->fCurl);
	}

	//--------------------------------------------------------------------------//

	/**
	 * Throws an exceprion with single message
	 * @param mixed $aMessage
	 * @throws PushoverException
	 */
	public function throwMessage($aMessage)
	{
		throw new PushoverException(array($aMessage));
	}

	/**
	 * Throws an exceprion with an array of messages
	 * @param array $aMessages
	 * @throws PushoverException
	 */
	public function throwMessages(array $aMessages)
	{
		throw new PushoverException($aMessages);
	}

	//--------------------------------------------------------------------------//

	/**
	 * Send pushover notification
	 */
	public function send()
	{
		if(!strlen($this->applicationToken))
			$this->throwMessage('Application token is empty');
		if(!strlen($this->userToken))
			$this->throwMessage('User token is empty');
		if(!strlen($this->notificationMessage))
			$this->throwMessage('Notification message is empty');

		if(intval($this->notificationTimestamp) <= 0)
			$this->notificationTimestamp = time();

		$lSendParams = array(
			'token'     => $this->applicationToken,
			'user'      => $this->userToken,
			'device'    => $this->userDevice,
			'title'     => $this->notificationTitle,
			'message'   => $this->notificationMessage,
			'priority'  => $this->notificationPriority,
			'timestamp' => $this->notificationTimestamp,
			'url'       => $this->notificationUrl,
			'url_title' => $this->notificationUrlTitle
		);

		foreach($lSendParams as $lKey => $lParam)
			if(empty($lParam))
				unset($lSendParams[$lKey]);

		curl_setopt($this->fCurl, CURLOPT_POSTFIELDS, $lSendParams);
		$lResponseJson = curl_exec($this->fCurl);

		if($lResponseJson === false)
			$this->throwMessage('API request error');

		$lResponse = json_decode($lResponseJson, true);

		if(empty($lResponse) || !is_array($lResponse))
			$this->throwMessage('Bad API response');

		if(!empty($lResponse['errors']))
			$this->throwMessages($lResponse['errors']);
		if(empty($lResponse['status']) || intval($lResponse['status']) != 1)
			$this->throwMessage('Unknown notification send error');
		
	}
}

Минимальное сообщение теперь довольно просто отправить, ошибки можно разбирать:

$lPushover = new Pushover('Write application token here');
$lPushover->userToken = 'scecify user token';
$lPushover->notificationMessage = 'Notification message';

try
{
	$lPushover->send();
	echo '<font color="green">Message sent</font>', PHP_EOL;
}
catch (PushoverException $aException)
{
	echo '<font color="red">Error sending messages</font><br>', PHP_EOL;
	echo '<ul>', PHP_EOL;
	foreach($aException->getMessages() as $lMessage)
		echo '<li>', $lMessage, '</li>', PHP_EOL;
	echo '</ul>', PHP_EOL;
}

Пользователь уже принял сообщение.

Итого

Знаем об удобном сервисе удаленных уведомлений, одинаково успешно передающий сообщения пользователям Android и iOS.
Имеем рабочий механизм отправки уведомлений с сайта на PHP.

Автор: Urvin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js