Developer Guide

Android Deeplink Integration Guide

X-Installer provides a robust deeplink protocol that allows third-party Android applications to seamlessly trigger the installation of complex split-APK formats without requiring root access.

Protocol Overview

Deeplink Schemexinstaller://install?uri=<content_uri>
Target Packagecom.pasta.xinstaller
ExtensionDescriptionHandler
.apkStandard Android PackageSystem default
.xapkSplit APK with OBB dataX-Installer
.apksAndroid App Bundle / AAB exportsX-Installer
.apkmAPKMirror split formatsX-Installer
.zipZIP Archive containing APK filesX-Installer

Environment Configuration

To securely share large APK/XAPK files with X-Installer without triggering FileUriExposedException on Android 7.0+, you must implement FileProvider.

1. Add Dependency

gradle
// File: app/build.gradle
dependencies {
    // Required for FileProvider implementation
    implementation 'androidx.core:core:1.10.1'
}

2. Register FileProvider

xml
<!-- File: AndroidManifest.xml -->
<application>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

3. Define File Paths

xml
<?xml version="1.0" encoding="utf-8"?>
<!-- File: res/xml/file_paths.xml -->
<paths>
    <cache-path name="cache" path="" />
    <files-path name="files" path="" />
</paths>

Core Integration Class (Kotlin)

Copy this helper class directly into your project. It handles format detection, URI conversion, permission granting, and fallback routing to Google Play if the user hasn't installed X-Installer yet.

kotlin
// File: app/src/main/java/com/yourdomain/utils/XInstallerHelper.kt
package com.yourdomain.utils

import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AlertDialog
import androidx.core.content.FileProvider
import java.io.File

class XInstallerHelper(private val context: Context) {

    companion object {
        // Official X-Installer package name
        private const val XINSTALLER_PACKAGE = "com.pasta.xinstaller"
    }

    /**
     * Entry point: Automatically routes the file to the correct installer based on extension.
     */
    fun handleFileInstall(file: File) {
        if (!file.exists() || !file.canRead()) return

        when (file.extension.lowercase()) {
            "apk" -> installApkDirectly(file)
            "xapk", "apks", "apkm", "zip" -> installViaXInstaller(file)
        }
    }

    private fun installViaXInstaller(file: File) {
        if (!isXInstallerInstalled()) {
            showDownloadFallback()
            return
        }

        val contentUri = createContentUri(file) ?: return

        try {
            // 1. Grant temporary read permission to X-Installer
            context.grantUriPermission(
                XINSTALLER_PACKAGE,
                contentUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION
            )

            // 2. Build the official deeplink protocol
            val deeplink = Uri.Builder()
                .scheme("xinstaller")
                .authority("install")
                .appendQueryParameter("uri", contentUri.toString())
                .build()

            // 3. Launch the intent
            val intent = Intent(Intent.ACTION_VIEW, deeplink).apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                setPackage(XINSTALLER_PACKAGE)
            }
            context.startActivity(intent)

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun installApkDirectly(file: File) {
        val uri = createContentUri(file) ?: return
        val intent = Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(uri, "application/vnd.android.package-archive")
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }
        context.startActivity(intent)
    }

    private fun isXInstallerInstalled(): Boolean {
        return try {
            context.packageManager.getPackageInfo(XINSTALLER_PACKAGE, 0)
            true
        } catch (e: PackageManager.NameNotFoundException) {
            false
        }
    }

    private fun createContentUri(file: File): Uri? {
        return try {
            val authority = "${context.packageName}.fileprovider"
            FileProvider.getUriForFile(context, authority, file)
        } catch (e: Exception) {
            null
        }
    }

    private fun showDownloadFallback() {
        AlertDialog.Builder(context)
            .setTitle("X-Installer Required")
            .setMessage("Installing this split APK format requires the official X-Installer. Would you like to download it now?")
            .setPositiveButton("Download from Google Play") { _, _ ->
                val intent = Intent(Intent.ACTION_VIEW).apply {
                    data = Uri.parse("https://play.google.com/store/apps/details?id=$XINSTALLER_PACKAGE")
                }
                context.startActivity(intent)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }
}

Usage Example

Once the helper is added, you can trigger the installation from any Activity or Fragment after your file download completes.

kotlin
// File: app/src/main/java/com/yourdomain/ui/MainActivity.kt

// Example invocation inside your download completion listener
val installerHelper = XInstallerHelper(this)
val downloadedFile = File(cacheDir, "awesome_game.xapk")

installerHelper.handleFileInstall(downloadedFile)

Need Help?

For the latest updates, format support, and advanced integration techniques, contact our team.

support@xapksinstaller.com