Мобильная Торговля
Версия
Взаимодействие HTML с Data-скриптом

MTCHANNEL - это транспорт, позволяющий передавать данные из HTML-шаблона в браузер или data-скрипт.

Как подключить mtchannel:

  • Пропишите внутри тэга <head> в HTML-шаблоне {{ MTCHANNEL|safe }}
  • Шаблонизатор вставит на страницу инлайновый скрипт

После подключения становится доступным объект stmobile.

Методы stmobile:

stmobile.channel.send(fn, [fn_arg], callback)
Запустить функцию из data-скрипта в основном потоке

  • fn - имя функции из data-скрипта
  • fn_arg - опциональный параметр, передаваемые в функцию параметры
  • callback - имя функции, в которую будет передан результат, вернувшийся из функции в data-скрипте

stmobile.channel.sendToThread(fn, [fn_arg], callback)
Запустить функцию из дата-скрипта в отдельном потоке (так можно запустить несколько функций одновременно)

  • fn - имя функции из data-скрипта
  • fn_arg - опциональный параметр, передаваемые в функцию параметры
  • callback - имя функции, в которую будет передан результат, вернувшийся из функции в data-скрипте

stmobile.channel.addListener(event, callback)
Подписаться на событие с помощью WebSocket - соединения.

  • event - название события
  • callback - функция, в которую в качестве аргумента, передается объект с данными, которые хранятся в свойстве message

stmobile.channel.removeListener(event)
Удалить обработчики события

  • event - название события

Пример: отправка данных на клиент через WebSocket - соединение

<-------------------- HTML-шаблон ------------------->
{{ MTCHANNEL|safe }}
<script type="text/javascript">
    stmobile.channel.addListener('event', function (data) {
        alert(JSON.stringify(data.message.someKey))
        stmobile.channel.removeListener('event')
    });
</script>

<-------------------- Дата-скрипт ------------------->
function doAction() {
    api.warp.channel.sendMessage('event', { someKey: 'Some data', value: 42 })
}

stmobile.observer.onViewStatusChanged
Функция, обрабатывающая событие смены статуса активности страницы (по умолчанию undefined)
Если страница сейчас видна пользователю, статус равен 'ViewActive'
Если страница перекрыта другой страницей (отчет, форма, msgbox), статус равен 'ViewInactive'

Пример: перезагрузка страницы после возврата из формы

<-------------------- HTML-шаблон ------------------->
{{ MTCHANNEL|safe }}
<script type="text/javascript">
    stmobile.observer.onViewStatusChanged = function(status) {
        if (status == 'ViewActive') stmobile.channel.send('reload');
    };
</script>

<-------------------- Дата-скрипт ------------------->
function reload() {
    api.builder.reload();
}

stmobile.launcher.open(uri)
Открыть заданный URI

  • uri - идентификатор ресурса

stmobile.launcher.close([uri])
Закрыть заданный URI

  • uri - опциональный параметр, идентификатор ресурса

stmobile.launcher.openUrl(url, [mode])
Открыть заданный URL

  • url - URL ресурса
  • mode - опциональный параметр, режим открытия, по умолчанию 'default'

stmobile.launcher.openHtml(url, [mode])
Открыть заданный HTML-файл

  • url - путь до файла
  • mode - опциональный параметр, режим открытия, по умолчанию 'default'

stmobile.launcher.openPdf(path, [mode])
Открыть заданный PDF-файл

  • path - путь до файла
  • mode - опциональный параметр, режим открытия, по умолчанию 'default'

stmobile.launcher.openImage(path, title, mode)
Открыть изображение

  • path - путь до файла
  • mode - опциональный параметр, режим открытия, по умолчанию 'default'

Доступные режимы открытия:

  • 'external' - во внешнем браузере
  • 'internal' - в окне МТ
  • 'default' - если не удалось открыть в МТ, то открыть в браузере

Пример:

Манифест:

{
    "uri": "stmobile://report/routereports/channeltest",
    "type": "report",
    "title": "qsTr(Тест MTChannel)",
    "datascript": {
        "script_file": "channel.js"
    },
    "template": {
        "template_file": "channel.html"
    }
}

Data-скрипт (channel.js):

function init() {}

function data() {}

function test1() {
    api.log.debug("js: test1");
    return "test1_ret";
}

HTML-шаблон (channel.html):

