Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,11 @@ set PATH=%PATH%;c:\msys64\usr\bin

The build produces three artifacts:

- The main .aar file, which contains the backend Kotlin code, web assets, and
Anki backend code compiled for Android.
- An Android wrapper .aar in `rsdroid-android/build/outputs/aar`. Its published
Maven metadata declares an API dependency on the main backend artifact.
- The backend API .aar in `rsdroid/build/outputs/aar`, which contains the backend
Kotlin code and generated Protocol Buffer classes.
- The Android .aar in `rsdroid-android/build/outputs/aar`, which contains the SQLite
adapter, web assets, and Anki backend code compiled for Android. Its published
Maven metadata declares an API dependency on the backend API artifact.
- A .jar that contains the backend code compiled for the host platform, for use
with Robolectric unit tests.

Expand Down Expand Up @@ -156,6 +157,10 @@ in the AnkiDroid repo, and add the following line:
local_backend=true
```

The local dependency configuration in AnkiDroid must include both
`rsdroid/build/outputs/aar/rsdroid-release.aar` and
`rsdroid-android/build/outputs/aar/rsdroid-android-release.aar`.

Check `Anki-AndroidBackend/gradle.properties`'s `BACKEND_VERSION` and
`Anki-Android/build.gradle`'s `ext.ankidroid_backend_version`. Both variables
should have the same value. If it is not the case, you must edit Anki-Android's
Expand Down
4 changes: 2 additions & 2 deletions build_rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::process::Command;
use streaming_iterator::StreamingIterator;
use tree_sitter::{Parser, Query, QueryCursor};

const ANDROID_OUT_DIR: &str = "rsdroid/build/generated/jniLibs";
const ANDROID_OUT_DIR: &str = "rsdroid-android/build/generated/jniLibs";
const ROBOLECTRIC_OUT_DIR: &str = "rsdroid-testing/build/generated/jniLibs";

fn main() -> Result<()> {
Expand Down Expand Up @@ -55,7 +55,7 @@ fn run_gradle() -> Result<()> {

fn build_web_artifacts() -> Result<()> {
println!("*** Building desktop web components");
let artifacts_dir = Path::new("rsdroid/build/generated/anki_artifacts/backend");
let artifacts_dir = Path::new("rsdroid-android/build/generated/anki_artifacts/backend");
let mut cmd = if cfg!(windows) {
let mut cmd = Command::new("cmd");
cmd.args(["/c", "tools\\ninja.bat"]);
Expand Down
2 changes: 1 addition & 1 deletion check-droid.bat
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if not exist rsdroid\build\outputs\aar\rsdroid-release.aar (
if not exist rsdroid-android\build\outputs\aar\rsdroid-android-release.aar (
echo "Run ./build.bat first"
exit 1
)
Expand Down
2 changes: 1 addition & 1 deletion check-droid.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -e

test -f rsdroid/build/outputs/aar/rsdroid-release.aar || (
test -f rsdroid-android/build/outputs/aar/rsdroid-android-release.aar || (
echo "Run ./build.sh first"
exit 1
)
Expand Down
6 changes: 3 additions & 3 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ This repo is comprised of three main components:
- `rsdroid` is a Kotlin library that provides a friendly interface to the backend code. The bulk of its code is automatically
generated from the service definitions in `anki/proto/anki`. It also exposes the Rust database functionality
through `SQLHandler`.
- `rsdroid-android` is the Android entry point, published as `anki-backend-android`. It is to be
referenced by `Anki-Android` and package the Android native libraries (`librsdroid.so` for each
supported architecture) and bundle web assets as Android assets. It exposes `rsdroid` through an `api` dependency.
- `rsdroid-android` is the Android entry point, published as `anki-backend-android`. It is
referenced by `Anki-Android`, packages the Android native libraries (`librsdroid.so` for each
supported architecture), and bundles web assets as Android assets. It exposes `rsdroid` through an `api` dependency.

Other folders:

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ android.useAndroidX=true
android.enableJetifier=false

GROUP=io.github.david-allison
VERSION_NAME=0.1.74-anki26.09.3
VERSION_NAME=0.1.75-anki26.09.3

POM_INCEPTION_YEAR=2020

Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ espresso = "3.7.0"
androidGradlePlugin = "9.4.1"
gradleMavenPublishPlugin = "0.37.0"
junit = "6.1.3"
junit4 = "4.13.2"
# https://github.com/JetBrains/kotlin/releases/
kotlin = '2.4.21'
# https://github.com/Kotlin/kotlinx.serialization/releases
Expand Down Expand Up @@ -55,6 +56,7 @@ slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidxTestJunit" }
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
jakewharton-timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
junit4 = { module = "junit:junit", version.ref = "junit4" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junit" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
Expand Down
6 changes: 3 additions & 3 deletions rsdroid-android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Android entry point for the Anki backend. This Android library exposes
[`:rsdroid`](../rsdroid) through an `api` dependency, so consumers can use the
backend API through this module.

## Planned contents
## Contents

After the split, `anki-backend-android` will contain:
`anki-backend-android` contains:

- Android native libraries (`librsdroid.so` for each supported architecture).
- Web assets packaged as Android assets.
- Android SQLite adapters
- Android SQLite adapters
31 changes: 31 additions & 0 deletions rsdroid-android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import com.android.build.gradle.tasks.BundleAar

import java.util.zip.ZipFile

plugins {
alias(libs.plugins.android.library)
id 'signing'
alias(libs.plugins.gradle.maven.publish.plugin)
}

// The Rust build generates the core sources and this module's native libraries and assets.
tasks.named('preBuild').configure { dependsOn(':rsdroid:buildRust') }

android {
namespace = 'net.ankiweb.rsdroid.android'
compileSdk = libs.versions.compileSdk.get().toInteger()
ndkVersion = libs.versions.ndk.get()

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
Expand All @@ -33,6 +41,29 @@ android {
lint {
targetSdk = libs.versions.targetSdk.get().toInteger()
}

sourceSets {
main {
jniLibs.srcDirs 'build/generated/jniLibs'
assets {
srcDirs "build/generated/anki_artifacts"
}
}
}
}

afterEvaluate {
// only the publishable AARs: AGP 9's bundle<Variant>LocalLintAar tasks omit jniLibs
tasks.withType(BundleAar).matching { it.name ==~ /bundle(Debug|Release)Aar/ }.configureEach { bundleAarTask ->
bundleAarTask.doLast {
def aarFile = bundleAarTask.outputs.files.singleFile
def zipFile = new ZipFile(aarFile)
int libCount = zipFile.entries().toList().count { it.name.contains(".so") }
if (libCount == 0 || (System.getenv("ALL_ARCHS") == "1" && libCount != 4)) {
throw new GradleException("AAR appears to be missing shared library!")
}
}
}
}

dependencies {
Expand Down
28 changes: 1 addition & 27 deletions rsdroid/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import com.android.build.gradle.tasks.BundleAar

import java.util.zip.ZipFile

plugins {
alias(libs.plugins.android.library) // required for aar generation to link to from AnkiDroid
id 'signing'
Expand Down Expand Up @@ -33,7 +29,6 @@ androidComponents {
android {
namespace = 'net.ankiweb.rsdroid'
compileSdk = libs.versions.compileSdk.get().toInteger()
ndkVersion = libs.versions.ndk.get()

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
Expand Down Expand Up @@ -65,27 +60,9 @@ android {
main {
kotlin.srcDirs += "build/generated/source/backend"
java.srcDirs += "build/generated/source/backend"
jniLibs.srcDirs 'build/generated/jniLibs'
resources {
srcDirs "src/main/resources"
}
assets {
srcDirs "build/generated/anki_artifacts"
}
}
}
}

afterEvaluate {
// only the publishable AARs: AGP 9's bundle<Variant>LocalLintAar tasks omit jniLibs
tasks.withType(BundleAar).matching { it.name ==~ /bundle(Debug|Release)Aar/ }.configureEach { bundleAarTask ->
bundleAarTask.doLast {
def aarFile = bundleAarTask.outputs.files.singleFile
def zipFile = new ZipFile(aarFile)
int libCount = zipFile.entries().toList().count { it.name.contains(".so") }
if (libCount == 0 || (System.getenv("ALL_ARCHS") == "1" && libCount != 4)) {
throw new GradleException("AAR appears to be missing shared library!")
}
}
}
}
Expand All @@ -99,10 +76,7 @@ dependencies {
implementation libs.androidx.annotation
implementation libs.slf4j.api

testImplementation libs.junit.jupiter
testImplementation libs.robolectric
testImplementation libs.androidx.core
testImplementation libs.androidx.test.junit
testImplementation libs.junit4
testImplementation project(path: ':rsdroid-testing')
}

Expand Down
3 changes: 0 additions & 3 deletions rsdroid/src/test/java/net/ankiweb/BackendCloseRaceTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
package net.ankiweb

import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.long
Expand All @@ -14,7 +13,6 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.concurrent.thread
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
Expand All @@ -27,7 +25,6 @@ import kotlin.time.Duration.Companion.minutes
*
* https://github.com/ankidroid/Anki-Android/issues/21455
*/
@RunWith(AndroidJUnit4::class)
class BackendCloseRaceTest {
@Before
fun loadLibrary() {
Expand Down
23 changes: 23 additions & 0 deletions rsdroid/src/test/java/net/ankiweb/CollectionCreationJvmTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package net.ankiweb

import net.ankiweb.rsdroid.BackendFactory.getBackend
import net.ankiweb.rsdroid.testing.RustBackendLoader.ensureSetup
import org.junit.Assert.assertEquals
import org.junit.Test

/** Verifies collection creation through the backend API on a plain JVM. */
class CollectionCreationJvmTest {
@Test
fun collectionOpensAndAnswersQueries() {
ensureSetup()
getBackend().use { backend ->
backend.openCollection(":memory:")
val response = backend.fullQueryProto("SELECT count(*) FROM col", emptyArray())
assertEquals(1, response.rowCount)
val row = response.result.getRows(0)
assertEquals(1L, row.getFields(0).longValue)
}
}
}
3 changes: 0 additions & 3 deletions rsdroid/src/test/java/net/ankiweb/DbRequestBindingTest.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
package net.ankiweb

import androidx.test.ext.junit.runners.AndroidJUnit4
import anki.ankidroid.SqlValue.DataCase
import net.ankiweb.rsdroid.BackendFactory.getBackend
import net.ankiweb.rsdroid.testing.RustBackendLoader.ensureSetup
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class DbRequestBindingTest {
@Test
fun bindArgumentsKeepTheirSqliteTypesAndValues() {
Expand Down
3 changes: 0 additions & 3 deletions rsdroid/src/test/java/net/ankiweb/FullQueryTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
package net.ankiweb

import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.double
import kotlinx.serialization.json.int
Expand All @@ -19,9 +18,7 @@ import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class FullQueryTest {
@Before
fun loadLibrary() {
Expand Down
Loading