Мобильное приложение 1С и приложение Java. Совместная работа через Intent. Часть 2. Получаем данные в 1С из приложения Java

Программирование - Мобильные приложения

Пишем два приложения - конфигурацию на мобильной платформе 1С и приложение Java Android Studio. На примере рассматриваем совместное использование двух приложений через Intent. Публикация состоит из 3 частей: Часть 1. Запуск приложения Java из 1С Часть 2. Получаем данные в 1С из приложения Java Часть 3. Отправляем данные в приложение Java из 1С.

Добрый день, уважаемые коллеги!

В данной части доработаем наши мобильные приложения, описанные в 1 части (//catalog.mista.ru/public/613072/) и посмотрим на примере, как передать данные, введенные в Java приложении, в 1С.

1.Открываем наш проект в Android Studio

Добавляем в activity_main.xml кнопку (Button) и элемент отображения текста (TextView)

<Button
    android:id="@+id/btnName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_margin="20dp"
    android:text="Ввести имя">
</Button>

<TextView
    android:id="@+id/tvName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:text="Ваше имя: ">
</TextView>

С помошью кнопки будем вызывать другое окно, в котором будем вводить, например, наше имя и потом передавать его в 1С. Должно получиться так:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:id="@+id/btnTime"
        android:text="Показать время">
    </Button>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:id="@+id/btnDate"
        android:text="Показать дату">
    </Button>
    <Button
        android:id="@+id/btnName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="20dp"
        android:text="Ввести имя">
    </Button>

    <TextView
        android:id="@+id/tvName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Ваше имя: ">
    </TextView>
</LinearLayout>

Кодим класс MainActivity. Определяем TextView и кнопку, настраиваем обработчик. В методе обработчика onClick создаем Intent и Action - ru.w0rm.intent.action.GetData. 

Для отправки используем startActivityForResult. Отличие от обычного startActivity в том, что MainActivity становится «родителем» для NameActivity. И когда NameActivity закрывается, вызывается метод onActivityResult в MainActivity, тем самым давая нам знать, что закрылось Activity, которое мы вызывали методом startActivityForResult.

В startActivityForResult в качестве параметров мы передаем Intent и requestCoderequestCode – необходим для идентификации.

В onActivityResult мы видим следующие параметры: 
requestCode – тот же идентификатор, что и в startActivityForResult. По нему определяем, с какого Activity пришел результат. 
resultCode – код возврата. Определяет успешно прошел вызов или нет.
data – Intent, в котором возвращаются данные

Должно получиться так MainActivity:

package ru.w0rm.develop.intentfilter;

import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements View.OnClickListener {

    TextView tvName;
    Button btnName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnTime = (Button) findViewById(R.id.btnTime);
        Button btnDate = (Button) findViewById(R.id.btnDate);

        tvName = (TextView) findViewById(R.id.tvName);
        btnName = (Button) findViewById(R.id.btnName);
        btnName.setOnClickListener(this);

        btnTime.setOnClickListener(this);
        btnDate.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent;

        switch(v.getId()) {
            case R.id.btnTime:
                intent = new Intent("ru.w0rm.intent.action.showtime");
                startActivity(intent);
                break;
            case R.id.btnDate:
                intent = new Intent("ru.w0rm.action.showdate");
                startActivity(intent);
                break;
            case R.id.btnName:
                intent = new Intent("ru.w0rm.intent.action.GetData");
                startActivityForResult(intent, 1);
                break;
        }

    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (data == null) {return;}
        String name = data.getStringExtra("name");
        tvName.setText("Ваше имя:  " + name);
    }
}

Создаем Layout, в котором будем вводить имя и потом передавать его в 1С name.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Имя">
        </TextView>
        <EditText
            android:id="@+id/etName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_weight="1">
            <requestFocus>
            </requestFocus>
        </EditText>
    </LinearLayout>
    <Button
        android:id="@+id/btnOK"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="OK">
    </Button>
</LinearLayout>

Создаем класс NameActivity:

