В прошлый раз я рассказывал о том, как выполнить телефонный звонок из приложения в Palm WebOS. Все манипуляции выполнялись с помощью сервиса Application Manager, который запускал приложение дозвона с параметрами.
В этот раз мы более детально рассмотрим возможность запуска приложений в Palm WebOS, а также механизмы, позволяющие обработать параметры, которые были переданы приложению при запуске.Итак, наша цель – создать приложение, корректно обрабатывающее параметры запуска.
Чтобы оно заработало, нам эти параметры надо как-то этому приложению передать. И вот для этих целей мы напишем утилиту-launcher, которая с помощью Application Manager будет запускать наше приложение и передавать в параметрах ему все что нужно.
Пишем Launcher
Создадим новый проект и добавим в него сцену.
app/views/main/main-scene.html
<div>
<div class="palm-group">
<div class="palm-group-title">Application</div>
<div clas="palm-list">
<div class="palm-row first">
<div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div class="label">Name</div>
<div id="AppTextBox" x-mojo-element="TextField"></div>
</div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div class="label">Action</div>
<div id="ActionTextBox" x-mojo-element="TextField"></div>
</div>
</div>
</div>
<div class="palm-row last">
<div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div class="label">Parameter</div>
<div id="ParamTextBox" x-mojo-element="TextField"></div>
</div>
</div>
</div>
</div>
</div>
<div id="LaunchButton" x-mojo-element="Button"></div>
<div id="ExitButton" x-mojo-element="Button"></div>
</div>
app/assistants/main-assistant.js
function MainAssistant() {
}
MainAssistant.prototype.setup = function() {
this.controller.setupWidget('AppTextBox',
{
modelProperty: 'originalValue',
textCase: Mojo.Widget.steModeLowerCase,
focus: true
},
this.appModel =
{
originalValue : 'com.mobiledeveloper.appparameters'
});
this.controller.setupWidget('ActionTextBox',
{
modelProperty: 'originalValue',
textCase: Mojo.Widget.steModeLowerCase,
focus: false
},
this.actionModel =
{
originalValue : 'add'
});
this.controller.setupWidget('ParamTextBox',
{
modelProperty: 'originalValue',
textCase: Mojo.Widget.steModeLowerCase,
focus: false
},
this.paramModel =
{
originalValue : 123.45
});
this.controller.setupWidget("LaunchButton", {}, {label:"Launch"});
this.controller.setupWidget("ExitButton", {}, {label:"Exit"});
Mojo.Event.listen(this.controller.get("LaunchButton"),
Mojo.Event.tap, this.handleLaunchButton.bind(this));
Mojo.Event.listen(this.controller.get("ExitButton"),
Mojo.Event.tap, this.handleExitButton.bind(this));
}
MainAssistant.prototype.cleanup = function(event) {
Mojo.Event.stopListening(this.controller.get("LaunchButton"),
Mojo.Event.tap, this.handleLaunchButton.bind(this));
Mojo.Event.stopListening(this.controller.get("ExitButton"),
Mojo.Event.tap, this.handleExitButton.bind(this));
}
MainAssistant.prototype.handleLaunchButton = function(event) {
try
{
this.controller.serviceRequest('palm://com.palm.applicationManager',
{
method:'launch',
parameters:
{
id: this.appModel.originalValue,
params:
{
action: this.actionModel.originalValue,
param: this.paramModel.originalValue
}
}
});
}
catch(e)
{
this.controller.showAlertDialog({
onChoose: function(value){},
title: 'Error',
message: e,
choices: [{label:'OK'}]
});
}
}
MainAssistant.prototype.handleExitButton = function(event) {
this.controller.stageController.getAppController().closeAllStages();
window.close();
}
Сцена содержит три поля ввода:
- В первом – вводим уникальный идентификатор приложения, которое будем запускать
- Во втором – параметр action, который будет передан запускаемому приложению
- В третьем – параметр param, который будет передан запускаемому приложению
При запуске Launcher выглядит так:

