带有 Intent.VIEW_ACTION 的 Android 安装 apk 不适用于文件提供程序 [英] Android install apk with Intent.VIEW_ACTION not working with File provider

查看:36
本文介绍了带有 Intent.VIEW_ACTION 的 Android 安装 apk 不适用于文件提供程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用有一个自动更新功能,可以下载一个 APK,下载完成后,一个 Intent.VIEW_ACTION 打开应用并让用户安装下载的 APK

My app has an auto-update feature that download an APK and when the download is finished that a Intent.VIEW_ACTION to open the app and let the user install the downloaded apk

Uri uri = Uri.parse("file://" + destination);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(uri,
    manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);

这适用于所有设备<24

This works great for all the device < 24

现在使用 Android 24 显然我们不再允许使用 file:///启动意图,经过一些谷歌搜索后,建议使用 A File Provider

Now with Android 24 apparently we are not allowed any more to start intents with file:/// and after some googling it was advised to use A File Provider

新代码:

Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri apkUri = FileProvider.getUriForFile(AutoUpdate.this,
    BuildConfig.APPLICATION_ID + ".provider", file);
install.setDataAndType(apkUri,
    manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);

现在activity.startActivity(安装);抛出错误

Now activity.startActivity(install); throws an error

没有找到处理 Intent { act=android.intent.action.VIEW 的活动dat=content://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apktyp=application/vnd.android.package-archive flg=0x4000000 }

No Activity found to handle Intent { act=android.intent.action.VIEW dat=content://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ=application/vnd.android.package-archive flg=0x4000000 }

有什么办法可以在 Android 7 (24) 中打开 APK 查看器吗?

Is there any way I can open the APK viewer in Android 7 (24) ?

推荐答案

经过多次尝试,我已经能够通过为低于 Nougat 的任何内容创建不同的 Intent 来解决这个问题,就像使用 FileProvider 创建 Android 版本的安装 Intent在牛轧糖导致错误之前:

After a lot of trying I have been able to solve this by creating different Intents for anything lower than Nougat as using the FileProvider to create an install intent with Android Versions before Nougat causes the error:

ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }

在 Android Nougat 上使用普通 Uri 会产生以下错误:

While using a normal Uri on Android Nougat creates the following error:

FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()

我的解决方案适用于模拟器上的 Android N 和运行 Android M 的手机.

My solution which is working for me with Android N on the emulator and a phone running Android M.

File toInstall = new File(appDirectory, appName + ".apk");
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", toInstall);
    intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
    intent.setData(apkUri);
    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
    Uri apkUri = Uri.fromFile(toInstall);
    intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
activity.startActivity(intent);

Android Nougat 7.1 更新:

您还需要在清单中添加权限 REQUEST_INSTALL_PACKAGES.它从 Api 级别 23 (Android 6.0 Marshmallow) 开始可用,从级别 25 (Android 7.1 Nougat) 开始需要.

You also need to add the permission REQUEST_INSTALL_PACKAGES in your manifest. Its available from Api Level 23 (Android 6.0 Marshmallow) and required from Level 25 (Android 7.1 Nougat).

更新:

如果您尝试安装的文件在外部存储上,请记住请求读取和写入外部存储的权限.以及为 Android Nougat 及更高版本设置正确的 FileProvider.

Remember to request the permissions for read and write to external storage if the file you try to install is on the external storage. And also to set up a correct FileProvider for Android Nougat and above.

首先通过调用下面的canReadWriteExternal()检查你是否有写权限,如果没有,则先调用requestPermission():

First check if you have write permission by calling canReadWriteExternal() below, if not call requestPermission() before:

private static final int REQUEST_WRITE_PERMISSION = 786;

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED)
        Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show();
}

private void requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
}

private boolean canReadWriteExternal() {
    return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
            ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}

以下是外部存储上下载文件夹的文件提供程序示例.AndroidManifest.xml:

Here is an example of a file provider for the Download folder on the external storage. AndroidManifest.xml:

<application ... >
    ...

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

resources/xml/filepaths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_download" path="Download"/>
</paths>

如果您在安装 .apk 时遇到错误,提示解析包时出现问题".可能是您没有请求读/写权限,或者您尝试安装的文件不存在或已损坏.

If you get an error while installing the .apk saying something like "There is a problem parsing the package." it could be that you haven't asked for the read/write permission or the file you try to install doesn't exist or is corrupt.

Android Oreo 8.0 更新:

您必须检查当前应用程序是否允许在 Android Oreo 8.0 或更高版本上安装 APK.

You have to check if current application is allowed to install the APK on Android Oreo 8.0 or above.

您可以使用 canRequestPackageInstalls 方法.如果返回 false,则您可以使用 ACTION_MANAGE_UNKNOWN_APP_SOURCES 操作启动 Intent启动设置对话框,用户可以在其中允许应用安装 APK.

You can check if your app is allowed to install APK by using canRequestPackageInstalls method of PackageManager class. If it returns false, then you can launch intent with ACTION_MANAGE_UNKNOWN_APP_SOURCES action to launch settings dialog where user can allow the app to install APKs.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O 
        && !getPackageManager().canRequestPackageInstalls()) {
    Intent unknownAppSourceIntent = new Intent()
            .setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
            .setData(Uri.parse(String.format("package:%s", getPackageName())));

    unknownAppSourceDialog.launch(unknownAppSourceIntent);
} else {
    // App already have the permission to install so launch the APK installation.
    startActivity(intent);
}

确保将以下代码添加到您的活动中以接收意图的结果.

Make sure you add the following code to your activity to receive the result of intent.

ActivityResultLauncher<Intent> unknownAppSourceDialog = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            // User has allowed app to install APKs
            // so we can now launch APK installation.
            startActivity(intent);
        }
    });

这篇关于带有 Intent.VIEW_ACTION 的 Android 安装 apk 不适用于文件提供程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