Подтвердить что ты не робот

Android install apk с Intent.VIEW_ACTION не работает с поставщиком файлов

В моем приложении есть функция автоматического обновления, которая загружает APK, и когда загрузка завершена, что Intent.VIEW_ACTION откроет приложение и позволит пользователю установить загруженный 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

Теперь, когда Android 24, видимо, нам больше не разрешено начинать с файла:///и после некоторого поиска в Google рекомендуется использовать Поставщик файлов

новый код:

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(install); выдает ошибку

Не найдено никаких действий для обработки Intent {act = android.intent.action.VIEW DAT = содержание://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ = application/vnd.android.package-archive flg = 0x4000000}

Можно ли открыть приложение APK в Android 7 (24)?

4b9b3361

Ответ 1

После долгих попыток я смог решить эту проблему, создав различные Intents для чего-либо ниже Nougat, так как с помощью FileProvider создавал намерение установки с версиями Android до того, как Nougat вызовет ошибку:

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

При использовании обычного Uri на Android Nougat создает следующую ошибку:

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

Мое решение, которое работает для меня с Android N на эмуляторе и телефоном под управлением 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 Level 23 (Android 6.0 Marshmallow) и требуется для Level 25 (Android 7.1 Nougat).

UPDATE:

Не забудьте запросить разрешения на чтение и запись во внешнее хранилище, если файл, который вы пытаетесь установить, находится во внешнем хранилище. А также для настройки правильного FileProvider для Android Nougat и выше.

Сначала проверьте, есть ли у вас разрешение на запись, позвонив canReadWriteExternal() ниже, если нет, позвоните requestPermission() раньше:

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;
}

Вот пример провайдера файлов для папки Download на внешнем хранилище. 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>

ресурсы/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 вы получаете сообщение об ошибке, например "При синтаксическом анализе пакета". возможно, вы не запросили разрешение на чтение/запись или файл, который вы пытаетесь установить, не существует или поврежден.

Ответ 2

Это может быть проблема, у вас есть

intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

в вашем примере это должно быть

install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

поскольку установка - это имя намерения.

Ответ 3

У меня была эта проблема при вызове запуска активности. После приостановки моей текущей активности он неожиданно вернулся и вызвал onResume. как будто ничего не случилось. моя проблема была с этим разрешением в манифесте:

 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

почти никто не упомянул это. так что запомни это. в SDK> = 24 вам нужно использовать провайдера, потому что ему нужно намерение, начиная с файла:/// ниже SDK 24 вы должны указать URI, начиная с содержимого:/// так что зачем нам нужен провайдер файлов для sdk 24 и выше. Я не думаю, что мне нужно писать какие-либо коды для этого, поскольку @just_user написал правильный ответ.

Ответ 4

Обратите внимание, что для API <24 необходимо использовать:

        setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive")

вместо того, чтобы устанавливать данные и вводить отдельно:

data = Uri.fromFile(apkFile)
    type = "application/vnd.android.package-archive"

в противном случае вы получите ActivityNotFoundException

Ответ 5

<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>