Skip to content

Commit 81e1bfd

Browse files
committed
feat(android): add AAR package build, release and documentation
1 parent eeb6328 commit 81e1bfd

File tree

12 files changed

+690
-37
lines changed

12 files changed

+690
-37
lines changed

.github/workflows/main.yml

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
build:
1313
runs-on: ${{ matrix.os }}
1414
container: ${{ matrix.container && matrix.container || '' }}
15-
name: ${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} build${{ matrix.arch != 'arm64-v8a' && matrix.name != 'ios-sim' && matrix.name != 'ios' && matrix.name != 'apple-xcframework' && ' + test' || ''}}
15+
name: ${{ matrix.name }}${{ matrix.arch && format('-{0}', matrix.arch) || '' }} build${{ matrix.arch != 'arm64-v8a' && matrix.name != 'ios-sim' && matrix.name != 'ios' && matrix.name != 'apple-xcframework' && matrix.name != 'android-aar' && ' + test' || ''}}
1616
timeout-minutes: 20
1717
strategy:
1818
fail-fast: false
@@ -55,6 +55,9 @@ jobs:
5555
- os: macos-15
5656
name: apple-xcframework
5757
make: xcframework
58+
- os: ubuntu-22.04
59+
name: android-aar
60+
make: aar
5861

5962
defaults:
6063
run:
@@ -69,6 +72,13 @@ jobs:
6972

7073
- uses: actions/[email protected]
7174

75+
- name: android setup java
76+
if: matrix.name == 'android-aar'
77+
uses: actions/setup-java@v4
78+
with:
79+
distribution: 'temurin'
80+
java-version: '17'
81+
7282
- uses: msys2/[email protected]
7383
if: matrix.name == 'windows'
7484
with:
@@ -224,12 +234,67 @@ jobs:
224234
- name: deploy coverage to GitHub Pages
225235
uses: actions/[email protected]
226236

