Отмазка #1
Эта публикация - не готовое решение, а лишь небольшой пример, иллюстрирующий расширение возможностей 1С и преимущества знания других языков программирования.
Отмазка #2
Код примеров приведён в минимально рабочее состояние. Ровно настолько, чтобы продемонстрировать саму возможность рассылки сообщений по WhatsApp из 1С.
В нём есть участки, в которых сознательно оставлена возможность для некорректной работы (отсутствие проверок, отсутствие перехвата исключений и т.д.).
Так же реализована очень малая часть потенциала API - только отправка текстовых сообщений.
Мотивирую это тем, что не хочу давать готовый инструмент в руки спамеров.
Предисловие
Если попытаться поискать официальный API WhatsApp, то можно узнать, что его не существует.
Однако задав в поиске "WhatsApp" на github можно найти 421 (в день написания публикации) проект на различных языках.
Я решил остановиться на проекте WhatsAPINet (https://github.com/perezdidac/WhatsAPINet). Этот проект содержит в себе API и демонстрацию его применения.
Казалось бы - как можно связать DLL на .Net с 1С?
Можно сделать внешнюю компоненту и использовать в своей конфигурации - мы этого делать не будем, потому что написание внешней компоненты всё-таки сложнее, чем переделка проекта под COM-объект, не будем усложнять наш пример.
Можно переделать проект так, чтобы на выходе DLL поставляла помимо экспортных методов ещё и COM-объект, который можно применять не только в 1С, но и в других отраслях (vbs-скрипты и прочее).
Скачав проект с github можно неприятно удивиться - тестовые примеры не будут работать.
Сервер Whatsapp будет ругаться на несоответствие версий, неправильный токен авторизации и так далее.
Это связано с тем, что какие-то участки протокола могут измениться в новой версии WhatsApp, а проект на github уже давненько не обновлялся.
Пилим COM-объект на C#
Где и что конкретно нужно исправить в проекте, чтобы заработали тестовые примеры я подробно расписывать не буду (смотри отмазку #2), скажу только, что нужно поправить 2 строки - версию и один из ключей, который берётся для генерации токена.
На момент публикации статьи этих исправлений будет достаточно, чтобы сервер WhatsApp был согласен с нами сотрудничать.
Далее, чтобы не таскать с собой 2 DLL-ки (API + COM-обёртка), мы изменим проект в VisualStudio таким образом, чтобы открыть нужный функционал в виде COM-объекта, поставляемого этой же DLL с API:
Готовых статей о том как написать COM-объект на .NET море, в том числе на инфостарте, поэтому не будем сильно останавливаться на этом вопросе
(например, Как написать COM-объект для 1С на Visual Studio C# 2008)
Итак, из трёх папок в скаченном проекте нас интересует папка WhatsAppApi - в неё содержится проект с реализацией API, остальные папки содержат примеры по работе с ним.
Открываем проект WhatsAppApi.csproj и далее по шагам:
1. Сделаем сборку видимой для COM:
Откроем файл AssemblyInfo.cs и изменим значение параметра сборки ComVisible на true
2. Добавим описание и реализацию интерфейсов
Добавим интерфейс IEvents. Он будет содержать описания событий, на которые мы сможем подписаться в 1С;
Добавим интерфейс IComWrapper. Он будет содержать описание методов, которые мы будем вызывать;
Добавим класс ComWrapper. Он будет наследовать IComWrapper, содержать реализацию его методов, а так же вызывать события.
3. Компилируем проект и регистрируем нашу сборку как COM
Средство регистрации сборки считывает метаданные сборки и добавляет в реестр необходимые записи, что позволяет COM-клиентам прозрачно создавать классы .NET Framework. После регистрации класса любой COM-клиент может использовать таким образом, словно это класс COM. Класс регистрируется только один раз, при установке сборки. Экземпляры классов внутри сборки не могут создаваться на основе COM-классов до их фактической регистрации.
Чтобы зарегистрировать нашу сборку, нужно выполнить следующий Код
c:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe WhatsAppApi.dll /codebase
Во вложениях есть допиленный проект со скромным функционалом (с учётом отмазки #2) и готовая скомпилированная DLL
Пилим обработку в 1С
Вот основная часть работы позади, нам осталось только прикрутить полученный COM-объект к 1С.
В исходном проекте многое завязано на событиях объекта, поэтому мы тоже не будем далеко уходить от этой практики.
Так как мы использовали интерфейс IEvent, основная часть вопросов будет решаться добавлением обработчиков событий COM-объекта.
Чтобы приступить к тестам, нам нужно зарегистрировать номер телефона в WhatsApp, получить пароль и авторизоваться. Но, перед этим, посмотрим, как мы будем работать с COM-объектом (сборка, на этом этапе, уже должна быть зарегистрирована):
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Вацап = Новый COMОбъект("WhatsAppApi.ComWrapper");
ДобавитьОбработчик Вацап.onGetMessage, ПолученоСообщение;
КонецПроцедуры
...
&НаКлиенте
Процедура ПолученоСообщение(ОтНомера, Имя, Текст)
НовоеСообщение = Сообщения.Добавить();
НовоеСообщение.Дата = ТекущаяДата();
НовоеСообщение.От = ОтНомера;
НовоеСообщение.Кому = "Мне";
НовоеСообщение.Текст = Текст;
НовоеСообщение.Доставлено = Истина;
КонецПроцедуры
Механизм регистрации
Аккаунт WhatsApp привязывается к номеру телефона, поэтому при первичной регистрации без телефона не обойтись.
В общем виде процесс регистрации выглядит так:
1. Мы отправляем на сервер WhatsApp сообщение о том, что хотим зарегистрировать свой номер. При этом указываем способ получения кода подтверждения регистрации - звонок или смс. В нашем случае это будет смс.
2. Сервер WhatsApp отправляет на указанный номер смс с кодом.
Тут нам пригодится телефон, смотрим, что за цифры пришли в смс сообщении.
3. Называем серверу полученные в смс цифры.
4. Сервер выдаёт нам пароль, который мы будем использовать для авторизации.
В коде 1С это выглядит приблизительно так:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Вацап = ЭтаФорма.ВладелецФормы.Вацап();
ДобавитьОбработчик Вацап.onRecievePassword, ПриПолученииПароля;
КонецПроцедуры
&НаКлиенте
Процедура ЗапроситьСМС(Команда)
Вацап.Create(НомерТелефона, "", "");
Если Вацап.RequestCode() Тогда
Сообщить("Запрос отправлен, ожидайте СМС сообщение");
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОтправитьКод(Команда)
Вацап.RegisterCode(КодСМС);
КонецПроцедуры
&НаКлиенте
Процедура ПриПолученииПароля(Строка)
Предупреждение("Пароль получен!");
Пароль = Строка;
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии()
УдалитьОбработчик Вацап.onRecievePassword, ПриПолученииПароля;
КонецПроцедуры
Механизм уведомлений, рассылки и получения сообщений
Процесс обмена сообщениями выглядит так:
1. Отправитель отправляет на сервер сообщение для указанного получателя
2. Сервер, получив сообщение, отчитывается отправителю о том, что сообщение получено сервером
3. Когда получатель получает сообщение, сервер отчитывается отправителю, что сообщение доставлено получателю
Чтобы эта цепочка корректно работала, у каждого сообщения есть свой идентификатор.
В исходном проекте этот идентификатор дополнен другими данными и выглядит неудобно для обработки внутри 1С, поэтому в своём классе ComWrapper при событии получения клиентом сообщения мы удаляем "лишнее", оставляя только цифровой идентификатор сообщения.
В коде 1С наше общение будет выглядить так:
&НаКлиенте
Перем Вацап, МойНомерТелефона;
&НаКлиенте
Функция Вацап() Экспорт
Если Вацап = Неопределено ИЛИ Вацап = null Тогда
Вацап = Новый COMОбъект("WhatsAppApi.ComWrapper");
КонецЕсли;
Возврат Вацап;
КонецФункции
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ФормаАвторизации = ПолучитьФорму("ВнешняяОбработка.ДемонстрацияWhatsApp.Форма.ФормаАвторизации", , ЭтаФорма);
ФормаАвторизации.ОткрытьМодально();
Если НЕ ФормаАвторизации.Авторизован Тогда
МойНомерТелефона = ФормаАвторизации.НомерТелефона;
Закрыть();
Возврат;
КонецЕсли;
ДобавитьОбработчик Вацап.onError, ПриОшибке;
ДобавитьОбработчик Вацап.onGetMessage, ПолученоСообщение;
ДобавитьОбработчик Вацап.onClientRecieveMessage, Доставлено;
КонецПроцедуры
&НаКлиенте
Процедура ПолученоСообщение(ОтНомера, Имя, Текст)
НовоеСообщение = Сообщения.Добавить();
НовоеСообщение.Дата = ТекущаяДата();
НовоеСообщение.От = ОтНомера;
НовоеСообщение.Кому = "Мне";
НовоеСообщение.Текст = Текст;
НовоеСообщение.Доставлено = Истина;
КонецПроцедуры
&НаКлиенте
Процедура ОтправитьСообщение(Команда)
КлючСообщения = Вацап().SengMessage(Адресат, Сообщение);
НовоеСообщение = Сообщения.Добавить();
НовоеСообщение.Дата = ТекущаяДата();
НовоеСообщение.От = "Я";
НовоеСообщение.Кому = Адресат;
НовоеСообщение.Текст = Сообщение;
НовоеСообщение.КлючСообщения = КлючСообщения;
Сообщение = "";
КонецПроцедуры
&НаКлиенте
Процедура Доставлено(Кому, КлючСообщения)
Отбор = Новый Структура("Кому, КлючСообщения", Кому, КлючСообщения);
НайденныеСтроки = Сообщения.НайтиСтроки(Отбор);
Для Каждого НайденнаяСтрока Из НайденныеСтроки Цикл
НайденнаяСтрока.Доставлено = Истина;
КонецЦикла;
КонецПроцедуры
На этом можно закончить, добавив, что допилив наш пример можно отправлять не только простые текстовые сообщения, но так же заставить бота отписываться в группах, кидать фотки с web-камеры по расписанию, записи с микрофона и вообще создать гаджет агента 007)