Advanced Options
Configure advanced SDK features including install referrer collection, session management, JavaScript integration, and alternative device identifiers for specialized use cases.
Install Referrer Collection (Legacy Devices)
Overview
The install referrer provides accurate attribution by identifying which ad the user clicked before installing your app from Google Play Store.
Deprecated: Google deprecated the
INSTALL_REFERRER intent broadcast. See
Still Using InstallBroadcast? Switch to the Play Referrer API by March 1, 2020.
Modern Singular SDK versions automatically use the
Google Play Referrer API.
Automatic Collection:
On devices with the latest Google Play Store, the Singular SDK collects the install referrer automatically using the Google Play Referrer API. Manual configuration is only needed for legacy device support.
Integrate with Existing Receiver
Forward install referrer data to Singular when your app already has a
BroadcastReceiver for INSTALL_REFERRER.
Implementation:
Add a call to SingularInstallReceiver within your existing
receiver's onReceive method.
class MyCustomInstallReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Forward install referrer to Singular
SingularInstallReceiver().onReceive(context, intent)
// Your existing logic
// ...
}
}
public class MyCustomInstallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Forward install referrer to Singular
new SingularInstallReceiver().onReceive(context, intent);
// Your existing logic
// ...
}
}
Register Singular Receiver
Configure the Singular install referrer receiver when your app doesn't
have an existing INSTALL_REFERRER handler.
AndroidManifest.xml Configuration:
<application>
<!-- Other application components -->
<receiver
android:name="com.singular.sdk.SingularInstallReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
</application>
Recommendation: This configuration is only necessary for apps supporting very old devices. Modern implementations should rely on the automatic Google Play Referrer API integration.
Session Management
Automatic Session Management
The Singular SDK automatically handles session management for Android API 14 (Ice Cream Sandwich) and above without additional configuration.
Default Behavior:
When the app moves to the background for 60 seconds or more, the SDK registers a new session upon returning to the foreground.
Configure Session Timeout
Customize the session timeout duration to match your app's usage patterns.
Method Signature:
SingularConfig.withSessionTimeoutInSec(int timeoutInSeconds)
// Set session timeout to 120 seconds (2 minutes)
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
.withSessionTimeoutInSec(120)
Singular.init(applicationContext, config)
// Set session timeout to 120 seconds (2 minutes)
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET")
.withSessionTimeoutInSec(120);
Singular.init(getApplicationContext(), config);
Timeout Values:
- Default: 60 seconds
- Minimum: 0 seconds (every background/foreground transition creates a new session)
- Recommended: 30-180 seconds depending on app usage patterns
Manual Session Management (API < 14)
For apps with minSdkVersion below 14, manually manage sessions
by calling lifecycle methods in each activity.
Important: Manual session management is only required for apps targeting Android API levels below 14 (Ice Cream Sandwich). Modern apps can skip this section.
Implementation
Call onActivityResumed() and onActivityPaused()
in each activity's lifecycle methods, or implement in a base activity
class.
class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
Singular.onActivityResumed()
// Your other code
}
override fun onPause() {
super.onPause()
Singular.onActivityPaused()
// Your other code
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
Singular.onActivityResumed();
// Your other code
}
@Override
protected void onPause() {
super.onPause();
Singular.onActivityPaused();
// Your other code
}
}
Best Practice: If you have a common base activity
class, implement these calls in the base class's onResume()
and onPause() methods instead of duplicating code across
all activities.
JavaScript Interface for Hybrid Apps
Overview
Enable Singular SDK functionality from JavaScript code in WebView-based
hybrid apps using the SingularJSInterface.
Supported Methods:
- setCustomUserId: Set custom user identifier
- unsetCustomUserId: Remove custom user identifier
- event: Track events with or without attributes
- revenue: Track revenue
Setup WebView Integration
Configure the JavaScript interface in your activity's
onCreate() method for each WebView that needs Singular functionality.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize Singular SDK
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
Singular.init(this, config)
// Configure WebView
val myWebView = findViewById<WebView>(R.id.webview)
myWebView.settings.javaScriptEnabled = true
myWebView.loadUrl("file:///android_asset/index.html")
// Add Singular JavaScript interface
val singularJSInterface = SingularJSInterface(this)
singularJSInterface.setWebViewId(R.id.webview)
myWebView.addJavascriptInterface(singularJSInterface, "SingularInterface")
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize Singular SDK
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET");
Singular.init(this, config);
// Configure WebView
WebView myWebView = findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.loadUrl("file:///android_asset/index.html");
// Add Singular JavaScript interface
SingularJSInterface singularJSInterface = new SingularJSInterface(this);
singularJSInterface.setWebViewId(R.id.webview);
myWebView.addJavascriptInterface(singularJSInterface, "SingularInterface");
}
Multiple WebViews:
- Configure the JavaScript interface for each WebView in your app
- Use the same interface name ("SingularInterface") for consistency
- Set unique WebView IDs for each instance
JavaScript Usage
Call Singular methods from JavaScript code running in your WebView.
Track Events
// Simple event without attributes
SingularInterface.event('level_completed');
// Event with attributes (pass as JSON string)
SingularInterface.event('purchase_attempt',
JSON.stringify({
"item_name": "sword",
"item_category": "weapons",
"item_price": 9.99
})
);
Track Revenue
// Track revenue in USD
SingularInterface.revenue('USD', 9.99);
// Track revenue in other currencies
SingularInterface.revenue('EUR', 8.50);
Manage Custom User ID
// Set custom user ID
SingularInterface.setCustomUserId('user_12345');
// Remove custom user ID
SingularInterface.unsetCustomUserId();
Alternative Device Identifiers
OAID (Open Advertising ID)
Enable tracking on Android devices in regions without Google Play using the Open Advertising Identifier (OAID).
OAID Support:
- Huawei Devices: Huawei's proprietary OAID implementation
- MSA Devices: Mobile Security Alliance member brands (OPPO, Vivo, Xiaomi, etc.)
Prerequisites
Integrate both the MSA SDK and Huawei OAID SDK to collect OAID on all supported platforms.
Enable OAID Collection
Configure the Singular SDK to collect and use OAID for tracking.
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
.withOAIDCollection()
Singular.init(applicationContext, config)
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET")
.withOAIDCollection();
Singular.init(getApplicationContext(), config);
Automatic Detection:
- The SDK automatically detects if the device has an OAID
- The SDK selects the appropriate OAID SDK (MSA or Huawei) based on device
- Amazon Advertising ID (AMID) is collected automatically without additional dependencies
IMEI (International Mobile Equipment Identity)
Collect the device IMEI number for tracking on devices in regions without Google Play Services.
Critical Warning: Collecting IMEI violates Google Play Services agreement. Only use IMEI collection for apps distributed outside Google Play Store in regions without Google services.
Add Required Permission
Add the READ_PHONE_STATE permission to your AndroidManifest.xml.
<manifest>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application>
<!-- Your application components -->
</application>
</manifest>
Retrieve IMEI Number
Obtain the device IMEI using TelephonyManager with proper API level handling.
val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val imei: String? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
telephonyManager.imei
} else {
@Suppress("DEPRECATION")
telephonyManager.deviceId
}
// Validate IMEI before use
if (imei != null && imei.isNotEmpty()) {
// Send to Singular
Log.d("IMEI", "Retrieved: $imei")
} else {
Log.w("IMEI", "Failed to retrieve IMEI")
}
TelephonyManager telephonyManager =
(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String imei = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
imei = telephonyManager.getImei();
} else {
imei = telephonyManager.getDeviceId();
}
// Validate IMEI before use
if (imei != null && !imei.isEmpty()) {
// Send to Singular
Log.d("IMEI", "Retrieved: " + imei);
} else {
Log.w("IMEI", "Failed to retrieve IMEI");
}
Send IMEI to Singular
Configure IMEI during SDK initialization (recommended) or set it dynamically after initialization.
Option 1: Configuration Method (Recommended)
// Set IMEI during initialization
val config = SingularConfig("SDK_KEY", "SDK_SECRET")
.withIMEI(imei)
Singular.init(applicationContext, config)
// Set IMEI during initialization
SingularConfig config = new SingularConfig("SDK_KEY", "SDK_SECRET")
.withIMEI(imei);
Singular.init(getApplicationContext(), config);
Option 2: Runtime Method
// Set IMEI after initialization
Singular.setIMEI(imei)
// Set IMEI after initialization
Singular.setIMEI(imei);
Best Practice: Set IMEI in SingularConfig
before SDK initialization to ensure it's available from the first
session. Use setIMEI() only when the IMEI becomes available
after initialization.