diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml
new file mode 100644
index 0000000..708fa17
--- /dev/null
+++ b/.github/workflows/publish-android.yml
@@ -0,0 +1,35 @@
+name: Publish Native Android Library
+
+on: workflow_dispatch
+
+jobs:
+ publish-android:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+ - name: set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ - name: Grant execute permission for gradlew
+ run: chmod +x ./gradlew
+ - name: Grant execute permission for publishing script
+ run: chmod +x ./scripts/publish-android.sh
+ - name: Make local props
+ run: |
+ cat << EOF > "local.properties"
+ centralTokenUsername=${{ secrets.ANDROID_CENTRAL_USERNAME }}
+ centralTokenPassword=${{ secrets.ANDROID_CENTRAL_PASSWORD }}
+ sonatypeStagingProfileId=${{ secrets.ANDROID_SONATYPE_STAGING_PROFILE_ID }}
+ signing.keyId=${{ secrets.ANDROID_SIGNING_KEY_ID }}
+ signing.password=${{ secrets.ANDROID_SIGNING_PASSWORD }}
+ signing.key=${{ secrets.ANDROID_SIGNING_KEY }}
+ EOF
+ echo "local.properties file has been created successfully."
+ - name: Run publish script
+ working-directory: ./scripts
+ run: ./publish-android.sh
\ No newline at end of file
diff --git a/.github/workflows/github_actions.yml b/.github/workflows/unit_tests.yml
similarity index 97%
rename from .github/workflows/github_actions.yml
rename to .github/workflows/unit_tests.yml
index b445f27..dc5b779 100644
--- a/.github/workflows/github_actions.yml
+++ b/.github/workflows/unit_tests.yml
@@ -1,4 +1,4 @@
-name: GitHub Actions
+name: Run Unit Tests
on:
workflow_dispatch:
diff --git a/build.gradle b/build.gradle
index 9eeb234..4b75f43 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,14 +4,25 @@ buildscript {
repositories {
google()
mavenCentral()
+ maven {
+ url = uri("https://plugins.gradle.org/m2/")
+ }
}
dependencies {
+ if (System.getenv("SHOULD_PUBLISH") == "true") {
+ classpath("io.github.gradle-nexus:publish-plugin:1.1.0")
+ }
classpath 'com.android.tools.build:gradle:8.7.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jacoco:org.jacoco.core:$jacocoVersion"
}
}
+if (System.getenv("SHOULD_PUBLISH") == "true") {
+ apply plugin: "io.github.gradle-nexus.publish-plugin"
+ apply from: file("./scripts/publish-root.gradle")
+}
+
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
apply plugin: "jacoco"
@@ -65,6 +76,12 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
+
+ publishing {
+ singleVariant("release") {
+ withSourcesJar()
+ }
+ }
}
repositories {
@@ -96,3 +113,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
}
+
+if (System.getenv("SHOULD_PUBLISH") == "true") {
+ apply from: file("./scripts/publish-module.gradle")
+}
diff --git a/docs/LICENSE b/docs/LICENSE
index c2979b0..774efa0 100644
--- a/docs/LICENSE
+++ b/docs/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2022 OutSystems
+Copyright (c) 2025 Ionic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a86319f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,10 @@
+
+
+
+ 4.0.0
+ io.ionic.libs
+ ioncamera-android
+ 0.1.0
+
\ No newline at end of file
diff --git a/scripts/publish-android.sh b/scripts/publish-android.sh
new file mode 100755
index 0000000..38b01a7
--- /dev/null
+++ b/scripts/publish-android.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+ANDROID_PATH=../
+LOG_OUTPUT=./tmp/publish-android.txt
+THE_VERSION=`sed -n 's/.*\(.*\)<\/version>.*/\1/p' ../pom.xml`
+
+# Get latest io.ionic:portals XML version info
+PUBLISHED_URL="https://repo1.maven.org/maven2/io/ionic/libs/ioncamera-android/maven-metadata.xml"
+PUBLISHED_DATA=$(curl -s $PUBLISHED_URL)
+PUBLISHED_VERSION="$(perl -ne 'print and last if s/.*(.*)<\/latest>.*/\1/;' <<< $PUBLISHED_DATA)"
+
+if [[ "$THE_VERSION" == "$PUBLISHED_VERSION" ]]; then
+ printf %"s\n\n" "Duplicate: a published version exists for $THE_VERSION, skipping..."
+else
+ # Make log dir if doesnt exist
+ mkdir -p ./tmp
+
+ # Export ENV variable used by Gradle for Versioning
+ export THE_VERSION
+ export SHOULD_PUBLISH=true
+
+ printf %"s\n" "Attempting to build and publish version $THE_VERSION"
+ # Publish a release to the Maven repo
+ "$ANDROID_PATH"/gradlew clean build publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --no-daemon --max-workers 1 -b "$ANDROID_PATH"/build.gradle -Pandroid.useAndroidX=true > $LOG_OUTPUT 2>&1
+ # Stage a version
+ # "$ANDROID_PATH"/gradlew clean build publishReleasePublicationToSonatypeRepository --no-daemon --max-workers 1 -b "$ANDROID_PATH"/build.gradle -Pandroid.useAndroidX=true > $LOG_OUTPUT 2>&1
+
+ echo $RESULT
+
+ if grep --quiet "BUILD SUCCESSFUL" $LOG_OUTPUT; then
+ printf %"s\n" "Success: Published to MavenCentral."
+ else
+ printf %"s\n" "Error publishing, check $LOG_OUTPUT for more info! Manually review and release from the Central Portal may be necessary https://central.sonatype.com/publishing/deployments/"
+ cat $LOG_OUTPUT
+ exit 1
+ fi
+
+fi
\ No newline at end of file
diff --git a/scripts/publish-module.gradle b/scripts/publish-module.gradle
new file mode 100644
index 0000000..2c08b84
--- /dev/null
+++ b/scripts/publish-module.gradle
@@ -0,0 +1,62 @@
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+def LIB_VERSION = System.getenv('THE_VERSION')
+
+group = 'io.ionic.libs'
+version = LIB_VERSION
+
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ // Coordinates
+ groupId 'io.ionic.libs'
+ artifactId 'ioncamera-android'
+ version LIB_VERSION
+
+ // Two artifacts, the `aar` (or `jar`) and the sources
+ if (project.plugins.findPlugin("com.android.library")) {
+ from components.release
+ } else {
+ artifact("$buildDir/libs/${project.getName()}-${version}.jar")
+ }
+
+ // POM Data
+ pom {
+ name = 'ioncamera-android'
+ description = 'Camera Android Lib'
+ url = 'https://github.com/ionic-team/ion-android-camera'
+ licenses {
+ license {
+ name = 'License'
+ url = 'https://github.com/ionic-team/ion-android-camera/blob/main/docs/LICENSE'
+ }
+ }
+ developers {
+ developer {
+ name = 'Ionic'
+ email = 'hi@ionic.io'
+ }
+ }
+
+ // Version Control Info
+ scm {
+ connection = 'scm:git:github.com:ionic-team/ion-android-camera.git'
+ developerConnection = 'scm:git:ssh://github.com:ionic-team/ion-android-camera.git'
+ url = 'https://github.com/ionic-team/ion-android-camera/tree/main'
+ }
+ }
+ }
+ }
+ }
+
+ signing {
+ useInMemoryPgpKeys(
+ rootProject.ext["signing.keyId"],
+ rootProject.ext["signing.key"],
+ rootProject.ext["signing.password"],
+ )
+ sign publishing.publications
+ }
+}
\ No newline at end of file
diff --git a/scripts/publish-root.gradle b/scripts/publish-root.gradle
new file mode 100644
index 0000000..1270cd3
--- /dev/null
+++ b/scripts/publish-root.gradle
@@ -0,0 +1,37 @@
+// Create variables with empty default values
+ext["signing.keyId"] = ''
+ext["signing.key"] = ''
+ext["signing.password"] = ''
+ext["centralTokenUsername"] = ''
+ext["centralTokenPassword"] = ''
+ext["sonatypeStagingProfileId"] = ''
+
+File secretPropsFile = file('./local.properties')
+if (secretPropsFile.exists()) {
+ // Read local.properties file first if it exists
+ Properties p = new Properties()
+ new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
+ p.each { name, value -> ext[name] = value }
+} else {
+ // Use system environment variables
+ ext["centralTokenUsername"] = System.getenv('ANDROID_CENTRAL_USERNAME')
+ ext["centralTokenPassword"] = System.getenv('ANDROID_CENTRAL_PASSWORD')
+ ext["sonatypeStagingProfileId"] = System.getenv('ANDROID_SONATYPE_STAGING_PROFILE_ID')
+ ext["signing.keyId"] = System.getenv('ANDROID_SIGNING_KEY_ID')
+ ext["signing.key"] = System.getenv('ANDROID_SIGNING_KEY')
+ ext["signing.password"] = System.getenv('ANDROID_SIGNING_PASSWORD')
+}
+
+// Set up Sonatype repository
+nexusPublishing {
+ repositories {
+ sonatype {
+ stagingProfileId = sonatypeStagingProfileId
+ username = centralTokenUsername
+ password = centralTokenPassword
+ nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
+ snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
+ }
+ }
+ repositoryDescription = 'IONCamera Android Lib v' + System.getenv('THE_VERSION')
+}
\ No newline at end of file
diff --git a/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRError.kt b/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRError.kt
index c861097..9928996 100644
--- a/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRError.kt
+++ b/src/main/kotlin/io/ionic/libs/ioncameralib/model/IONCAMRError.kt
@@ -11,15 +11,15 @@ enum class IONCAMRError(val code: Int, val description: String) {
EDIT_CANCELLED_ERROR(13, "Couldn't edit photo because the process was canceled."),
CAPTURE_VIDEO_ERROR(16, "Couldn't record video."),
CAPTURE_VIDEO_CANCELLED_ERROR(17, "Couldn't record video because the process was canceled."),
- GENERIC_CHOOSE_MULTIMEDIA_ERROR(19, "Couldn't choose media from the gallery."),
- CHOOSE_MULTIMEDIA_CANCELLED_ERROR(21, "Couldn't choose media from the gallery because the process was canceled."),
- MEDIA_PATH_ERROR(22, "Couldn't get media file path."),
- PLAY_VIDEO_GENERAL_ERROR(24, "Couldn't play video."),
- EDIT_PICTURE_EMPTY_URI_ERROR(25, "URI parameter cannot be empty."),
- FILE_DOES_NOT_EXIST_ERROR(28, "The selected file doesn't exist."),
- FETCH_IMAGE_FROM_URI_ERROR(29, "Couldn't retrieve image from the URI."),
- INVALID_ARGUMENT_ERROR(32, "Invalid argument provided to plugin method."),
+ GENERIC_CHOOSE_MULTIMEDIA_ERROR(18, "Couldn't choose media from the gallery."),
+ CHOOSE_MULTIMEDIA_CANCELLED_ERROR(20, "Couldn't choose media from the gallery because the process was canceled."),
+ MEDIA_PATH_ERROR(21, "Couldn't get media file path."),
+ PLAY_VIDEO_GENERAL_ERROR(23, "Couldn't play video."),
+ EDIT_PICTURE_EMPTY_URI_ERROR(24, "URI parameter cannot be empty."),
+ FILE_DOES_NOT_EXIST_ERROR(27, "The selected file doesn't exist."),
+ FETCH_IMAGE_FROM_URI_ERROR(28, "Couldn't retrieve image from the URI."),
+ INVALID_ARGUMENT_ERROR(31, "Invalid argument provided to plugin method."),
// Overall Android specific
- CONTEXT_ERROR(34, "Unable to get the context.")
+ CONTEXT_ERROR(33, "Unable to get the context.")
}
\ No newline at end of file