package ru.w0rm.develop.intentfilter;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class NameActivity extends Activity implements OnClickListener {

    EditText etName;
    Button btnOK;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.name);

        etName = (EditText) findViewById(R.id.etName);
        btnOK = (Button) findViewById(R.id.btnOK);
        btnOK.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.putExtra("name", etName.getText().toString());
        setResult(RESULT_OK, intent);
        finish();
    }
}

Определяем поле ввода и кнопку, прописываем обработчик. В методе onClick мы создаем Intent и помещаем в него данные из поля ввода под именем name. Обратите внимание, мы никак не адресуем этот Intent. Т.е. ни класс, ни action мы не указываем. И получается, что непонятно куда пойдет этот Intent. Но метод setResult знает, куда его адресовать - в «родительское» Activity, в котором был вызван метод startActivityForResult. Также в setResult мы передаем константу RESULT_OK, означающую успешное завершение вызова. И именно она передастся в параметр resultCode метода onActivityResult в MainActivity.java.

Прописываем класс NameActivity манифесте:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ru.w0rm.develop.intentfilter">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="ActivityTime">
            <intent-filter>
                <action android:name="ru.w0rm.intent.action.showtime"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>
        <activity android:name="ActivityDate" android:label="Date basic">
            <intent-filter>
                <action android:name="ru.w0rm.action.showdate"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>

        <activity android:name="NameActivity" android:label="Get data">
            <intent-filter>
                <action android:name="ru.w0rm.intent.action.GetData"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>

    </application>

</manifest>

Запускаем Java приложение и проверяем. Нажимаем кнопку Ввести имя. В открывшемся окне вводим текст и нажимает ОК. Видим, что данные передались на главную форму.

2.Теперь реализуем вызов окна Java приложения из 1С, введем данные в наше Java приложение и передадим введенные данные в 1С.

Открываем нашу конфигурацию 1С.

В общую форму НачальнаяФорма добавляем команду ПолучитьДанные

Добавляем обработчик команды:


&НаКлиенте
Процедура ПоказатьВремя(Команда)
	
	#Если МобильноеПриложениеКлиент Тогда 
		НовВз = Новый ЗапускПриложенияМобильногоУстройства();
    	НовВз.Действие="ru.w0rm.intent.action.showtime";
    	НовВз.Запустить(Истина);
	#КонецЕсли

КонецПроцедуры

&НаКлиенте
Процедура ПоказатьДату(Команда)
	
	#Если МобильноеПриложениеКлиент Тогда 
		НовВз = Новый ЗапускПриложенияМобильногоУстройства();
    	НовВз.Действие="ru.w0rm.action.showdate";
    	НовВз.Запустить(Истина);
	#КонецЕсли

КонецПроцедуры

&НаКлиенте
Процедура ПолучитьДанные(Команда)
	#Если МобильноеПриложениеКлиент Тогда 
		НовВз = Новый ЗапускПриложенияМобильногоУстройства();
    	НовВз.Действие="ru.w0rm.intent.action.GetData";
    	НовВз.Запустить(Истина);
	    Для Каждого Стр Из НовВз.ДополнительныеДанные Цикл
       	 Сообщить(Стр.Ключ+" - "+Стр.Значение);
   		КонецЦикла;  		
	#КонецЕсли

КонецПроцедуры

В обработчике запускаем Java приложение с Action - ru.w0rm.intent.action.GetData. Далее проходим по коллекции Дополнительные данные и выводим на экран.

Запускаем мобильное приложение 1С и проверяем:

При нажатии на кнопку Получить данные запускается форма нашего мобильного приложения. В ней вводим текст и жмем ОК. Окно закрывается и в 1С передаются данные.

На этом у меня все. В третьей части рассмотрим как передать данные из 1С в Java приложение.

Спасибо Виталию Непочатову за теорию по java http://startandroid.ru/ru/uroki.html

Спасибо за внимание!

См. также

