md2link

Quick Start — Tera Beauty SDK (15 minutes)

DraftJul 15, 2026

Quick Start — Tera Beauty SDK (15 minutes)

Integrate the on-device Beauty Editor into an existing app: one repository, one dependency, one Activity call. For the full reference see partner-guide.md.


Step 1 — Repository + credentials (the step people get wrong)

The dependency line is trivial; wiring the Artifactory repo with credentials is what trips most consumers. In your settings.gradle.kts:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
        maven {
            url = uri("https://artifactory.apero.vn/artifactory/gradle-release/")
            credentials {
                username = providers.gradleProperty("artifactoryUser").orNull
                    ?: System.getenv("ARTIFACTORY_USER")
                password = providers.gradleProperty("artifactoryPassword").orNull
                    ?: System.getenv("ARTIFACTORY_PASSWORD")
            }
        }
    }
}

Put the credentials in ~/.gradle/gradle.properties (never commit them):

artifactoryUser=<your-user>
artifactoryPassword=<your-token>

Contact the Apero team for credentials.


Step 2 — One dependency

In your app module's build.gradle.kts:

dependencies {
    implementation("apero-inhouse:tera-sdk-beauty:1.0.0")
}

That's the only apero-inhouse:* line you need — the 8 engine artifacts (beauty-core, beauty-renderer, beauty-detection, beauty-face, beauty-body, beauty-adjust, beauty-retouch, beauty-sdk) resolve transitively.

Requirements: minSdk 24, compileSdk 36, Java 11.


Step 3 — Launch the editor and read the result

The API mirrors ML Kit: getClient(options) → build an IntentSender → launch it with StartIntentSenderForResult → parse the result.

class MainActivity : AppCompatActivity() {

    // 1) Launcher that receives the edited image (null Intent = user cancelled).
    private val editorLauncher =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
            val edited = BeautyEditingResult.fromActivityResultIntent(result.data) ?: return@registerForActivityResult
            // edited.imageUri / edited.imagePath — the saved result
            binding.preview.setImageURI(edited.imageUri)
        }

    private fun launchEditor(inputUri: Uri) {
        // 2) Configure
        val options = BeautyEditorOptions.Builder()
            .setEnabledTools(Tool.CROP, Tool.ADJUST, Tool.FACE_EDIT, Tool.BODY, Tool.MAKEUP, Tool.AUTO_RETOUCH)
            .setOutputFormat(OutputFormat.JPEG)
            .setOutputQuality(95)
            .build()

        // 3) Build the intent and launch
        BeautyEditing.getClient(options)
            .getStartEditingIntent(this, inputUri = inputUri)
            .addOnSuccessListener { editorLauncher.launch(IntentSenderRequest.Builder(it).build()) }
            .addOnFailureListener { e -> Log.e("Beauty", "Failed to build editor intent", e) }
    }
}

Passing the input image safely

The editor is a separate Activity, so it must be able to read inputUri on its own:

  • file:// or a plain path → always works.
  • content:// from another app (e.g. the system picker) → copy it into your cache first and pass a file:// uri. The sample's MainActivity does exactly this:
val file = File(cacheDir, "beauty_input_${System.currentTimeMillis()}.jpg")
contentResolver.openInputStream(pickedContentUri)?.use { input ->
    file.outputStream().use { input.copyTo(it) }
}
launchEditor(Uri.fromFile(file))

Step 4 (optional) — Open straight into one tool

To wire a Home-screen "Makeup" button directly to the Makeup tool, keep all tools enabled and set the initial tool:

val options = BeautyEditorOptions.Builder()
    .setInitialTool(Tool.MAKEUP)   // opens on Makeup; closing it returns to the full tool bar
    .build()

null (the default) opens on the full tool bar.


Done

You now have a working integration. Next: