Важно (9.07.22)

Если картинки в постах не отображаются, зайдите в блог через прокси. РКН заблокировал поддомены blogger.com на которые загружались картинки.

пятница, 11 июля 2014 г.

Как подключить и использовать свой JAVA-класс

В этой статье вы узнаете, как подключить свой JAVA-класс, как создаётся файл «classes.dex», как пишутся обёртки (об этом уже писал) и как потом использовать подключенный JAVA-код. Советую читать и изучать материал внимательно, чтобы все ваши вопросы решились сами собой.












Начнём!

Составим план того, что нам необходимо:
  1. Иметь сторонний JAVA-класс или написать самостоятельно
  2. Написать обёртку для выбранного JAVA-класса
  3. Создать файл "classes.dex" и склеить со стандартным файлом
  4. Написать приложение, в котором используется наш класс
Ну вот, план готов, давайте приступать.

1) Иметь сторонний JAVA-класс или написать самостоятельно

В данной статье, для примера, я написал собственный простейший Java-класс. Вы же можете попробовать подключить любой другой Java-класс, в интернете полно готового кода. Писать их можно где угодно, я делал это в среде «Eclipse» (Скачать можно тут Get the Android SDK). 

О том, как писать код на языке Java читайте на просторах интернета.

Класс, который я написал, имеет два метода:
Один статический, второй обычный. Это сделано для того, чтобы потом (в последнем шаге) показать, как использовать их в коде.

Мой класс принадлежит к пакету «TestClassHello» и имеет имя «HelloWorld», хранится по такому пути «C:\Users\Пользователь\workspace\TestClass\src\TestClassHello\HelloWorld.java».

Код класса:
package TestClassHello;

public class HelloWorld {

 /**
  * @param args
  */

 public static String getStrStatic(String str) {

  String strAnswer;
  String strHelloDelphi = "hello from delphi!";

  if (str.toLowerCase().equals(strHelloDelphi))
   strAnswer = "Hello World!\nHello Delphi Community! ;)\n(JAVA! Static method)";
  else
   strAnswer = str + "\n(JAVA! Static method)";

  return strAnswer;
 }

 public String getStrNoStatic(String str) {
  return str + "\n(Java! Not a static method)";
 }

}

Что умеет класс.

Класс при использовании любого из двух методов, возвращает текст. Также в методы можно передавать любой текст, и он будет возвращён с добавлениями. А при определённой фразе, поздоровается со всем Delphi сообществом (хоть какое-то разнообразие :).

Теперь создадим папку (например, на рабочем столе) для нашего будущего приложения, пускай называется «testJAVA», в ней создадим папку «java» и скопируем в эту папку всё из «C:\Users\Пользователь\workspace\TestClass\». 

Получим вот такое дерево папок:

В дальнейшем мы будем работать только с этой «testJAVA» папкой, поэтому можно забыть про всё остальное :)

Ну вот, первый пункт успешно выполнили. Быстренько переходим ко второму пункту, долго не задерживаемся.

2) Написать обёртку для выбранного JAVA-класса

Если вы посещаете/читаете мой блог, то скорее всего уже видели (и надеюсь читали) статью о том как создавать обёртки. Почти всё, что написано в той статье также справедливо и для обёрток сторонних Java-классов. Разница только в том, что список методов мы берём не с сайта, а из нашего JAVA-класса.

В классе всего два метода:
  • статический «getStrStatic» – значит, пишем его в interface(JObjectClass)
  • обычный «getStrNoStatic» – пишем в interface(JObject)
Оба метода принимают и возвращают строку.
Файл я так и назвал «TestClassHello».
Код обёртки для JAVA-класса:
unit TestClassHello;

interface

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes;

type
  JHelloWorld = interface;

  JHelloWorldClass = interface(JObjectClass)
  ['{77C14F6E-4D89-419B-A721-366D48D6A671}']
    function getStrStatic(str: JString): JString; cdecl;
  end;

  [JavaSignature('TestClassHello/HelloWorld')]
  JHelloWorld = interface(JObject)
  ['{11121974-C65D-48B0-B9E2-B16E4F93B275}']
    {Property Methods}
    {Methods}
    function getStrNoStatic(str: JString): JString; cdecl;
    {Properties}
  end;
  TJHelloWorld = class(TJavaGenericImport<JHelloWorldClass, JHelloWorld>) end;


implementation

  procedure RegisterTypes;
  begin
    TRegTypes.RegisterType('TestClassHello', TypeInfo(TestClassHello.JHelloWorld));
  end;

initialization
  RegisterTypes;
end.

Обёртка готова, кладём её в корень папки «testJAVA». Половину пути прошли, теперь уже ни как нельзя бросать всё из-за лени, например)) Продолжаем…

3) Создать файл classes.dex и склеить со стандартным файлом
Файл с java реализацией дополнительного функционала FireMonkey.

Шаги создания:
  1. Компилируем наш класс
  2. Создаём jar, содержащий наш класс
  3. Конвертируем jar в dex
  4. Склеиваем стандартный classes.dex с нашим classes.dex

Для того чтобы создавать всё автоматически, уважаемый Brian Long написал bat-файл. Этим файлом мы и воспользуемся, изменив его под себя. Этот bat-файл, необходимо создать и сохранить в папке «\testJAVA\java\».

У всех этот файл выглядит по-разному, но выполняет одинаковые функции, вот вам мой, ниже будет небольшое описание.

Код файла «build.bat»:
@echo off

setlocal

