Android установить 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, по-видимому, нам больше не разрешают начинать намерения с file:///, и после некоторого поиска в Google было рекомендовано использовать 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(установить); выдает ошибку
Не найдено действий для обработки Intent { act=android.intent.action.VIEW dat=content://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ=application/vnd.android.package-archive flg=0x4000000 }
Можно ли как-нибудь открыть средство просмотра APK в Android 7 (24)?
5 ответов
После многих попыток я смог решить эту проблему, создав различные 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");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", toInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
activity.startActivity(intent)
} else {
Uri apkUri = Uri.fromFile(toInstall);
Intent 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 Oreo:
Как упомянуто в комментариях @Jasongiss
"Стоит отметить, что начиная с Oreo вы также должны добавить разрешение REQUEST_INSTALL_PACKAGES в свой манифест. В противном случае оно просто молча завершится неудачей".
ОБНОВИТЬ:
Не забудьте запросить разрешения на чтение и запись во внешнее хранилище, если файл, который вы пытаетесь установить, находится во внешнем хранилище. А также настроить правильный 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>
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 вы получаете сообщение об ошибке, наподобие "Есть проблема с анализом пакета". возможно, вы не запросили разрешение на чтение / запись или файл, который вы пытаетесь установить, не существует или поврежден.
У меня была эта проблема при вызове start activity. После приостановки моей текущей активности она внезапно вернулась и вызвала onResume. вроде ничего не произошло. моя проблема заключалась в этом разрешении в манифесте:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
почти никто не упомянул об этом. так что запомни это. в sdk >= 24 вам нужно использовать provider, потому что для него нужно намерение, начинающееся с file:/// ниже sdk 24, вы должны указать uri, начиная с content:///, поэтому нам нужен поставщик файлов для sdk 24 и выше. Я не думаю, что мне нужно писать для этого какие-либо коды, поскольку @just_user написал правильный ответ.
Это может быть проблемой, у вас есть
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
в вашем примере это должно быть
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
как установить имя намерения.
Обратите внимание, что для API < 24 необходимо использовать:
setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive")
вместо того, чтобы устанавливать данные и вводить отдельно:
data = Uri.fromFile(apkFile)
type = "application/vnd.android.package-archive"
в противном случае вы получите ActivityNotFoundException
Для всех тех, кто сталкивается с проблемой "Возникла проблема при синтаксическом анализе этого пакета".
Установите вручную премиссии.
ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
См. этот пример:Загрузите и установите приложение программно .