JNI Bindings

Начиная с 1.0.5 в Tracer есть возможность делать часть вызовов в Tracer Android из нативного кода сквозь libtracernative.so.Под капотом это резолвится в JNI-вызов в Java в основной SDK. Очевидно, делать это именно сквозь libtracernative.so необязательно, обёртки поставляются для удобства пользования.

Нужно ли это мне?

Если не собираете свой native-код (например, не используете NDK вообще или используете только предсобранные библиотеки из зависимостей) - нет.

Если вам не нужно инструментировать свой native-код и достаточно просто минидампов на крешах - тоже нет.

В данных случаях достаточно зависимости на ru.ok.tracer:tracer-crash-report-native в соответствии с быстрым стартом.

Подключение

Библиотека и заголовочный файл находятся в пакете ru.ok.tracer:tracer-native-bindings, но требует некоторых осторожностей при подключении.
Инициализация самого "моста" из JNI в Java-Tracer лежит в ru.ok.tracer:tracer-crash-report-native, т.е. зависимость на него (прямо или транзитивно) в итоговом приложении должна быть.
tracer-crash-report-native транзитивно подтягивает tracer-native-bindings, но в силу специфики инструментов этого недостаточно - потребуются более явные манипуляции.

Подключение через Prefab + AGP

Про Prefab можно почитать здесь.

tracer-native-bindings пакуется с prefab-модулем tracernative внутри, AGP сам меняет инвокации ndk-build/cmake (добавляет пути для поиска) чтобы он был доступен в Android.mk/CMakeLists.txt. На практике на AGP 7.4.1 интеграция с ndk-build была отломана, так что рекомендуется CMake

  1. В модуле с нативным кодом включаем prefab как buildFeature:
android { /* ... */ buildFeatures { prefab = true } }
  1. Добавляем зависимость на ru.ok.tracer:tracer-native-bindings

  2. В CMakeLists.txt появится возможность найти библиотеку и приликноваться к ней

find_package(tracer-native-bindings REQUIRED) target_link_libraries(${YOUR_LIBRARY_NAME} PRIVATE tracer-native-bindings::tracernative)
  1. Теперь в include'ах должен появиться tracer.h; ваша библиотека будет собираться с динамической зависимостью на libtracernative.so

Подключение другими способами

При невозможности пользоваться AGP в теории можно инвокать prefab руками, пример здесь

При большом нежелании пользоваться prefab'ом в принципе можно раздирать .aar-архив руками и выцарапывать из него .so / .h

  • .so лежат в prefab/modules/tracernative/libs/android.${ARCH}/libtracernative.so
  • .h лежит в prefab/modules/tracernative/include

Использование

#include "tracer.h" /* ... */ void call_to_java_tracer() { tracer_log("log message from native"); tracer_log(u8"лог-сообщение из натива, с юникодом"); tracer_set_key("native_key", "native_value"); } /* ... */

tracer.h одинаковый с tracer.h из Tracer Native, большая часть методов оттуда поставляются с пустой имплементацией (можно вызывать, ничего не произойдёт).
Сделано специально чтобы кросплатформенный код с инструментацией Tracer'ом максимально просто кросскомпилировался.

На данный момент из native в Java пробрасываются только два метода:

  • tracer_log(char* message) -> TracerCrashReport::log
  • tracer_set_key(char* key, char* value) -> Tracer::setKey

Постепенно будут добавлены другие.

Подводные камни

ru.ok.android:tracer-crash-report-native транзитивно притягивает ru.ok.android:tracer-native-bindings, но Prefab игнорирует транзитивные зависимости - нужна явная зависимость на tracer-native-bindings во всех модулях, где планируется использовать JNI-мост.

В CMake, tracer-native-bindings::tracernative считается IMPROTED-библиотекой - т.е. target_link_libraries(..) до него подцепляется Android Gradle Plugin'ом и генерирует packaging-конфликт (между libtracernative.so поднятым как SHARED IMPORTED и между libtracernative.so поднятым как jni-либа внутри tracer-native-bindings.aar).
Решается добавлением pickFirsts в опции запаковки приложения.
В app/build.gradle.kts:

android { /* ... */ packaging { jniLibs { pickFirsts += "**/libtracernative.so" } } }