if x%ANDROID% == x set ANDROID=C:\Users\Public\Documents\Embarcadero\Studio\14.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk
set ANDROID_PLATFORM=%ANDROID%\platforms\android-19
set DX_LIB=%ANDROID%\build-tools\android-4.4\lib
set EMBO_DEX="C:\Program Files\Embarcadero\Studio\14.0\lib\android\debug\classes.dex"
set PROJ_DIR=%CD%
set VERBOSE=0

echo.
echo Compiling the Java service activity source files
echo.
mkdir output 2> nul
mkdir output\classes 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose
javac %VERBOSE_FLAG% -Xlint:deprecation -cp %ANDROID_PLATFORM%\android.jar -d output\classes src\TestClassHello\HelloWorld.java

echo.
echo Creating jar containing the new classes
echo.
mkdir output\jar 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=v
jar c%VERBOSE_FLAG%f output\jar\test_classes.jar -C output\classes TestClassHello

echo.
echo Converting from jar to dex...
echo.
mkdir output\dex 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=--verbose
call %DX_LIB%\dx.jar --dex %VERBOSE_FLAG% --output=%PROJ_DIR%\output\dex\test_classes.dex --positions=lines %PROJ_DIR%\output\jar\test_classes.jar

echo.
echo Merging dex files
echo.com.android.dx.merge.DexMerger
java -cp %DX_LIB%\dx.jar com.android.dx.merge.DexMerger %PROJ_DIR%\output\dex\classes.dex %PROJ_DIR%\output\dex\test_classes.dex %EMBO_DEX%

echo Tidying up
echo.
del output\classes\TestClassHello\HelloWorld.class
rmdir output\classes\TestClassHello
rmdir output\classes
del output\dex\test_classes.dex
del output\jar\test_classes.jar
rmdir output\jar

echo.
echo Now we have the end result, which is output\dex\classes.dex

:Exit

endlocal

Теперь разберём этот файл, процесс выполняется пошагово в соответствии с описанными выше шагами создания.

Что необходимо сделать, чтобы данный bat-файл заработал у вас:

а) Необходимо прописать глобальный путь до главной директории JAVA

Как это сделать (для Windows 7. Для остальных ОС можно почитать тут и тут):
  • Жмёте «Пуск» -> «Компьютер», далее жмёте «Свойства системы», там жмёте «Дополнительные параметры системы»
  • В открывшемся окне, выбираем вкладку «Дополнительно» и жмём на кнопку «Переменные среды…»
  • В открывшемся окне, в «Системных переменных» ищем переменную «Path», выбераем её и жмём «Изменить»
  • В конец строки добавляем путь до папки «bin», примерно такой «;C:\Program Files\Java\jdk1.7.0_25\bin», обратите внимание на точку с запятой в начале, это необходимо чтобы отделить добавляемый путь от уже указанных.
  • Жмём «OK» и всё закрываем.
Теперь командная строка умеет работать с JAVA командами.

б) Далее необходимо в коде изменить пути, в самом начале файла.
У меня в файле это:
  • ANDROID - Путь до SDK
  • ANDROID_PLATFORM – Путь до модуля SDK Platform
  • DX_LIB – каталог с библиотекой поддержки Dalvik, dx.jar
  • EMBO_DEX – путь до стандартного файла «classes.dex»
Стандартный файл «classes.dex» бывает двух видов:

Debug – «C:\Program Files\Embarcadero\Studio\14.0\lib\android\debug\classes.dex»
Release – «C:\Program Files\Embarcadero\Studio\14.0\lib\android\release\classes.dex»

в) Далее в 18 строке, в конце, необходимо изменить путь на свой или оставить также (если вы придерживаетесь статьи). Этот путь берётся из папки «\testJAVA\java\», если вы не забыли, то там у нас лежит наш класс «Desktop\testJAVA\java\src\TestClassHello\HelloWorld.java», путь указывается, начиная с папки «\src\».

На 25 строчке, в конце укажите название папки, которая вложена в папку «src». В моём случае это «TestClassHello». На 41 и 42 строчках также измените названия папок и имя класса.

Если вы всё сделали правильно, то можете смело запускать файл и смотреть результат.


Результат будет таким: в папке «java» появится папка «output», в которой будет лежать новый файл «classes.dex».


Ну вот, кончились мучения, теперь у нас есть файл «C:\Users\Пользователь\Desktop\testJAVA\java\output\dex\classes.dex». Приступаем к последнему шагу.

4) Написать приложение, в котором используется наш класс

Приложение получилось простое:


Код:
  • В uses подключаем два модуля, в том числе и нашу обёртку: Androidapi.Helpers, TestClassHello;
  • Обращение к статическим методам происходит через "JavaClass", в коде это "Button1".
  • Обычные методы – перед обращением необходимо создать объект, в коде это "Button2".
uses
  Androidapi.Helpers, TestClassHello;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Text := 'Answer: ' + #13#10 +
  JStringToString(TJHelloWorld.JavaClass.getStrStatic(StringToJString(Edit1.Text)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  TestClass: JHelloWorld;
begin
  TestClass := TJHelloWorld.Create;
  Label1.Text := 'Answer: ' + #13#10 +
  JStringToString(TestClass.getStrNoStatic(StringToJString(Edit1.Text)));
end;

Также необходимо задеплоить новый файл «classes.dex», а со стандартного снять галочку.


Результат:




На этом всё. Как видите всё получилось хорошо. Статья получилась большой, но надеюсь читабельной.


Благодарю Anatoly Zakusilov, именно ваши вопросы подтолкнули меня на то чтобы дописать эту статью :)

Если у вас возникли вопросы, то пишите в комментарии.

Исходный код: Скачать с Google Drive

p.s. Ну вот, юбилейная запись в блоге - 50-ая :)