<!DOCTYPE html>
<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src='{{ libPath }}/libs/jquery.js'></script>
    <script type="text/javascript">

        function test1() {
            stmobile.channel.send('test1', '', function(ret) {
                $('#test1').text(ret);
            });
        }

        function launcherOpenTasks() {
            stmobile.launcher.open("stmobile://tasks/hub");
        }

    </script>

    {{ MTCHANNEL|safe }}

    </head>
    <body>
        <button onclick="test1()">test1</button> <span id="test1"> def </span><br><br>
        <button onclick="launcherOpenTasks()">launcherOpenTasks</button><br>
    </body>
</html>

stmobile.launcher.callPhone(number)
Набрать номер телефона

  • number - номер телефона для вызова. Пример: "+74999200000"

Пример:

Манифест:

{
    "uri": "stmobile://support/techsupport",
    "type": "report",
    "title": "qsTr(Technical Support)",
    "visible": false,
    "datascript": {
        "script_file": "techsupport.js"
    },
    "template": {
        "template_file": "techsupport.html"
    }
}

Data-скрипт (channel.js):

function init() {}
function data() {
    mapper.phoneNumber = '+78005553533';
}

HTML-шаблон (channel.html):

<!DOCTYPE html>
<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src='{{ libPath }}/libs/jquery.js'></script>
    <script type="text/javascript">

        function launcherCallPhone() {
            stmobile.launcher.callPhone({{ phoneNumber }});
        }

    </script>

    {{MTCHANNEL|safe}}

    </head>
    <body>
        <button onclick="launcherCallPhone()">ПОЗВОНИТЬ</button>
        <br>
    </body>
</html>

stmobile.launcher.startIntent(paramString)
Метод служит для запуска и обработки намерений (Intents) Android.

  • paramString - JSON-строка или объект с параметрами:
    data - массив объектов; набор параметров, которые будут подставлены при обработке намерения через нативный метод Intent.putExtra()
    Пример:

    "data": [
    { "name": "latitude", "type": "float", "value": "51.3234" },
    { "name": "longitude", "type": "float", "value": "24.3234" }
    ]

    В массив data записываются объекты со следующими полями:
    name - имя параметра - ключ в методе Intent.putExtra
    type - тип значения - строка конвертируемая в тип данных Java
    Доступные значения и типы данных Java, в которые они будут сконвертированы:
    int -> Int, float -> Float, long -> Long, string -> String, short -> Short, double -> Double, boolean -> Boolean, fileuri -> Uri-ссылка на файл, сформированная из переданной строки вызовом метода Uri.fromFile, weburi -> ссылка на вебресурс, сформированная методом Uri.parse
    value - значение параметра.

    action - действие, которое нужно выполнить при обработке намерения (см. документацию, раздел Intent Structure).
    Важно! В параметр должно записываться значение строковой константы, а не ее имя с учетом пространства имен Java, то есть, если в документации Android сказано, что для обработки намерения требуется указать action = Intent.ACTION_VIEW, то в документации можно найти строковое значение данной константы - android.intent.action.VIEW. Именно его нужно указывать в качестве значения параметра. Например: "android.intent.action.DIAL"
    actionUrl - если при создании намерения необходимо указать url, значение этой переменной будет передано в конструктор объекта Intent
    chooserTitle - если указан данный параметр, то во время обработки намерения будет показан экран выбора приложений, которые могут его обработать
    actionType - тип действия
    intentPackage - если при создании намерения необходимо передать название пакета, будет вызван метод Intent.setPackage.
    Если значение пустое, то метод Intent.setPackage вызван не будет.
    component - имя компонента (пакет + имя класса), который должен обработать намерение. Если задан компонент, то задавать intentPackage не нужно
    flags - строка, содержащая список флагов в виде чисел, разделённых запятой. Например, '268435456, 536870912'. Список доступных флагов можно посмотреть в справке андроид с префиксом FLAG_ACTIVITY_. Если не задан, то по умолчанию устанавливается флаг FLAG_ACTIVITY_RESET_TASK_IF_NEEDED Например, для вызова активности в приложении Yandex Navigator можно передать строку "ru.yandex.yandexnavi/com.yandex.yandexnavi.activity.RouteActivity", чтобы указать, что необходимо открыть конкретную активность для построения маршрута. marketUrl - ссылка на источник для загрузки вызываемого приложения. Указанная ссылка может вести на Google Play маркет (например, market://details?id=ru.yandex.yandexnavi), веб-страницу (например, https://www.google.com/search?q=yandex.navigator) или любой другой магазин приложений, доступный на устройстве (устройство должно уметь обрабатывать ссылки на данный источник). Eсли значение пустое, то поиск производиться не будет, а метод вернет false.

В большинстве случаев разработчику расширений достаточно получить пример, как вызвать то или иное намерение из JAVA кода, а затем просто подставить необходимые параметры при вызове метода API.

Пример вызова внешнего приложения Yandex Navigator:
Процесс вызова из JAVA-кода описан по ссылке

Intent intent = new Intent("ru.yandex.yandexnavi.action.BUILD_ROUTE_ON_MAP");
intent.setPackage("ru.yandex.yandexnavi");

PackageManager pm = getPackageManager();
List<ResolveInfo> infos = pm.queryIntentActivities(intent, 0);

// Проверяем, установлен ли Яндекс.Навигатор
if (infos == null || infos.size() == 0) {
    // Если нет - будем открывать страничку Навигатора в Google Play
    intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("market://details?id=ru.yandex.yandexnavi"));
} else {
    intent.putExtra("lat_from", 55.751802);
    intent.putExtra("lon_from", 37.586684);
    intent.putExtra("lat_to", 55.758192);
    intent.putExtra("lon_to", 37.642817);
}