Комментарии
1. Иван Коротеев (kiv1c) 336 20.04.17 14:03 Сейчас в теме
Вроде бы интересно, но что если у нас есть уже готовое андроид приложение, кода которого мы не знаем? что тогда, смотреть в манифест и пытаться понять что за данные нам вернутся?
2. Дмитрий Васильев (user621724_Dimav1979) 195 20.04.17 15:04 Сейчас в теме
(1) Если в манифесте прописан Action <action android:name="ru.w0rm.intent.action.GetData"></action> то можно вызвать без проблем из 1С. А далее анализируем то, что вернулось через Дополнительные данные

НовВз = Новый ЗапускПриложенияМобильногоУстройства();
НовВз.Действие="ru.w0rm.intent.action.GetData";
НовВз.Запустить(Истина);
Для Каждого Стр Из НовВз.ДополнительныеДанные Цикл
Сообщить(Стр.Ключ+" - "+Стр.Значение);
КонецЦикла;
dj_serega; smirnov.es; +2 Ответить
3. 1ckun (smirnov.es) 21.04.17 05:26 Сейчас в теме
Очень полезная статья. Ждем дальнейших публикаций
4. Кирилл Власов (neikist) 21.04.17 19:53 Сейчас в теме
Статьи интересные и полезные, имхо, объяснение гораздо понятнее и лучше чем у "курсы по 1с". Большое спасибо. Ждем третьей статьи, хотя конечно провести аналогии между типами "ЗапускПриложенияМобильногоУстройства"-Intent и "ДополнительныеДанныеЗапускаПриложенияМобильногоУстройства"-Bundle довольно просто теперь) Получается зеркальный процесс где мы в 1с в как бы "Intent" указываем дополнительные данные, а в нативном приложении извлекаем из Bundle. Ох уж эти 1сники с их тягой к длинным именам)))
5. Сергей Галюк (dj_serega) 250 22.04.17 08:12 Сейчас в теме
(4)
Статьи интересные и полезные, имхо, объяснение гораздо понятнее и лучше чем у "курсы по 1с".

Ну да... тут в 2х словах а там на пальцах ;)

А по поводу публикаций то действительно Спасибо! По факту, для разбора интентов нужна специфика явовщика. Ну допустим, как получить IMEI устройства? Я так понял что нужно написать свое приложение которое получит IMEI і вернет в 1С.
6. DonPedroGonsales (saudin) 25.04.17 11:08 Сейчас в теме
7. DonPedroGonsales (saudin) 25.04.17 11:33 Сейчас в теме
Ага, появилась. Спасибо большое.
8. Дмитрий К. (Dementor) 9 26.04.17 14:36 Сейчас в теме
(5)
Ну допустим, как получить IMEI устройства?

Большинство Android-телефонов на рынке поставляется с двумя сим-слотами, у каждого из которых свой условно уникальный IMEI. Типовым методом getDeviceId() из стандартного класса TelephonyManager можно получить IMEI только активной симки. При использовании двух сим-карт получение этого кода вообще не предсказуемо. А ведь еще есть телефоны на 3 СИМки!!!

Простого метода получить IMEI для всех СИМ-слотов не существует. Есть НЕ универсальные приемы на рефлексию, которые работают только на конкретных моделях телефонов. Детальнее можно почитать тут.

Поэтому мне нравится как выкрутились в 1С. Их мобильная платформа с помощью свойства ИдентификаторКлиента из свойства объекта СистемнаяИнформация в рамках одной конкретной инсталяции конкретной конфигурации выдает уникальный код. Если базу на телефоне переустановить, то этот код изменится. И я считаю, что это правильно - для центральной базы какая разница будет ли это переустановка на одном и том же телефоне или на другом, если там не будет никаких данных и настроек и придется делать все по новой. А если доступ не анонимный, а по логину/паролю или по токену, то и идентификация по коду устройства уже не нужна. И если уж так сильно приспичит опознавать конкретный телефон, то можно после первого запуска создать текстовый файлик на устройстве и далее сообщать код из него в центральную базу.

Увлекся :) Я хотел сказать, что программа на Android - это не серебренная пуля!
Оставьте свое сообщение