237+
- name: zip artifacts
238+
run: |
239+
VERSION=$(make version)
240+
for folder in "artifacts"/*; do
241+
if [ -d "$folder" ]; then
242+
name=$(basename "$folder")
243+
if [[ "$name" != "github-pages" ]]; then
244+
if [[ "$name" != "cloudsync-apple-xcframework" && "$name" != "cloudsync-android-aar" ]]; then
245+
tar -czf "${name}-${VERSION}.tar.gz" -C "$folder" .
246+
fi
247+
if [[ "$name" != "cloudsync-android-aar" ]]; then
248+
(cd "$folder" && zip -rq "../../${name}-${VERSION}.zip" .)
249+
else
250+
cp "$folder"/*.aar "${name}-${VERSION}.aar"
251+
fi
252+
fi
253+
fi
254+
done
255+
227256
- name: release tag version from cloudsync.h
228257
id: tag
229258
run: |
230259
VERSION=$(make version)
231260
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
232-
LATEST=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r '.name')
261+
LATEST_RELEASE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest)
262+
LATEST=$(echo "$LATEST_RELEASE" | jq -r '.name')
263+
# Check artifact sizes against previous release
264+
if [ -n "$LATEST" ] && [ "$LATEST" != "null" ]; then
265+
echo "Checking artifact sizes against previous release: $LATEST"
266+
FAILED=0
267+
for artifact in cloudsync-*-${VERSION}.*; do
268+
if [ ! -f "$artifact" ]; then
269+
continue
270+
fi
271+
# Get current artifact size
272+
NEW_SIZE=$(stat -c%s "$artifact" 2>/dev/null || stat -f%z "$artifact")
273+
# Get artifact name for previous release
274+
ARTIFACT_NAME=$(echo "$artifact" | sed "s/${VERSION}/${LATEST}/")
275+
# Get previous artifact size from GitHub API
276+
OLD_SIZE=$(echo "$LATEST_RELEASE" | jq -r ".assets[] | select(.name == \"$(basename "$ARTIFACT_NAME")\") | .size")
277+
if [ -z "$OLD_SIZE" ] || [ "$OLD_SIZE" = "null" ]; then
278+
echo "⚠️ Previous artifact not found: $(basename "$ARTIFACT_NAME"), skipping comparison"
279+
continue
280+
fi
281+
# Calculate percentage increase
282+
INCREASE=$(awk "BEGIN {printf \"%.2f\", (($NEW_SIZE - $OLD_SIZE) / $OLD_SIZE) * 100}")
283+
echo "📦 $artifact: $OLD_SIZE → $NEW_SIZE bytes (${INCREASE}% change)"
284+
# Check if increase is more than 5%
285+
if (( $(echo "$INCREASE > 5" | bc -l) )); then
286+
echo "❌ ERROR: $artifact size increased by ${INCREASE}% (limit: 5%)"
287+
FAILED=1
288+
fi
289+
done
290+
if [ $FAILED -eq 1 ]; then
291+
echo ""
292+
echo "❌ One or more artifacts exceeded the 5% size increase limit"
293+
exit 1
294+
fi
295+
echo "✅ All artifacts within 5% size increase limit"
296+
fi
297+
233298
if [[ "$VERSION" != "$LATEST" || "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
234299
echo "version=$VERSION" >> $GITHUB_OUTPUT
235300
else
@@ -261,29 +326,22 @@ jobs:
261326
git commit -m "Bump sqlite-sync version to ${{ steps.tag.outputs.version }}"
262327
git push origin main
263328
264-
- name: zip artifacts
329+
- uses: actions/setup-java@v4
265330
if: steps.tag.outputs.version != ''
266-
run: |
267-
for folder in "artifacts"/*; do
268-
if [ -d "$folder" ]; then
269-
name=$(basename "$folder")
270-
if [[ "$name" != "github-pages" ]]; then
271-
if [[ "$name" != "cloudsync-apple-xcframework" ]]; then
272-
tar -czf "${name}-${{ steps.tag.outputs.version }}.tar.gz" -C "$folder" .
273-
fi
274-
(cd "$folder" && zip -rq "../../${name}-${{ steps.tag.outputs.version }}.zip" .)
275-
fi
276-
fi
277-
done
331+
with:
332+
distribution: 'temurin'
333+
java-version: '17'
334+
335+
- name: release android aar to maven central
336+
if: steps.tag.outputs.version != ''
337+
run: make aar && cd packages/android && ./gradlew publishAggregationToCentralPortal -PSIGNING_KEY="${{ secrets.SIGNING_KEY }}" -PSIGNING_PASSWORD="${{ secrets.SIGNING_PASSWORD }}" -PSONATYPE_USERNAME="${{ secrets.MAVEN_CENTRAL_USERNAME }}" -PSONATYPE_PASSWORD="${{ secrets.MAVEN_CENTRAL_TOKEN }}" -PVERSION="${{ steps.tag.outputs.version }}"
278338

279339
- uses: softprops/[email protected]
280340
if: steps.tag.outputs.version != ''
281341
with:
282342
generate_release_notes: true
283343
tag_name: ${{ steps.tag.outputs.version }}
284344
files: |
285-
cloudsync-*-${{ steps.tag.outputs.version }}.zip
286-
cloudsync-*-${{ steps.tag.outputs.version }}.tar.gz
287-
CloudSync-*-${{ steps.tag.outputs.version }}.zip
288-
CloudSync-*-${{ steps.tag.outputs.version }}.tar.gz
345+
cloudsync-*-${{ steps.tag.outputs.version }}.*
346+
CloudSync-*-${{ steps.tag.outputs.version }}.*
289347
make_latest: true

.gitignore

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
1-
.DS_Store
2-
*.xcworkspacedata
3-
*.xcuserstate
4-
*.xcbkptlist
5-
*.plist
6-
/build
1+
# Build artifacts
2+
build/
3+
/dist
4+
.build
5+
*.a
6+
*.sqlite
7+
/curl/src
78
**/dist/**
9+
10+
# Test artifacts
811
/coverage
9-
*.sqlite
10-
*.a
1112
unittest
12-
/curl/src
13-
.vscode
1413
**/node_modules/**
1514
.env
1615
package-lock.json
17-
.build
16+
17+
# iOS/macOS
18+
*.xcworkspacedata
19+
*.xcuserstate
20+
*.xcbkptlist
21+
*.plist
22+
23+
# Android
24+
.gradle/
25+
*.aar
26+
local.properties
27+
jniLibs/
28+
*.apk
29+
*.ap_
30+
*.dex
31+
32+
# IDE
33+
.vscode
34+
.idea/
35+
*.iml
36+
37+
# System
38+
.DS_Store

Makefile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ $(DIST_DIR)/%.xcframework: $(LIB_NAMES)
346346

347347
xcframework: $(DIST_DIR)/CloudSync.xcframework
348348

349+
AAR_ARM = packages/android/src/main/jniLibs/arm64-v8a/
350+
AAR_X86 = packages/android/src/main/jniLibs/x86_64/
351+
aar:
352+
mkdir -p $(AAR_ARM) $(AAR_X86)
353+
$(MAKE) clean && $(MAKE) PLATFORM=android ARCH=arm64-v8a
354+
mv $(DIST_DIR)/cloudsync.so $(AAR_ARM)
355+
$(MAKE) clean && $(MAKE) PLATFORM=android ARCH=x86_64
356+
mv $(DIST_DIR)/cloudsync.so $(AAR_X86)
357+
cd packages/android && ./gradlew clean assembleRelease
358+
cp packages/android/build/outputs/aar/android-release.aar $(DIST_DIR)/cloudsync.aar
359+
349360
# Tools
350361
version:
351362
@echo $(shell sed -n 's/^#define CLOUDSYNC_VERSION[[:space:]]*"\([^"]*\)".*/\1/p' src/cloudsync.h)
@@ -373,5 +384,7 @@ help:
373384
@echo " clean - Remove built files"
374385
@echo " test [COVERAGE=true] - Test the extension with optional coverage output"
375386
@echo " help - Display this help message"
387+
@echo " xcframework - Build the Apple XCFramework"
388+
@echo " aar - Build the Android AAR package"
376389