// Запускаем нужную Activity
startActivity(intent);

Можно провести соответствие параметров вызова метода stmobile.launcher.startIntent. Здесь в конструктор объекта Intent в качестве параметра передается строка action, что в данном примере эквивалентно тому, что параметр action равен "ru.yandex.yandexnavi.action.BUILD_ROUTE_ON_MAP". В указанном выше коде присутствует вызов метода setPackage, соответсвенно, при вызове метода API придется передать параметр intentPackage со значением "ru.yandex.yandexnavi". Также присутствует ссылка на Play Market - значит, параметр marketUrl тоже необходимо установить в значение "market://details?id=ru.yandex.yandexnavi". Для намерения задаются дополнительные данные:

intent.putExtra("lat_from", 55.751802);
intent.putExtra("lon_from", 37.586684);
intent.putExtra("lat_to", 55.758192);
intent.putExtra("lon_to", 37.642817);

Чтобы передать их при вызове метода stmobile.launcher.startIntent, необходимо сформировать параметр data следующим образом:

{
"data": [
{ "name": "lat_from", "type": "double", "value": "55.751802" },
{ "name": "lon_from", "type": "double", "value": "37.586684" },
{ "name": "lat_to", "type": "double", "value": "55.758192" },
{ "name": "lon_to", "type": "double", "value": "37.642817" }
]
}

В итоге, чтобы из расширения вызвать внешнее приложение Yandex Navigator так, чтобы оно построило маршрут от from до to координаты, необходимо осуществить вызов метода startIntent со следующим json-объектом в качестве параметра:

"{
action: 'ru.yandex.yandexnavi.action.BUILD_ROUTE_ON_MAP',
data: [
{ name: 'lat_from', type: 'double', value: '55.751802' },
{ name: 'lon_from', type: 'double', value: '37.586684' },
{ name: 'lat_to', type: 'double', value: '55.758192' },
{ name: 'lon_to', type: 'double', value: '37.642817' }
],
intentPackage: 'ru.yandex.yandexnavi',
marketUrl: 'market://details?id=ru.yandex.yandexnavi'
}"

Получилась достаточно громоздкая конструкция. Ее сложность обусловлена большим количеством вариаций создания намерений для различных действий и необходимостью установки дополнительных параметров при одновременном сохранении универсальности.

Пример вызова внешнего приложения Google Maps:
Процесс вызова из JAVA-кода описан по ссылке
По аналогии с предыдущим примером вызов метода будет осуществляться со следующими параметрами:

{
action: 'android.intent.action.VIEW',
data: [],
actionUrl: ''
intentPackage: 'com.google.android.apps.maps',
marketUrl: 'market://details?id=com.google.android.apps.maps'
}

Пример вызова внешнего приложения CityGuide:
Процесс вызова из JAVA-кода доступен по запросу разработчикам
По аналогии с предыдущим примером вызов метода будет осуществляться со следующими параметрами:

{
action: 'android.intent.action.SEND',
data: [
{
name: 'android.intent.extra.TEXT',
type: 'string',
value: 'cgcmd delroute setroute 1 55.344323 24.324543'
}
],
intentPackage: 'cityguide.probki.net',
marketUrl: 'market://details?id=cityguide.probki.net',
actionType: 'vnd.android.cursor.item/vnd.net.probki.cityguide.cmd'
}

Больше примеров использования намерений можно также найти здесь