# Android : Fix URI Restrictions 🔥

When working with files in Android, we often come across `content://` URIs from file pickers, downloads, or external storage. However, **WebView, third-party libraries, or some APIs might not accept** `content://` URIs directly, which can cause errors such as:

```plaintext
java.lang.IllegalArgumentException: Uri lacks 'file' scheme
```

Android enforces strict **scoped storage policies**, so directly converting `content://` to \[`file://`\](file://) is no longer allowed. Instead, we **use a secure method** to create a **temporary file** and provide access through `FileProvider`.

## **The Problem: Why Can't We Use** `content://` Directly?

Modern Android security policies prevent apps from accessing another app's files **directly**. If we try to use a `content://` URI in WebView or share it externally, we'll often run into:

* SecurityException (Permission Denied)
    
* IllegalArgumentException (URI Lacks 'File' Scheme)
    
* File Not Found Exception
    

To **safely** access and use `content://` URIs, we **convert them into a secure** \[`file://`\](file://) URI using a `FileProvider`.

## **The Solution: Convert** `content://` to a Secure File URI

**→ Step 1: Add** `FileProvider` to AndroidManifest.xml

First, register `FileProvider` inside `<application>`:

```xml
<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/provider_paths" />
</provider>
```

> The `${applicationId}.fileProvider` should match our app's package.

**→ Step 2: Define Secure File Paths**

Create a new XML file `res/xml/provider_paths.xml` to specify **which directories can be accessed**:

```xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path name="cache" path="." />
    <external-files-path name="external_files" path="." />
</paths>
```

> This ensures **only files in cache or external storage** can be shared securely.

**→ Step 3: Convert** `content://` to a Secure URI

Now, use this Kotlin function to safely access any `Uri`:

```kotlin
class FailedToEnableAccessForURI(override val message: String = "Failed to provide access.") : Exception()

fun Uri.grantAppAccess(context: Context): Uri {
    return try {
        // Get the file extension from the original Uri
        val fileExtension = context.contentResolver.getType(this)?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
            ?: "tmp" // Default to "tmp" if the extension cannot be determined

        // Open an input stream for the URI (reads the content of the file)
        val inputStream = context.contentResolver.openInputStream(this)
            ?: throw FailedToEnableAccessForURI("Input stream is null.")

        // Create a temporary file in the app's cache directory with the correct extension
        val tempFile = File(context.cacheDir, "upload_${System.currentTimeMillis()}.$fileExtension")

        // Write the input stream's data to the temporary file
        FileOutputStream(tempFile).use { output ->
            inputStream.copyTo(output)
        }

        // Close the input stream after usage
        inputStream.close()

        // Generate a URI for the temp file using FileProvider
        FileProvider.getUriForFile(context, "${context.packageName}.fileProvider", tempFile)

    } catch (e: Exception) {
        throw FailedToEnableAccessForURI().apply {
            this.stackTrace = e.stackTrace
        }
    }
}
```

**→ Step 4: How to Use It?**

Use this function whenever you need a **secure file URI**:

```kotlin
val secureUri = selectedUri.grantAppAccess(context)
webView.loadUrl(secureUri.toString()) // ✅ No more URI access issues!
```

## **Why This Works?**

* **Bypasses restrictions** on `content://` URIs
    
* **Creates a temporary file** for easy access
    
* **Works with WebView, File Uploads, and Third-party APIs**
    
* **Follows Android security policies** (Scoped Storage, FileProvider)
    

## **What to Keep in Mind if the App is Multi-Modular or Each Module Has Its Own FileProvider**

If our app is **multi-modular**, or each module **has its own FileProvider**, we need to be careful about **URI authority conflicts**. Here’s what we need to consider:

1. ***Each Module Should Have a Unique Authority***
    

If each module registers its own `FileProvider`, the **authority must be unique**.  
For example:

* **Main app (**`com.myapp.main`) → `"com.myapp.main.fileprovider"`
    
* **Module A (**`com.myapp.modulea`) → `"com.myapp.modulea.fileprovider"`
    
* **Module B (**`com.myapp.moduleb`) → `"com.myapp.moduleb.fileprovider"`
    

> If two modules use the **same authority**, the app might **crash** or **fail to resolve URIs**.

2. ***Use the Correct Authority When Generating URIs***
    

If we are calling `FileProvider.getUriForFile()`, we must use the correct authority for the module handling the file:

```kotlin
FileProvider.getUriForFile(context, "com.myapp.modulea.fileprovider", file)
```

> **Do not hardcode the main app’s authority** unless the module explicitly shares its FileProvider.

3. ***Grant URI Permissions Correctly***
    

When sharing a file URI between modules, we **must grant temporary access permissions**:

```kotlin
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
```

Otherwise, the receiving module **won’t be able to read the file**.

4. **Consider a Single Centralized FileProvider**
    

Instead of multiple `FileProviders`, we can define **one** `FileProvider` in the main app and let all modules use it:

* **Declare FileProvider in the Main App (**`com.myapp.main.fileprovider`)
    
* **All modules use** `com.myapp.main.fileprovider` instead of their own
    

> This avoids confusion, duplicate authorities, and makes URI access easier across the app.

5. **Debugging Authority Issues**
    

If we get an error like **"Couldn't find meta-data for provider"**, check:

* **Does the module have its own FileProvider?**
    
* **Are we using the correct authority?**
    
* **Does** `provider_paths.xml` exist in the correct module?
    

### **TL;DR - Best Practices for Multi-Modular Apps**

* **Use unique authorities for each module’s FileProvider**
    
* **Use the correct authority when generating URIs**
    
* **Grant read/write permissions when sharing URIs**
    
* **Consider a single centralized FileProvider to simplify access**
    

With these best practices, we can safely access `Uri` files in Android **without security restrictions**—even in multi-modular apps!

---

That’s for today. Happy Coding…

%%[buymeacoffee-donate]
