Архив за год: 2020



Android Studio: Создание плагина для Unity

Сразу предупреждаю, что заголовок очень расплывчатый, т.к. не совсем корректно отображает суть проблемы. В нескольких прошлых статьях я рассказывал, как прикрутить к Unity плагин для общения с устройством на Андроид. Меня же интересовал доступ к датчику Шагомер (Step Counter или Pedometer), а в новой системе ввода Unity (New Input System) такая возможность появилась в классе InputSystem.StepCounter. Появиться-то появилась, да вот только не совсем она удобная для меня. Мало того, что её нужно отдельно подключать в виде пакета через Package Manager, плюс к этому она отключает старую систему ввода. Для меня это выливается в проблему невозможности использования её функционала, который применяется в некоторых утилитах типа consolation.
Поэтому, чтобы не городить огород и не исправлять эти утилиты для работы с новой системой ввода, я решил написать нужные мне функции для доступа к датчикам Андроид самостоятельно.
В статье Создание и подключение плагина для Android был рассмотрен простейший пример создания плагина и подключение его к Unity. Потом я разобрался, как получить доступ к данным датчика Шагомера (Создание простого шагомера), но когда я попытался объединить всё это, то получил кучу ошибок.

Ошибки с проектом

1. При запуске проекта Unity получил ошибку NoClassDefFoundError

AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of t.androidx/appcompat/app/AppCompatActivity;

Здесь получился конфликт UnityPlayer.currentActivity и стандартного для приложения Android класса AppCompatActivity. Т.е. я уже не мог использовать такую запись:

public class MainActivity extends AppCompatActivity implements SensorEventListener

Я не могу использовать базовый класс для активности в приложении, т.к. у нас была библиотека. При этом всю работу выполнял подобный класс, который предоставлен Unity: unity-classes.jar (внутри этого файла есть класс unity3d.player, с ним и был конфликт).
Пришлось вместо строки:

sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);

использовать другую:

sensorManager = (SensorManager) UnityPlayer.currentActivity.getSystemService(Context.SENSOR_SERVICE);

Но тогда компилятор ничего не знал про UnityPlayer.currentActivity. IDE выделял UnityPlayer красным цветом, а при наведении на это слово всплывала ошибка:

Cannot resolve symbol ‘UnityPlayer’

 

Я импортировал запись о нём в самом начале файла:

import com.unity3d.player.UnityPlayer;

Это тоже не помогло, поэтому я добавил нужную библиотеку в проект:

  • Через Проводник скопировать библиотеку unity-classes.jar в папку библиотек модуля (у меня это «SensorPluginProject\SensorsLibrary\libs»).
    Найти этот файл можно во временной папке проекта Unity, например:
    \[ProjectName]\Temp\gradleOut\unityLibrary\libs

     

  • После чего в Android Studio открыть дерево проекта, найти файл unity-classes.jar
  • Нажать на нём правую кнопку мышки и выбрать Add As Library…:
  • Подтвердить создание Библиотеки:

2. Теперь проект можно было собрать без ошибок, но сейчас я не мог собрать проект в Unity, т.к. с нашей новой библиотекой получал другие ошибки:

java.lang.RuntimeException: Duplicate class bitter.jnibridge.JNIBridge found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class bitter.jnibridge.JNIBridge$a found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.google.androidgamesdk.ChoreographerCallback found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.google.androidgamesdk.SwappyDisplayManager found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.AudioVolumeHandler found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.Camera2Wrapper found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.GoogleARCoreApi found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.GoogleVrApi found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.GoogleVrProxy found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.GoogleVrVideo found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.HFPStatus found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.IUnityPlayerLifecycleEvents found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.NativeLoader found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.NetworkConnectivity found in modules unity-classes.jar

 

Duplicate class com.unity3d.player.ReflectionHelper found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class com.unity3d.player.UnityPlayer found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Duplicate class org.fmod.FMODAudioDevice found in modules unity-classes.jar (:SensorsLibrary-release:) and unity-classes.jar (unity-classes.jar)

 

Создать файл *.jar

Это уже второй шаг. Здесь мы попытаемся исправить ошибки, возникшие в прошлый раз. Они были связаны с тем, что в процессе сборки был создан файл AAR, в котором скомпилированный исходный код в файле classes.jar, Android-ресурсы, AndroidManifest, и другие файлы, из состава APK. Т.е. что-то явно лишнее, сделаем обычную библиотеку.
1. В папке модуля/библиотеки есть файл build.gradle, нужно добавить к нему такой код:

task deleteJar(type: Delete) {
    delete 'libs/jars/SensorsLibrary.jar'
}

task createJar(type: Copy) {
    from('build/intermediates/aar_main_jar/release/')
    into('libs/jars/')
    include('classes.jar')
    rename('classes.jar', 'SensorsLibrary.jar')
}

createJar.dependsOn(deleteJar, build)

2. После этого в правой верхней части окна Android Studio нажимаем вкладку Gradle
3. В списке запускаем задачу SensorPluginProjectSensorsLibraryTasksothercreateJar:

Если задачу неудаётся найти в списке, можно нажать на кнопку Execute Gradle Task и ввести название задачи:

Ещё можно перезайти в Android Studio, чтобы список задач обновился.

 

4. В логах появится запись следующего вида:

> Task :SensorsLibrary:createJar

BUILD SUCCESSFUL in 2s
53 actionable tasks: 2 executed, 51 up-to-date
21:42:07: Task execution finished 'createJar'.

4. Нужный файл SensorsLibrary.jar можно будет найти в отдельной папке:
C:\Users\<USER>\Documents\GitHub\SensorPluginProject\SensorsLibrary\libs\jars