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:
- Not as direct as before.
- Good thing is that it might also be possible to handle even files that are outside of the device storage.
- It looks like a workaround, and I'm not sure for how long it will work.
- 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; }}