Create Dynamic Links on Android
Create dynamic or unified links programmatically from your Kotlin code using the ULink SDK.
Prerequisites
Before creating links, ensure you've completed the SDK setup:
SDK Integration
- ULink SDK installed and initialized in your app
ULink.initializecalled in yourApplicationclass with valid configuration
ULink Dashboard Configuration
- API key generated from Dashboard → Settings → API Keys → Generate API Key
- Domain configured in your project (Domains → Add Domain)
If you haven't completed these steps, follow the Android Getting Started guide to set up the SDK and configure your project.
Understanding Link Types
Before creating links, understand the difference between the two types:
Unified Links
- Redirect users based on platform (iOS/Android/Desktop)
- Do not carry parameters into the app
- Best for: Marketing campaigns, App Store redirects, simple sharing
- Example use case: Share a link that opens the App Store on iOS, Play Store on Android, or a website on desktop
Dynamic Links
- Include structured parameters for deep linking
- Best for: In-app navigation, personalized content, tracking campaigns
- Example use case: Share a product link that opens directly to that product screen in your app
1. Create Dynamic Links
Dynamic links include parameters that your app can use for navigation and personalization.
Step 1.1: Build Link Parameters
Use the ULinkParameters.dynamic() factory method to create parameters:
val parameters = ULinkParameters.dynamic(
domain = "links.shared.ly", // Your configured domain (required)
slug = "promo-${UUID.randomUUID()}", // Optional: unique identifier
fallbackUrl = "https://example.com", // Web fallback (required)
iosFallbackUrl = "https://apps.apple.com/app/id123", // iOS fallback (App Store)
androidFallbackUrl = "https://play.google.com/store/apps/details?id=com.app", // Android fallback
parameters = mapOf(
"screen" to "promo",
"campaign" to "spring",
"productId" to "12345"
),
socialMediaTags = SocialMediaTags(
ogTitle = "Spring Sale - 50% Off!",
ogDescription = "Don't miss our biggest sale of the year",
ogImage = "https://example.com/sale-image.jpg"
),
metadata = mapOf(
"source" to "mobile_app",
"campaign_id" to "spring2024"
)
)
domain: Must be a domain you've configured in your ULink dashboard. This is required for all link types.fallbackUrl: Required for dynamic links - where users land if the app isn't installed
- Slug: Make it descriptive and unique. If omitted, ULink generates one automatically.
- Parameters: Use these for in-app navigation (e.g.,
screen,productId,userId) - Social Media Tags: Improve link previews when shared on social platforms
- Fallback URLs: Always provide fallbacks so links work even when the app isn't installed
Step 1.2: Create the Link
Call createLink with your parameters. This is a suspend function, so it must be called from a coroutine scope:
lifecycleScope.launch {
try {
val response = ulink.createLink(parameters)
if (response.success && response.url != null) {
Log.d("ULink", "Link created successfully: ${response.url}")
// Share the link or save it for later use
} else {
Log.e("ULink", "Failed to create link: ${response.error ?: "Unknown error"}")
}
} catch (e: Exception) {
Log.e("ULink", "Error creating link: ${e.message}", e)
}
}
Since createLink is a suspend function, you must call it from a coroutine scope:
- In Activities/Fragments: Use
lifecycleScope.launch - In ViewModels: Use
viewModelScope.launch - In other contexts: Use
CoroutineScope(Dispatchers.Main).launchor similar
Always check response.success before using the link. Common errors include:
- Invalid domain configuration
- Slug conflicts: If you use a slug that already exists in your domain, the API will return an error. Each slug must be unique per domain.
- Missing required parameters
- Network errors
If you receive a slug conflict error, either:
- Use a different slug for the new link
- Use the update API endpoint to modify the existing link with that slug
Response Structure
The createLink method returns a ULinkResponse with the following structure:
data class ULinkResponse(
val success: Boolean,
val url: String?, // The created link URL
val error: String?, // Error message if creation failed
val data: JsonElement? // Additional response data
)
Example response:
ULinkResponse(
success = true,
url = "https://links.shared.ly/promo-123abc",
error = null,
data = jsonObject {
put("slug", "promo-123abc")
put("shortUrl", "https://links.shared.ly/promo-123abc")
}
)
2. Create Unified Links
Unified links are simpler - they just redirect based on platform without carrying parameters.
Step 2.1: Build Unified Link Parameters
val parameters = ULinkParameters.unified(
domain = "links.shared.ly",
slug = "app-download", // Optional
iosUrl = "https://apps.apple.com/app/id123", // Required
androidUrl = "https://play.google.com/store/apps/details?id=com.app", // Required
fallbackUrl = "https://example.com", // Required
socialMediaTags = SocialMediaTags(
ogTitle = "Download Our App",
ogDescription = "Get the best experience with our mobile app",
ogImage = "https://example.com/app-preview.jpg"
)
)
iosUrl: Required - where iOS users should be redirectedandroidUrl: Required - where Android users should be redirectedfallbackUrl: Required - where desktop users or fallback cases goparameters: Not supported in unified links (use dynamic links if you need parameters)
Step 2.2: Create the Unified Link
lifecycleScope.launch {
try {
val response = ulink.createLink(parameters)
if (response.success && response.url != null) {
Log.d("ULink", "Unified link created: ${response.url}")
} else {
Log.e("ULink", "Failed to create unified link: ${response.error}")
}
} catch (e: Exception) {
Log.e("ULink", "Error: ${e.message}", e)
}
}
3. Complete Example
Here's a complete example showing how to create and use a dynamic link in an Activity:
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import ly.ulink.sdk.ULink
import ly.ulink.sdk.models.ULinkParameters
import ly.ulink.sdk.models.SocialMediaTags
import java.util.UUID
class MainActivity : AppCompatActivity() {
private lateinit var ulink: ULink
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Get the ULink instance (already initialized in Application class)
ulink = ULink.getInstance()
}
private fun createProductLink(productId: String, productName: String) {
lifecycleScope.launch {
try {
val parameters = ULinkParameters.dynamic(
domain = "links.shared.ly",
slug = "product-$productId",
fallbackUrl = "https://myshop.com/products/$productId",
iosFallbackUrl = "https://apps.apple.com/app/myshop",
androidFallbackUrl = "https://play.google.com/store/apps/details?id=com.myshop",
parameters = mapOf(
"screen" to "product",
"productId" to productId,
"productName" to productName
),
socialMediaTags = SocialMediaTags(
ogTitle = productName,
ogDescription = "Check out $productName in our app",
ogImage = "https://myshop.com/images/$productId.jpg"
)
)
val response = ulink.createLink(parameters)
if (response.success && response.url != null) {
// Share the link
shareLink(response.url!!)
} else {
Log.e("ULink", "Failed to create link: ${response.error}")
showError("Failed to create link: ${response.error}")
}
} catch (e: Exception) {
Log.e("ULink", "Error creating link", e)
showError("Error: ${e.message}")
}
}
}
private fun shareLink(url: String) {
// Implement your sharing logic here
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, url)
}
startActivity(Intent.createChooser(intent, "Share link"))
}
private fun showError(message: String) {
// Show error to user (e.g., Toast, Snackbar)
}
}
Best Practices
Link Creation
- Slugs must be unique: Each slug can only be used once per domain. If you try to create a link with an existing slug, it will return an error. Use unique slugs for each link.
- Validate before sharing: Always check
response.successbefore sharing or storing the link - Handle errors gracefully: Provide user feedback if link creation fails, especially for slug conflicts
- Use descriptive slugs: Make slugs meaningful (e.g.,
product-12345instead of random strings) but ensure they're unique - Use coroutine scope: Always call
createLinkfrom a coroutine scope since it's a suspend function
Social Media Tags
- Always include OG tags: Better link previews improve click-through rates
- Use high-quality images: OG images should be at least 1200x630 pixels
- Write compelling descriptions: Keep descriptions under 200 characters for best display
Parameters
- Keep parameters simple: Use flat key-value pairs for best compatibility
- Avoid sensitive data: Don't put passwords, tokens, or PII in parameters
- Use consistent keys: Establish a naming convention (e.g.,
screen,productId,userId)
Coroutines
- Use appropriate scope: Use
lifecycleScopein Activities/Fragments,viewModelScopein ViewModels - Handle exceptions: Always wrap
createLinkcalls in try-catch blocks - Don't block the UI: Since
createLinkis async, it won't block the main thread
Next Steps
Once you've created links, learn how to handle them when users tap them:
- Receive Links → Android - Handle incoming links in your app
- Troubleshoot & Test Deep Links - Debug and verify your links