How to open an APK file for all Android versions

霸气de小男生 提交于 2019-12-01 18:08:08

I can just add a check for the version of Android OS, and use either methods, but as I've read, there should be a single method to use: FileProvider.

Well, as the saying goes, "it takes two to tango".

To use any particular scheme (file, content, http, etc.), not only do you have to provide the data in that scheme, but the recipient needs to be able to support accepting the data in that scheme.

In the case of the package installer, support for content as a scheme was only added in Android 7.0 (and then, perhaps only because I pointed out the problem).

Why does it occur?

Because Google (see this and this).

Is there anything wrong with the custom provider I've created?

Probably not.

Should I just add a check if it's Android API 24 and above, and if so, use the provider, and if not, use a normal Uri.fromFile call ?

Yes. Or, if you prefer, catch the ActivityNotFoundException and react to that, or use PackageManager and resolveActivity() to see ahead of time if a given Intent (e.g., one with a content Uri) will work properly.

If I use this, the support library actually loses its purpose, because it will be used for newer Android versions

The "support library" has little to do with newer-vs.-older Android versions. Only a small percentage of the classes across the various Android Support artifacts are backports or compatibility shims. Vast quantities of it — FileProvider, ViewPager, ConstraintLayout, etc. — are simply classes that Google wanted to provide and support but wanted to make them available outside of the firmware.

Will the support library FileProvider be enough for all use cases

Only on Android 7.0+. Again, the stock Android package installer does not support content schemes prior to Android 7.0.

just for those who wonder how to finally install an APK properly, here:

@JvmStatic
fun prepareAppInstallationIntent(context: Context, file: File, requestResult: Boolean): Intent? {
    var intent: Intent? = null
    try {
        intent = Intent(Intent.ACTION_INSTALL_PACKAGE)//
                .setDataAndType(
                        if (VERSION.SDK_INT >= VERSION_CODES.N)
                            androidx.core.content.FileProvider.getUriForFile(context, context.packageName + ".provider", file)
                        else
                            Uri.fromFile(file),
                        "application/vnd.android.package-archive")
                .putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
                .putExtra(Intent.EXTRA_RETURN_RESULT, requestResult)
                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        if (VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN)
            intent!!.putExtra(Intent.EXTRA_ALLOW_REPLACE, true)
    } catch (e: Throwable) {
    }
    return intent
}

manifest

<provider
  android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>
</provider>

/res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
  <!--<external-path name="external_files" path="."/>-->
  <external-path
    name="files_root" path="Android/data/${applicationId}"/>
  <external-path
    name="external_storage_root" path="."/>
</paths>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!