diff --git a/PUBLISHING.md b/PUBLISHING.md
new file mode 100644
index 0000000..884f306
--- /dev/null
+++ b/PUBLISHING.md
@@ -0,0 +1,159 @@
+# GlamAR Android SDK Publishing Guide
+
+This is a minimal guide for publishing the GlamAR Android SDK to Maven Central via Sonatype Central Portal.
+
+## Prerequisites
+
+- Ensure you have the latest version code ready
+- Update the version number in the Gradle build file (`coordinates("io.pixelbin.glamar", "glamar", "1.0.1")`)
+- Create and push a git tag matching the version
+
+## Repository Information
+
+The GlamAR Android SDK is hosted pixelbin Github
+
+```text
+https://github.com/pixelbin-io/glamar-android
+```
+
+## Credentials Setup
+
+### 1. Sonatype Central Portal Credentials
+
+You need a Sonatype Central Portal account with access to the `io.pixelbin.glamar` group ID.
+
+#### Generate Access Tokens (Recommended)
+
+Instead of using your actual username and password, it's recommended to use access tokens:
+
+1. Log in to [Sonatype Central Portal](https://central.sonatype.com/)
+
+## Sonatype ossh and nexus repository manager account details
+Username: pixelbin@dev
+email: dev@pixelbin.io
+password: Captureretail@123
+
+## glamar user token
+
+${server}
+v5Er7V
+p9JDU2TysmZcWzS2Ndne2unbYhiVYzcEX
+
+
+### 2. GPG Signing Key Setup
+
+Maven Central requires all artifacts to be signed with a GPG key.
+
+#### Generate a GPG Key on macOS (if you don't have one)
+
+On macOS, you can use GPG Suite or the command line:
+
+```bash
+# Install GPG if you don't have it
+brew install gnupg
+
+# Generate a key
+gpg --gen-key
+```
+
+Follow the prompts to create a key. Use dev@pixelbin.io email address
+And optional dev@pixelbin as password or you can use your own password but make sure to remember it.
+
+#### Export Your Public Key
+
+```bash
+# List your keys to find your key ID
+gpg --list-keys --keyid-format SHORT
+
+# Export your public key to a keyserver
+gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID
+
+mkdir -p ~/.gnupg
+gpg --export-secret-keys YOUR_KEY_ID > ~/.gnupg/secring.gpg
+ls -l ~/.gnupg/secring.gpg
+
+gpg --export-secret-keys -o ~/Library/Application\ Support/gnupg/secring.gpg
+
+//in case if you cannot find your securing.gpg file
+
+find ~/.gnupg -name "secring.gpg"
+```
+
+Replace `YOUR_KEY_ID` with your GPG key ID (the 8-character ID shown after "pub" in the key listing).
+
+#### Option 1: Configure Signing in Gradle Properties
+
+Create a `~/.gradle/gradle.properties` file with your Sonatype credentials:
+
+```properties
+signing.keyId=your gpg key
+signing.password=dev@pixelbin or your own password
+signing.secretKeyRingFile=/Users/[replace with your mac username]/.gnupg/secring.gpg // or whatever path you stored securing.gpg
+# Sonatype credentials using access tokens
+mavenCentralUsername=v5Er7V
+mavenCentralPassword=p9JDU2TysmZcWzS2Ndne2unbYhiVYzcEX
+```
+
+## Publishing Steps
+
+### 1. Validate the Project
+
+```bash
+./gradlew clean build
+```
+
+Ensure all tests pass and the build completes successfully.
+
+### 2. Publish to Maven Central
+
+```bash
+./gradlew publishToMavenCentral
+```
+
+This command will:
+
+- Build the project
+- Generate the necessary artifacts
+- Sign all artifacts with your GPG key
+- Upload to Sonatype Central Portal
+
+### 3. Release Process
+
+The release process with the vanniktech-maven-publish plugin is automated. After publishing, your artifacts will be automatically released to Maven Central.
+
+If you need to manually check the status:
+
+1. Visit [Sonatype Central Portal](https://central.sonatype.com/)
+2. Log in with your credentials
+3. Navigate to "Deployments" to see your published artifacts
+
+### 4. Verify Publication
+
+After the release process completes (which may take some time), verify your package is available:
+
+```bash
+# Check if your package is available on Maven Central
+curl -s "https://repo1.maven.org/maven2/io/pixelbin/glamar/glamar/1.0.1/"
+```
+
+You can also check the [Maven Central Repository](https://central.sonatype.org/artifact/io.pixelbin.glamar/glamar/) directly.
+
+## Troubleshooting
+
+### Authentication Issues
+
+- Verify your Sonatype credentials are correct
+- Ensure you have permissions to publish to the `io.pixelbin.glamar` group ID
+- Check that your GPG key is properly configured
+
+### Signing Issues
+
+- Verify your GPG key is correctly set up in `gradle.properties`
+- Ensure your GPG key password is correct
+- Try exporting your GPG key again if using GPG 2.1+
+
+### Publication Issues
+
+- Check that all required POM information is provided (already configured in your build file)
+- Ensure all dependencies are correctly specified
+- Verify that your artifacts pass Sonatype's requirements
diff --git a/README.md b/README.md
index f6fdef8..c1e6caa 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ The GlamAR SDK is available on Maven Central. Add the following dependency to yo
```groovy
dependencies {
- implementation 'io.pixelbin.glamar:glamar:1.0.2'
+ implementation 'io.pixelbin.glamar:glamar:2.0.6'
}
```
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e4e85e6..ebeec97 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -4,13 +4,13 @@ plugins {
}
android {
- namespace = "io.pixelbin.galmar.sample"
- compileSdk = 34
+ namespace = "io.pixelbin.glamar.sample"
+ compileSdk = 36
defaultConfig {
- applicationId = "io.pixelbin.galmar.sample"
+ applicationId = "io.pixelbin.glamar.sample"
minSdk = 26
- targetSdk = 34
+ targetSdk = 36
versionCode = 1
versionName = "1.0"
diff --git a/app/src/androidTest/java/io/pixelbin/glamar/sample/ExampleInstrumentedTest.kt b/app/src/androidTest/java/io/pixelbin/glamar/sample/ExampleInstrumentedTest.kt
index 254b0f7..414c332 100644
--- a/app/src/androidTest/java/io/pixelbin/glamar/sample/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/io/pixelbin/glamar/sample/ExampleInstrumentedTest.kt
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("io.pixelbin.galmar.sample", appContext.packageName)
+ assertEquals("io.pixelbin.glamar.sample", appContext.packageName)
}
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 075a389..4047695 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,7 +11,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/Theme.GalmARSample"
+ android:theme="@style/Theme.GlamARSample"
tools:targetApi="31">
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ec7b245..5c31445 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,3 @@
- GalmAR Sample
+ GlamAR Sample
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5fbd428..bc78a8c 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,9 +1,9 @@
-
-
+
\ No newline at end of file
diff --git a/glamar/build.gradle b/glamar/build.gradle
index d11c6a1..5355473 100644
--- a/glamar/build.gradle
+++ b/glamar/build.gradle
@@ -9,10 +9,10 @@ plugins {
android {
namespace 'io.pixelbin.glamar'
- compileSdk 34
+ compileSdk = 36
defaultConfig {
- minSdk 26
+ minSdk = 26
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
@@ -46,7 +46,7 @@ dependencies {
}
mavenPublishing {
- coordinates("io.pixelbin.glamar", "glamar", "1.0.2")
+ coordinates("io.pixelbin.glamar", "glamar", "2.0.6")
pom {
name = "GlamAR"
diff --git a/glamar/src/main/java/io/pixelbin/glamar/GlamAr.kt b/glamar/src/main/java/io/pixelbin/glamar/GlamAr.kt
index 97b78b0..fc90bc8 100644
--- a/glamar/src/main/java/io/pixelbin/glamar/GlamAr.kt
+++ b/glamar/src/main/java/io/pixelbin/glamar/GlamAr.kt
@@ -4,15 +4,23 @@ package io.pixelbin.glamar
import android.annotation.SuppressLint
import android.content.Context
import android.webkit.WebView
+import io.pixelbin.glamar.model.ConfigData
import io.pixelbin.glamar.model.GlamAROverrides
+import org.json.JSONArray
+import org.json.JSONObject
class GlamAr private constructor(val accessKey: String) {
companion object {
@SuppressLint("StaticFieldLeak")
@Volatile
private var instance: GlamAr? = null
- var BASE_URL = "https://cdn.glamar.io/sdk"
- var API_URL = "https://api.pixelbin.io"
+ private const val DEBUG_BASE_URL = "https://cdn.glamar.io/sdk"
+ private const val DEBUG_API_URL = "https://api.pixelbin.io"
+ private const val PRODUCTION_BASE_URL = "https://cdn.glamar.io/sdk"
+ private const val PRODUCTION_API_URL = "https://api.pixelbin.io"
+
+ var BASE_URL = PRODUCTION_BASE_URL
+ var API_URL = PRODUCTION_API_URL
@SuppressLint("SetJavaScriptEnabled")
@@ -24,6 +32,7 @@ class GlamAr private constructor(val accessKey: String) {
debug: Boolean = false,
): GlamAr {
GlamArLogger.init(debug)
+ configureUrls(debug)
// 1) Ensure instance exists BEFORE anything that might call getInstance()
val inst = instance ?: synchronized(this) {
@@ -40,6 +49,11 @@ class GlamAr private constructor(val accessKey: String) {
return inst
}
+ private fun configureUrls(debug: Boolean) {
+ BASE_URL = if (debug) DEBUG_BASE_URL else PRODUCTION_BASE_URL
+ API_URL = if (debug) DEBUG_API_URL else PRODUCTION_API_URL
+ }
+
fun addEventListener(event: String, callback: (Any?) -> Unit) {
GlamArEventManager.addEventListener(event, callback)
}
@@ -60,6 +74,46 @@ class GlamAr private constructor(val accessKey: String) {
fun applyByCategory(category: String) {
evaluateJavascript("window.parent.postMessage({ type: 'applyByCategory' , payload: '${category}' }, '*');")
}
+
+ fun comparison(state: String, skus: List) {
+ val payload = JSONObject()
+ .put("state", state)
+ .put("skus", JSONArray(skus))
+
+ evaluateJavascript("window.parent.postMessage({ type: 'comparison', payload: $payload }, '*');")
+ }
+
+ fun onNailColorEvents(options: String? = null, value: Any? = null) {
+ val payload = JSONObject().apply {
+ options?.let { put("options", it) }
+ value?.let { put("value", JSONObject.wrap(it)) }
+ }
+
+ evaluateJavascript("window.parent.postMessage({ type: 'nailColor', payload: $payload }, '*');")
+ }
+
+ @JvmOverloads
+ fun configChange(
+ type: String,
+ value: Number? = null,
+ skuId: String? = null,
+ subCategory: String? = null
+ ) {
+ val configData = ConfigData(
+ type = type,
+ value = value,
+ skuId = skuId,
+ subCategory = subCategory
+ )
+ val payload = JSONObject().put("type", configData.type)
+
+ configData.value?.let { payload.put("value", it) }
+ configData.skuId?.let { payload.put("skuId", it) }
+ configData.subCategory?.let { payload.put("subCategory", it) }
+
+ evaluateJavascript("window.parent.postMessage({ type: 'onConfigChange', payload: $payload }, '*');")
+ }
+
fun applyByMultipleConfigData(config: (Any?) -> Unit) {
evaluateJavascript("window.parent.postMessage({ type: 'applyByMultipleConfigData' , payload: '${config}' }, '*');")
}
@@ -95,14 +149,24 @@ class GlamAr private constructor(val accessKey: String) {
evaluateJavascript("window.parent.postMessage({ type: 'snapshot'} , '*');")
}
- fun reset() {
- evaluateJavascript("window.parent.postMessage({ type: 'clearSku'} , '*');")
+ @JvmOverloads
+ fun reset(value: Any? = null) {
+ sendClearSku(normalizeClearSkuPayload(value))
}
fun skinAnalysis(options: String) {
evaluateJavascript("window.parent.postMessage({ type: 'skinAnalysis' , payload: { options: '${options}' } }, '*');")
}
+ fun setViewportMirrored(state: Boolean) {
+ val option = if (state == true) "start" else "close"
+ val payload = JSONObject()
+ .put("options", option)
+
+ evaluateJavascript("window.parent.postMessage({ type: 'mirrorMode', payload: $payload }, '*');")
+ }
+
+
fun eyePD(options: String) {
evaluateJavascript("window.parent.postMessage({ type: 'eyePD' , payload: { options: '${options}' } }, '*');")
}
@@ -115,6 +179,65 @@ class GlamAr private constructor(val accessKey: String) {
GlamArWebViewManager.evaluateJavascript(script)
}
+ private fun emitError(message: String) {
+ val payload = JSONObject()
+ .put("message", message)
+
+ GlamArLogger.e("GlamAR", message)
+ GlamArEventManager.dispatchEvent("error", payload)
+ }
+
+ private fun normalizeClearSkuPayload(value: Any?): JSONObject? {
+ if (value == null) return null
+
+ if (value is String) {
+ return if (value.isEmpty()) {
+ null
+ } else {
+ JSONObject().put("subCategory", value)
+ }
+ }
+
+ if (value !is Map<*, *>) return null
+
+ val payload = JSONObject()
+ val subCategory = value["subCategory"]
+ val skuIds = normalizeSkuIds(value["skuIds"])
+
+ if (subCategory is String && subCategory.isNotEmpty()) {
+ payload.put("subCategory", subCategory)
+ }
+
+ if (skuIds != null && skuIds.length() > 0) {
+ payload.put("skuIds", skuIds)
+ }
+
+ return if (payload.length() == 0) null else payload
+ }
+
+ private fun normalizeSkuIds(value: Any?): JSONArray? {
+ val items = when (value) {
+ is Collection<*> -> value.toList()
+ is Array<*> -> value.toList()
+ is JSONArray -> (0 until value.length()).map { value.opt(it) }
+ else -> return null
+ }
+
+ if (items.isEmpty() || items.any { it !is String }) return null
+
+ return JSONArray().apply {
+ items.forEach { put(it) }
+ }
+ }
+
+ private fun sendClearSku(payload: JSONObject?) {
+ if (payload != null) {
+ evaluateJavascript("window.parent.postMessage({ type: 'clearSku', payload: $payload }, '*');")
+ } else {
+ evaluateJavascript("window.parent.postMessage({ type: 'clearSku' }, '*');")
+ }
+ }
+
fun getInstance(): GlamAr {
return instance ?: throw Exception("GlamAR not initialized. Call initialize() first.")
}
diff --git a/glamar/src/main/java/io/pixelbin/glamar/GlamArApi.kt b/glamar/src/main/java/io/pixelbin/glamar/GlamArApi.kt
index 8efb535..5481678 100644
--- a/glamar/src/main/java/io/pixelbin/glamar/GlamArApi.kt
+++ b/glamar/src/main/java/io/pixelbin/glamar/GlamArApi.kt
@@ -8,6 +8,7 @@ import com.google.gson.JsonElement
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
@@ -45,9 +46,15 @@ class GlamArApi(private val accessKey: String, private val development: Boolean
}
- fun getVersion(callback: (Result) -> Unit) {
+ fun getVersion(appId: String? = null, callback: (Result) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
val url = "${GlamAr.API_URL}/service/private/misc/v3.0/sdk-settings/version"
+ .toHttpUrl()
+ .newBuilder()
+ .apply {
+ appId?.takeIf { it.isNotBlank() }?.let { addQueryParameter("appId", it) }
+ }
+ .build()
val request = Request.Builder()
.url(url)
.header(
@@ -174,4 +181,4 @@ private class DateDeserializer : JsonDeserializer {
data class VersionResponse(
val success: Boolean,
val sdkVersion: String?
-)
\ No newline at end of file
+)
diff --git a/glamar/src/main/java/io/pixelbin/glamar/GlamArWebViewManager.kt b/glamar/src/main/java/io/pixelbin/glamar/GlamArWebViewManager.kt
index c17c7ad..52dd3d2 100644
--- a/glamar/src/main/java/io/pixelbin/glamar/GlamArWebViewManager.kt
+++ b/glamar/src/main/java/io/pixelbin/glamar/GlamArWebViewManager.kt
@@ -91,8 +91,9 @@ object GlamArWebViewManager {
val api = GlamArApi(GlamAr.getInstance().accessKey, development = true)
+ val skinAnalysisAppId = overRides?.configuration?.skinAnalysis?.appId
- api.getVersion { result ->
+ api.getVersion(appId = skinAnalysisAppId) { result ->
webView.post {
result
.onSuccess { sdkVersion ->
diff --git a/glamar/src/main/java/io/pixelbin/glamar/model/GlamAROverrides.kt b/glamar/src/main/java/io/pixelbin/glamar/model/GlamAROverrides.kt
index 3eb31d8..fc7b8fa 100644
--- a/glamar/src/main/java/io/pixelbin/glamar/model/GlamAROverrides.kt
+++ b/glamar/src/main/java/io/pixelbin/glamar/model/GlamAROverrides.kt
@@ -42,4 +42,11 @@ data class WatermarkConfig(
data class ARConfig(
val disable3DUI: Boolean? = null
-)
\ No newline at end of file
+)
+
+data class ConfigData(
+ val type: String,
+ val value: Number? = null,
+ val skuId: String? = null,
+ val subCategory: String? = null
+)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d935fc5..2ec2bfc 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,18 +1,18 @@
[versions]
-agp = "8.5.1"
-glamar = "1.0.0"
+agp = "8.9.1"
+glamar = "2.0.6"
glamarAndroid = "main"
-gson = "2.10.1"
-kotlin = "1.9.0"
-coreKtx = "1.10.1"
+gson = "2.11.0"
+kotlin = "2.2.21"
+coreKtx = "1.17.0"
junit = "4.13.2"
-junitVersion = "1.1.5"
-espressoCore = "3.5.1"
-appcompat = "1.6.1"
-material = "1.10.0"
-activity = "1.8.0"
-constraintlayout = "2.1.4"
-okhttp = "4.11.0"
+junitVersion = "1.3.0"
+espressoCore = "3.7.0"
+appcompat = "1.7.1"
+material = "1.13.0"
+activity = "1.11.0"
+constraintlayout = "2.2.1"
+okhttp = "4.12.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -32,4 +32,3 @@ okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }
-
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fb4f5da..e700644 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed Jul 31 15:58:34 IST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/settings.gradle.kts b/settings.gradle.kts
index be70b1c..833cbb5 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -19,6 +19,6 @@ dependencyResolutionManagement {
}
}
-rootProject.name = "GalmAR Sample"
+rootProject.name = "GlamAR Sample"
include(":app")
include(":glamar")