Вышел релиз JNIKit 2.11.0 – Swift-библиотеки для лёгкого взаимодействия с Java через JNI, которая активно развивается как часть проекта Swift на Android.

Попробовать Swift на Android в один клик можно в Swift Stream IDE.
Подробный туториал Swift на Android: создаём библиотеку.

Улучшенное управление памятью

Те��ерь JObject автоматически освобождает глобальный референс на jobject при деинициализации объекта (deinit).

⚠️ Это ломающее изменение если ранее вы вручную управляли jobject . Обновите код, чтобы избежать ошибок от попытки повторного удаления референса.

Также переработана логика управления памятью JClass, JClassLoader и JObjectArray.

На данном этапе предполагается, что вам ни где больше не придётся иметь дело с ручным удалением JNI-референсов, можно просто положиться на то, что при деинициализации Swift объектов всё будет сделано автоматически.

Логирование

Была улучшена трассировка создания и удаления глобальных референсов, чтобы можно было легко отследить весь цикл, конкретный объект и место откуда он создаётся.

Для трассировки действий совершаемых JNIKit предусмотрено включение логов через флаг компиляции JNILOGS. В Swift Stream IDE этот флаг включается одной галочкой.

Одномерные массивы

Работа с массивами в JNIKit была проста и удобна, но стала ещё лучше.

Карта типов Swift-массивов и их обёрток:

[Int8]

jbyte[]

JInt8Array / JByteArray

[Int16]

jshort[]

JInt16Array / JShortArray

[Int32]

jint[]

JInt32Array / JIntArray

[Int64]

jlong[]

JInt64Array / JLongArray

[UInt16]

jchar[]

JUInt16Array / JCharArray

[Bool]

jboolean[]

JBoolArray

[Float]

jfloat[]

JFloatArray

[Double]

jdouble[]

JDoubleArray

[Any]

jobject[]

JObjectArray

Примеры инициализации

Стандартный Array:

JIntArray([1, 2, 3])

Новый InlineArray:

let inlineArray: InlineArray<5, Int32> = [1, 2, 3, 4, 5]
JIntArray(inlineArray)

Чтение массива

let intArray = JIntArray([1, 2, 3]) 
let swiftArray: [Int32] = intArray.toArray()

⚠️ Будьте осторожны, подобное чтение создаёт полную копию массива и это может создать проблемы с производительностью при чтении большого массива

Чтение с помощью итератора даёт возможность избежать копирования

for value in intArray {
    Log.d("value: \(value)")
}

2D массивы

Теперь доступны не только одномерные массивы ([Int]), но и двумерные массивы ([[Int]][[Float]] и т.д.) – этот часто используется в Java и в Android API в частности.

Например, в ColorStateList конструктор ColorStateList(int[][] states, int[] colors).

Конвенция имён такая же, просто добавляется 2D в конце:

[[Int8]]

jbyte[][]

JInt8Array2D / JByteArray2D

[[Int16]]

jshort[][]

JInt16Array2D / JShortArray2D

[[Int32]]

jint[][]

JInt32Array2D / JIntArray2D

[[Int64]]

jlong[][]

JInt64Array2D / JLongArray2D

[[UInt16]]

jchar[][]

JUInt16Array2D / JCharArray2D

[[Bool]]

jboolean[][]

JBoolArray2D

[[Float]]

jfloat[][]

JFloatArray2D

[[Double]]

jdouble[][]

JDoubleArray2D

Инициализация

Так же легко как и с 1D массивами:

let intArray2d = JIntArray2D([[1, 2, 3], [4, 5, 6]])

Чтение

Всё так же прямо и просто:

let swiftArray: [[Int32]] = intArray2d.toArray()

И итератор тоже присутствует:

for array in intArray2d {
    Log.d("arrray: \(array)")
}

Передача массивов в методы

Если метод или конструктор объекта принимают 1D или 2D массив, то вы можете передать туда просто Swift массив без дополнительного создания его обёртки

object.callVoidMethod(name: "send1DArray", args: [1, 2, 3])
object.callVoidMethod(name: "send2DArray", args: [[1, 2, 3], [4, 5, 6]])

README на GitHub обновлён и содержит все новые примеры.

Поддержка проекта

Если вы используете JNIKit, поставьте звёздочку на GitHub – это поможет другим разработчикам найти библиотеку и поддержит дальнейшее развитие Swift на Android.

Полный список изменений: 2.10.0 → 2.11.0