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("tera-soft:tera-sdk-beauty:1.1.0")
}
That's the only tera-soft:* 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(input: BeautyInput) {
// 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)
.setThemeMode(ThemeMode.DARK) // DARK (default) / LIGHT / SYSTEM — see Step 4
.build()
// 3) Build the intent and launch
BeautyEditing.getClient(options)
.getStartEditingIntent(this, input)
.addOnSuccessListener { editorLauncher.launch(IntentSenderRequest.Builder(it).build()) }
.addOnFailureListener { e -> Log.e("Beauty", "Failed to build editor intent", e) }
}
}
Passing the input image — BeautyInput
The input is a BeautyInput. Build it with the factory matching your source:
BeautyInput.fromUri(uri) // content:// , file:// or a path — used as-is (no copy)
BeautyInput.fromFile(file) // a File on disk — used as-is
BeautyInput.fromBitmap(bitmap) // in-memory bitmap (e.g. an AI-generated image) — encoded to PNG
BeautyInput.fromByteArray(bytes)// encoded image bytes (e.g. a network/AI response) — written verbatim
The editor is a separate Activity that must survive process death, so in-memory inputs
(fromBitmap / fromByteArray) are materialized to a private cache file by the SDK for you —
you no longer copy anything by hand. fromUri / fromFile pass through untouched.
// System picker → content:// . Hand it straight to the editor:
launchEditor(BeautyInput.fromUri(pickedContentUri))
// Already have a generated Bitmap? No cache dance needed:
launchEditor(BeautyInput.fromBitmap(generatedBitmap))
For a
content://from another app, make sure it is still readable when the editor launches (a short-lived picker grant can expire). If in doubt, copy into your cache and useBeautyInput.fromFile(...). A legacygetStartEditingIntent(activity, inputUri)overload is also kept for backward compatibility.
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.
Step 5 (optional) — Light / Dark theme
The editor ships both palettes; pick which one renders with setThemeMode(...):
val options = BeautyEditorOptions.Builder()
.setThemeMode(ThemeMode.SYSTEM) // follow the device's day/night setting
.build()
| Mode | Behaviour |
|---|---|
ThemeMode.DARK |
Always dark — the SDK's original look. Default (existing integrations unchanged). |
ThemeMode.LIGHT |
Always light. |
ThemeMode.SYSTEM |
Follows the device's dark/light setting. |
The mode is chosen at runtime — not by the device unless you pass SYSTEM. To recolor either palette
to your brand, see theming-guide.md (values/ = light, values-night/ = dark).