Android load a config file from external Documents directory

1. Create a json file like this, config.json

{
  "environment": "dev"
}

2. Upload this config.json to the Android device

adb push config.json /sdcard/Documents/config.json

3. In Android Studio, click the Device Explorer on the right bottom panel, and check that this file is loaded.

4. Create a new Android Project, and add this permission in the Manifest file. As well as adding this flag to the application tag in the manifest file. android:requestLegacyExternalStorage="true"

    

5. Add these dependencies in the build gradle file.

implementation "androidx.preference:preference-ktx:1.1.0"
implementation 'com.google.code.gson:gson:2.8.6'

6. Create Config.kt

data class Config(val environment: String)

7. Add this id android:id="@+id/tv_result"to the TextView in activity_main.xml

8. Update the MainActivity file with the following code.

import android.Manifest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.Charset
import android.content.pm.PackageManager
import android.os.Environment
import android.os.Environment.getExternalStoragePublicDirectory
import androidx.core.content.ContextCompat
import androidx.core.app.ActivityCompat
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    companion object {
        const val TAG = "MainActivity"

    }

    // /storage/emulated/0/Documents/test.txt or link /sdcard/Documents/config.json
    private var CONFIG_FILE_PATH = "${getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)}/config.json"
    private val REQUEST_PERMISSIONS = 100
    private val PERMISSIONS_REQUIRED = arrayOf(
        Manifest.permission.READ_EXTERNAL_STORAGE
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Log.d(TAG, "CONFIG_FILE_PATH: ${CONFIG_FILE_PATH}")

        if (checkPermission(PERMISSIONS_REQUIRED)) {
            showFileData()
        } else {
            ActivityCompat.requestPermissions(this, PERMISSIONS_REQUIRED, REQUEST_PERMISSIONS)
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        Log.d(TAG, "requestCode: $requestCode")
        Log.d(TAG, "Permissions:" + permissions.contentToString())
        Log.d(TAG, "grantResults: " + grantResults.contentToString())

        if (requestCode == REQUEST_PERMISSIONS) {
            var hasGrantedPermissions = true
            for (i in grantResults.indices) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    hasGrantedPermissions = false
                    break
                }
            }

            if (hasGrantedPermissions) {
                showFileData()
            } else {
                finish()
            }

        } else {
            finish()
        }
    }

    private fun showFileData() {
        val targetFile = File(CONFIG_FILE_PATH)
        val targetFileContent = if (targetFile.exists()) {
            readFile(targetFile)
        } else {
            ""
        }

        val config = Gson().fromJson(targetFileContent, Config::class.java)

        val stringBuilder = StringBuilder()
        stringBuilder.append("\n")
        stringBuilder.append("file location: $CONFIG_FILE_PATH")
        stringBuilder.append("\n")
        stringBuilder.append("file content: $targetFileContent")
        stringBuilder.append("\n")
        stringBuilder.append("environment: ${config.environment}")

        Log.d("file_debug", stringBuilder.toString())
        tv_result.text = stringBuilder.toString()
    }

    private fun readFile(file: File) : String {
        var resultStr = ""
        try {
            val fileInputStream = FileInputStream(file)
            val size = fileInputStream.available()
            val buffer = ByteArray(size)
            fileInputStream.read(buffer)
            resultStr = String(buffer, Charset.forName("UTF-8"))
            fileInputStream.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return resultStr
    }

    private fun checkPermission(permissions: Array): Boolean {
        for (permission in permissions) {
            if (ContextCompat.checkSelfPermission(applicationContext, permission) != PackageManager.PERMISSION_GRANTED) {
                return false
            }
        }
        return true
    }

}

9. Run the app.

10. When asked for file permission, click allow.

Note: This only works for Android 10 or lower, for Android 11, scoped storage is strictly enforced and apps can no longer freely access external directories without using Documents Provider API.

Complete example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search