Background
My app (here) can scan for APK files throughout the file system, showing information about each, allowing to delete, share, install...
As part of the scoped-storage feature on Android Q, Google announced that SAF (storage access framework) will replace the normal storage permissions. This means that even if you will try to use storage permissions, it will only grant to access to specific types of files for File and file-path to be used or completely be sandboxed (written about here).
This means that a lot of frameworks will need to rely on SAF instead of File and file-path.
The problem
One of them is packageManager.getPackageArchiveInfo , which given a file path, returns PackageInfo , which I can get various information about:
- name (on the current configuration) , AKA "label", using
packageInfo.applicationInfo.loadLabel(packageManager) - package name , using
packageInfo.packageName - version code , using
packageInfo.versionCodeorpackageInfo.longVersionCode. - version number , using
packageInfo.versionName - app icon, using various ways, on the current configuration:
a. BitmapFactory.decodeResource(packageManager.getResourcesForApplication(applicationInfo),packageInfo.applicationInfo.icon, bitmapOptions)
b. if installed, AppCompatResources.getDrawable(createPackageContext(packageInfo.packageName, 0), packageInfo.applicationInfo.icon )
c. ResourcesCompat.getDrawable(packageManager.getResourcesForApplication(applicationInfo), packageInfo.applicationInfo.icon, null)
What I've tried
It's quite easy to use the Uri that I get from SAF and have an InputStream from it :
@TargetApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
packageInstaller = packageManager.packageInstaller
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "application/vnd.android.package-archive"
startActivityForResult(intent, 1)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && requestCode == 1 && resultCode == Activity.RESULT_OK && resultData != null) {
val uri = resultData.data
val inputStream = contentResolver.openInputStream(uri)
But now you are stuck, because all the framework I've seen needs a File or file-path.
I've tried to find any kind of alternative using the Android framework but I couldn't find any. Not only that, but all libraries I've found don't offer such a thing either.
The questions
-
How can I get an APK information (at least the things I've mentioned in the list) out of an InputStream of an APK file?
-
If there is no alternative on the normal framework, where can I find such a thing that will allow it? Is there any popular library that offers it for Android?
Note: Of course I could copy the InputStream to a file and then use it, but this is very inefficient as I will have to do it for every file that I find, and I waste space and time in doing so, because the files already exist.
from How to get information of an APK file without using File or file-path?
No comments:
Post a Comment