377-
.PHONY: all clean test extension help version xcframework
390+
.PHONY: all clean test extension help version xcframework aar

README.md

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ Download the appropriate pre-built binary for your platform from the official [R
116116
- Android
117117
- iOS
118118

119+
### Loading the Extension
120+
121+
```sql
122+
-- In SQLite CLI
123+
.load ./cloudsync
124+
125+
-- In SQL
126+
SELECT load_extension('./cloudsync');
127+
```
128+
119129
### WASM Version
120130

121131
You can download the WebAssembly (WASM) version of SQLite with the SQLite Sync extension enabled from: https://www.npmjs.com/package/@sqliteai/sqlite-wasm
@@ -143,14 +153,84 @@ log("cloudsync_version(): \(String(cString: sqlite3_column_text(stmt, 0)))")
143153
sqlite3_close(db)
144154
```
145155

146-
### Loading the Extension
156+
### Android Package
157+
158+
You can [add this project as a dependency to your Android project](https://central.sonatype.com/artifact/ai.sqlite/sync).
159+
160+
**Groovy:**
161+
```gradle
162+
repositories {
163+
google()
164+
mavenCentral()
165+
maven { url 'https://jitpack.io' }
166+
}
167+
dependencies {
168+
// ...
169+
// Use requery's SQLite instead of Android's built-in SQLite to support loading custom extensions
170+
implementation 'com.github.requery:sqlite-android:3.49.0'
171+
// Both packages below are identical - use either one
172+
implementation 'ai.sqlite:sync:0.8.39' // Maven Central
173+
// implementation 'com.github.sqliteai:sqlite-sync:0.8.39' // JitPack (alternative)
174+
}
175+
```
147176

148-
```sql
149-
-- In SQLite CLI
150-
.load ./cloudsync
177+
**Kotlin:**
178+
```kotlin
179+
repositories {
180+
google()
181+
mavenCentral()
182+
maven(url = "https://jitpack.io")
183+
}
184+
185+
dependencies {
186+
// ...
187+
188+
// Use requery's SQLite instead of Android's built-in SQLite to support loading custom extensions
189+
implementation("com.github.requery:sqlite-android:3.49.0")
190+
// Both packages below are identical - use either one
191+
implementation("ai.sqlite:sync:0.8.39") // Maven Central
192+
// implementation("com.github.sqliteai:sqlite-sync:0.8.39") // JitPack (alternative)
193+
}
194+
```
151195

152-
-- In SQL
153-
SELECT load_extension('./cloudsync');
196+
After adding the package, you'll need to [enable extractNativeLibs](https://github.com/sqliteai/sqlite-extensions-guide/blob/18acfc56d6af8791928f3ac8df7dc0e6a9741dd4/examples/android/src/main/AndroidManifest.xml#L6).
197+
198+
Here's an example of how to use the package:
199+
```java
200+
import android.database.Cursor;
201+
import android.util.Log;
202+
import io.requery.android.database.sqlite.SQLiteCustomExtension;
203+
import io.requery.android.database.sqlite.SQLiteDatabase;
204+
import io.requery.android.database.sqlite.SQLiteDatabaseConfiguration;
205+
import java.util.Collections;
206+
207+
...
208+
209+
private void cloudsyncExtension() {
210+
try {
211+
SQLiteCustomExtension cloudsyncExtension = new SQLiteCustomExtension(getApplicationInfo().nativeLibraryDir + "/cloudsync", null);
212+
SQLiteDatabaseConfiguration config = new SQLiteDatabaseConfiguration(
213+
getCacheDir().getPath() + "/cloudsync_test.db",
214+
SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.OPEN_READWRITE,
215+
Collections.emptyList(),
216+
Collections.emptyList(),
217+
Collections.singletonList(cloudsyncExtension)
218+
);
219+
220+
SQLiteDatabase db = SQLiteDatabase.openDatabase(config, null, null);
221+
222+
Cursor cursor = db.rawQuery("SELECT cloudsync_version()", null);
223+
if (cursor.moveToFirst()) {
224+
String version = cursor.getString(0);
225+
Log.i("sqlite-sync", "cloudsync_version(): " + version);
226+
}
227+
cursor.close();
228+
db.close();
229+
230+
} catch (Exception e) {
231+
Log.e("sqlite-sync", "Error: " + e.getMessage());
232+
}
233+
}
154234
```
155235

156236
## Getting Started

jitpack.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
jdk:
2+
- openjdk17
3+
install:
4+
- make aar ANDROID_NDK=$ANDROID_HOME/ndk-bundle
5+
- export VERSION=$(make version 2>/dev/null | tail -1)
6+
- cd packages/android && ./gradlew publishToMavenLocal -PVERSION="$VERSION"

0 commit comments

Comments
 (0)