How to get information of an APK file in the file system (not just installed ones) without using File or file-path? How to get information of an APK file in the file system (not just installed ones) without using File or file-path? android android

How to get information of an APK file in the file system (not just installed ones) without using File or file-path?


OK I think I found a way using the Android framework (someone on reddit gave me this solution), to use file-path and use it, but it's not perfect at all. Some notes:

  1. Not as direct as before.
  2. Good thing is that it might also be possible to handle even files that are outside of the device storage.
  3. It looks like a workaround, and I'm not sure for how long it will work.
  4. For some reason, I can't load the app label (it always returns just the package name instead), and same goes for the app-icon (always null or default icon).

The solution, in short, is using this:

val fileDescriptor = contentResolver.openFileDescriptor(uri, "r") ?: returnval packageArchiveInfo = packageManager.getPackageArchiveInfo("/proc/self/fd/" + fileDescriptor.fd, 0)

I think this same approach can be used for all cases that you need a file-path.

Here's a sample app (also available here) :

class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        startActivityForResult(                Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)                        .setType("application/vnd.android.package-archive"), 1        )    }    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {        super.onActivityResult(requestCode, resultCode, data)        try {            val uri = data?.data ?: return            val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION            contentResolver.takePersistableUriPermission(uri, takeFlags)            val isDocumentUri = DocumentFile.isDocumentUri(this, uri)            if (!isDocumentUri)                return            val documentFile = DocumentFile.fromSingleUri(this, uri) ?: return            val fileDescriptor = contentResolver.openFileDescriptor(uri, "r") ?: return            val packageArchiveInfo = packageManager.getPackageArchiveInfo("/proc/self/fd/" + fileDescriptor.fd, 0)            Log.d("AppLog", "got APK info?${packageArchiveInfo != null}")            if (packageArchiveInfo != null) {                val appLabel = loadAppLabel(packageArchiveInfo.applicationInfo, packageManager)                Log.d("AppLog", "appLabel:$appLabel")            }        } catch (e: Exception) {            e.printStackTrace()            Log.e("AppLog", "failed to get app info: $e")        }    }    fun loadAppLabel(applicationInfo: ApplicationInfo, packageManager: PackageManager): String =            try {                applicationInfo.loadLabel(packageManager).toString()            } catch (e: java.lang.Exception) {                ""            }    }}


Use below code

/*** Get the apk path of this application.** @param context any context (e.g. an Activity or a Service)* @return full apk file path, or null if an exception happened (it should not happen)*/public static String getApkName(Context context) {    String packageName = context.getPackageName();    PackageManager pm = context.getPackageManager();    try {        ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);        String apk = ai.publicSourceDir;        return apk;    } catch (Throwable x) {        return null;    }}