Рассмотрим более детально, как же происходит запуск стороннего приложения:
- Мы вызываем Application Manager с помощью метода serviceRequest() объекта-контроллера
- Методу serviceRequest мы скармливаем название сервиса и JSON-объект с параметрами вызова сервиса
- В параметрах вызова сервиса указываем, что вызывается метод launch, а также указывается JSON-объект , который будет передан в качестве параметра методу launch.
- Объект, передаваемый методу launch содержит поле id, а котором указан идентификатор вызываемого приложения, а также поле params, содержащее JSON-объект, передаваемый в качестве параметра запускаемому приложению.
И вот, c launcher’ом мы закончили. Теперь приступим к примеру, демонстрирующему обработку параметров запуска.
Учимся обрабатывать параметры запуска приложения
Для начала создадим новое приложение и в нем сцены с названием first и add.
Если приложение должно обрабатывать параметры запуска, это значит что нам необходимо создать свой Application Assistant – класс, обеспечивающий логику работы приложения. Если мы создаем свой Application Assistant, то и создание GUI мы тоже должны будем прописывать руками. По умолчанию генератор проектов создает проект, содержащий главное окно. В нашем же случае все окна мы будем создавать руками (в коде). Для того, чтобы создавать окна в коде и избавиться от автоматически создаваемого окна, нам надо править файл appinfo.json. В нем необходимо указать параметр noWindow равным true.
{
"id": "com.mobiledeveloper.appparameters",
"version": "1.0.0",
"vendor": "Mobile-Developer.ru",
"type": "web",
"main": "index.html",
"title": "AppParameters",
"icon": "icon.png",
"noWindow": "true"
}
Указание значения noWindow является очень важным шагом, т.к. без этого свойства в приложении будут создаваться два окна и при запуске это будет выглядеть очень странно, что может в последствии стать причиной отказа в приеме приложения в Palm’овский e-commerce для приложений.
По умолчанию, кодогенератор для проектов создает код для Stage Assistant. Нам он теперь не понадобится и поэтому файл app/assistants/stage-assistant.js можно смело удалять.
Теперь поработаем над созданными ранее сценами:
app/views/first/first-scene.html
<div id="main" class="palm-hasheader">
<div class="palm-header center" id="main-hdr">Main Scene</div>
</div>
<div x-mojo-element="Button" id="AddSceneButton"></div>
<div x-mojo-element="Button" id="ExitButton"></div>
app/assistants/first-assistant.js
function FirstAssistant() {
}
FirstAssistant.prototype.setup = function() {
this.controller.setupWidget("AddSceneButton", {}, {label:"Add"});
this.controller.setupWidget("ExitButton", {}, {label:"Exit"});
Mojo.Event.listen(this.controller.get("AddSceneButton"),
Mojo.Event.tap, this.handleAddButton.bind(this));
Mojo.Event.listen(this.controller.get("ExitButton"),
Mojo.Event.tap, this.handleExitButton.bind(this));
}
FirstAssistant.prototype.cleanup = function(event) {
Mojo.Event.stopListening(this.controller.get("AddSceneButton"),
Mojo.Event.tap, this.handleAddButton.bind(this));
Mojo.Event.stopListening(this.controller.get("ExitButton"),
Mojo.Event.tap, this.handleExitButton.bind(this));
}
FirstAssistant.prototype.handleAddButton = function(event) {
this.controller.stageController.pushScene("add");
}
FirstAssistant.prototype.handleExitButton = function(event) {
this.controller.stageController.getAppController().closeAllStages();
window.close();
}
Сцена First содержит две кнопки. Первая кнопка запускает сцену Add, а вторая – завершает работу приложения
app/views/add/add-scene.html
<div class="palm-row">
<div class="palm-hasheader">
<div class="palm-header">Add Scene</div>
</div>
</div>
<div class="palm-row">
<div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
<div class="title">
<div id="ParamTextBox" x-mojo-element="TextField"></div>
</div>
</div>
</div>
app/assistants/add-assistants.js
function AddAssistant(param) {
if(param)
{
this.initialValue = param;
}
else
{
this.initialValue = '';
}
}
AddAssistant.prototype.setup = function() {
this.controller.setupWidget('ParamTextBox',
{
modelProperty: 'originalValue',
focus: true
},
{
originalValue: this.initialValue
});
}
Сцена Add содержит текстовое поле, в котором отображается значение аргумента, переданного сцене в качестве параметра.
И вот мы подошли к самому главному – как именно наше приложение должно получать и обрабатывать параметры запуска.
Для того чтобы обработать параметры запуска, в Application Assistant есть метод handleLaunch, у которого есть параметр launchParams – это объект, содержащий параметры запуска. Если приложение было запущено без параметров, то launchParams будет равен null.
app/assistants/app-assistant.js
var AppParameters = {}
AppParameters.StageName = "AppParamaters";
function AppAssistant() {
}
AppAssistant.prototype.handleLaunch = function(launchParams) {
if(!launchParams)
{
Mojo.Log.info('Applicaion was started without parameters');
this.startDefault();
}
else
{
Mojo.Log.info('Applicaion was started with parameters');
switch(launchParams.action)
{
case 'add':
Mojo.Log.info('ADD action');
this.addSceneParam = launchParams.param;
this.handleAddAction();
break;
}
}
}
AppAssistant.prototype.startDefault = function() {
this.stageController = this.controller.getStageController(AppParameters.StageName);
if (this.stageController)
{
this.stageController.popSceneTo('first');
this.stageController.activate();
}
else
{
var stageParams =
{
name: AppParameters.StageName,
lightweight: true
}
this.controller.createStageWithCallback(stageParams,
this.pushFirstScene.bind(this));
}
}
AppAssistant.prototype.handleAddAction = function() {
this.stageController = this.controller.getStageController(AppParameters.StageName);
if (this.stageController)
{
this.stageController.popSceneTo('first');
this.stageController.pushScene('add', this.addSceneParam);
this.stageController.activate();
}
else
{
var stageParams =
{
name: AppParameters.StageName,
lightweight: true
}
var addStageCallback = function(stageController)
{
stageController.pushScene('first');
stageController.pushScene('add', this.addSceneParam);
}
this.controller.createStageWithCallback(stageParams,
addStageCallback.bind(this));
}
}
AppAssistant.prototype.pushFirstScene = function(stageController) {
stageController.pushScene('first');
}
В методе handleLaunch мы проверяем значение launchParams и если оно равно null, то вызываем метод startDefault(). Если launchParams не null, то мы выполняем проверку значения поля action и если оно равно add, то вызываем сцену Add.
Метод handleLaunch может быть вызван в двух случаях – при запуске первого экземпляра приложения и для уже запущенного приложения. Об этом надо помнить, когда мы реализуем логику создания сцен в методах startDefault() и handleAddSAction().
В теле метода startDefault() мы получаем объект Stage Controller с именем “AppParameters”. Если полученное значение равно null, то у нас первый запуск приложения. Мы создаем новое окно (stage) с помощью метода createStageWithCallback() и в callback-функции, которая отрабатывает после успешного создания окна, создаем сцену first.
Если же ссылка на Stage Controller, полученная в методе startDefault(), не равна null, то у нас произошел вызов уже запущенного приложения. Мы закрываем все сцены, которые находятся над сценой first. Делаем мы это с помощью метода popSceneTo().
Метод handleAddAction() работает аналогично. Если у нас происходит вызов уже запущенного приложения, то мы закрываем все сцены, находящиеся над сценой first, а затем открываем сцену add и передаем ей в качестве параметра поле param из launchParameters.
Если же мы вызываем приложение первый раз с параметром action=add, то создаем новое окно, в нем создаем сцену first, а затем сцену add и точно так же, скармливаем ей в качестве параметра поле param из launchParameters.

На этом все.
Скачать исходный код примера.