Android Getting Started
Install the Android SDK, hook it up to your project, and validate the flow.
1. Prerequisites
Development Environment
- Android Studio Giraffe or newer
- Gradle 8+
- Min SDK 21+
ULink Account Setup
- ULink account and project (create one here)
- API key generated from Dashboard → Settings → API Keys → Generate API Key
- Domain configured in your project (Domains → Add Domain)
2. Add the dependency
Ensure Maven Central is in your repositories:
- Kotlin DSL
- Groovy DSL
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
Add the ULink SDK dependency to your app module:
- Kotlin DSL
- Groovy DSL
dependencies {
implementation("ly.ulink:ulink-sdk:1.0.8")
}
dependencies {
implementation 'ly.ulink:ulink-sdk:1.0.8'
}
3. Configure Deep Links in AndroidManifest.xml
Before initializing the SDK, you need to configure your app to handle incoming links. Android supports two types of deep links:
- Android App Links (e.g.,
https://yourdomain.com) - HTTPS links verified by Android that open your app directly - Custom URL Schemes (e.g.,
myapp://) - Custom schemes that always open your app (no verification required)
Step 3.1: Add Required Permissions
First, add the necessary permissions to your AndroidManifest.xml file:
- Open
app/src/main/AndroidManifest.xmlin your project - Add these permissions inside the
<manifest>tag, before the<application>tag:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
These permissions go at the top level of your manifest, not inside the <application> tag.
Step 3.2: Configure Android App Links (Recommended)
Android App Links are the recommended approach because they work seamlessly and don't show a disambiguation dialog.
- Open
app/src/main/AndroidManifest.xml - Find your main activity (usually
MainActivity) - Add an intent filter with
android:autoVerify="true"inside the activity:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
<!-- Existing launcher intent filter -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Android App Link intent filter -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="links.shared.ly" />
</intent-filter>
</activity>
- Replace
links.shared.lywith the domain you configured in the ULink dashboard - If using a custom domain, use that domain (e.g.,
android:host="yourdomain.com") - The host must match exactly with the domain in your ULink dashboard
- The
android:autoVerify="true"attribute tells Android to verify the domain association
Using android:launchMode="singleTop" ensures that if your app is already running, it reuses the existing activity instance instead of creating a new one. This is important for handling deep links properly.
Step 3.3: Configure Custom URL Scheme (Optional)
If you want to support custom URL schemes (e.g., myapp://path), add an additional intent filter:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
<!-- ... existing intent filters ... -->
<!-- Custom URL scheme intent filter -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>
- Use lowercase letters and numbers only
- Keep it short and memorable (e.g.,
myapp,shop,news) - Avoid special characters or spaces
- If you add a custom scheme, also add it to your ULink dashboard configuration
Step 3.4: Create Application Class and Initialize SDK
Create a custom Application class to initialize the ULink SDK when your app starts.
- Create a new file:
app/src/main/java/com/yourapp/MyApp.kt(or.java) — replacecom.yourappwith your package name - Add the following code:
- Kotlin
- Java (CompletableFuture)
- Java (Callbacks)
package com.yourapp // Replace with your actual package name
import android.app.Application
import ly.ulink.sdk.ULink
import ly.ulink.sdk.models.ULinkConfig
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
ULink.initialize(
context = this,
config = ULinkConfig(
apiKey = "ULINK_API_KEY", // Replace with your API key
baseUrl = "https://api.ulink.ly",
debug = true // Set to false in production
)
)
}
}
package com.yourapp; // Replace with your actual package name
import android.app.Application;
import android.util.Log;
import ly.ulink.sdk.ULink;
import ly.ulink.sdk.models.ULinkConfig;
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
ULinkConfig config = new ULinkConfig(
"ULINK_API_KEY", // Replace with your API key
"https://api.ulink.ly", // Base URL
true, // debug (set to false in production)
true, // enableDeepLinkIntegration
true, // autoCheckDeferredLink
false // persistLastLinkData
);
ULink.initializeAsync(this, config)
.thenAccept(ulink -> {
Log.d("ULink", "SDK initialized successfully");
})
.exceptionally(error -> {
Log.e("ULink", "SDK initialization failed", error);
return null;
});
}
}
package com.yourapp; // Replace with your actual package name
import android.app.Application;
import android.util.Log;
import ly.ulink.sdk.ULink;
import ly.ulink.sdk.models.ULinkConfig;
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
ULinkConfig config = new ULinkConfig(
"ULINK_API_KEY", // Replace with your API key
"https://api.ulink.ly", // Base URL
true, // debug (set to false in production)
true, // enableDeepLinkIntegration
true, // autoCheckDeferredLink
false // persistLastLinkData
);
ULink.initialize(this, config,
ulink -> {
Log.d("ULink", "SDK initialized successfully");
},
error -> {
Log.e("ULink", "SDK initialization failed", error);
}
);
}
}
Register Application Class
- Register your Application class in
AndroidManifest.xml:
<application
android:name=".MyApp"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
...>
<!-- ... rest of your manifest ... -->
</application>
Make sure to add android:name=".MyApp" to your <application> tag in the manifest. Replace MyApp with the actual name of your Application class if different.
Step 3.5: Handle Deep Links in Your Activity (Optional)
If you're using automatic deep link integration (enabled by default), the SDK handles intents automatically. However, if you need manual control or want to handle the initial intent, add this to your MainActivity:
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()
// Handle initial intent if app was opened via deep link
handleIntent(intent)
// Listen to deep link streams
observeDeepLinks()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent) // Update the activity's intent
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
intent?.data?.let { uri ->
ulink.handleDeepLink(uri)
}
}
private fun observeDeepLinks() {
lifecycleScope.launch {
ulink.dynamicLinkStream.collect { linkData ->
// Handle dynamic link data
handleDeepLinkData(linkData)
}
}
lifecycleScope.launch {
ulink.unifiedLinkStream.collect { linkData ->
// Handle unified link data
handleDeepLinkData(linkData)
}
}
}
private fun handleDeepLinkData(data: ULinkResolvedData) {
// Navigate based on link data
// See Receive Links guide for examples
}
}
With enableDeepLinkIntegration = true (the default), the SDK automatically handles deep links. You only need to listen to the streams. The manual handling above is optional and mainly useful for debugging or special cases.
4. Configure Dashboard Settings
Now that your app is configured, you need to match those settings in the ULink dashboard. These settings are required for ULink to generate the Digital Asset Links (assetlinks.json) file that enables Android App Links.
Package Name
Your Package Name uniquely identifies your app on Android and must match exactly between your app and the ULink dashboard.
- Find your package name in one of these locations:
app/build.gradle.ktsasnamespace = "com.yourapp"AndroidManifest.xmlaspackage="com.yourapp"(in the<manifest>tag)
- In the ULink dashboard, go to Configuration → General → Android
- Enter your Package Name in the Package Name field
SHA-256 Certificate Fingerprints
SHA-256 fingerprints are required for Android App Links verification. ULink uses them to generate the Digital Asset Links file that Android uses to verify your app owns the domain.
Get Your Fingerprint
The easiest way is to run this command in your project root:
./gradlew signingReport
Look for the SHA-256 line under your signing configuration. It looks like:
SHA-256: AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99
Alternatively, use keytool directly:
# Debug keystore (for development)
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep SHA-256
# Release keystore (for production)
keytool -list -v -keystore your-release-key.keystore -alias your-alias | grep SHA-256
Add Fingerprints to Dashboard
- In the ULink dashboard, go to Configuration → General → Android
- Click Add Fingerprint in the SHA-256 Fingerprints section
- Paste your SHA-256 fingerprint (with or without colons — ULink normalizes the format automatically)
- Click Add to save the fingerprint
- Repeat for additional fingerprints if needed
You should add fingerprints for all signing keys you use:
- Debug keystore — For development and testing on emulators/devices
- Release keystore — For production builds you distribute directly
- Play App Signing — If you use Google Play App Signing, add the App signing key certificate fingerprint from the Play Console (Setup → App signing)
Without the correct fingerprints, App Links won't work and users will see a disambiguation dialog instead of your app opening directly.
URL Scheme (Optional)
If you configured a custom URL scheme (step 3.3), add it to the dashboard:
- In the ULink dashboard, go to Configuration → General → Android
- Enter your URL Scheme (e.g.,
myapp— notmyapp://)
Domain Configuration
- Navigate to the Domains section in your project
- If you haven't already, add your domain:
- For shared domains: Click Add Domain → Select Shared Domain (.shared.ly) → Enter your subdomain
- For custom domains: Click Add Domain → Enter your custom domain → Complete DNS verification
- Ensure the domain matches exactly what you used in your intent filter's
android:hostattribute (step 3.2)
- The Package Name in the dashboard must match your app's package name exactly
- The SHA-256 Fingerprints must match your app's signing certificates
- The Domain in the dashboard must match the
android:hostvalue in your intent filter - If you added a custom URL scheme, the URL Scheme in the dashboard must match the
android:schemevalue
If any of these don't match, App Links won't work and Android will show a disambiguation dialog instead of opening your app directly.
5. Create a verification link
- Links → Create Link
- Choose Unified (store) or Dynamic (deep link parameters).
- Provide:
- Slug (e.g.
android-test) - Android fallback (Play Store link)
- Optional metadata or custom parameters
- Slug (e.g.
- Save and copy the short URL.
6. Test via ADB or device share
-
Install a build that contains the SDK.
-
Start the app once so it initializes ULink.
-
Trigger the link:
adb shell am start \
-a android.intent.action.VIEW \
-d "https://links.shared.ly/android-test" -
Watch Logcat for
ULink/ULinkBridgemessages and ensure your app receives the resolved data. See Receive Links → Android for handling code.
6.5 Verify with ULink CLI (Recommended)
The ULink CLI provides comprehensive verification of your deep link configuration, checking everything from your manifest to the Asset Links file on your domain.
Install the CLI
- macOS / Linux
- Windows (PowerShell)
curl -fsSL https://ulink.ly/install.sh | bash
irm https://ulink.ly/install.ps1 | iex
Run Verification
# Step 1: Authenticate
ulink login
# Step 2: Link your project directory
cd /path/to/your/android-app
ulink project set
# Step 3: Run verification
ulink verify -v
What the CLI Verifies
The CLI performs a comprehensive check of your Android deep link setup:
| Check | Description |
|---|---|
| SDK dependency | Verifies ly.ulink:ulink-sdk is in your build.gradle |
| AndroidManifest.xml | Validates intent filters and android:autoVerify="true" |
| Asset Links file | Fetches and validates /.well-known/assetlinks.json from your domain |
| Package name | Confirms package name matches between app and dashboard |
| SHA256 fingerprint | Verifies signing key fingerprints are configured correctly |
| App Links status | Checks Android 12+ App Links verification state |
Fixing Issues
The verification report highlights exactly what's misconfigured. Common issues include:
- Missing or incorrect intent filters — Update your
AndroidManifest.xml - SHA256 fingerprint mismatches — Add the correct fingerprints in the ULink dashboard
- Asset Links file problems — Check domain configuration in the dashboard
- Domain verification failures — Ensure the domain matches between manifest and dashboard
Run ulink verify after any changes to your manifest, signing configuration, or dashboard settings to catch issues early.
7. Confirm analytics
- In Links, check that click counts increment.
- Click the Analytics button for that specific link to open its analytics page and ensure the platform is
Androidand geo data populates.
If nothing appears, review your intent filter host/scheme and consult Troubleshoot & Test Deep Links.